/* * Copyright (C) 2020 Jo-Philipp Wich <jo@mein.io> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "lexer.h" #include "parser.h" #include "eval.h" #include "lib.h" #include <math.h> #include <ctype.h> #include <errno.h> #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, ...) { struct json_object *msg; va_list ap; char *s; int len; va_start(ap, 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; return json_object_get(msg); } bool ut_val_is_truish(struct json_object *val) { struct ut_op *tag = json_object_get_userdata(val); double d; switch (tag ? tag->type : 0) { case T_EXCEPTION: return false; default: switch (json_object_get_type(val)) { case json_type_int: return (json_object_get_int64(val) != 0); case json_type_double: d = json_object_get_double(val); return (d != 0 && !isnan(d)); case json_type_boolean: return (json_object_get_boolean(val) != false); case json_type_string: return (json_object_get_string_len(val) > 0); case json_type_array: case json_type_object: return true; default: return false; } } } enum json_type ut_cast_number(struct json_object *v, int64_t *n, double *d) { bool is_double = false; const char *s; char *e; *d = 0.0; *n = 0; switch (json_object_get_type(v)) { case json_type_int: *n = json_object_get_int64(v); return json_type_int; case json_type_double: *d = json_object_get_double(v); return json_type_double; case json_type_null: return json_type_int; case json_type_boolean: *n = json_object_get_boolean(v) ? 1 : 0; return json_type_int; case json_type_string: s = json_object_get_string(v); while (isspace(*s)) s++; if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X') && isxdigit(s[2])) { *n = strtoll(s, &e, 16); } else if (s[0] == '0' && isdigit(s[2])) { *n = strtoll(s, &e, 8); } else { *n = strtoll(s, &e, 10); if (*e == '.') { *d = strtod(s, &e); is_double = (e > s); } } while (isspace(*e)) e++; if (*e) { *d = NAN; return json_type_double; } if (is_double) return json_type_double; return json_type_int; default: *d = NAN; return json_type_double; } } static struct json_object * ut_getscope(struct ut_state *state, uint8_t depth) { if (depth >= state->stack.off) return NULL; return state->stack.scope[state->stack.off - depth - 1]; } static struct json_object * 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"); 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); state->stack.scope = tmp; state->stack.size++; } scope = ut_new_object(NULL); if (!scope) return ut_exception(state, decl, UT_ERRMSG_OOM); state->stack.scope[state->stack.off++] = scope; return scope; } void ut_putval(struct json_object *val) { struct ut_op *tag = json_object_get_userdata(val); if (tag && tag->val != val) json_object_put(tag->val); json_object_put(val); } static struct json_object * ut_execute_op(struct ut_state *state, uint32_t off); static struct json_object * ut_execute_list(struct ut_state *state, uint32_t off); static char * ut_ref_to_str(struct ut_state *state, uint32_t off) { struct ut_op *op = ut_get_op(state, off); struct ut_op *op2 = ut_get_child(state, off, 1); const char *l; char *s, *p; switch (op ? op->type : 0) { case T_DOT: s = ut_ref_to_str(state, op->tree.operand[0]); l = ((op2 ? op2->type : 0) == T_LABEL) ? json_object_get_string(op2->val) : "???"; if (asprintf(&p, "%s.%s", s ? s : "(...)", l) == -1) p = NULL; free(s); return p; case T_LBRACK: if (!op->is_postfix) return NULL; /* fall through */ case T_LPAREN: s = ut_ref_to_str(state, op->tree.operand[0]); switch (op2 ? op2->type : 0) { case T_STRING: l = json_object_to_json_string_ext(op2->val, JSON_C_TO_STRING_NOSLASHESCAPE); break; case T_NUMBER: case T_LABEL: case T_BOOL: l = json_object_get_string(op2->val); break; default: l = "..."; } if (asprintf(&p, "%s%c%s%c", s ? s : "(...)", (op->type == T_LPAREN) ? '(' : '[', l, (op->type == T_LPAREN) ? ')' : ']') == -1) p = NULL; free(s); return p; case T_LABEL: return strdup(json_object_get_string(op->val)); default: return NULL; } } #define alloca_sprintf(...) \ ({ \ char *__p = NULL; \ int __n = snprintf(NULL, 0, __VA_ARGS__); \ if (__n >= 0) { \ __p = alloca(__n + 1); \ snprintf(__p, __n + 1, __VA_ARGS__); \ } \ __p; \ }) static struct json_object * ut_getref(struct ut_state *state, uint32_t off, struct json_object **key) { struct ut_op *op = ut_get_op(state, off); uint32_t off1 = op ? op->tree.operand[0] : 0; uint32_t off2 = op ? op->tree.operand[1] : 0; struct json_object *val, *scope, *next; uint8_t i; if (op && op->type == T_DOT) { if (key) *key = off2 ? json_object_get(ut_get_op(state, off2)->val) : NULL; return ut_execute_op(state, off1); } else if (op && op->type == T_LBRACK && op->is_postfix) { if (key) { val = off2 ? ut_execute_op(state, off2) : NULL; if (ut_is_type(val, T_EXCEPTION)) return val; *key = val; } return ut_execute_op(state, off1); } else if (op && op->type == T_LABEL) { i = 0; scope = ut_getscope(state, i); while (true) { if (json_object_object_get_ex(scope, json_object_get_string(op->val), NULL)) break; next = ut_getscope(state, ++i); if (!next) { if (state->strict_declarations) { return ut_exception(state, off, "Reference error: access to undeclared variable %s", json_object_get_string(op->val)); } break; } scope = next; } if (key) *key = json_object_get(op->val); return json_object_get(scope); } else { if (key) *key = NULL; return NULL; } } static struct json_object * ut_getref_required(struct ut_state *state, uint32_t off, struct json_object **key) { 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 = NULL; scope = ut_getref(state, off, &skey); if (!json_object_is_type(scope, json_type_array) && !json_object_is_type(scope, json_type_object)) { lhs = off1 ? ut_ref_to_str(state, off1) : NULL; if (lhs) { p = alloca_sprintf("Type error: the result of `%s` is %s", lhs, scope ? "not an array or object" : "null"); free(lhs); } json_object_put(scope); json_object_put(skey); rv = ut_exception(state, off1, p ? p : "Type error: left-hand side is not an array or object"); *key = NULL; return rv; } *key = skey; return scope; } static struct json_object * ut_getproto(struct json_object *obj) { struct ut_op *op = json_object_get_userdata(obj); if (!op || (op->type != T_LBRACE && op->type <= __T_MAX) || !op->val) return NULL; return op->tag.proto; } static struct json_object * ut_getval(struct json_object *scope, struct json_object *key) { struct json_object *o, *v; int64_t idx; double d; if (!key) return NULL; if (json_object_is_type(scope, json_type_array)) { /* only consider doubles with integer values as array keys */ if (json_object_is_type(key, json_type_double)) { d = json_object_get_double(key); if ((double)(int64_t)(d) != d) return NULL; idx = (int64_t)d; } else { errno = 0; idx = json_object_get_int64(key); if (errno != 0) return NULL; } return json_object_get(json_object_array_get_idx(scope, idx)); } for (o = scope; o; o = ut_getproto(o)) { if (!json_object_is_type(o, json_type_object)) continue; if (json_object_object_get_ex(o, key ? json_object_get_string(key) : "null", &v)) return json_object_get(v); } return NULL; } static struct json_object * ut_setval(struct json_object *scope, struct json_object *key, struct json_object *val) { int64_t idx; if (!key) return NULL; if (json_object_is_type(scope, json_type_array)) { errno = 0; idx = json_object_get_int64(key); if (errno != 0) return NULL; if (json_object_array_put_idx(scope, idx, val)) return NULL; return json_object_get(val); } if (json_object_object_add(scope, key ? json_object_get_string(key) : "null", val)) return NULL; return json_object_get(val); } static struct json_object * ut_execute_assign(struct ut_state *state, uint32_t off) { struct ut_op *op = ut_get_op(state, off); uint32_t label = op ? op->tree.operand[0] : 0; uint32_t value = op ? op->tree.operand[1] : 0; struct json_object *scope, *key, *val; scope = ut_getref_required(state, label, &key); if (!key) return scope; val = ut_execute_op(state, value); if (!ut_is_type(val, T_EXCEPTION)) ut_setval(scope, key, val); ut_putval(scope); ut_putval(key); return val; } static struct json_object * ut_execute_local(struct ut_state *state, uint32_t off) { struct ut_op *as = ut_get_child(state, off, 0); struct json_object *val, *rv = NULL; struct ut_op *label; while (as) { label = ut_get_op(state, as->tree.operand[0]); if (label) { val = as->tree.operand[1] ? ut_execute_op(state, as->tree.operand[1]) : NULL; if (ut_is_type(val, T_EXCEPTION)) return val; rv = ut_setval(ut_getscope(state, 0), label->val, val); } as = ut_get_op(state, as->tree.next); } return rv; } static struct json_object * ut_execute_op_sequence(struct ut_state *state, uint32_t off); static bool ut_test_condition(struct ut_state *state, uint32_t off) { struct json_object *val = ut_execute_op_sequence(state, off); bool istrue = ut_val_is_truish(val); ut_putval(val); return istrue; } static struct json_object * ut_execute_if(struct ut_state *state, uint32_t off) { struct ut_op *op = ut_get_op(state, off); uint32_t cond = op ? op->tree.operand[0] : 0; uint32_t Then = op ? op->tree.operand[1] : 0; uint32_t Else = op ? op->tree.operand[2] : 0; if (ut_test_condition(state, cond)) return ut_execute_op_sequence(state, Then); else if (Else) return ut_execute_op_sequence(state, Else); return NULL; } static struct json_object * ut_execute_for(struct ut_state *state, uint32_t off) { struct json_object *scope, *val, *item, *rv = NULL; struct ut_op *loop = ut_get_op(state, off); struct ut_op *init = ut_get_child(state, off, 0); struct ut_op *test = ut_get_child(state, off, 1); struct ut_op *incr = ut_get_child(state, off, 2); struct ut_op *body = ut_get_child(state, off, 3); struct ut_op *ivar, *tag; size_t arridx, arrlen; bool local = false; /* for (x in ...) loop variant */ if (loop->is_for_in) { if (init->type == T_LOCAL) { local = true; init = ut_get_op(state, init->tree.operand[0]); } if (init->type != T_IN) 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) 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]); if (ut_is_type(val, T_EXCEPTION)) return val; scope = local ? ut_getscope(state, 0) : ut_getref(state, ut_get_off(state, ivar), NULL); if (json_object_is_type(val, json_type_array)) { for (arridx = 0, arrlen = json_object_array_length(val); arridx < arrlen; arridx++) { item = json_object_array_get_idx(val, arridx); ut_setval(scope, ivar->val, item); ut_putval(rv); rv = ut_execute_op_sequence(state, ut_get_off(state, body)); tag = json_object_get_userdata(rv); switch (tag ? tag->type : 0) { case T_RETURN: case T_EXCEPTION: ut_putval(val); return rv; case T_BREAK: ut_putval(val); ut_putval(rv); return NULL; } } } else if (json_object_is_type(val, json_type_object)) { json_object_object_foreach(val, key, item) { ut_setval(scope, ivar->val, json_object_new_string(key)); ut_putval(rv); rv = ut_execute_op_sequence(state, ut_get_off(state, body)); tag = json_object_get_userdata(rv); switch (tag ? tag->type : 0) { case T_RETURN: case T_EXCEPTION: ut_putval(val); return rv; case T_BREAK: ut_putval(val); ut_putval(rv); return NULL; } } } ut_putval(val); ut_putval(rv); return NULL; } if (init) { val = ut_execute_op_sequence(state, ut_get_off(state, init)); if (ut_is_type(val, T_EXCEPTION)) return val; ut_putval(val); } while (test ? ut_test_condition(state, ut_get_off(state, test)) : true) { ut_putval(rv); rv = ut_execute_op_sequence(state, ut_get_off(state, body)); tag = json_object_get_userdata(rv); switch (tag ? tag->type : 0) { case T_RETURN: case T_EXCEPTION: return rv; case T_BREAK: ut_putval(rv); return NULL; } if (incr) { val = ut_execute_op_sequence(state, ut_get_off(state, incr)); if (ut_is_type(val, T_EXCEPTION)) { ut_putval(rv); return val; } ut_putval(val); } } ut_putval(rv); return NULL; } static struct json_object * ut_execute_while(struct ut_state *state, uint32_t off) { struct ut_op *op = ut_get_op(state, off); uint32_t test = op ? op->tree.operand[0] : 0; uint32_t body = op ? op->tree.operand[1] : 0; struct json_object *v, *rv = NULL; struct ut_op *tag = NULL; bool cond; while (1) { ut_putval(rv); v = test ? ut_execute_op_sequence(state, test) : NULL; cond = test ? ut_val_is_truish(v) : true; if (ut_is_type(v, T_EXCEPTION)) return v; ut_putval(v); if (!cond) return NULL; rv = ut_execute_op_sequence(state, body); tag = json_object_get_userdata(rv); switch (tag ? tag->type : 0) { case T_RETURN: case T_EXCEPTION: return rv; case T_BREAK: ut_putval(rv); return NULL; } } ut_putval(rv); return NULL; } static struct json_object * ut_execute_and_or(struct ut_state *state, uint32_t off) { struct ut_op *op = ut_get_op(state, off); struct json_object *val = NULL; int i; for (i = 0; i < ARRAY_SIZE(op->tree.operand) && op->tree.operand[i]; i++) { ut_putval(val); val = ut_execute_op(state, op->tree.operand[i]); if (ut_is_type(val, T_EXCEPTION)) break; if (ut_val_is_truish(val) == (op->type == T_OR)) break; } return val; } bool ut_cmp(int how, struct json_object *v1, struct json_object *v2) { enum json_type t1 = json_object_get_type(v1); enum json_type t2 = json_object_get_type(v2); int64_t n1, n2, delta; double d1, d2; if (t1 == json_type_string && t2 == json_type_string) { delta = strcmp(json_object_get_string(v1), json_object_get_string(v2)); } else { if ((t1 == json_type_array && t2 == json_type_array) || (t1 == json_type_object && t2 == json_type_object)) { delta = (void *)v1 - (void *)v2; } else { t1 = ut_cast_number(v1, &n1, &d1); t2 = ut_cast_number(v2, &n2, &d2); if (t1 == json_type_double || t2 == json_type_double) { d1 = (t1 == json_type_double) ? d1 : (double)n1; d2 = (t2 == json_type_double) ? d2 : (double)n2; if (d1 == d2) delta = 0; else if (d1 < d2) delta = -1; else delta = 1; } else { delta = n1 - n2; } } } switch (how) { case T_LT: return (delta < 0); case T_LE: return (delta <= 0); case T_GT: return (delta > 0); case T_GE: return (delta >= 0); case T_EQ: return (delta == 0); case T_NE: return (delta != 0); default: return false; } } static struct json_object * _ut_get_operands(struct ut_state *state, struct ut_op *op, size_t n, struct json_object **v) { struct ut_op *child; size_t i, j; for (i = 0; i < n; i++) { child = op ? ut_get_op(state, op->tree.operand[i]) : NULL; if (child && child->is_list) v[i] = ut_execute_list(state, ut_get_off(state, child)); else if (child) v[i] = ut_execute_op(state, ut_get_off(state, child)); else v[i] = NULL; if (ut_is_type(v[i], T_EXCEPTION)) { for (j = 0; j < i; j++) ut_putval(v[j]); return v[i]; } } return NULL; } #define ut_get_operands(state, op, vals) \ do { \ struct json_object *ex = _ut_get_operands(state, op, ARRAY_SIZE(vals), vals); \ if (ex) return ex; \ } while(0) static struct json_object * ut_execute_rel(struct ut_state *state, uint32_t off) { struct ut_op *op = ut_get_op(state, off); struct json_object *v[2], *rv; ut_get_operands(state, op, v); rv = json_object_new_boolean(ut_cmp(op->type, v[0], v[1])); ut_putval(v[0]); ut_putval(v[1]); return rv; } static struct json_object * ut_execute_equality(struct ut_state *state, uint32_t off) { struct ut_op *tag1, *tag2, *op = ut_get_op(state, off); struct json_object *v[2], *rv; enum json_type t1, t2; bool equal = false; ut_get_operands(state, op, v); tag1 = json_object_get_userdata(v[0]); tag2 = json_object_get_userdata(v[1]); t1 = json_object_get_type(v[0]); t2 = json_object_get_type(v[1]); if ((tag1 ? tag1->type : 0) != (tag2 ? tag2->type : 0)) { equal = false; } else if (t1 != t2) { equal = false; } else { switch (t1) { case json_type_array: case json_type_object: equal = (v[0] == v[1]); break; case json_type_boolean: equal = (json_object_get_boolean(v[0]) == json_object_get_boolean(v[1])); break; case json_type_double: if (isnan(json_object_get_double(v[0])) || isnan(json_object_get_double(v[1]))) equal = false; else equal = (json_object_get_double(v[0]) == json_object_get_double(v[1])); break; case json_type_int: equal = (json_object_get_int64(v[0]) == json_object_get_int64(v[1])); break; case json_type_string: equal = !strcmp(json_object_get_string(v[0]), json_object_get_string(v[1])); break; case json_type_null: equal = true; break; } } rv = json_object_new_boolean((op->type == T_EQS) ? equal : !equal); ut_putval(v[0]); ut_putval(v[1]); return rv; } static struct json_object * ut_execute_in(struct ut_state *state, uint32_t off) { struct ut_op *op = ut_get_op(state, off); struct json_object *v[2], *item; size_t arrlen, arridx; bool found = false; const char *key; ut_get_operands(state, op, v); if (json_object_is_type(v[1], json_type_array)) { for (arridx = 0, arrlen = json_object_array_length(v[1]); arridx < arrlen; arridx++) { item = json_object_array_get_idx(v[1], arridx); if (ut_cmp(T_EQ, v[0], item)) { found = true; break; } } } else if (json_object_is_type(v[1], json_type_object)) { key = v[0] ? json_object_get_string(v[0]) : "null"; found = json_object_object_get_ex(v[1], key, NULL); } ut_putval(v[0]); ut_putval(v[1]); return json_object_new_boolean(found); } static struct json_object * ut_execute_inc_dec(struct ut_state *state, uint32_t off) { struct ut_op *op = ut_get_op(state, off); struct json_object *val, *nval, *scope, *key; uint32_t label = op ? op->tree.operand[0] : 0; int64_t n; double d; scope = ut_getref_required(state, label, &key); if (!key) return scope; val = ut_getval(scope, key); ut_putval(scope); ut_putval(key); if (ut_cast_number(val, &n, &d) == json_type_double) nval = ut_new_double(d + (op->type == T_INC ? 1.0 : -1.0)); else nval = json_object_new_int64(n + (op->type == T_INC ? 1 : -1)); ut_putval(ut_setval(scope, key, nval)); /* postfix inc/dec, return old val */ if (op->is_postfix) return val; ut_putval(val); return json_object_get(nval); } static struct json_object * ut_execute_list(struct ut_state *state, uint32_t off) { struct ut_op *op = ut_get_op(state, off); struct json_object *val, *arr = json_object_new_array(); if (!arr) return ut_exception(state, off, UT_ERRMSG_OOM); while (op) { val = ut_execute_op(state, ut_get_off(state, op)); if (ut_is_type(val, T_EXCEPTION)) { json_object_put(arr); return val; } json_object_array_add(arr, val); op = ut_get_op(state, op->tree.next); } return arr; } static struct json_object * ut_execute_object(struct ut_state *state, uint32_t off) { struct json_object *v, *obj = ut_new_object(NULL); struct ut_op *key, *val; if (!obj) 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; key = ut_get_op(state, val->tree.next), val = ut_get_op(state, key ? key->tree.next : 0)) { v = ut_execute_op(state, ut_get_off(state, val)); if (ut_is_type(v, T_EXCEPTION)) { json_object_put(obj); return v; } json_object_object_add(obj, json_object_get_string(key->val), v); } return obj; } struct json_object * ut_invoke(struct ut_state *state, uint32_t off, struct json_object *scope, struct json_object *func, struct json_object *argvals) { struct ut_op *tag = json_object_get_userdata(func); struct ut_op *arg, *decl; struct json_object *s, *rv = NULL; size_t arridx; ut_c_fn *cfn; if (!tag) return NULL; /* is native function */ if (tag->type == T_CFUNC) { cfn = (ut_c_fn *)tag->tag.data; return cfn ? cfn(state, off, argvals) : NULL; } decl = tag->tag.data; arg = ut_get_op(state, decl ? decl->tree.operand[1] : 0); s = scope ? scope : ut_addscope(state, ut_get_off(state, decl)); if (!json_object_is_type(s, json_type_object)) return s; for (arridx = 0; arg; arridx++, arg = ut_get_op(state, arg->tree.next)) ut_setval(s, arg->val, argvals ? json_object_array_get_idx(argvals, arridx) : NULL); /* store the function "this" context in the proto member of the scope tag structure */ tag = json_object_get_userdata(s); tag->tag.proto = json_object_get(state->ctx); rv = ut_execute_op_sequence(state, decl->tree.operand[2]); tag = json_object_get_userdata(rv); switch (tag ? tag->type : 0) { 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]); break; case T_RETURN: /* handle magic null */ if (json_object_is_type(rv, json_type_boolean)) { if (!strcmp(json_object_get_string(rv), "null")) { ut_putval(rv); rv = NULL; } } break; } /* we left the function, remove the "this" context from the scope tag structure */ tag = json_object_get_userdata(s); json_object_put(tag->tag.proto); tag->tag.proto = NULL; if (!scope) { state->stack.scope[--state->stack.off] = NULL; json_object_put(s); } return rv; } static struct json_object * ut_execute_call(struct ut_state *state, uint32_t off) { struct ut_op *decl, *op = ut_get_op(state, off); struct json_object *v[2], *rv; char *lhs, *p = NULL; ut_get_operands(state, op, v); decl = json_object_get_userdata(v[0]); if (!decl || (decl->type != T_FUNC && decl->type != T_CFUNC)) { lhs = ut_ref_to_str(state, op->tree.operand[0]); if (lhs) { p = alloca_sprintf("Type error: %s is not a function", lhs); free(lhs); } rv = ut_exception(state, op->tree.operand[0], p ? p : "Type error: left-hand side expression is not a function"); } else { rv = ut_invoke(state, off, NULL, v[0], v[1]); } ut_putval(v[0]); ut_putval(v[1]); return rv; } static void ut_write_str(struct json_object *v) { const char *p; size_t len; switch (json_object_get_type(v)) { case json_type_object: case json_type_array: p = json_object_to_json_string_ext(v, JSON_C_TO_STRING_NOSLASHESCAPE|JSON_C_TO_STRING_SPACED); len = strlen(p); break; case json_type_string: p = json_object_get_string(v); len = json_object_get_string_len(v); break; case json_type_null: p = ""; len = 0; break; default: p = json_object_get_string(v); len = strlen(p); } fwrite(p, 1, len, stdout); } static struct json_object * ut_execute_exp(struct ut_state *state, uint32_t off) { struct ut_op *op = ut_get_op(state, off); struct json_object *val = ut_execute_op_sequence(state, op ? op->tree.operand[0] : 0); struct ut_op *tag = val ? json_object_get_userdata(val) : NULL; switch (tag ? tag->type : 0) { case T_EXCEPTION: printf("<exception: %s>", json_object_get_string(val)); break; default: ut_write_str(val); break; } ut_putval(val); return NULL; } static struct json_object * ut_execute_unary_plus_minus(struct ut_state *state, uint32_t off) { struct ut_op *op = ut_get_op(state, off); struct ut_op *op1 = ut_get_child(state, off, 0); struct json_object *v[1]; enum json_type t; int64_t n; double d; ut_get_operands(state, op, v); t = ut_cast_number(v[0], &n, &d); ut_putval(v[0]); switch (t) { case json_type_int: if (op1->is_overflow) return json_object_new_int64(((n >= 0) == (op->type == T_SUB)) ? INT64_MIN : INT64_MAX); return json_object_new_int64((op->type == T_SUB) ? -n : n); default: return ut_new_double((op->type == T_SUB) ? -d : d); } } static struct json_object * ut_execute_arith(struct ut_state *state, uint32_t off) { struct ut_op *op = ut_get_op(state, off); struct json_object *v[2], *rv; enum json_type t1, t2; const char *s1, *s2; size_t len1, len2; int64_t n1, n2; double d1, d2; char *s; if (!op->tree.operand[1]) return ut_execute_unary_plus_minus(state, off); ut_get_operands(state, op, v); if (op->type == T_ADD && (json_object_is_type(v[0], json_type_string) || json_object_is_type(v[1], json_type_string))) { s1 = v[0] ? json_object_get_string(v[0]) : "null"; s2 = v[1] ? json_object_get_string(v[1]) : "null"; len1 = strlen(s1); len2 = strlen(s2); s = calloc(1, len1 + len2 + 1); if (!s) { ut_putval(v[0]); ut_putval(v[1]); return NULL; } snprintf(s, len1 + len2 + 1, "%s%s", s1, s2); rv = json_object_new_string(s); ut_putval(v[0]); ut_putval(v[1]); free(s); return rv; } t1 = ut_cast_number(v[0], &n1, &d1); t2 = ut_cast_number(v[1], &n2, &d2); ut_putval(v[0]); ut_putval(v[1]); if (t1 == json_type_double || t2 == json_type_double) { d1 = (t1 == json_type_double) ? d1 : (double)n1; d2 = (t2 == json_type_double) ? d2 : (double)n2; switch (op->type) { case T_ADD: return ut_new_double(d1 + d2); case T_SUB: return ut_new_double(d1 - d2); case T_MUL: return ut_new_double(d1 * d2); case T_DIV: if (d2 == 0.0) return ut_new_double(INFINITY); else if (isnan(d2)) return ut_new_double(NAN); else if (!isfinite(d2)) return ut_new_double(isfinite(d1) ? 0.0 : NAN); return ut_new_double(d1 / d2); case T_MOD: return ut_new_double(NAN); } } switch (op->type) { case T_ADD: return json_object_new_int64(n1 + n2); case T_SUB: return json_object_new_int64(n1 - n2); case T_MUL: return json_object_new_int64(n1 * n2); case T_DIV: if (n2 == 0) return ut_new_double(INFINITY); return json_object_new_int64(n1 / n2); case T_MOD: return json_object_new_int64(n1 % n2); } return ut_new_double(NAN); } static struct json_object * ut_execute_bitop(struct ut_state *state, uint32_t off) { struct ut_op *op = ut_get_op(state, off); struct json_object *v[2]; int64_t n1, n2; double d; ut_get_operands(state, op, v); if (ut_cast_number(v[0], &n1, &d) == json_type_double) n1 = isnan(d) ? 0 : (int64_t)d; if (ut_cast_number(v[1], &n2, &d) == json_type_double) n2 = isnan(d) ? 0 : (int64_t)d; ut_putval(v[0]); ut_putval(v[1]); switch (op->type) { case T_LSHIFT: return json_object_new_int64(n1 << n2); case T_RSHIFT: return json_object_new_int64(n1 >> n2); case T_BAND: return json_object_new_int64(n1 & n2); case T_BXOR: return json_object_new_int64(n1 ^ n2); case T_BOR: return json_object_new_int64(n1 | n2); default: return NULL; } } static struct json_object * ut_execute_not(struct ut_state *state, uint32_t off) { struct ut_op *op = ut_get_op(state, off); return json_object_new_boolean(!ut_test_condition(state, op ? op->tree.operand[0] : 0)); } static struct json_object * ut_execute_compl(struct ut_state *state, uint32_t off) { struct ut_op *op = ut_get_op(state, off); struct json_object *v[1]; int64_t n; double d; ut_get_operands(state, op, v); if (ut_cast_number(v[0], &n, &d) == json_type_double) n = isnan(d) ? 0 : (int64_t)d; ut_putval(v[0]); return json_object_new_int64(~n); } static struct json_object * ut_execute_return(struct ut_state *state, uint32_t off) { struct ut_op *op = ut_get_op(state, off); struct json_object *v[1]; ut_get_operands(state, op, v); if (!v[0]) v[0] = ut_new_null(); json_object_set_userdata(v[0], op, NULL); return v[0]; } static struct json_object * ut_execute_break_cont(struct ut_state *state, uint32_t off) { struct ut_op *op = ut_get_op(state, off); struct json_object *rv = json_object_new_int64(0); json_object_set_userdata(rv, op, NULL); return rv; } static struct json_object * ut_execute_function(struct ut_state *state, uint32_t off) { struct ut_op *op = ut_get_op(state, off); struct json_object *obj = ut_new_func(op); if (!obj) return ut_exception(state, off, UT_ERRMSG_OOM); return obj; } static struct json_object * ut_execute_this(struct ut_state *state, uint32_t off) { return json_object_get(ut_getproto(ut_getscope(state, 0))); } static struct json_object * ut_execute_try_catch(struct ut_state *state, uint32_t off) { struct ut_op *op = ut_get_op(state, off); struct json_object *rv; rv = ut_execute_op_sequence(state, op->tree.operand[0]); if (ut_is_type(rv, T_EXCEPTION)) { if (op->tree.operand[1]) ut_putval(ut_setval(ut_getscope(state, 0), ut_get_child(state, off, 1)->val, json_object_new_string(json_object_get_string(rv)))); memset(&state->error, 0, sizeof(state->error)); ut_putval(rv); rv = ut_execute_op_sequence(state, op->tree.operand[2]); } return rv; } static struct json_object * ut_execute_op(struct ut_state *state, uint32_t off) { struct ut_op *op = ut_get_op(state, off); struct ut_op *op1 = ut_get_child(state, off, 0); struct json_object *scope, *key, *val; switch (op->type) { case T_NUMBER: case T_DOUBLE: case T_BOOL: case T_STRING: case T_NULL: return json_object_get(op->val); case T_THIS: return ut_execute_this(state, off); case T_FUNC: val = ut_execute_function(state, off); if (op1) ut_setval(ut_getscope(state, 0), op1->val, val); return val; case T_TEXT: printf("%s", json_object_get_string(op->val)); return NULL; case T_ASSIGN: return ut_execute_assign(state, off); case T_LOCAL: return ut_execute_local(state, off); case T_LABEL: scope = ut_getref(state, off, &key); ut_putval(state->ctx); state->ctx = NULL; if (state->strict_declarations && scope == NULL) { return ut_exception(state, off, "Reference error: %s is not defined", json_object_get_string(op->val)); } val = ut_getval(scope, key); ut_putval(scope); ut_putval(key); return val; case T_DOT: scope = ut_getref_required(state, off, &key); ut_putval(state->ctx); state->ctx = json_object_get(scope); if (!key) return scope; val = ut_getval(scope, key); ut_putval(scope); ut_putval(key); return val; case T_LBRACK: /* postfix access */ if (op->is_postfix) { scope = ut_getref_required(state, off, &key); ut_putval(state->ctx); state->ctx = json_object_get(scope); if (!key) return scope; val = ut_getval(scope, key); ut_putval(scope); ut_putval(key); return val; } return ut_execute_list(state, ut_get_off(state, op1)); case T_LBRACE: return ut_execute_object(state, off); case T_IF: case T_QMARK: return ut_execute_if(state, off); case T_FOR: return ut_execute_for(state, off); case T_WHILE: return ut_execute_while(state, off); case T_AND: case T_OR: return ut_execute_and_or(state, off); case T_LT: case T_LE: case T_GT: case T_GE: case T_EQ: case T_NE: return ut_execute_rel(state, off); case T_EQS: case T_NES: return ut_execute_equality(state, off); case T_IN: return ut_execute_in(state, off); case T_INC: case T_DEC: return ut_execute_inc_dec(state, off); case T_LPAREN: return ut_execute_call(state, off); case T_LEXP: return ut_execute_exp(state, off); case T_ADD: case T_SUB: case T_MUL: case T_DIV: case T_MOD: return ut_execute_arith(state, off); case T_LSHIFT: case T_RSHIFT: case T_BAND: case T_BXOR: case T_BOR: return ut_execute_bitop(state, off); case T_COMPL: return ut_execute_compl(state, off); case T_NOT: return ut_execute_not(state, off); case T_RETURN: return ut_execute_return(state, off); case T_BREAK: case T_CONTINUE: return ut_execute_break_cont(state, off); case T_TRY: return ut_execute_try_catch(state, off); default: return ut_exception(state, off, "Runtime error: Unrecognized opcode %d", op->type); } } static struct json_object * ut_execute_op_sequence(struct ut_state *state, uint32_t off) { struct json_object *v = NULL; struct ut_op *tag = NULL; struct ut_op *op = NULL; while (off) { ut_putval(v); v = ut_execute_op(state, off); tag = v ? json_object_get_userdata(v) : NULL; switch (tag ? tag->type : 0) { case T_BREAK: case T_CONTINUE: case T_RETURN: case T_EXCEPTION: return v; } op = ut_get_op(state, off); off = op ? op->tree.next : 0; } return v; } static void ut_globals_init(struct ut_state *state, struct json_object *scope) { struct json_object *arr = json_object_new_array(); const char *p, *last; if (!arr) return; for (p = last = LIB_SEARCH_PATH;; p++) { if (*p == ':' || *p == '\0') { json_object_array_add(arr, json_object_new_string_len(last, p - last)); if (!*p) break; last = p + 1; } } json_object_object_add(scope, "REQUIRE_SEARCH_PATH", arr); } static void ut_register_variable(struct json_object *scope, const char *key, struct json_object *val) { char *name = strdup(key); char *p; if (!name) return; for (p = name; *p; p++) if (!isalnum(*p) && *p != '_') *p = '_'; json_object_object_add(scope, name, val); free(name); } enum ut_error_type ut_run(struct ut_state *state, struct json_object *env, struct json_object *modules) { struct ut_op *op = ut_get_op(state, state->main); struct json_object *entry, *scope, *args, *rv; size_t i; if (!op || op->type != T_FUNC) { ut_exception(state, state->main, "Runtime error: Invalid root operation in AST"); return UT_ERROR_EXCEPTION; } 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; if (env) { json_object_object_foreach(env, key, val) ut_register_variable(scope, key, json_object_get(val)); } ut_globals_init(state, scope); ut_lib_init(state, scope); args = json_object_new_array(); if (modules) { for (i = 0; i < json_object_array_length(modules); i++) { json_object_array_put_idx(args, 0, json_object_get(json_object_array_get_idx(modules, i))); rv = ut_invoke(state, 0, NULL, json_object_object_get(scope, "require"), args); if (ut_is_type(rv, T_EXCEPTION)) goto out; ut_register_variable(scope, json_object_get_string(json_object_array_get_idx(modules, i)), rv); } json_object_array_del_idx(args, 0, 1); } rv = ut_invoke(state, state->main, NULL, entry, args); out: json_object_put(entry); json_object_put(args); json_object_put(rv); return state->error.code; }