diff options
-rw-r--r-- | ast.c | 2 | ||||
-rw-r--r-- | ast.h | 7 | ||||
-rw-r--r-- | eval.c | 139 | ||||
-rw-r--r-- | eval.h | 4 | ||||
-rw-r--r-- | lib.c | 71 |
5 files changed, 117 insertions, 106 deletions
@@ -262,7 +262,7 @@ ut_reset(struct ut_state *s) s->off = 0; if (s->error.code == UT_ERROR_EXCEPTION) - free(s->error.info.exception.message); + json_object_put(s->error.info.exception); memset(&s->error, 0, sizeof(s->error)); } @@ -20,7 +20,6 @@ #include <stddef.h> #include <stdint.h> #include <stdbool.h> -#include <setjmp.h> #ifdef JSONC #include <json.h> @@ -88,13 +87,9 @@ struct ut_state { struct { enum ut_error_type code; union { - struct { - size_t off; - char *message; - } exception; + struct json_object *exception; uint64_t tokens[2]; } info; - jmp_buf jmp; } error; struct { struct json_object **scope; @@ -25,9 +25,13 @@ #include <stdlib.h> #include <stdarg.h> -__attribute__((noreturn,format(printf, 3, 0))) void -ut_throw(struct ut_state *state, uint32_t off, const char *fmt, ...) +char exception_tag_space[sizeof(struct ut_op) + sizeof(struct ut_op *)]; +static struct ut_op *exception_tag = (struct ut_op *)exception_tag_space; + +__attribute__((format(printf, 3, 0))) struct json_object * +ut_exception(struct ut_state *state, uint32_t off, const char *fmt, ...) { + struct json_object *msg; va_list ap; char *s; int len; @@ -36,11 +40,23 @@ ut_throw(struct ut_state *state, uint32_t off, const char *fmt, ...) len = vasprintf(&s, fmt, ap); va_end(ap); + if (len < 0) { + msg = json_object_new_string(UT_ERRMSG_OOM); + } + else { + msg = json_object_new_string_len(s, len); + free(s); + } + + exception_tag->type = T_EXCEPTION; + exception_tag->tree.operand[0] = off; + + json_object_set_userdata(msg, exception_tag, NULL); + state->error.code = UT_ERROR_EXCEPTION; - state->error.info.exception.message = len ? s : NULL; - state->error.info.exception.off = off; + state->error.info.exception = msg; - longjmp(state->error.jmp, 1); + return json_object_get(msg); } bool @@ -165,13 +181,13 @@ ut_addscope(struct ut_state *state, uint32_t decl) struct json_object *scope, **tmp; if (state->stack.off >= 255) - ut_throw(state, decl, "Runtime error: Too much recursion"); + return ut_exception(state, decl, "Runtime error: Too much recursion"); if (state->stack.off >= state->stack.size) { tmp = realloc(state->stack.scope, (state->stack.size + 1) * sizeof(*state->stack.scope)); if (!tmp) - ut_throw(state, decl, UT_ERRMSG_OOM); + return ut_exception(state, decl, UT_ERRMSG_OOM); state->stack.scope = tmp; state->stack.size++; @@ -180,7 +196,7 @@ ut_addscope(struct ut_state *state, uint32_t decl) scope = ut_new_object(NULL); if (!scope) - ut_throw(state, decl, UT_ERRMSG_OOM); + return ut_exception(state, decl, UT_ERRMSG_OOM); state->stack.scope[state->stack.off++] = scope; @@ -304,10 +320,11 @@ ut_getref(struct ut_state *state, uint32_t off, struct json_object **key) next = ut_getscope(state, ++i); if (!next) { - if (state->strict_declarations) - ut_throw(state, off, - "Reference error: access to undeclared variable %s", - json_object_get_string(op->val)); + if (state->strict_declarations) { + return ut_exception(state, off, + "Reference error: access to undeclared variable %s", + json_object_get_string(op->val)); + } break; } @@ -334,7 +351,7 @@ ut_getref_required(struct ut_state *state, uint32_t off, struct json_object **ke struct ut_op *op = ut_get_op(state, off); uint32_t off1 = op ? op->tree.operand[0] : 0; struct json_object *scope, *skey, *rv; - char *lhs, *p; + char *lhs; scope = ut_getref(state, off, &skey); @@ -343,20 +360,17 @@ ut_getref_required(struct ut_state *state, uint32_t off, struct json_object **ke lhs = off1 ? ut_ref_to_str(state, off1) : NULL; if (lhs) { - p = alloca(strlen(lhs) + 1); - strcpy(p, lhs); - free(lhs); + rv = ut_exception(state, off1, "Type error: %s is null", lhs); - json_object_put(scope); - ut_throw(state, off1, "Type error: %s is null", p); + free(lhs); } else { - json_object_put(scope); - ut_throw(state, off, - "Syntax error: Invalid left-hand side operand %s", - tokennames[op->type]); + rv = ut_exception(state, off, + "Syntax error: Invalid left-hand side operand %s", tokennames[op->type]); } + json_object_put(scope); + *key = NULL; return rv; } @@ -536,14 +550,14 @@ ut_execute_for(struct ut_state *state, uint32_t off) } if (init->type != T_IN) - ut_throw(state, ut_get_off(state, init), - "Syntax error: missing ';' after for loop initializer"); + return ut_exception(state, ut_get_off(state, init), + "Syntax error: missing ';' after for loop initializer"); ivar = ut_get_op(state, init->tree.operand[0]); if (!ivar || ivar->type != T_LABEL) - ut_throw(state, ut_get_off(state, init), - "Syntax error: invalid for-in left-hand side"); + return ut_exception(state, ut_get_off(state, init), + "Syntax error: invalid for-in left-hand side"); val = ut_execute_op(state, init->tree.operand[1]); scope = local ? ut_getscope(state, 0) : ut_getref(state, ut_get_off(state, ivar), NULL); @@ -907,7 +921,7 @@ ut_execute_list(struct ut_state *state, uint32_t off) struct json_object *arr = json_object_new_array(); if (!arr) - ut_throw(state, off, UT_ERRMSG_OOM); + return ut_exception(state, off, UT_ERRMSG_OOM); while (op) { json_object_array_add(arr, ut_execute_op(state, ut_get_off(state, op))); @@ -924,7 +938,7 @@ ut_execute_object(struct ut_state *state, uint32_t off) struct ut_op *key, *val; if (!obj) - ut_throw(state, off, UT_ERRMSG_OOM); + return ut_exception(state, off, UT_ERRMSG_OOM); for (key = ut_get_child(state, off, 0), val = ut_get_op(state, key ? key->tree.next : 0); key != NULL && val != NULL; @@ -978,9 +992,9 @@ ut_invoke(struct ut_state *state, uint32_t off, struct json_object *scope, case T_BREAK: case T_CONTINUE: ut_putval(rv); - ut_throw(state, ut_get_off(state, tag), - "Syntax error: %s statement must be inside loop", - tokennames[tag->type]); + rv = ut_exception(state, ut_get_off(state, tag), + "Syntax error: %s statement must be inside loop", + tokennames[tag->type]); break; case T_RETURN: @@ -1018,21 +1032,15 @@ ut_execute_call(struct ut_state *state, uint32_t off) struct ut_op *decl = func ? json_object_get_userdata(func) : NULL; struct json_object *argvals = ut_execute_list(state, off2); struct json_object *rv; - char *lhs, *p; + char *lhs; if (!decl || (decl->type != T_FUNC && decl->type != T_CFUNC)) { lhs = ut_ref_to_str(state, off1); + rv = ut_exception(state, off1, + "Type error: %s is not a function", + lhs ? lhs : "left-hand side expression"); - if (lhs) { - p = alloca(strlen(lhs) + 1); - strcpy(p, lhs); - free(lhs); - } - else { - p = "left-hand side expression"; - } - - ut_throw(state, off1, "Type error: %s is not a function", p); + free(lhs); } else { rv = ut_invoke(state, off, NULL, func, argvals); @@ -1308,7 +1316,7 @@ ut_execute_function(struct ut_state *state, uint32_t off) struct json_object *obj = ut_new_func(op); if (!obj) - ut_throw(state, off, UT_ERRMSG_OOM); + return ut_exception(state, off, UT_ERRMSG_OOM); return obj; } @@ -1363,8 +1371,9 @@ ut_execute_op(struct ut_state *state, uint32_t off) state->ctx = NULL; if (state->strict_declarations && scope == NULL) { - ut_throw(state, off, "Reference error: %s is not defined", - json_object_get_string(op->val)); + return ut_exception(state, off, + "Reference error: %s is not defined", + json_object_get_string(op->val)); } val = ut_getval(scope, key); @@ -1475,7 +1484,7 @@ ut_execute_op(struct ut_state *state, uint32_t off) return ut_execute_break_cont(state, off); default: - ut_throw(state, off, "Runtime error: Unrecognized opcode %d", op->type); + return ut_exception(state, off, "Runtime error: Unrecognized opcode %d", op->type); } } @@ -1550,30 +1559,38 @@ ut_register_variable(struct json_object *scope, const char *key, struct json_obj enum ut_error_type ut_run(struct ut_state *state, struct json_object *env) { - struct json_object *entry = NULL, *scope = NULL, *args = NULL, *rv = NULL; struct ut_op *op = ut_get_op(state, state->main); + struct json_object *entry, *scope, *args, *rv; - if (!setjmp(state->error.jmp)) { - if (!op || op->type != T_FUNC) - ut_throw(state, state->main, "Runtime error: Invalid root operation in AST"); + if (!op || op->type != T_FUNC) { + ut_exception(state, state->main, "Runtime error: Invalid root operation in AST"); - entry = ut_execute_function(state, state->main); - scope = ut_addscope(state, state->main); + return UT_ERROR_EXCEPTION; + } - state->ctx = NULL; + entry = ut_execute_function(state, state->main); - if (env) { - json_object_object_foreach(env, key, val) - ut_register_variable(scope, key, val); - } + if (!entry) + return UT_ERROR_EXCEPTION; + + scope = ut_addscope(state, state->main); - ut_globals_init(state, scope); - ut_lib_init(state, scope); + if (!json_object_is_type(scope, json_type_object)) + return UT_ERROR_EXCEPTION; - args = json_object_new_array(); - rv = ut_invoke(state, state->main, NULL, entry, args); + state->ctx = NULL; + + if (env) { + json_object_object_foreach(env, key, val) + ut_register_variable(scope, key, val); } + ut_globals_init(state, scope); + ut_lib_init(state, scope); + + args = json_object_new_array(); + rv = ut_invoke(state, state->main, NULL, entry, args); + json_object_put(entry); json_object_put(args); json_object_put(rv); @@ -24,8 +24,8 @@ #include "ast.h" -__attribute__((noreturn,format(printf, 3, 0))) void -ut_throw(struct ut_state *state, uint32_t off, const char *fmt, ...); +__attribute__((format(printf, 3, 0))) struct json_object * +ut_exception(struct ut_state *state, uint32_t op, const char *fmt, ...); void ut_putval(struct json_object *val); @@ -134,10 +134,10 @@ char * ut_format_error(struct ut_state *state, const char *expr) { size_t off = state ? state->off : 0; - char *msg = NULL, *p; - size_t msglen = 0; + struct ut_op *tag; bool first = true; - struct ut_op *op; + size_t msglen = 0; + char *msg = NULL; int i, max_i; switch (state ? state->error.code : UT_ERROR_OUT_OF_MEMORY) { @@ -202,11 +202,10 @@ ut_format_error(struct ut_state *state, const char *expr) break; case UT_ERROR_EXCEPTION: - p = state->error.info.exception.message; - op = ut_get_op(state, state->error.info.exception.off); - off = op ? op->off : 0; + tag = json_object_get_userdata(state->error.info.exception); + off = (tag && tag->tree.operand[0]) ? ut_get_op(state, tag->tree.operand[0])->off : 0; - sprintf_append(&msg, &msglen, "%s\n", p ? p : UT_ERRMSG_OOM); + sprintf_append(&msg, &msglen, "%s\n", json_object_get_string(state->error.info.exception)); break; } @@ -510,7 +509,7 @@ ut_chr(struct ut_state *s, uint32_t off, struct json_object *args) str = calloc(1, len); if (!str) - ut_throw(s, off, UT_ERRMSG_OOM); + return ut_exception(s, off, UT_ERRMSG_OOM); for (idx = 0; idx < len; idx++) { n = ut_cast_int64(json_object_array_get_idx(args, idx)); @@ -554,7 +553,7 @@ ut_die(struct ut_state *s, uint32_t off, struct json_object *args) { const char *msg = json_object_get_string(json_object_array_get_idx(args, 0)); - ut_throw(s, off, "%s", msg ? msg : "Died"); + return ut_exception(s, off, "%s", msg ? msg : "Died"); } static struct json_object * @@ -604,7 +603,7 @@ ut_filter(struct ut_state *s, uint32_t off, struct json_object *args) ut_putval(arr); ut_putval(cmpargs); - ut_throw(s, off, UT_ERRMSG_OOM); + return ut_exception(s, off, UT_ERRMSG_OOM); } json_object_array_put_idx(cmpargs, 2, json_object_get(obj)); @@ -680,7 +679,7 @@ ut_join(struct ut_state *s, uint32_t off, struct json_object *args) p = res = calloc(1, len); if (!res) - ut_throw(s, off, UT_ERRMSG_OOM); + return ut_exception(s, off, UT_ERRMSG_OOM); for (arrlen = json_object_array_length(arr), arridx = 0; arridx < arrlen; arridx++) { if (arridx > 0) { @@ -726,7 +725,7 @@ ut_keys(struct ut_state *s, uint32_t off, struct json_object *args) arr = json_object_new_array(); if (!arr) - ut_throw(s, off, UT_ERRMSG_OOM); + return ut_exception(s, off, UT_ERRMSG_OOM); json_object_object_foreach(obj, key, val) json_object_array_add(arr, json_object_new_string(key)); @@ -748,7 +747,7 @@ ut_lc(struct ut_state *s, uint32_t off, struct json_object *args) res = p = calloc(1, len); if (!res) - ut_throw(s, off, UT_ERRMSG_OOM); + return ut_exception(s, off, UT_ERRMSG_OOM); while (*str) if (*str >= 'A' && *str <= 'Z') @@ -780,7 +779,7 @@ ut_map(struct ut_state *s, uint32_t off, struct json_object *args) ut_putval(arr); ut_putval(cmpargs); - ut_throw(s, off, UT_ERRMSG_OOM); + return ut_exception(s, off, UT_ERRMSG_OOM); } json_object_array_put_idx(cmpargs, 2, json_object_get(obj)); @@ -866,7 +865,7 @@ ut_reverse(struct ut_state *s, uint32_t off, struct json_object *args) rv = json_object_new_array(); if (!rv) - ut_throw(s, off, UT_ERRMSG_OOM); + return ut_exception(s, off, UT_ERRMSG_OOM); for (arridx = json_object_array_length(obj); arridx > 0; arridx--) json_object_array_add(rv, json_object_get(json_object_array_get_idx(obj, arridx - 1))); @@ -877,7 +876,7 @@ ut_reverse(struct ut_state *s, uint32_t off, struct json_object *args) p = dup = calloc(1, len + 1); if (!dup) - ut_throw(s, off, UT_ERRMSG_OOM); + return ut_exception(s, off, UT_ERRMSG_OOM); while (len > 0) *p++ = str[--len]; @@ -936,7 +935,7 @@ ut_sort(struct ut_state *s, uint32_t off, struct json_object *args) sort_ctx.args = json_object_new_array(); if (!sort_ctx.args) - ut_throw(s, off, UT_ERRMSG_OOM); + return ut_exception(s, off, UT_ERRMSG_OOM); } json_object_array_sort(arr, sort_fn); @@ -1033,7 +1032,7 @@ ut_split(struct ut_state *s, uint32_t off, struct json_object *args) arr = json_object_new_array(); if (!arr) - ut_throw(s, off, UT_ERRMSG_OOM); + return ut_exception(s, off, UT_ERRMSG_OOM); sepstr = json_object_get_string(sep); splitstr = json_object_get_string(str); @@ -1140,7 +1139,7 @@ ut_uc(struct ut_state *s, uint32_t off, struct json_object *args) res = p = calloc(1, len); if (!res) - ut_throw(s, off, UT_ERRMSG_OOM); + return ut_exception(s, off, UT_ERRMSG_OOM); while (*str) if (*str >= 'a' && *str <= 'z') @@ -1181,7 +1180,7 @@ ut_uchr(struct ut_state *s, uint32_t off, struct json_object *args) str = calloc(1, ulen); if (!str) - ut_throw(s, off, UT_ERRMSG_OOM); + return ut_exception(s, off, UT_ERRMSG_OOM); for (idx = 0, p = str, rem = ulen; idx < len; idx++) { n = ut_cast_int64(json_object_array_get_idx(args, idx)); @@ -1208,7 +1207,7 @@ ut_values(struct ut_state *s, uint32_t off, struct json_object *args) arr = json_object_new_array(); if (!arr) - ut_throw(s, off, UT_ERRMSG_OOM); + return ut_exception(s, off, UT_ERRMSG_OOM); json_object_object_foreach(obj, key, val) { (void)key; @@ -1471,7 +1470,7 @@ ut_sprintf(struct ut_state *s, uint32_t off, struct json_object *args) len = ut_printf_common(s, off, args, &str); if (!str) - ut_throw(s, off, UT_ERRMSG_OOM); + return ut_exception(s, off, UT_ERRMSG_OOM); return json_object_new_string_len(str, len); } @@ -1485,7 +1484,7 @@ ut_printf(struct ut_state *s, uint32_t off, struct json_object *args) len = ut_printf_common(s, off, args, &str); if (!str) - ut_throw(s, off, UT_ERRMSG_OOM); + return ut_exception(s, off, UT_ERRMSG_OOM); len = fwrite(str, 1, len, stdout); @@ -1507,17 +1506,17 @@ ut_require_so(struct ut_state *s, uint32_t off, const char *path) dlh = dlopen(path, RTLD_LAZY|RTLD_LOCAL); if (!dlh) - ut_throw(s, off, "Unable to dlopen file %s: %s", path, dlerror()); + return ut_exception(s, off, "Unable to dlopen file %s: %s", path, dlerror()); init = dlsym(dlh, "ut_module_init"); if (!init) - ut_throw(s, off, "Module %s provides no 'ut_module_init' function", path); + return ut_exception(s, off, "Module %s provides no 'ut_module_init' function", path); scope = json_object_new_object(); if (!scope) - ut_throw(s, off, UT_ERRMSG_OOM); + return ut_exception(s, off, UT_ERRMSG_OOM); init(&ut, s, scope); @@ -1527,8 +1526,8 @@ ut_require_so(struct ut_state *s, uint32_t off, const char *path) static struct json_object * ut_require_utpl(struct ut_state *s, uint32_t off, const char *path) { - struct json_object *scope; - char *source, *msg, *p; + struct json_object *ex, *scope; + char *source, *msg; struct stat st; FILE *sfile; @@ -1538,14 +1537,14 @@ ut_require_utpl(struct ut_state *s, uint32_t off, const char *path) sfile = fopen(path, "rb"); if (!sfile) - ut_throw(s, off, "Unable to open file %s: %s", path, strerror(errno)); + return ut_exception(s, off, "Unable to open file %s: %s", path, strerror(errno)); source = calloc(1, st.st_size + 1); if (!source) { fclose(sfile); - ut_throw(s, off, UT_ERRMSG_OOM); + return ut_exception(s, off, UT_ERRMSG_OOM); } fread(source, 1, st.st_size, sfile); @@ -1553,12 +1552,12 @@ ut_require_utpl(struct ut_state *s, uint32_t off, const char *path) if (ut_parse(s, source)) { msg = ut_format_error(s, source); - p = alloca(strlen(msg)); - strcpy(p, msg); + ex = ut_exception(s, off, "Module loading failed: %s", msg); + free(source); free(msg); - ut_throw(s, off, "Module loading failed: %s", p); + return ex; } free(source); @@ -1566,7 +1565,7 @@ ut_require_utpl(struct ut_state *s, uint32_t off, const char *path) scope = json_object_new_object(); if (!scope) - ut_throw(s, off, UT_ERRMSG_OOM); + return ut_exception(s, off, UT_ERRMSG_OOM); return ut_invoke(s, off, scope, ut_get_op(s, s->main)->val, NULL); } @@ -1627,7 +1626,7 @@ ut_require(struct ut_state *s, uint32_t off, struct json_object *args) search = json_object_object_get(s->stack.scope[0], "REQUIRE_SEARCH_PATH"); if (!json_object_is_type(search, json_type_array)) - ut_throw(s, off, "Global require search path not set"); + return ut_exception(s, off, "Global require search path not set"); for (arridx = 0, arrlen = json_object_array_length(search); arridx < arrlen; arridx++) { se = json_object_array_get_idx(search, arridx); @@ -1641,7 +1640,7 @@ ut_require(struct ut_state *s, uint32_t off, struct json_object *args) return res; } - ut_throw(s, off, "No module named '%s' could be found", name); + return ut_exception(s, off, "No module named '%s' could be found", name); } static struct json_object * |