diff options
-rw-r--r-- | ast.c | 63 | ||||
-rw-r--r-- | ast.h | 10 | ||||
-rw-r--r-- | eval.c | 27 | ||||
-rw-r--r-- | lib.c | 89 | ||||
-rw-r--r-- | lib/fs.c | 8 | ||||
-rw-r--r-- | lib/math.c | 2 | ||||
-rw-r--r-- | lib/ubus.c | 4 | ||||
-rw-r--r-- | lib/uci.c | 4 | ||||
-rw-r--r-- | module.h | 6 | ||||
-rw-r--r-- | tests/02_runtime/04_switch_case | 2 | ||||
-rw-r--r-- | tests/02_runtime/06_recursion | 3 |
11 files changed, 135 insertions, 83 deletions
@@ -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); } @@ -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; }; @@ -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)); @@ -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); } @@ -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); @@ -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); } @@ -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); } @@ -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); } @@ -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 --^ |