/* * Copyright (C) 2020 Jo-Philipp Wich * * 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 #include #include #include #include static struct ut_opcode exception_tag = { .type = T_EXCEPTION }; __attribute__((format(printf, 3, 0))) struct json_object * ut_exception(struct ut_state *state, struct ut_opcode *op, 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.operand[0] = op; 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_opcode *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, struct ut_opcode *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 = json_object_new_object(); 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_opcode *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, struct ut_opcode *op); static char * ut_ref_to_str(struct ut_opcode *op) { struct ut_opcode *op1 = op->operand[0]; struct ut_opcode *op2 = op->operand[1]; const char *l; size_t n1, n2; char *s, *p; switch (op ? op->type : 0) { case T_DOT: s = ut_ref_to_str(op1); n1 = strlen(s ? s : "(null)"); l = ((op2 ? op2->type : 0) == T_LABEL) ? json_object_get_string(op2->val) : "???"; n2 = strlen(l); p = calloc(1, n1 + n2 + 2); if (!p) return NULL; snprintf(p, n1 + n2 + 2, "%s.%s", s ? s : "(null)", l); free(s); return p; case T_LBRACK: if (!op->val) return NULL; s = ut_ref_to_str(op1); n1 = strlen(s ? s : "(null)"); l = "..."; n2 = strlen(l); p = calloc(1, n1 + n2 + 3); if (!p) return NULL; snprintf(p, n1 + n2 + 3, "%s[%s]", s, l); free(s); return p; case T_LABEL: return strdup(json_object_get_string(op->val)); default: return NULL; } } static struct json_object * ut_getref(struct ut_state *state, struct ut_opcode *op, struct json_object **key) { struct json_object *scope, *next; uint8_t i; if (op && op->type == T_DOT) { *key = op->operand[1] ? op->operand[1]->val : NULL; return ut_execute_op(state, op->operand[0]); } else if (op && op->type == T_LBRACK && op->val) { *key = op->operand[1] ? ut_execute_op(state, op->operand[1]) : NULL; return ut_execute_op(state, op->operand[0]); } 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) break; scope = next; } *key = op->val; return json_object_get(scope); } else { *key = NULL; return NULL; } } static struct json_object * ut_getref_required(struct ut_state *state, struct ut_opcode *op, struct json_object **key) { struct json_object *scope, *skey, *rv; char *lhs; scope = ut_getref(state, op, &skey); if (!json_object_is_type(scope, json_type_array) && !json_object_is_type(scope, json_type_object)) { lhs = op->operand[0] ? ut_ref_to_str(op->operand[0]) : NULL; if (lhs) { rv = ut_exception(state, op->operand[0], "Type error: %s is null", lhs); free(lhs); } else { rv = ut_exception(state, op, "Syntax error: Invalid left-hand side operand %s", tokennames[op->type]); } json_object_put(scope); *key = NULL; return rv; } *key = skey; return scope; } static struct json_object * ut_getproto(struct json_object *obj) { struct ut_tagvalue *tag = json_object_get_userdata(obj); if (!tag || (tag->type != T_LBRACE && tag->type <= __T_MAX) || !tag->val) return NULL; return 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 (ceil(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, struct ut_opcode *op) { struct ut_opcode *label = op->operand[0]; struct ut_opcode *value = op->operand[1]; struct json_object *scope, *key, *val; scope = ut_getref_required(state, label, &key); if (!key) return scope; val = ut_setval(scope, key, ut_execute_op(state, value)); ut_putval(scope); return val; } static struct json_object * ut_execute_local(struct ut_state *state, struct ut_opcode *op) { struct ut_opcode *as = op->operand[0]; struct json_object *rv = NULL; while (as) { rv = ut_setval( state->stack.scope[state->stack.off-1], as->operand[0]->val, as->operand[1] ? ut_execute_op(state, as->operand[1]) : NULL); as = as->sibling; } return rv; } static struct json_object * ut_execute_op_sequence(struct ut_state *state, struct ut_opcode *op); static bool ut_test_condition(struct ut_state *state, struct ut_opcode *op) { struct json_object *val = ut_execute_op_sequence(state, op); bool istrue = ut_val_is_truish(val); ut_putval(val); return istrue; } static struct json_object * ut_execute_if(struct ut_state *state, struct ut_opcode *op) { struct ut_opcode *cond = op->operand[0]; struct ut_opcode *Then = op->operand[1]; struct ut_opcode *Else = op->operand[2]; 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, struct ut_opcode *op) { struct json_object *ivar, *val, *item, *rv = NULL; struct ut_opcode *init = op->operand[0]; struct ut_opcode *test = op->operand[1]; struct ut_opcode *incr = op->operand[2]; struct ut_opcode *body = op->operand[3]; struct ut_opcode *tag; size_t arridx, arrlen; /* for (x in ...) loop variant */ if (init != NULL && test == NULL && incr == NULL) { if (init->type != T_IN) return ut_exception(state, init, "Syntax error: missing ';' after for loop initializer"); ivar = init->operand[0]->val; val = ut_execute_op(state, init->operand[1]); 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(ut_getscope(state, 0), ivar, item); ut_putval(rv); rv = ut_execute_op_sequence(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(ut_getscope(state, 0), ivar, json_object_new_string(key)); ut_putval(rv); rv = ut_execute_op_sequence(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) ut_putval(ut_execute_op_sequence(state, init)); while (test ? ut_test_condition(state, test) : true) { ut_putval(rv); 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; } if (incr) ut_putval(ut_execute_op_sequence(state, incr)); } ut_putval(rv); return NULL; } static struct json_object * ut_execute_while(struct ut_state *state, struct ut_opcode *op) { struct ut_opcode *test = op->operand[0]; struct ut_opcode *body = op->operand[1]; struct json_object *v, *rv = NULL; struct ut_opcode *tag = NULL; bool cond; while (1) { v = test ? ut_execute_op_sequence(state, test) : NULL; cond = test ? ut_val_is_truish(v) : true; ut_putval(rv); 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, struct ut_opcode *op) { struct json_object *val = NULL; int i; for (i = 0; i < sizeof(op->operand) / sizeof(op->operand[0]); i++) { if (!op->operand[i]) break; ut_putval(val); val = ut_execute_op(state, op->operand[i]); 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_execute_rel(struct ut_state *state, struct ut_opcode *op) { struct json_object *v1 = ut_execute_op(state, op->operand[0]); struct json_object *v2 = ut_execute_op(state, op->operand[1]); struct json_object *rv; rv = json_object_new_boolean(ut_cmp(op->type, v1, v2)); ut_putval(v1); ut_putval(v2); return rv; } static struct json_object * ut_execute_in(struct ut_state *state, struct ut_opcode *op) { struct json_object *op1 = ut_execute_op(state, op->operand[0]); struct json_object *op2 = ut_execute_op(state, op->operand[1]); struct json_object *item; size_t arrlen, arridx; bool found = false; const char *key; if (json_object_is_type(op2, json_type_array)) { for (arridx = 0, arrlen = json_object_array_length(op2); arridx < arrlen; arridx++) { item = json_object_array_get_idx(op2, arridx); if (ut_cmp(T_EQ, op1, item)) { found = true; break; } } } else if (json_object_is_type(op2, json_type_object)) { key = op1 ? json_object_get_string(op1) : "null"; found = json_object_object_get_ex(op2, key, NULL); } ut_putval(op1); ut_putval(op2); return json_object_new_boolean(found); } static struct json_object * ut_execute_inc_dec(struct ut_state *state, struct ut_opcode *op) { struct json_object *val, *nval, *scope, *key; struct ut_opcode *label = op->operand[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); if (ut_cast_number(val, &n, &d) == json_type_double) nval = json_object_new_double_rounded(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->val) return val; ut_putval(val); return json_object_get(nval); } static struct json_object * ut_execute_list(struct ut_state *state, struct ut_opcode *op) { struct json_object *arr = json_object_new_array(); if (!arr) return ut_exception(state, op, UT_ERRMSG_OOM); while (op) { json_object_array_add(arr, ut_execute_op(state, op)); op = op->sibling; } return arr; } static struct json_object * ut_execute_object(struct ut_state *state, struct ut_opcode *op) { struct json_object *obj = ut_new_object(state, NULL); struct ut_opcode *key, *val; if (!obj) return ut_exception(state, op, UT_ERRMSG_OOM); for (key = op->operand[0], val = key ? key->sibling : NULL; key != NULL && val != NULL; key = val->sibling, val = key ? key->sibling : NULL) { json_object_object_add(obj, json_object_get_string(key->val), ut_execute_op(state, val)); } return obj; } struct json_object * ut_invoke(struct ut_state *state, struct ut_opcode *op, struct json_object *scope, struct json_object *func, struct json_object *argvals) { struct ut_opcode *decl = json_object_get_userdata(func); struct ut_opcode *arg = decl ? decl->operand[1] : NULL; struct ut_tagvalue *tag = (struct ut_tagvalue *)decl; struct json_object *s, *rv = NULL; size_t arridx; ut_c_fn *cfn; if (!decl) return NULL; /* is native function */ if (tag->type == T_CFUNC) { cfn = (ut_c_fn *)tag->data; return cfn ? cfn(state, op, argvals) : NULL; } s = scope ? scope : ut_addscope(state, decl); if (!json_object_is_type(s, json_type_object)) return s; for (arridx = 0; arg; arridx++, arg = arg->sibling) ut_setval(s, arg->val, argvals ? json_object_array_get_idx(argvals, arridx) : NULL); json_object_set_userdata(s, json_object_get(state->ctx), NULL); rv = ut_execute_op_sequence(state, decl->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, (struct ut_opcode *)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; } if (!scope) { state->stack.scope[--state->stack.off] = NULL; json_object_put(json_object_get_userdata(s)); json_object_put(s); } return rv; } static struct json_object * ut_execute_call(struct ut_state *state, struct ut_opcode *op) { struct json_object *func = ut_execute_op(state, op->operand[0]); struct ut_opcode *decl = func ? json_object_get_userdata(func) : NULL; struct json_object *argvals = ut_execute_list(state, op->operand[1]); struct json_object *rv; char *lhs; if (!decl || (decl->type != T_FUNC && decl->type != T_CFUNC)) { lhs = ut_ref_to_str(op->operand[0]); rv = ut_exception(state, op->operand[0], "Type error: %s is not a function", lhs ? lhs : "left-hand side expression"); free(lhs); } else { rv = ut_invoke(state, op, NULL, func, argvals); } ut_putval(argvals); ut_putval(func); return rv; } static void ut_write_str(struct json_object *v) { const char *p; size_t len; p = v ? json_object_get_string(v) : ""; len = json_object_is_type(v, json_type_string) ? json_object_get_string_len(v) : strlen(p); fwrite(p, 1, len, stdout); } static struct json_object * ut_execute_exp(struct ut_state *state, struct ut_opcode *op) { struct json_object *val = ut_execute_op_sequence(state, op->operand[0]); struct ut_opcode *tag = val ? json_object_get_userdata(val) : NULL; switch (tag ? tag->type : 0) { case T_RETURN: ut_write_str(tag->val); break; case T_BREAK: return val; case T_EXCEPTION: printf("", 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, struct ut_opcode *op) { struct json_object *val = ut_execute_op(state, op->operand[0]); enum json_type t; int64_t n; double d; t = ut_cast_number(val, &n, &d); ut_putval(val); switch (t) { case json_type_int: return json_object_new_int64((op->type == T_SUB) ? -n : n); default: return json_object_new_double_rounded((op->type == T_SUB) ? -d : d); } } static struct json_object * ut_execute_arith(struct ut_state *state, struct ut_opcode *op) { struct json_object *v1, *v2, *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->operand[1]) return ut_execute_unary_plus_minus(state, op); v1 = ut_execute_op(state, op->operand[0]); v2 = ut_execute_op(state, op->operand[1]); if (op->type == T_ADD && (json_object_is_type(v1, json_type_string) || json_object_is_type(v2, json_type_string))) { s1 = v1 ? json_object_get_string(v1) : "null"; s2 = v1 ? json_object_get_string(v2) : "null"; len1 = strlen(s1); len2 = strlen(s2); s = calloc(1, len1 + len2 + 1); if (!s) { ut_putval(v1); ut_putval(v2); return NULL; } snprintf(s, len1 + len2 + 1, "%s%s", s1, s2); rv = json_object_new_string(s); ut_putval(v1); ut_putval(v2); free(s); return rv; } t1 = ut_cast_number(v1, &n1, &d1); t2 = ut_cast_number(v2, &n2, &d2); ut_putval(v1); ut_putval(v2); 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 json_object_new_double_rounded(d1 + d2); case T_SUB: return json_object_new_double_rounded(d1 - d2); case T_MUL: return json_object_new_double_rounded(d1 * d2); case T_DIV: if (d2 == 0.0) return json_object_new_double_rounded(NAN); return json_object_new_double_rounded(d1 / d2); case T_MOD: return json_object_new_double_rounded(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 json_object_new_double_rounded(NAN); return json_object_new_int64(n1 / n2); case T_MOD: return json_object_new_int64(n1 % n2); } return json_object_new_double_rounded(NAN); } static struct json_object * ut_execute_bitop(struct ut_state *state, struct ut_opcode *op) { struct ut_opcode *op1 = op->operand[0]; struct ut_opcode *op2 = op->operand[1]; struct json_object *v1, *v2; int64_t n1, n2; double d; v1 = op1 ? ut_execute_op(state, op1) : NULL; v2 = op2 ? ut_execute_op(state, op2) : NULL; if (ut_cast_number(v1, &n1, &d) == json_type_double) n1 = isnan(d) ? 0 : (int64_t)d; if (ut_cast_number(v2, &n2, &d) == json_type_double) n2 = isnan(d) ? 0 : (int64_t)d; ut_putval(v1); ut_putval(v2); 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, struct ut_opcode *op) { return json_object_new_boolean(!ut_test_condition(state, op->operand[0])); } static struct json_object * ut_execute_compl(struct ut_state *state, struct ut_opcode *op) { struct json_object *val = op->operand[0] ? ut_execute_op(state, op->operand[0]) : NULL; int64_t n; double d; if (ut_cast_number(val, &n, &d) == json_type_double) n = isnan(d) ? 0 : (int64_t)d; ut_putval(val); return json_object_new_int64(~n); } static struct json_object * ut_execute_return(struct ut_state *state, struct ut_opcode *op) { struct json_object *val = op->operand[0] ? ut_execute_op(state, op->operand[0]) : NULL; if (!val) val = json_object_new_null_obj(); json_object_set_userdata(val, op, NULL); return val; } static struct json_object * ut_execute_break_cont(struct ut_state *state, struct ut_opcode *op) { struct json_object *rv = json_object_new_int64(0); json_object_set_userdata(rv, op, NULL); return rv; } static struct json_object * ut_execute_op(struct ut_state *state, struct ut_opcode *op) { 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 json_object_get_userdata(ut_getscope(state, 0)); case T_FUNC: if (op->operand[0]) ut_setval(ut_getscope(state, 0), op->operand[0]->val, op->val); return json_object_get(op->val); case T_TEXT: printf("%s", json_object_get_string(op->val)); return NULL; case T_ASSIGN: return ut_execute_assign(state, op); case T_LOCAL: return ut_execute_local(state, op); case T_LABEL: scope = ut_getref(state, op, &key); state->ctx = scope; val = ut_getval(scope, key); ut_putval(scope); return val; case T_DOT: scope = ut_getref_required(state, op, &key); state->ctx = scope; if (!key) return scope; val = ut_getval(scope, key); ut_putval(scope); return val; case T_LBRACK: /* postfix access */ if (op->val) { scope = ut_getref_required(state, op, &key); state->ctx = scope; if (!key) return scope; val = ut_getval(scope, key); json_object_put(scope); return val; } return ut_execute_list(state, op->operand[0]); case T_LBRACE: return ut_execute_object(state, op); case T_IF: case T_QMARK: return ut_execute_if(state, op); case T_FOR: return ut_execute_for(state, op); case T_WHILE: return ut_execute_while(state, op); case T_AND: case T_OR: return ut_execute_and_or(state, op); case T_LT: case T_LE: case T_GT: case T_GE: case T_EQ: case T_NE: return ut_execute_rel(state, op); case T_IN: return ut_execute_in(state, op); case T_INC: case T_DEC: return ut_execute_inc_dec(state, op); case T_LPAREN: return ut_execute_call(state, op); case T_LEXP: return ut_execute_exp(state, op); case T_ADD: case T_SUB: case T_MUL: case T_DIV: case T_MOD: return ut_execute_arith(state, op); case T_LSHIFT: case T_RSHIFT: case T_BAND: case T_BXOR: case T_BOR: return ut_execute_bitop(state, op); case T_COMPL: return ut_execute_compl(state, op); case T_NOT: return ut_execute_not(state, op); case T_RETURN: return ut_execute_return(state, op); case T_BREAK: case T_CONTINUE: return ut_execute_break_cont(state, op); default: return ut_exception(state, op, "Runtime error: Unrecognized opcode %d", op->type); } } static struct json_object * ut_execute_op_sequence(struct ut_state *state, struct ut_opcode *op) { struct json_object *v = NULL; struct ut_opcode *tag = NULL; while (op) { ut_putval(v); v = ut_execute_op(state, op); 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 = op->sibling; } return v; } enum ut_error_type ut_run(struct ut_state *state) { struct json_object *scope, *args, *rv; if (!state->main || state->main->type != T_FUNC || !state->main->val) { ut_exception(state, state->main, "Runtime error: Invalid root operation in AST"); 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 = scope; ut_lib_init(state, scope); args = json_object_new_array(); rv = ut_invoke(state, state->main, NULL, state->main->val, args); json_object_put(args); json_object_put(rv); return state->error.code; }