summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--ast.c2
-rw-r--r--ast.h7
-rw-r--r--eval.c139
-rw-r--r--eval.h4
-rw-r--r--lib.c71
5 files changed, 117 insertions, 106 deletions
diff --git a/ast.c b/ast.c
index 85825b8..cb6f438 100644
--- a/ast.c
+++ b/ast.c
@@ -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));
}
diff --git a/ast.h b/ast.h
index 6f2b12c..ecbd763 100644
--- a/ast.h
+++ b/ast.h
@@ -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;
diff --git a/eval.c b/eval.c
index 8c3107a..d6e0b5b 100644
--- a/eval.c
+++ b/eval.c
@@ -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);
diff --git a/eval.h b/eval.h
index 2bd8dd0..090a4db 100644
--- a/eval.h
+++ b/eval.h
@@ -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);
diff --git a/lib.c b/lib.c
index d2222f4..1ca1c6d 100644
--- a/lib.c
+++ b/lib.c
@@ -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 *