summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--ast.c63
-rw-r--r--ast.h10
-rw-r--r--eval.c27
-rw-r--r--lib.c89
-rw-r--r--lib/fs.c8
-rw-r--r--lib/math.c2
-rw-r--r--lib/ubus.c4
-rw-r--r--lib/uci.c4
-rw-r--r--module.h6
-rw-r--r--tests/02_runtime/04_switch_case2
-rw-r--r--tests/02_runtime/06_recursion3
11 files changed, 135 insertions, 83 deletions
diff --git a/ast.c b/ast.c
index 126676a..6c9d2da 100644
--- a/ast.c
+++ b/ast.c
@@ -313,8 +313,6 @@ func_to_string(struct json_object *v, struct printbuf *pb, int level, int flags)
return sprintbuf(pb, ") { ... }%s", strict ? "\"" : "");
}
-#define ALIGN(x) (((x) + sizeof(size_t) - 1) & -sizeof(size_t))
-
struct json_object *
ut_new_func(struct ut_state *s, struct ut_op *decl, struct ut_scope *scope)
{
@@ -346,7 +344,7 @@ ut_new_func(struct ut_state *s, struct ut_op *decl, struct ut_scope *scope)
json_object_array_add(fn->args, json_object_get(arg->val));
}
- fn->source = s->source;
+ fn->source = s->function ? s->function->source : NULL;
fn->parent_scope = ut_acquire_scope(scope);
op->val = val;
@@ -371,32 +369,34 @@ exception_to_string(struct json_object *v, struct printbuf *pb, int level, int f
}
static void
-add_stacktrace(struct json_object *a, struct ut_source *source, const char *funcname, size_t off) {
+add_stacktrace(struct json_object *a, struct ut_function *function, size_t off) {
struct json_object *o = xjs_new_object();
size_t line = 1, rlen = 0, len;
bool truncated = false;
char buf[256];
- if (source->filename)
- json_object_object_add(o, "filename", xjs_new_string(source->filename));
+ if (function->source->filename)
+ json_object_object_add(o, "filename", xjs_new_string(function->source->filename));
- if (funcname)
- json_object_object_add(o, "function", xjs_new_string(funcname));
+ if (function->name)
+ json_object_object_add(o, "function", xjs_new_string(function->name));
- fseek(source->fp, 0, SEEK_SET);
+ if (function->source->fp) {
+ fseek(function->source->fp, 0, SEEK_SET);
- while (fgets(buf, sizeof(buf), source->fp)) {
- len = strlen(buf);
- rlen += len;
+ while (fgets(buf, sizeof(buf), function->source->fp)) {
+ len = strlen(buf);
+ rlen += len;
- if (rlen > off) {
- json_object_object_add(o, "line", xjs_new_int64(line));
- json_object_object_add(o, "byte", xjs_new_int64(len - (rlen - off) + (truncated ? sizeof(buf) : 0) + 1));
- break;
- }
+ if (rlen > off) {
+ json_object_object_add(o, "line", xjs_new_int64(line));
+ json_object_object_add(o, "byte", xjs_new_int64(len - (rlen - off) + (truncated ? sizeof(buf) : 0) + 1));
+ break;
+ }
- truncated = (len > 0 && buf[len-1] != '\n');
- line += !truncated;
+ truncated = (len > 0 && buf[len-1] != '\n');
+ line += !truncated;
+ }
}
json_object_array_add(a, o);
@@ -405,7 +405,7 @@ add_stacktrace(struct json_object *a, struct ut_source *source, const char *func
__attribute__((format(printf, 3, 4))) struct json_object *
ut_new_exception(struct ut_state *s, uint32_t off, const char *fmt, ...)
{
- struct ut_callstack *callstack, *prevcall;
+ struct ut_callstack *callstack, *prevcall, here = {};
struct json_object *a;
struct ut_op *op;
va_list ap;
@@ -416,21 +416,19 @@ ut_new_exception(struct ut_state *s, uint32_t off, const char *fmt, ...)
op->type = T_EXCEPTION;
op->val = xjs_new_object();
op->off = off;
- op->tag.data = s->source;
+ op->tag.data = s->function ? s->function->source : s->source;
a = xjs_new_array();
- add_stacktrace(a,
- s->function ? s->function->source : s->source,
- s->function ? s->function->name : NULL,
- off);
+ here.next = s->callstack;
+ here.function = s->function;
+ here.off = off;
- for (callstack = s->callstack ? s->callstack->next : NULL, prevcall = NULL;
- callstack != NULL;
+ for (callstack = &here, prevcall = NULL; callstack != NULL;
prevcall = callstack, callstack = callstack->next)
- if (callstack->off &&
- (!prevcall || callstack->source != prevcall->source || callstack->off != prevcall->off))
- add_stacktrace(a, callstack->source, callstack->funcname, callstack->off);
+ if (callstack->off && callstack->function->source &&
+ (!prevcall || callstack->function != prevcall->function || callstack->off != prevcall->off))
+ add_stacktrace(a, callstack->function, callstack->off);
json_object_object_add(op->val, "stacktrace", a);
@@ -560,7 +558,10 @@ ut_free(struct ut_state *s)
for (src = s->sources; src; src = src_next) {
src_next = src->next;
- fclose(src->fp);
+
+ if (src->fp)
+ fclose(src->fp);
+
free(src->filename);
free(src);
}
diff --git a/ast.h b/ast.h
index 26eee73..e9c8c0c 100644
--- a/ast.h
+++ b/ast.h
@@ -31,6 +31,8 @@
#include <json-c/json.h>
#endif
+#define ALIGN(x) (((x) + sizeof(size_t) - 1) & -sizeof(size_t))
+
#define JSON_C_TO_STRING_STRICT (1<<31)
enum ut_lex_state {
@@ -87,7 +89,10 @@ struct ut_source {
struct ut_function {
char *name;
- struct json_object *args;
+ union {
+ struct json_object *args;
+ void *cfn;
+ };
struct ut_scope *parent_scope;
struct ut_source *source;
uint32_t entry;
@@ -95,10 +100,9 @@ struct ut_function {
struct ut_callstack {
struct ut_callstack *next;
- struct ut_source *source;
+ struct ut_function *function;
struct ut_scope *scope;
struct json_object *ctx;
- char *funcname;
uint32_t off;
};
diff --git a/eval.c b/eval.c
index c0ad2c3..d76af9b 100644
--- a/eval.c
+++ b/eval.c
@@ -975,7 +975,7 @@ ut_invoke(struct ut_state *state, uint32_t off, struct json_object *this,
struct json_object *rv = NULL;
struct ut_scope *sc;
size_t arridx;
- ut_c_fn *cfn;
+ ut_c_fn *fptr;
if (!tag)
return NULL;
@@ -986,32 +986,30 @@ ut_invoke(struct ut_state *state, uint32_t off, struct json_object *this,
return ut_new_exception(state, op->off, "Runtime error: Too much recursion");
callstack.next = state->callstack;
- callstack.source = state->source;
- callstack.funcname = state->function ? state->function->name : NULL;
+ callstack.function = state->function;
callstack.off = op ? op->off : 0;
callstack.ctx = json_object_get(this ? this : state->ctx);
state->callstack = &callstack;
state->calldepth++;
+ fn = tag->tag.data;
+
+ prev_fn = state->function;
+ state->function = fn;
+
/* is native function */
if (tag->type == T_CFUNC) {
- cfn = (ut_c_fn *)tag->tag.data;
- rv = cfn ? cfn(state, off, argvals) : NULL;
+ fptr = (ut_c_fn *)fn->cfn;
+ rv = fptr ? fptr(state, off, argvals) : NULL;
}
/* is utpl function */
else {
- fn = tag->tag.data;
-
callstack.scope = ut_new_scope(state, fn->parent_scope);
sc = state->scope;
-
state->scope = ut_acquire_scope(callstack.scope);
- prev_fn = state->function;
- state->function = fn;
-
if (fn->args)
for (arridx = 0; arridx < json_object_array_length(fn->args); arridx++)
ut_setval(callstack.scope->scope, json_object_array_get_idx(fn->args, arridx),
@@ -1042,9 +1040,10 @@ ut_invoke(struct ut_state *state, uint32_t off, struct json_object *this,
/* ... and release it */
ut_release_scope(callstack.scope);
- state->function = prev_fn;
}
+ state->function = prev_fn;
+
json_object_put(callstack.ctx);
state->callstack = callstack.next;
state->calldepth--;
@@ -1679,11 +1678,15 @@ struct json_object *
ut_run(struct ut_state *state, struct json_object *env, struct json_object *modules)
{
struct json_object *args, *rv;
+ struct ut_function fn = {};
size_t i;
state->scope = ut_new_scope(state, NULL);
state->ctx = NULL;
+ fn.source = state->source;
+ state->function = &fn;
+
if (env) {
json_object_object_foreach(env, key, val)
ut_register_variable(state->scope->scope, key, json_object_get(val));
diff --git a/lib.c b/lib.c
index edcf975..359a8b0 100644
--- a/lib.c
+++ b/lib.c
@@ -112,7 +112,7 @@ format_context_line(char **msg, size_t *msglen, const char *line, size_t off)
static void
format_error_context(char **msg, size_t *msglen, struct ut_source *src, struct json_object *stacktrace, size_t off)
{
- struct json_object *e, *fn, *file;
+ struct json_object *e, *fn, *file, *line, *byte;
size_t len, rlen, idx;
const char *path;
bool truncated;
@@ -144,12 +144,20 @@ format_error_context(char **msg, size_t *msglen, struct ut_source *src, struct j
json_object_get_int64(json_object_object_get(e, "byte")));
}
else {
- sprintf_append(msg, msglen, " at %s%s (%s:%" PRId64 ":%" PRId64 ")\n",
- fn ? "function " : "main function",
+ line = json_object_object_get(e, "line");
+ byte = json_object_object_get(e, "byte");
+
+ sprintf_append(msg, msglen, " called from %s%s (%s",
+ fn ? "function " : "anonymous function",
fn ? json_object_get_string(fn) : "",
- json_object_get_string(file),
- json_object_get_int64(json_object_object_get(e, "line")),
- json_object_get_int64(json_object_object_get(e, "byte")));
+ json_object_get_string(file));
+
+ if (line && byte)
+ sprintf_append(msg, msglen, ":%" PRId64 ":%" PRId64 ")\n",
+ json_object_get_int64(line),
+ json_object_get_int64(byte));
+ else
+ sprintf_append(msg, msglen, " [C])\n");
}
}
@@ -278,27 +286,38 @@ ut_cast_int64(struct json_object *v)
static int
ut_c_fn_to_string(struct json_object *v, struct printbuf *pb, int level, int flags)
{
- return sprintbuf(pb, "%sfunction(...) { [native code] }%s",
- level ? "\"" : "", level ? "\"" : "");
+ struct ut_op *op = json_object_get_userdata(v);
+ struct ut_function *fn = (void *)op + ALIGN(sizeof(*op));
+
+ return sprintbuf(pb, "%sfunction %s(...) { [native code] }%s",
+ level ? "\"" : "", fn->name, level ? "\"" : "");
}
static void
ut_c_fn_free(struct json_object *v, void *ud)
{
- struct ut_op *op = json_object_get_userdata(v);
+ struct ut_op *op = ud;
json_object_put(op->tag.proto);
free(ud);
}
static bool
-ut_register_function(struct json_object *scope, const char *name, ut_c_fn *fn)
+ut_register_function(struct ut_state *state, struct json_object *scope, const char *name, ut_c_fn *cfn)
{
struct json_object *val = xjs_new_object();
- struct ut_op *op = xalloc(sizeof(*op));
+ struct ut_function *fn;
+ struct ut_op *op;
+ op = xalloc(ALIGN(sizeof(*op)) + ALIGN(sizeof(*fn)) + ALIGN(strlen(name) + 1));
op->val = val;
op->type = T_CFUNC;
+
+ fn = (void *)op + ALIGN(sizeof(*op));
+ fn->source = state->function ? state->function->source : NULL;
+ fn->name = strcpy((char *)fn + ALIGN(sizeof(*fn)), name);
+ fn->cfn = cfn;
+
op->tag.data = fn;
json_object_set_serializer(val, ut_c_fn_to_string, op, ut_c_fn_free);
@@ -1513,6 +1532,8 @@ ut_require_so(struct ut_state *s, uint32_t off, const char *path)
{
void (*init)(const struct ut_ops *, struct ut_state *, struct json_object *);
struct ut_op *op = ut_get_op(s, off);
+ struct ut_function fn = {}, *prev_fn;
+ struct ut_source *src, *prev_src;
struct json_object *scope;
struct stat st;
void *dlh;
@@ -1531,10 +1552,26 @@ ut_require_so(struct ut_state *s, uint32_t off, const char *path)
if (!init)
return ut_new_exception(s, op->off, "Module %s provides no 'ut_module_init' function", path);
+ src = xalloc(sizeof(*src));
+ src->filename = xstrdup(path);
+ src->next = s->sources;
+
+ fn.name = "require";
+ fn.source = src;
+
+ prev_fn = s->function;
+ s->function = &fn;
+
+ prev_src = s->source;
+ s->source = s->sources = src;
+
scope = xjs_new_object();
init(&ut, s, scope);
+ s->source = prev_src;
+ s->function = prev_fn;
+
return scope;
}
@@ -1542,10 +1579,6 @@ struct json_object *
ut_execute_source(struct ut_state *s, struct ut_source *src, struct ut_scope *scope)
{
struct json_object *entry, *rv;
- struct ut_source *prev_src;
-
- prev_src = s->source;
- s->source = src;
rv = ut_parse(s, src->fp);
@@ -1558,8 +1591,6 @@ ut_execute_source(struct ut_state *s, struct ut_source *src, struct ut_scope *sc
json_object_put(entry);
}
- s->source = prev_src;
-
return rv;
}
@@ -1567,7 +1598,9 @@ static struct json_object *
ut_require_utpl(struct ut_state *s, uint32_t off, const char *path, struct ut_scope *scope)
{
struct ut_op *op = ut_get_op(s, off);
- struct ut_source *src;
+ struct ut_function fn = {}, *prev_fn;
+ struct ut_source *src, *prev_src;
+ struct json_object *rv;
struct stat st;
FILE *fp;
@@ -1584,9 +1617,21 @@ ut_require_utpl(struct ut_state *s, uint32_t off, const char *path, struct ut_sc
src->filename = path ? xstrdup(path) : NULL;
src->next = s->sources;
- s->sources = src;
+ prev_src = s->source;
+ s->source = s->sources = src;
+
+ fn.name = "require";
+ fn.source = src;
+
+ prev_fn = s->function;
+ s->function = &fn;
- return ut_execute_source(s, src, scope);
+ rv = ut_execute_source(s, src, scope);
+
+ s->function = prev_fn;
+ s->source = prev_src;
+
+ return rv;
}
static struct json_object *
@@ -2096,7 +2141,7 @@ ut_include(struct ut_state *s, uint32_t off, struct json_object *args)
if (scope && !json_object_is_type(scope, json_type_object))
return ut_new_exception(s, op->off, "Passed scope value is not an object");
- p = include_path(s->source->filename, json_object_get_string(path));
+ p = include_path(s->callstack->function->source->filename, json_object_get_string(path));
if (!p)
return ut_new_exception(s, op->off, "Include file not found");
@@ -2198,5 +2243,5 @@ ut_lib_init(struct ut_state *state, struct json_object *scope)
int i;
for (i = 0; i < sizeof(functions) / sizeof(functions[0]); i++)
- ut_register_function(scope, functions[i].name, functions[i].func);
+ ut_register_function(state, scope, functions[i].name, functions[i].func);
}
diff --git a/lib/fs.c b/lib/fs.c
index 9e15111..f8888c5 100644
--- a/lib/fs.c
+++ b/lib/fs.c
@@ -726,10 +726,10 @@ void ut_module_init(const struct ut_ops *ut, struct ut_state *s, struct json_obj
file_proto = ops->new_object(NULL);
dir_proto = ops->new_object(NULL);
- register_functions(ops, global_fns, scope);
- register_functions(ops, proc_fns, proc_proto);
- register_functions(ops, file_fns, file_proto);
- register_functions(ops, dir_fns, dir_proto);
+ register_functions(s, ops, global_fns, scope);
+ register_functions(s, ops, proc_fns, proc_proto);
+ register_functions(s, ops, file_fns, file_proto);
+ register_functions(s, ops, dir_fns, dir_proto);
ops->register_type("fs.proc", proc_proto, close_proc);
ops->register_type("fs.file", file_proto, close_file);
diff --git a/lib/math.c b/lib/math.c
index 37bd33f..efbc21c 100644
--- a/lib/math.c
+++ b/lib/math.c
@@ -181,5 +181,5 @@ void ut_module_init(const struct ut_ops *ut, struct ut_state *s, struct json_obj
{
ops = ut;
- register_functions(ops, global_fns, scope);
+ register_functions(s, ops, global_fns, scope);
}
diff --git a/lib/ubus.c b/lib/ubus.c
index 21f7a7b..b707e51 100644
--- a/lib/ubus.c
+++ b/lib/ubus.c
@@ -320,8 +320,8 @@ void ut_module_init(const struct ut_ops *ut, struct ut_state *s, struct json_obj
ops = ut;
conn_proto = ops->new_object(NULL);
- register_functions(ops, global_fns, scope);
- register_functions(ops, conn_fns, conn_proto);
+ register_functions(s, ops, global_fns, scope);
+ register_functions(s, ops, conn_fns, conn_proto);
ops->register_type("ubus.connection", conn_proto, close_connection);
}
diff --git a/lib/uci.c b/lib/uci.c
index 6a40df5..a56531a 100644
--- a/lib/uci.c
+++ b/lib/uci.c
@@ -1023,8 +1023,8 @@ void ut_module_init(const struct ut_ops *ut, struct ut_state *s, struct json_obj
ops = ut;
uci_proto = ops->new_object(NULL);
- register_functions(ops, global_fns, scope);
- register_functions(ops, cursor_fns, uci_proto);
+ register_functions(s, ops, global_fns, scope);
+ register_functions(s, ops, cursor_fns, uci_proto);
ops->register_type("uci.cursor", uci_proto, close_uci);
}
diff --git a/module.h b/module.h
index 77c4f99..ab15893 100644
--- a/module.h
+++ b/module.h
@@ -21,7 +21,7 @@
#include "lib.h"
struct ut_ops {
- bool (*register_function)(struct json_object *, const char *, ut_c_fn *);
+ bool (*register_function)(struct ut_state *, struct json_object *, const char *, ut_c_fn *);
bool (*register_type)(const char *, struct json_object *, void (*)(void *));
struct json_object *(*set_type)(struct json_object *, const char *, void *);
void **(*get_type)(struct json_object *, const char *);
@@ -33,10 +33,10 @@ struct ut_ops {
extern const struct ut_ops ut;
-#define register_functions(ops, functions, scope) \
+#define register_functions(state, ops, functions, scope) \
if (scope) \
for (int i = 0; i < ARRAY_SIZE(functions); i++) \
- ops->register_function(scope, functions[i].name, functions[i].func)
+ ops->register_function(state, scope, functions[i].name, functions[i].func)
void ut_module_init(const struct ut_ops *, struct ut_state *, struct json_object *);
diff --git a/tests/02_runtime/04_switch_case b/tests/02_runtime/04_switch_case
index d3f6c94..0de87dc 100644
--- a/tests/02_runtime/04_switch_case
+++ b/tests/02_runtime/04_switch_case
@@ -243,7 +243,7 @@ one
-- Expect stderr --
Died
In test(), line 6, byte 7:
- at main function ([stdin]:17:12)
+ called from anonymous function ([stdin]:17:12)
` die();`
Near here -----^
diff --git a/tests/02_runtime/06_recursion b/tests/02_runtime/06_recursion
index 028feba..b222640 100644
--- a/tests/02_runtime/06_recursion
+++ b/tests/02_runtime/06_recursion
@@ -40,8 +40,7 @@ Testing recursive invocations.
-- Expect stderr --
Runtime error: Too much recursion
In test(), line 3, byte 7:
- at function test ([stdin]:3:7)
- at main function ([stdin]:6:6)
+ called from anonymous function ([stdin]:6:6)
` test();`
Near here --^