diff options
author | Jo-Philipp Wich <jo@mein.io> | 2020-10-12 19:49:41 +0200 |
---|---|---|
committer | Jo-Philipp Wich <jo@mein.io> | 2020-10-14 12:09:28 +0200 |
commit | 05cc0ee7a7c7dc442e22dfdc22c0574ac6b3e71b (patch) | |
tree | 16355886feba68f498a723b74a830dda4c5efa84 /eval.c | |
parent | 8b4134e040561c19de733b017c6e2ce5bb49de48 (diff) |
treewide: rework source file and callstack handling
- Keep an open FILE* reference to processed source files in order to
be able to rewind and extract error context later
- Build a proper call stack when invoking utpl functions
- Report call stack in exceptions
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
Diffstat (limited to 'eval.c')
-rw-r--r-- | eval.c | 96 |
1 files changed, 54 insertions, 42 deletions
@@ -977,71 +977,83 @@ struct json_object * ut_invoke(struct ut_state *state, uint32_t off, struct json_object *this, struct json_object *func, struct json_object *argvals) { - struct ut_op *tag = json_object_get_userdata(func); + struct ut_op *op, *tag = json_object_get_userdata(func); + struct ut_callstack callstack = {}; + struct ut_function *fn, *prev_fn; struct json_object *rv = NULL; - struct ut_function *fn; struct ut_scope *sc; - char *filename; size_t arridx; ut_c_fn *cfn; if (!tag) return NULL; + op = ut_get_op(state, off); + + callstack.next = state->callstack; + callstack.source = state->source; + callstack.funcname = state->function ? state->function->name : NULL; + callstack.off = op ? op->off : 0; + state->callstack = &callstack; + /* is native function */ if (tag->type == T_CFUNC) { cfn = (ut_c_fn *)tag->tag.data; - - return cfn ? cfn(state, off, argvals) : NULL; + rv = cfn ? cfn(state, off, argvals) : NULL; } - fn = tag->tag.data; - fn->scope = ut_new_scope(state, fn->parent_scope); - fn->scope->ctx = json_object_get(this ? this : state->ctx); + /* is utpl function */ + else { + fn = tag->tag.data; + fn->scope = ut_new_scope(state, fn->parent_scope); + fn->scope->ctx = json_object_get(this ? this : state->ctx); - sc = state->scope; - filename = state->filename; + sc = state->scope; - state->scope = ut_acquire_scope(fn->scope); - state->filename = fn->filename; + state->scope = ut_acquire_scope(fn->scope); - if (fn->args) - for (arridx = 0; arridx < json_object_array_length(fn->args); arridx++) - ut_setval(fn->scope->scope, json_object_array_get_idx(fn->args, arridx), - argvals ? json_object_array_get_idx(argvals, arridx) : NULL); + prev_fn = state->function; + state->function = fn; - rv = ut_execute_op_sequence(state, fn->entry); - tag = json_object_get_userdata(rv); + if (fn->args) + for (arridx = 0; arridx < json_object_array_length(fn->args); arridx++) + ut_setval(fn->scope->scope, json_object_array_get_idx(fn->args, arridx), + argvals ? json_object_array_get_idx(argvals, arridx) : NULL); - switch (tag ? tag->type : 0) { - case T_BREAK: - case T_CONTINUE: - json_object_put(rv); - rv = ut_exception(state, ut_get_off(state, tag), - "Syntax error: %s statement must be inside loop", - ut_get_tokenname(tag->type)); - break; + rv = ut_execute_op_sequence(state, fn->entry); + tag = json_object_get_userdata(rv); - case T_RETURN: - json_object_put(rv); - rv = json_object_get(state->rval); - break; - } + switch (tag ? tag->type : 0) { + case T_BREAK: + case T_CONTINUE: + json_object_put(rv); + rv = ut_exception(state, ut_get_off(state, tag), + "Syntax error: %s statement must be inside loop", + ut_get_tokenname(tag->type)); + break; - /* we left the function, pop the function scope... */ - ut_release_scope(state->scope); - state->scope = sc; + case T_RETURN: + json_object_put(rv); + rv = json_object_get(state->rval); + break; + } - /* ... and remove the "this" context... */ - json_object_put(fn->scope->ctx); - fn->scope->ctx = NULL; + /* we left the function, pop the function scope... */ + ut_release_scope(state->scope); + state->scope = sc; - /* ... and reset the function scope... */ - ut_release_scope(fn->scope); - fn->scope = NULL; + /* ... and remove the "this" context... */ + json_object_put(fn->scope->ctx); + fn->scope->ctx = NULL; + + /* ... and reset the function scope... */ + ut_release_scope(fn->scope); + fn->scope = NULL; + + state->function = prev_fn; + } - /* ... and the file name context */ - state->filename = filename; + state->callstack = callstack.next; return rv; } |