summaryrefslogtreecommitdiffhomepage
path: root/eval.c
diff options
context:
space:
mode:
Diffstat (limited to 'eval.c')
-rw-r--r--eval.c119
1 files changed, 52 insertions, 67 deletions
diff --git a/eval.c b/eval.c
index dfc599c..954f596 100644
--- a/eval.c
+++ b/eval.c
@@ -25,13 +25,9 @@
#include <stdlib.h>
#include <stdarg.h>
-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, ...)
+__attribute__((noreturn,format(printf, 3, 0))) void
+ut_throw(struct ut_state *state, uint32_t off, const char *fmt, ...)
{
- struct json_object *msg;
va_list ap;
char *s;
int len;
@@ -40,23 +36,11 @@ ut_exception(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 = msg;
+ state->error.info.exception.message = len ? s : NULL;
+ state->error.info.exception.off = off;
- return json_object_get(msg);
+ longjmp(state->error.jmp, 1);
}
bool
@@ -181,13 +165,13 @@ ut_addscope(struct ut_state *state, uint32_t decl)
struct json_object *scope, **tmp;
if (state->stack.off >= 255)
- return ut_exception(state, decl, "Runtime error: Too much recursion");
+ ut_throw(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)
- return ut_exception(state, decl, UT_ERRMSG_OOM);
+ ut_throw(state, decl, UT_ERRMSG_OOM);
state->stack.scope = tmp;
state->stack.size++;
@@ -196,7 +180,7 @@ ut_addscope(struct ut_state *state, uint32_t decl)
scope = ut_new_object(NULL);
if (!scope)
- return ut_exception(state, decl, UT_ERRMSG_OOM);
+ ut_throw(state, decl, UT_ERRMSG_OOM);
state->stack.scope[state->stack.off++] = scope;
@@ -344,7 +328,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;
+ char *lhs, *p;
scope = ut_getref(state, off, &skey);
@@ -353,17 +337,20 @@ 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) {
- rv = ut_exception(state, off1, "Type error: %s is null", lhs);
-
+ p = alloca(strlen(lhs) + 1);
+ strcpy(p, lhs);
free(lhs);
+
+ json_object_put(scope);
+ ut_throw(state, off1, "Type error: %s is null", p);
}
else {
- rv = ut_exception(state, off,
- "Syntax error: Invalid left-hand side operand %s", tokennames[op->type]);
+ json_object_put(scope);
+ ut_throw(state, off,
+ "Syntax error: Invalid left-hand side operand %s",
+ tokennames[op->type]);
}
- json_object_put(scope);
-
*key = NULL;
return rv;
}
@@ -543,14 +530,14 @@ ut_execute_for(struct ut_state *state, uint32_t off)
}
if (init->type != T_IN)
- return ut_exception(state, ut_get_off(state, init),
- "Syntax error: missing ';' after for loop initializer");
+ ut_throw(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)
- return ut_exception(state, ut_get_off(state, init),
- "Syntax error: invalid for-in left-hand side");
+ ut_throw(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);
@@ -914,7 +901,7 @@ ut_execute_list(struct ut_state *state, uint32_t off)
struct json_object *arr = json_object_new_array();
if (!arr)
- return ut_exception(state, off, UT_ERRMSG_OOM);
+ ut_throw(state, off, UT_ERRMSG_OOM);
while (op) {
json_object_array_add(arr, ut_execute_op(state, ut_get_off(state, op)));
@@ -931,7 +918,7 @@ ut_execute_object(struct ut_state *state, uint32_t off)
struct ut_op *key, *val;
if (!obj)
- return ut_exception(state, off, UT_ERRMSG_OOM);
+ ut_throw(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;
@@ -985,9 +972,9 @@ ut_invoke(struct ut_state *state, uint32_t off, struct json_object *scope,
case T_BREAK:
case T_CONTINUE:
ut_putval(rv);
- rv = ut_exception(state, ut_get_off(state, tag),
- "Syntax error: %s statement must be inside loop",
- tokennames[tag->type]);
+ ut_throw(state, ut_get_off(state, tag),
+ "Syntax error: %s statement must be inside loop",
+ tokennames[tag->type]);
break;
case T_RETURN:
@@ -1025,15 +1012,21 @@ 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;
+ char *lhs, *p;
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");
- free(lhs);
+ 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);
}
else {
rv = ut_invoke(state, off, NULL, func, argvals);
@@ -1309,7 +1302,7 @@ ut_execute_function(struct ut_state *state, uint32_t off)
struct json_object *obj = ut_new_func(op);
if (!obj)
- return ut_exception(state, off, UT_ERRMSG_OOM);
+ ut_throw(state, off, UT_ERRMSG_OOM);
return obj;
}
@@ -1471,7 +1464,7 @@ ut_execute_op(struct ut_state *state, uint32_t off)
return ut_execute_break_cont(state, off);
default:
- return ut_exception(state, off, "Runtime error: Unrecognized opcode %d", op->type);
+ ut_throw(state, off, "Runtime error: Unrecognized opcode %d", op->type);
}
}
@@ -1529,32 +1522,24 @@ ut_globals_init(struct ut_state *state, struct json_object *scope)
enum ut_error_type
ut_run(struct ut_state *state)
{
+ 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 (!op || op->type != T_FUNC) {
- ut_exception(state, state->main, "Runtime error: Invalid root operation in AST");
+ if (!setjmp(state->error.jmp)) {
+ if (!op || op->type != T_FUNC)
+ ut_throw(state, state->main, "Runtime error: Invalid root operation in AST");
- return UT_ERROR_EXCEPTION;
- }
+ entry = ut_execute_function(state, state->main);
+ scope = ut_addscope(state, state->main);
- entry = ut_execute_function(state, state->main);
-
- if (!entry)
- return UT_ERROR_EXCEPTION;
-
- scope = ut_addscope(state, state->main);
-
- if (!json_object_is_type(scope, json_type_object))
- return UT_ERROR_EXCEPTION;
-
- state->ctx = NULL;
+ state->ctx = NULL;
- ut_globals_init(state, scope);
- ut_lib_init(state, scope);
+ ut_globals_init(state, scope);
+ ut_lib_init(state, scope);
- args = json_object_new_array();
- rv = ut_invoke(state, state->main, NULL, entry, args);
+ args = json_object_new_array();
+ rv = ut_invoke(state, state->main, NULL, entry, args);
+ }
json_object_put(entry);
json_object_put(args);