diff options
author | Jo-Philipp Wich <jo@mein.io> | 2020-12-02 20:21:27 +0100 |
---|---|---|
committer | Jo-Philipp Wich <jo@mein.io> | 2020-12-06 16:49:10 +0100 |
commit | 30d3682b7a35496110044bfe2c02a48eedf52a9f (patch) | |
tree | 35a7c64000f9b0dc1930ee760dbe7117afb6afe7 | |
parent | 7caf3331ba7d8f0dd91659e4001c9d8256bf4558 (diff) |
treewide: prevent stale pointer access in opcode handlers
Instead of obtaining and caching direct opcode pointers, use relative
references when dealing with opcodes since direct or indirect calls to
uc_execute_op() might lead to reallocations of the opcode array, shifting
memory addresses and invalidating pointers taken before the invocation.
Such stale pointer accesses could be commonly triggered when one part
of the processed expression was a require() or include() call loading
relatively large ucode sources.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
-rw-r--r-- | ast.c | 78 | ||||
-rw-r--r-- | ast.h | 43 | ||||
-rw-r--r-- | eval.c | 416 | ||||
-rw-r--r-- | lexer.c | 83 | ||||
-rw-r--r-- | lib.c | 116 | ||||
-rw-r--r-- | main.c | 49 | ||||
-rw-r--r-- | parser.y | 139 |
7 files changed, 454 insertions, 470 deletions
@@ -54,28 +54,25 @@ uc_new_op(struct uc_state *s, int type, struct json_object *val, ...) va_start(ap, val); - while (n_op < ARRAY_SIZE(newop->tree.operand) && (child = va_arg(ap, uint32_t)) != UINT32_MAX) + while (n_op < OPn_NUM && (child = va_arg(ap, uint32_t)) != UINT32_MAX) newop->tree.operand[n_op++] = child; va_end(ap); - s->poolsize++; - - return s->poolsize; + return s->poolsize++; } uint32_t -uc_wrap_op(struct uc_state *s, uint32_t parent, ...) +uc_wrap_op(struct uc_state *state, uint32_t parent, ...) { - struct uc_op *op = uc_get_op(s, parent); uint32_t child; int n_op = 0; va_list ap; va_start(ap, parent); - while (n_op < ARRAY_SIZE(op->tree.operand) && (child = va_arg(ap, uint32_t)) != UINT32_MAX) - op->tree.operand[n_op++] = child; + while (n_op < OPn_NUM && (child = va_arg(ap, uint32_t)) != UINT32_MAX) + OPn(parent, n_op++) = child; va_end(ap); @@ -83,14 +80,16 @@ uc_wrap_op(struct uc_state *s, uint32_t parent, ...) } uint32_t -uc_append_op(struct uc_state *s, uint32_t a, uint32_t b) +uc_append_op(struct uc_state *state, uint32_t a, uint32_t b) { - struct uc_op *tail = uc_get_op(s, a); + uint32_t tail_off, next_off; - while (tail && tail->tree.next) - tail = uc_get_op(s, tail->tree.next); + for (tail_off = a, next_off = OP_NEXT(tail_off); + next_off != 0; + tail_off = next_off, next_off = OP_NEXT(next_off)) + ; - tail->tree.next = b; + OP_NEXT(tail_off) = b; return a; } @@ -303,49 +302,50 @@ func_to_string(struct json_object *v, struct printbuf *pb, int level, int flags) } struct json_object * -uc_new_func(struct uc_state *s, struct uc_op *decl, struct uc_scope *scope) +uc_new_func(struct uc_state *state, uint32_t decl, struct uc_scope *scope) { struct json_object *val = xjs_new_object(); - struct uc_op *op, *name, *args, *arg; + uint32_t name_off, args_off, arg_off; struct uc_function *fn; + struct uc_op *op; size_t sz; sz = ALIGN(sizeof(*op)) + ALIGN(sizeof(*fn)); - name = uc_get_op(s, decl->tree.operand[0]); - args = uc_get_op(s, decl->tree.operand[1]); + name_off = OPn(decl, 0); + args_off = OPn(decl, 1); - if (name) - sz += ALIGN(json_object_get_string_len(name->val) + 1); + if (name_off) + sz += ALIGN(json_object_get_string_len(OP_VAL(name_off)) + 1); op = xalloc(sz); fn = (void *)op + ALIGN(sizeof(*op)); - fn->entry = decl->tree.operand[2]; + fn->entry = OPn(decl, 2); - if (name) - fn->name = strcpy((char *)fn + ALIGN(sizeof(*fn)), json_object_get_string(name->val)); + if (name_off) + fn->name = strcpy((char *)fn + ALIGN(sizeof(*fn)), json_object_get_string(OP_VAL(name_off))); - if (args) { + if (args_off) { fn->args = xjs_new_array(); - for (arg = args; arg; arg = uc_get_op(s, arg->tree.next)) { - json_object_array_add(fn->args, json_object_get(arg->val)); + for (arg_off = args_off; arg_off != 0; arg_off = OP_NEXT(arg_off)) { + json_object_array_add(fn->args, json_object_get(OP_VAL(arg_off))); /* if the last argument is a rest one (...arg), add extra null entry */ - if (arg->is_ellip) { + if (OP_IS_ELLIP(arg_off)) { json_object_array_add(fn->args, NULL); break; } } } - fn->source = s->function ? s->function->source : NULL; + fn->source = state->function ? state->function->source : NULL; fn->parent_scope = uc_acquire_scope(scope); op->val = val; op->type = T_FUNC; - op->is_arrow = (decl->type == T_ARROW); + op->is_arrow = (OP_TYPE(decl) == T_ARROW); op->tag.data = fn; json_object_set_serializer(val, func_to_string, op, func_free); @@ -568,36 +568,34 @@ uc_free(struct uc_state *s) } struct json_object * -uc_parse(struct uc_state *s, FILE *fp) +uc_parse(struct uc_state *state, FILE *fp) { - struct uc_op *op; void *pParser; uint32_t off; - uc_reset(s); + uc_reset(state); pParser = ParseAlloc(xalloc); - while (s->lex.state != UT_LEX_EOF) { - off = uc_get_token(s, fp); - op = uc_get_op(s, off); + while (state->lex.state != UT_LEX_EOF) { + off = uc_get_token(state, fp); - if (s->exception) + if (state->exception) goto out; - if (op) - Parse(pParser, op->type, off, s); + if (off) + Parse(pParser, OP_TYPE(off), off, state); - if (s->exception) + if (state->exception) goto out; } - Parse(pParser, 0, 0, s); + Parse(pParser, 0, 0, state); out: ParseFree(pParser, free); - return s->exception; + return state->exception; } bool @@ -154,34 +154,31 @@ struct uc_extended_type { void (*free)(void *); }; -static inline struct uc_op *uc_get_op(struct uc_state *s, uint32_t off) -{ - if (off == 0 || off > s->poolsize) - return NULL; - - return &s->pool[off - 1]; -} - -static inline struct uc_op *uc_get_child(struct uc_state *s, uint32_t off, int n) -{ - struct uc_op *op = uc_get_op(s, off); - - if (!op || n >= ARRAY_SIZE(op->tree.operand) || !op->tree.operand[n]) - return NULL; - - return uc_get_op(s, op->tree.operand[n]); -} - -static inline uint32_t uc_get_off(struct uc_state *s, struct uc_op *op) { - return op ? (op - s->pool + 1) : 0; -}; - static inline bool uc_is_type(struct json_object *val, int type) { struct uc_op *tag = json_object_get_userdata(val); return (tag && tag->type == type); }; +#define OP(idx) (&state->pool[idx]) +#define OP_POS(idx) OP(idx)->off +#define OP_VAL(idx) OP(idx)->val +#define OP_TYPE(idx) OP(idx)->type +#define OP_NEXT(idx) OP(idx)->tree.next +#define OP_IS_LIST(idx) OP(idx)->is_list +#define OP_IS_ELLIP(idx) OP(idx)->is_ellip +#define OP_IS_FOR_IN(idx) OP(idx)->is_for_in +#define OP_IS_POSTFIX(idx) OP(idx)->is_postfix + +#define OPn_NUM ARRAY_SIZE(((struct uc_op *)NULL)->tree.operand) +#define OPn(idx, n) OP(idx)->tree.operand[n] +#define OPn_POS(idx, n) OP(OPn(idx, n))->off +#define OPn_VAL(idx, n) OP(OPn(idx, n))->val +#define OPn_TYPE(idx, n) OP(OPn(idx, n))->type +#define OPn_IS_LIST(idx, n) OP(OPn(idx, n))->is_list +#define OPn_IS_OVERFLOW(idx, n) OP(OPn(idx, n))->is_overflow + + uint32_t uc_new_op(struct uc_state *s, int type, struct json_object *val, ...); uint32_t uc_wrap_op(struct uc_state *s, uint32_t parent, ...); @@ -189,7 +186,7 @@ uint32_t uc_append_op(struct uc_state *s, uint32_t a, uint32_t b); struct json_object *uc_parse(struct uc_state *s, FILE *fp); void uc_free(struct uc_state *s); -struct json_object *uc_new_func(struct uc_state *s, struct uc_op *decl, struct uc_scope *scope); +struct json_object *uc_new_func(struct uc_state *s, uint32_t decl, struct uc_scope *scope); struct json_object *uc_new_object(struct json_object *proto); struct json_object *uc_new_double(double v); struct json_object *uc_new_null(void); @@ -145,15 +145,15 @@ uc_execute_list(struct uc_state *state, uint32_t off); static char * uc_ref_to_str(struct uc_state *state, uint32_t off) { - struct uc_op *op = uc_get_op(state, off); - struct uc_op *op2 = uc_get_child(state, off, 1); + int child_type = OPn_TYPE(off, 1); + int op_type = OP_TYPE(off); const char *l; char *s, *p; - switch (op ? op->type : 0) { + switch (op_type) { case T_DOT: - s = uc_ref_to_str(state, op->tree.operand[0]); - l = ((op2 ? op2->type : 0) == T_LABEL) ? json_object_get_string(op2->val) : "???"; + s = uc_ref_to_str(state, OPn(off, 0)); + l = (child_type == T_LABEL) ? json_object_get_string(OPn_VAL(off, 1)) : "???"; if (asprintf(&p, "%s.%s", s ? s : "(...)", l) == -1) p = NULL; @@ -163,23 +163,23 @@ uc_ref_to_str(struct uc_state *state, uint32_t off) return p; case T_LBRACK: - if (!op->is_postfix) + if (!OP_IS_POSTFIX(off)) return NULL; /* fall through */ case T_LPAREN: - s = uc_ref_to_str(state, op->tree.operand[0]); + s = uc_ref_to_str(state, OPn(off, 0)); - switch (op2 ? op2->type : 0) { + switch (child_type) { case T_STRING: - l = json_object_to_json_string_ext(op2->val, JSON_C_TO_STRING_NOSLASHESCAPE); + l = json_object_to_json_string_ext(OPn_VAL(off, 1), JSON_C_TO_STRING_NOSLASHESCAPE); break; case T_NUMBER: case T_LABEL: case T_BOOL: - l = json_object_get_string(op2->val); + l = json_object_get_string(OPn_VAL(off, 1)); break; default: @@ -187,8 +187,8 @@ uc_ref_to_str(struct uc_state *state, uint32_t off) } if (asprintf(&p, "%s%c%s%c", s ? s : "(...)", - (op->type == T_LPAREN) ? '(' : '[', l, - (op->type == T_LPAREN) ? ')' : ']') == -1) + (op_type == T_LPAREN) ? '(' : '[', l, + (op_type == T_LPAREN) ? ')' : ']') == -1) p = NULL; free(s); @@ -196,7 +196,7 @@ uc_ref_to_str(struct uc_state *state, uint32_t off) return p; case T_LABEL: - return strdup(json_object_get_string(op->val)); + return strdup(json_object_get_string(OP_VAL(off))); default: return NULL; @@ -206,22 +206,22 @@ uc_ref_to_str(struct uc_state *state, uint32_t off) static struct json_object * uc_getref(struct uc_state *state, uint32_t off, struct json_object **key) { - struct uc_op *op = uc_get_op(state, off); - uint32_t off1 = op ? op->tree.operand[0] : 0; - uint32_t off2 = op ? op->tree.operand[1] : 0; + uint32_t off1 = OPn(off, 0); + uint32_t off2 = OPn(off, 1); + int type = OP_TYPE(off); struct uc_scope *sc, *next; struct json_object *val; if (key) *key = NULL; - if (op && op->type == T_DOT) { + if (type == T_DOT) { if (key) - *key = off2 ? json_object_get(uc_get_op(state, off2)->val) : NULL; + *key = off2 ? json_object_get(OP_VAL(off2)) : NULL; return uc_execute_op_sequence(state, off1); } - else if (op && op->type == T_LBRACK && op->is_postfix) { + else if (type == T_LBRACK && OP_IS_POSTFIX(off)) { if (key) { val = off2 ? uc_execute_op_sequence(state, off2) : NULL; @@ -233,20 +233,20 @@ uc_getref(struct uc_state *state, uint32_t off, struct json_object **key) return uc_execute_op_sequence(state, off1); } - else if (op && op->type == T_LABEL) { + else if (type == T_LABEL) { sc = state->scope; while (true) { - if (json_object_object_get_ex(sc->scope, json_object_get_string(op->val), NULL)) + if (json_object_object_get_ex(sc->scope, json_object_get_string(OP_VAL(off)), NULL)) break; next = uc_parent_scope(sc); if (!next) { if (state->strict_declarations) { - return uc_new_exception(state, op->off, + return uc_new_exception(state, OP_POS(off), "Reference error: access to undeclared variable %s", - json_object_get_string(op->val)); + json_object_get_string(OP_VAL(off))); } break; @@ -256,7 +256,7 @@ uc_getref(struct uc_state *state, uint32_t off, struct json_object **key) } if (key) - *key = json_object_get(op->val); + *key = json_object_get(OP_VAL(off)); return json_object_get(sc->scope); } @@ -271,7 +271,7 @@ uc_getref(struct uc_state *state, uint32_t off, struct json_object **key) static struct json_object * uc_getref_required(struct uc_state *state, uint32_t off, struct json_object **key) { - struct uc_op *op1 = uc_get_child(state, off, 0); + uint32_t child_off = OPn(off, 0); struct json_object *scope, *skey, *rv; char *lhs; @@ -280,15 +280,17 @@ uc_getref_required(struct uc_state *state, uint32_t off, struct json_object **ke if (!json_object_is_type(scope, json_type_array) && !json_object_is_type(scope, json_type_object)) { if (!uc_is_type(scope, T_EXCEPTION)) { - lhs = op1 ? uc_ref_to_str(state, uc_get_off(state, op1)) : NULL; + lhs = child_off ? uc_ref_to_str(state, child_off) : NULL; if (lhs) { - rv = uc_new_exception(state, op1->off, "Type error: `%s` is %s", + rv = uc_new_exception(state, OPn_POS(off, 0), + "Type error: `%s` is %s", lhs, scope ? "not an array or object" : "null"); free(lhs); } else { - rv = uc_new_exception(state, op1->off, "Type error: left-hand side is not an array or object"); + rv = uc_new_exception(state, OPn_POS(off, 0), + "Type error: left-hand side is not an array or object"); } json_object_put(scope); @@ -310,12 +312,12 @@ uc_getref_required(struct uc_state *state, uint32_t off, struct json_object **ke static struct json_object * uc_getproto(struct json_object *obj) { - struct uc_op *op = json_object_get_userdata(obj); + struct uc_op *tag = json_object_get_userdata(obj); - if (!op || (op->type != T_LBRACE && op->type <= __T_MAX) || !op->val) + if (!tag || (tag->type != T_LBRACE && tag->type <= __T_MAX) || !tag->val) return NULL; - return op->tag.proto; + return tag->tag.proto; } static struct json_object * @@ -390,17 +392,16 @@ uc_setval(struct json_object *scope, struct json_object *key, struct json_object static struct json_object * uc_execute_assign(struct uc_state *state, uint32_t off) { - struct uc_op *op = uc_get_op(state, off); - uint32_t label = op ? op->tree.operand[0] : 0; - uint32_t value = op ? op->tree.operand[1] : 0; + uint32_t label_off = OPn(off, 0); + uint32_t value_off = OPn(off, 1); struct json_object *scope, *key, *val; - scope = uc_getref_required(state, label, &key); + scope = uc_getref_required(state, label_off, &key); if (!key) return scope; - val = uc_execute_op_sequence(state, value); + val = uc_execute_op_sequence(state, value_off); if (!uc_is_type(val, T_EXCEPTION)) uc_setval(scope, key, val); @@ -414,18 +415,14 @@ uc_execute_assign(struct uc_state *state, uint32_t off) static struct json_object * uc_execute_local(struct uc_state *state, uint32_t off) { - struct uc_op *op = uc_get_op(state, off), *asop, *alop; - uint32_t as = op ? op->tree.operand[0] : 0; struct json_object *val, *rv = NULL; + uint32_t assign_off, label_off; - while (as) { - asop = uc_get_op(state, as); - as = asop ? asop->tree.next : 0; - - switch (asop ? asop->type : 0) { + for (assign_off = OPn(off, 0); assign_off != 0; assign_off = OP_NEXT(assign_off)) { + switch (OP_TYPE(assign_off)) { case T_ASSIGN: - alop = uc_get_op(state, asop->tree.operand[0]); - val = uc_execute_op_sequence(state, asop->tree.operand[1]); + label_off = OPn(assign_off, 0); + val = uc_execute_op_sequence(state, OPn(assign_off, 1)); if (uc_is_type(val, T_EXCEPTION)) return val; @@ -433,7 +430,7 @@ uc_execute_local(struct uc_state *state, uint32_t off) break; case T_LABEL: - alop = asop; + label_off = assign_off; val = NULL; break; @@ -441,9 +438,9 @@ uc_execute_local(struct uc_state *state, uint32_t off) continue; } - if (alop) { + if (label_off) { json_object_put(rv); - rv = uc_setval(state->scope->scope, alop->val, val); + rv = uc_setval(state->scope->scope, OP_VAL(label_off), val); } } @@ -467,18 +464,17 @@ uc_test_condition(struct uc_state *state, uint32_t off) static struct json_object * uc_execute_if(struct uc_state *state, uint32_t off) { - struct uc_op *op = uc_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; - bool res = uc_test_condition(state, cond); + uint32_t cond_off = OPn(off, 0); + uint32_t then_off = OPn(off, 1); + uint32_t else_off = OPn(off, 2); + bool res = uc_test_condition(state, cond_off); if (state->exception) return json_object_get(state->exception); else if (res) - return uc_execute_op_sequence(state, Then); - else if (Else) - return uc_execute_op_sequence(state, Else); + return uc_execute_op_sequence(state, then_off); + else if (else_off) + return uc_execute_op_sequence(state, else_off); return NULL; } @@ -487,39 +483,40 @@ static struct json_object * uc_execute_for(struct uc_state *state, uint32_t off) { struct json_object *kscope, *vscope, *val, *item, *ik, *iv = NULL, *rv = NULL; - struct uc_op *loop = uc_get_op(state, off); - struct uc_op *init = uc_get_child(state, off, 0); - uint32_t test = loop ? loop->tree.operand[1] : 0; - uint32_t incr = loop ? loop->tree.operand[2] : 0; - uint32_t body = loop ? loop->tree.operand[3] : 0; - struct uc_op *ikvar, *ivvar, *tag; + uint32_t init_off = OPn(off, 0); + uint32_t cond_off = OPn(off, 1); + uint32_t step_off = OPn(off, 2); + uint32_t body_off = OPn(off, 3); + uint32_t ik_off, iv_off; size_t arridx, arrlen; bool local = false; + struct uc_op *tag; /* for (x in ...) loop variant */ - if (loop->is_for_in) { - if (init->type == T_LOCAL) { + if (OP_IS_FOR_IN(off)) { + if (OP_TYPE(init_off) == T_LOCAL) { local = true; - init = uc_get_op(state, init->tree.operand[0]); + init_off = OPn(init_off, 0); } - ikvar = uc_get_op(state, init->tree.operand[0]); - ik = ikvar->val; - kscope = local ? state->scope->scope : uc_getref(state, uc_get_off(state, ikvar), NULL); + ik_off = OPn(init_off, 0); + ik = OP_VAL(ik_off); + kscope = local ? state->scope->scope : uc_getref(state, ik_off, NULL); if (uc_is_type(kscope, T_EXCEPTION)) return kscope; - if (ikvar->tree.next) { - ivvar = uc_get_op(state, ikvar->tree.next); - iv = ivvar->val; - vscope = local ? kscope : uc_getref(state, uc_get_off(state, ivvar), NULL); + iv_off = OP_NEXT(ik_off); + + if (iv_off) { + iv = OP_VAL(iv_off); + vscope = local ? kscope : uc_getref(state, iv_off, NULL); if (uc_is_type(vscope, T_EXCEPTION)) return vscope; } - val = uc_execute_op_sequence(state, init->tree.operand[1]); + val = uc_execute_op_sequence(state, OPn(init_off, 1)); if (uc_is_type(val, T_EXCEPTION)) return val; @@ -539,7 +536,7 @@ uc_execute_for(struct uc_state *state, uint32_t off) json_object_put(rv); - rv = uc_execute_op_sequence(state, body); + rv = uc_execute_op_sequence(state, body_off); tag = json_object_get_userdata(rv); switch (tag ? tag->type : 0) { @@ -566,7 +563,7 @@ uc_execute_for(struct uc_state *state, uint32_t off) json_object_put(rv); - rv = uc_execute_op_sequence(state, body); + rv = uc_execute_op_sequence(state, body_off); tag = json_object_get_userdata(rv); switch (tag ? tag->type : 0) { @@ -591,8 +588,8 @@ uc_execute_for(struct uc_state *state, uint32_t off) return NULL; } - if (init) { - val = uc_execute_op_sequence(state, uc_get_off(state, init)); + if (init_off) { + val = uc_execute_op_sequence(state, init_off); if (uc_is_type(val, T_EXCEPTION)) return val; @@ -600,10 +597,10 @@ uc_execute_for(struct uc_state *state, uint32_t off) json_object_put(val); } - while (test ? uc_test_condition(state, test) : true) { + while (cond_off ? uc_test_condition(state, cond_off) : true) { json_object_put(rv); - rv = uc_execute_op_sequence(state, body); + rv = uc_execute_op_sequence(state, body_off); tag = json_object_get_userdata(rv); switch (tag ? tag->type : 0) { @@ -617,8 +614,8 @@ uc_execute_for(struct uc_state *state, uint32_t off) return NULL; } - if (incr) { - val = uc_execute_op_sequence(state, incr); + if (step_off) { + val = uc_execute_op_sequence(state, step_off); if (uc_is_type(val, T_EXCEPTION)) { json_object_put(rv); @@ -638,9 +635,8 @@ uc_execute_for(struct uc_state *state, uint32_t off) static struct json_object * uc_execute_while(struct uc_state *state, uint32_t off) { - struct uc_op *op = uc_get_op(state, off); - uint32_t test = op ? op->tree.operand[0] : 0; - uint32_t body = op ? op->tree.operand[1] : 0; + uint32_t test = OPn(off, 0); + uint32_t body = OPn(off, 1); struct json_object *v, *rv = NULL; struct uc_op *tag = NULL; bool cond; @@ -682,19 +678,20 @@ uc_execute_while(struct uc_state *state, uint32_t off) static struct json_object * uc_execute_and_or(struct uc_state *state, uint32_t off) { - struct uc_op *op = uc_get_op(state, off); + bool is_or = (OP_TYPE(off) == T_OR); struct json_object *val = NULL; - int i; + uint32_t op_off; + int i = 0; - for (i = 0; i < ARRAY_SIZE(op->tree.operand) && op->tree.operand[i]; i++) { + for (op_off = OPn(off, 0); op_off != 0 && i < OPn_NUM; op_off = OPn(off, ++i)) { json_object_put(val); - val = uc_execute_op_sequence(state, op->tree.operand[i]); + val = uc_execute_op_sequence(state, op_off); if (uc_is_type(val, T_EXCEPTION)) break; - if (uc_val_is_truish(val) == (op->type == T_OR)) + if (uc_val_is_truish(val) == is_or) break; } @@ -763,19 +760,19 @@ uc_cmp(int how, struct json_object *v1, struct json_object *v2) } static struct json_object * -_uc_get_operands(struct uc_state *state, struct uc_op *op, size_t n, struct json_object **v) +_uc_get_operands(struct uc_state *state, uint32_t op_off, size_t n, struct json_object **v) { struct json_object *ctx = NULL; - struct uc_op *child; + uint32_t child_off; size_t i, j; for (i = 0; i < n; i++) { - child = op ? uc_get_op(state, op->tree.operand[i]) : NULL; + child_off = OPn(op_off, i); - if (child && child->is_list) - v[i] = uc_execute_list(state, uc_get_off(state, child)); - else if (child) - v[i] = uc_execute_op_sequence(state, uc_get_off(state, child)); + if (child_off && OP_IS_LIST(child_off)) + v[i] = uc_execute_list(state, child_off); + else if (child_off) + v[i] = uc_execute_op_sequence(state, child_off); else v[i] = NULL; @@ -798,21 +795,20 @@ _uc_get_operands(struct uc_state *state, struct uc_op *op, size_t n, struct json return NULL; } -#define uc_get_operands(state, op, vals) \ +#define uc_get_operands(state, off, vals) \ do { \ - struct json_object *ex = _uc_get_operands(state, op, ARRAY_SIZE(vals), vals); \ + struct json_object *ex = _uc_get_operands(state, off, ARRAY_SIZE(vals), vals); \ if (ex) return ex; \ } while(0) static struct json_object * uc_execute_rel(struct uc_state *state, uint32_t off) { - struct uc_op *op = uc_get_op(state, off); struct json_object *v[2], *rv; - uc_get_operands(state, op, v); + uc_get_operands(state, off, v); - rv = xjs_new_boolean(uc_cmp(op->type, v[0], v[1])); + rv = xjs_new_boolean(uc_cmp(OP_TYPE(off), v[0], v[1])); json_object_put(v[0]); json_object_put(v[1]); @@ -864,14 +860,13 @@ uc_eq(struct json_object *v1, struct json_object *v2) static struct json_object * uc_execute_equality(struct uc_state *state, uint32_t off) { - struct uc_op *op = uc_get_op(state, off); struct json_object *v[2], *rv; bool equal = false; - uc_get_operands(state, op, v); + uc_get_operands(state, off, v); equal = uc_eq(v[0], v[1]); - rv = xjs_new_boolean((op->type == T_EQS) ? equal : !equal); + rv = xjs_new_boolean((OP_TYPE(off) == T_EQS) ? equal : !equal); json_object_put(v[0]); json_object_put(v[1]); @@ -882,13 +877,12 @@ uc_execute_equality(struct uc_state *state, uint32_t off) static struct json_object * uc_execute_in(struct uc_state *state, uint32_t off) { - struct uc_op *op = uc_get_op(state, off); struct json_object *v[2], *item; size_t arrlen, arridx; bool found = false; const char *key; - uc_get_operands(state, op, v); + uc_get_operands(state, off, v); if (json_object_is_type(v[1], json_type_array)) { for (arridx = 0, arrlen = json_object_array_length(v[1]); @@ -915,13 +909,12 @@ uc_execute_in(struct uc_state *state, uint32_t off) static struct json_object * uc_execute_inc_dec(struct uc_state *state, uint32_t off) { - struct uc_op *op = uc_get_op(state, off); + bool is_inc = (OP_TYPE(off) == T_INC); struct json_object *val, *nval, *scope, *key; - uint32_t label = op ? op->tree.operand[0] : 0; int64_t n; double d; - scope = uc_getref_required(state, label, &key); + scope = uc_getref_required(state, OPn(off, 0), &key); if (!key) return scope; @@ -932,14 +925,14 @@ uc_execute_inc_dec(struct uc_state *state, uint32_t off) json_object_put(key); if (uc_cast_number(val, &n, &d) == json_type_double) - nval = uc_new_double(d + (op->type == T_INC ? 1.0 : -1.0)); + nval = uc_new_double(d + (is_inc ? 1.0 : -1.0)); else - nval = xjs_new_int64(n + (op->type == T_INC ? 1 : -1)); + nval = xjs_new_int64(n + (is_inc ? 1 : -1)); json_object_put(uc_setval(scope, key, nval)); /* postfix inc/dec, return old val */ - if (op->is_postfix) + if (OP_IS_POSTFIX(off)) return val; json_object_put(val); @@ -950,12 +943,11 @@ uc_execute_inc_dec(struct uc_state *state, uint32_t off) static struct json_object * uc_execute_list(struct uc_state *state, uint32_t off) { - struct uc_op *op = uc_get_op(state, off); struct json_object *ex, *val, *arr = xjs_new_array(); size_t i; - while (op) { - val = uc_execute_op(state, uc_get_off(state, op)); + while (off) { + val = uc_execute_op(state, off); if (uc_is_type(val, T_EXCEPTION)) { json_object_put(arr); @@ -963,9 +955,10 @@ uc_execute_list(struct uc_state *state, uint32_t off) return val; } - if (op->is_ellip) { + if (OP_IS_ELLIP(off)) { if (!json_object_is_type(val, json_type_array)) { - ex = uc_new_exception(state, op->off, "Type error: (%s) is not iterable", + ex = uc_new_exception(state, OP_POS(off), + "Type error: (%s) is not iterable", json_object_get_string(val)); json_object_put(arr); @@ -983,7 +976,7 @@ uc_execute_list(struct uc_state *state, uint32_t off) json_object_array_add(arr, val); } - op = uc_get_op(state, op->tree.next); + off = OP_NEXT(off); } return arr; @@ -993,12 +986,12 @@ static struct json_object * uc_execute_object(struct uc_state *state, uint32_t off) { struct json_object *ex, *v, *obj = uc_new_object(NULL); - struct uc_op *key; + uint32_t key_off; char *istr; size_t i; - for (key = uc_get_child(state, off, 0); key; key = uc_get_op(state, key->tree.next)) { - v = uc_execute_op_sequence(state, key->tree.operand[0]); + for (key_off = OPn(off, 0); key_off != 0; key_off = OP_NEXT(key_off)) { + v = uc_execute_op_sequence(state, OPn(key_off, 0)); if (uc_is_type(v, T_EXCEPTION)) { json_object_put(obj); @@ -1006,7 +999,7 @@ uc_execute_object(struct uc_state *state, uint32_t off) return v; } - if (key->type == T_ELLIP) { + if (OP_TYPE(key_off) == T_ELLIP) { switch (json_object_get_type(v)) { case json_type_object: ; /* a label can only be part of a statement and a declaration is not a statement */ @@ -1029,7 +1022,8 @@ uc_execute_object(struct uc_state *state, uint32_t off) break; default: - ex = uc_new_exception(state, key->off, "Type error: (%s) is not iterable", + ex = uc_new_exception(state, OP_POS(key_off), + "Type error: (%s) is not iterable", json_object_get_string(v)); json_object_put(obj); @@ -1039,7 +1033,7 @@ uc_execute_object(struct uc_state *state, uint32_t off) } } else { - json_object_object_add(obj, json_object_get_string(key->val), v); + json_object_object_add(obj, json_object_get_string(OP_VAL(key_off)), v); } } @@ -1050,7 +1044,7 @@ struct json_object * uc_invoke(struct uc_state *state, uint32_t off, struct json_object *this, struct json_object *func, struct json_object *argvals) { - struct uc_op *op, *tag = json_object_get_userdata(func); + struct uc_op *tag = json_object_get_userdata(func); struct json_object *arr, *rv = NULL; struct uc_callstack callstack = {}; struct uc_function *fn, *prev_fn; @@ -1062,14 +1056,12 @@ uc_invoke(struct uc_state *state, uint32_t off, struct json_object *this, if (!tag) return NULL; - op = uc_get_op(state, off); - if (state->calldepth >= 1000) - return uc_new_exception(state, op->off, "Runtime error: Too much recursion"); + return uc_new_exception(state, OP_POS(off), "Runtime error: Too much recursion"); callstack.next = state->callstack; callstack.function = state->function; - callstack.off = op ? op->off : 0; + callstack.off = OP_POS(off); if (tag->is_arrow) callstack.ctx = state->callstack ? json_object_get(state->callstack->ctx) : NULL; @@ -1128,7 +1120,7 @@ uc_invoke(struct uc_state *state, uint32_t off, struct json_object *this, case T_BREAK: case T_CONTINUE: json_object_put(rv); - rv = uc_new_exception(state, uc_get_off(state, tag), + rv = uc_new_exception(state, tag->off, "Syntax error: %s statement must be inside loop", uc_get_tokenname(tag->type)); break; @@ -1160,19 +1152,19 @@ uc_invoke(struct uc_state *state, uint32_t off, struct json_object *this, static struct json_object * uc_execute_call(struct uc_state *state, uint32_t off) { - struct uc_op *decl, *op = uc_get_op(state, off); - struct uc_op *op1 = uc_get_child(state, off, 0); struct json_object *v[2], *rv; + struct uc_op *decl; char *lhs; - uc_get_operands(state, op, v); + uc_get_operands(state, off, v); decl = json_object_get_userdata(v[0]); if (!decl || (decl->type != T_FUNC && decl->type != T_CFUNC)) { - lhs = uc_ref_to_str(state, uc_get_off(state, op1)); + lhs = uc_ref_to_str(state, OPn(off, 0)); - rv = uc_new_exception(state, op1->off, "Type error: %s is not a function", + rv = uc_new_exception(state, OPn_POS(off, 0), + "Type error: %s is not a function", lhs ? lhs : "left-hand side expression"); free(lhs); @@ -1224,8 +1216,7 @@ uc_write_str(struct json_object *v) static struct json_object * uc_execute_exp(struct uc_state *state, uint32_t off) { - struct uc_op *op = uc_get_op(state, off); - struct json_object *val = uc_execute_op_sequence(state, op ? op->tree.operand[0] : 0); + struct json_object *val = uc_execute_op_sequence(state, OPn(off, 0)); struct uc_op *tag = val ? json_object_get_userdata(val) : NULL; switch (tag ? tag->type : 0) { @@ -1246,14 +1237,13 @@ uc_execute_exp(struct uc_state *state, uint32_t off) static struct json_object * uc_execute_unary_plus_minus(struct uc_state *state, uint32_t off) { - struct uc_op *op = uc_get_op(state, off); - struct uc_op *op1 = uc_get_child(state, off, 0); + bool is_sub = (OP_TYPE(off) == T_SUB); struct json_object *v[1]; enum json_type t; int64_t n; double d; - uc_get_operands(state, op, v); + uc_get_operands(state, off, v); t = uc_cast_number(v[0], &n, &d); @@ -1261,20 +1251,20 @@ uc_execute_unary_plus_minus(struct uc_state *state, uint32_t off) switch (t) { case json_type_int: - if (op1->is_overflow) - return xjs_new_int64(((n >= 0) == (op->type == T_SUB)) ? INT64_MIN : INT64_MAX); + if (OPn_IS_OVERFLOW(off, 0)) + return xjs_new_int64(((n >= 0) == is_sub) ? INT64_MIN : INT64_MAX); - return xjs_new_int64((op->type == T_SUB) ? -n : n); + return xjs_new_int64(is_sub ? -n : n); default: - return uc_new_double((op->type == T_SUB) ? -d : d); + return uc_new_double(is_sub ? -d : d); } } static struct json_object * uc_execute_arith(struct uc_state *state, uint32_t off) { - struct uc_op *op = uc_get_op(state, off); + int type = OP_TYPE(off); struct json_object *v[2], *rv; enum json_type t1, t2; const char *s1, *s2; @@ -1283,12 +1273,12 @@ uc_execute_arith(struct uc_state *state, uint32_t off) double d1, d2; char *s; - if (!op->tree.operand[1]) + if (!OPn(off, 1)) return uc_execute_unary_plus_minus(state, off); - uc_get_operands(state, op, v); + uc_get_operands(state, off, v); - if (op->type == T_ADD && + if (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"; @@ -1318,7 +1308,7 @@ uc_execute_arith(struct uc_state *state, uint32_t off) d1 = (t1 == json_type_double) ? d1 : (double)n1; d2 = (t2 == json_type_double) ? d2 : (double)n2; - switch (op->type) { + switch (type) { case T_ADD: return uc_new_double(d1 + d2); @@ -1343,7 +1333,7 @@ uc_execute_arith(struct uc_state *state, uint32_t off) } } - switch (op->type) { + switch (type) { case T_ADD: return xjs_new_int64(n1 + n2); @@ -1369,12 +1359,11 @@ uc_execute_arith(struct uc_state *state, uint32_t off) static struct json_object * uc_execute_bitop(struct uc_state *state, uint32_t off) { - struct uc_op *op = uc_get_op(state, off); struct json_object *v[2]; int64_t n1, n2; double d; - uc_get_operands(state, op, v); + uc_get_operands(state, off, v); if (uc_cast_number(v[0], &n1, &d) == json_type_double) n1 = isnan(d) ? 0 : (int64_t)d; @@ -1385,7 +1374,7 @@ uc_execute_bitop(struct uc_state *state, uint32_t off) json_object_put(v[0]); json_object_put(v[1]); - switch (op->type) { + switch (OP_TYPE(off)) { case T_LSHIFT: return xjs_new_int64(n1 << n2); @@ -1409,20 +1398,17 @@ uc_execute_bitop(struct uc_state *state, uint32_t off) static struct json_object * uc_execute_not(struct uc_state *state, uint32_t off) { - struct uc_op *op = uc_get_op(state, off); - - return xjs_new_boolean(!uc_test_condition(state, op ? op->tree.operand[0] : 0)); + return xjs_new_boolean(!uc_test_condition(state, OPn(off, 0))); } static struct json_object * uc_execute_compl(struct uc_state *state, uint32_t off) { - struct uc_op *op = uc_get_op(state, off); struct json_object *v[1]; int64_t n; double d; - uc_get_operands(state, op, v); + uc_get_operands(state, off, v); if (uc_cast_number(v[0], &n, &d) == json_type_double) n = isnan(d) ? 0 : (int64_t)d; @@ -1432,20 +1418,29 @@ uc_execute_compl(struct uc_state *state, uint32_t off) return xjs_new_int64(~n); } +static void +uc_free_tag(struct json_object *v, void *ud) +{ + free(ud); +} + static struct json_object * uc_execute_return(struct uc_state *state, uint32_t off) { - struct uc_op *op = uc_get_op(state, off); + struct uc_op *cpy = xalloc(sizeof(*cpy)); struct json_object *v[1], *rv; - uc_get_operands(state, op, v); + memcpy(cpy, OP(off), sizeof(*cpy)); + cpy->off = off; + + uc_get_operands(state, off, v); json_object_put(state->rval); state->rval = v[0]; rv = xjs_new_boolean(false); - json_object_set_userdata(rv, op, NULL); + json_object_set_userdata(rv, cpy, uc_free_tag); return rv; } @@ -1453,10 +1448,13 @@ uc_execute_return(struct uc_state *state, uint32_t off) static struct json_object * uc_execute_break_cont(struct uc_state *state, uint32_t off) { - struct uc_op *op = uc_get_op(state, off); + struct uc_op *cpy = xalloc(sizeof(*cpy)); struct json_object *rv = xjs_new_int64(0); - json_object_set_userdata(rv, op, NULL); + memcpy(cpy, OP(off), sizeof(*cpy)); + cpy->off = off; + + json_object_set_userdata(rv, cpy, uc_free_tag); return rv; } @@ -1464,12 +1462,11 @@ uc_execute_break_cont(struct uc_state *state, uint32_t off) static struct json_object * uc_execute_function(struct uc_state *state, uint32_t off) { - struct uc_op *op = uc_get_op(state, off); - struct uc_op *op1 = uc_get_child(state, off, 0); - struct json_object *obj = uc_new_func(state, op, state->scope); + struct json_object *obj = uc_new_func(state, off, state->scope); + struct json_object *val = OPn_VAL(off, 0); - if (op1) - uc_setval(state->scope->scope, op1->val, obj); + if (val) + uc_setval(state->scope->scope, val, obj); return obj; } @@ -1483,19 +1480,21 @@ uc_execute_this(struct uc_state *state, uint32_t off) static struct json_object * uc_execute_try_catch(struct uc_state *state, uint32_t off) { - struct uc_op *tag, *op = uc_get_op(state, off); - struct json_object *rv; + struct json_object *evar, *rv; + struct uc_op *tag; - rv = uc_execute_op_sequence(state, op->tree.operand[0]); + rv = uc_execute_op_sequence(state, OPn(off, 0)); if (uc_is_type(rv, T_EXCEPTION)) { - if (op->tree.operand[1]) { + evar = OPn_VAL(off, 1); + + if (evar) { /* remove the T_EXCEPTION type from the object to avoid handling * it as a new exception in the catch block */ tag = json_object_get_userdata(rv); tag->type = T_LBRACE; - json_object_put(uc_setval(state->scope->scope, uc_get_child(state, off, 1)->val, + json_object_put(uc_setval(state->scope->scope, evar, json_object_get(rv))); } @@ -1503,16 +1502,16 @@ uc_execute_try_catch(struct uc_state *state, uint32_t off) state->exception = NULL; json_object_put(rv); - rv = uc_execute_op_sequence(state, op->tree.operand[2]); + rv = uc_execute_op_sequence(state, OPn(off, 2)); } return rv; } static bool -uc_match_case(struct uc_state *state, struct json_object *v, struct uc_op *Case) +uc_match_case(struct uc_state *state, struct json_object *v, uint32_t case_off) { - struct json_object *caseval = uc_execute_op_sequence(state, Case->tree.operand[0]); + struct json_object *caseval = uc_execute_op_sequence(state, OPn(case_off, 0)); bool rv = uc_eq(v, caseval); json_object_put(caseval); @@ -1522,48 +1521,41 @@ uc_match_case(struct uc_state *state, struct json_object *v, struct uc_op *Case) static struct json_object * uc_execute_switch_case(struct uc_state *state, uint32_t off) { - struct uc_op *Default = NULL, *Case = NULL, *jmp = NULL; - struct uc_op *op = uc_get_op(state, off); + uint32_t case_off, default_off = 0, jmp_off = 0; struct json_object *v[1], *rv = NULL; - uc_get_operands(state, op, v); + uc_get_operands(state, off, v); /* First try to find matching case... */ - for (Case = uc_get_child(state, off, 1); - Case != NULL; - Case = uc_get_op(state, Case->tree.next)) - { + for (case_off = OPn(off, 1); case_off != 0; case_off = OP_NEXT(case_off)) { /* remember default case and throw on dupes */ - if (Case->type == T_DEFAULT) { - if (Default) { + if (OP_TYPE(case_off) == T_DEFAULT) { + if (default_off) { json_object_put(v[0]); - return uc_new_exception(state, Case->off, + return uc_new_exception(state, OP_POS(case_off), "Syntax error: more than one switch default case"); } - Default = Case; + default_off = case_off; continue; } /* Found a matching case, remember jump offset */ - if (uc_match_case(state, v[0], Case)) { - jmp = Case; + if (uc_match_case(state, v[0], case_off)) { + jmp_off = case_off; break; } } /* jump to matching case (or default) and continue until break */ - for (Case = jmp ? jmp : Default; - Case != NULL; - Case = uc_get_op(state, Case->tree.next)) - { + for (case_off = jmp_off ? jmp_off : default_off; case_off != 0; case_off = OP_NEXT(case_off)) { json_object_put(rv); - if (Case == Default) - rv = uc_execute_op_sequence(state, Default->tree.operand[0]); + if (OP_TYPE(case_off) == T_DEFAULT) + rv = uc_execute_op_sequence(state, OPn(case_off, 0)); else - rv = uc_execute_op_sequence(state, Case->tree.operand[1]); + rv = uc_execute_op_sequence(state, OPn(case_off, 1)); if (uc_is_type(rv, T_BREAK)) { json_object_put(rv); @@ -1583,13 +1575,13 @@ uc_execute_switch_case(struct uc_state *state, uint32_t off) static struct json_object * uc_execute_atom(struct uc_state *state, uint32_t off) { - return json_object_get(uc_get_op(state, off)->val); + return json_object_get(OP_VAL(off)); } static struct json_object * uc_execute_text(struct uc_state *state, uint32_t off) { - printf("%s", json_object_get_string(uc_get_op(state, off)->val)); + printf("%s", json_object_get_string(OP_VAL(off))); return NULL; } @@ -1597,7 +1589,6 @@ uc_execute_text(struct uc_state *state, uint32_t off) static struct json_object * uc_execute_label(struct uc_state *state, uint32_t off) { - struct uc_op *op = uc_get_op(state, off); struct json_object *scope, *key, *val; scope = uc_getref(state, off, &key); @@ -1606,9 +1597,9 @@ uc_execute_label(struct uc_state *state, uint32_t off) state->ctx = NULL; if (state->strict_declarations && scope == NULL) { - return uc_new_exception(state, op->off, + return uc_new_exception(state, OP_POS(off), "Reference error: %s is not defined", - json_object_get_string(op->val)); + json_object_get_string(OP_VAL(off))); } val = uc_getval(scope, key); @@ -1641,21 +1632,17 @@ uc_execute_dot(struct uc_state *state, uint32_t off) static struct json_object * uc_execute_lbrack(struct uc_state *state, uint32_t off) { - struct uc_op *op = uc_get_op(state, off); - /* postfix access */ - if (op->is_postfix) + if (OP_IS_POSTFIX(off)) return uc_execute_dot(state, off); - return uc_execute_list(state, op->tree.operand[0]); + return uc_execute_list(state, OPn(off, 0)); } static struct json_object * uc_execute_exp_list(struct uc_state *state, uint32_t off) { - struct uc_op *op = uc_get_op(state, off); - - return uc_execute_op_sequence(state, op->tree.operand[0]); + return uc_execute_op_sequence(state, OPn(off, 0)); } static struct json_object *(*fns[__T_MAX])(struct uc_state *, uint32_t) = { @@ -1718,12 +1705,13 @@ static struct json_object *(*fns[__T_MAX])(struct uc_state *, uint32_t) = { static struct json_object * uc_execute_op(struct uc_state *state, uint32_t off) { - struct uc_op *op = uc_get_op(state, off); + int type = OP_TYPE(off); - if (!fns[op->type]) - return uc_new_exception(state, op->off, "Runtime error: Unrecognized opcode %d", op->type); + if (!fns[type]) + return uc_new_exception(state, OP_POS(off), + "Runtime error: Unrecognized opcode %d", type); - return fns[op->type](state, off); + return fns[type](state, off); } static struct json_object * @@ -1731,7 +1719,6 @@ uc_execute_op_sequence(struct uc_state *state, uint32_t off) { struct json_object *v = NULL; struct uc_op *tag = NULL; - struct uc_op *op = NULL; while (off) { json_object_put(v); @@ -1747,8 +1734,7 @@ uc_execute_op_sequence(struct uc_state *state, uint32_t off) return v; } - op = uc_get_op(state, off); - off = op ? op->tree.next : 0; + off = OP_NEXT(off); } return v; @@ -221,12 +221,11 @@ utf8enc(char **out, int *rem, int code) /* length of the longest token in our lookup table */ #define UT_LEX_MAX_TOKEN_LEN 3 -static uint32_t emit_op(struct uc_state *s, uint32_t pos, int type, struct json_object *val) +static uint32_t emit_op(struct uc_state *state, uint32_t pos, int type, struct json_object *val) { - uint32_t off = uc_new_op(s, type, val, UINT32_MAX); - struct uc_op *op = uc_get_op(s, off); + uint32_t off = uc_new_op(state, type, val, UINT32_MAX); - op->off = pos; + OP(off)->off = pos; /* Follow JSLint logic and treat a slash after any of the * `(,=:[!&|?{};` characters as the beginning of a regex @@ -272,11 +271,11 @@ static uint32_t emit_op(struct uc_state *s, uint32_t pos, int type, struct json_ case T_LEXP: case T_SCOL: - s->lex.expect_div = false; + state->lex.expect_div = false; break; default: - s->lex.expect_div = true; + state->lex.expect_div = true; } return off; @@ -616,62 +615,62 @@ enum { }; static uint32_t -parse_regexp(struct uc_state *s) +parse_regexp(struct uc_state *state) { struct json_object *pattern; struct uc_op *op; uint32_t rv; char *err; - switch (s->lex.esc[0]) { + switch (state->lex.esc[0]) { case UT_LEX_PARSE_REGEX_INIT: - if (s->lex.expect_div) { - s->lex.expect_div = false; + if (state->lex.expect_div) { + state->lex.expect_div = false; - if (buf_startswith(s, "=")) { - buf_consume(s, 1); + if (buf_startswith(state, "=")) { + buf_consume(state, 1); - return emit_op(s, s->source->off, T_ASDIV, NULL); + return emit_op(state, state->source->off, T_ASDIV, NULL); } - return emit_op(s, s->source->off, T_DIV, NULL); + return emit_op(state, state->source->off, T_DIV, NULL); } - s->lex.esc[0] = UT_LEX_PARSE_REGEX_PATTERN; + state->lex.esc[0] = UT_LEX_PARSE_REGEX_PATTERN; break; case UT_LEX_PARSE_REGEX_PATTERN: - rv = parse_string(s); + rv = parse_string(state); if (rv != 0 && rv != UINT32_MAX) { - s->lex.lookbehind = (char *)uc_get_op(s, rv); - s->lex.esc[0] = UT_LEX_PARSE_REGEX_FLAGS; + state->lex.lookbehind = (char *)OP(rv); + state->lex.esc[0] = UT_LEX_PARSE_REGEX_FLAGS; } break; case UT_LEX_PARSE_REGEX_FLAGS: - op = (struct uc_op *)s->lex.lookbehind; + op = (struct uc_op *)state->lex.lookbehind; - while (s->lex.bufstart < s->lex.bufend) { - switch (s->lex.bufstart[0]) { + while (state->lex.bufstart < state->lex.bufend) { + switch (state->lex.bufstart[0]) { case 'g': - buf_consume(s, 1); + buf_consume(state, 1); op->is_reg_global = true; break; case 'i': - buf_consume(s, 1); + buf_consume(state, 1); op->is_reg_icase = true; break; case 's': - buf_consume(s, 1); + buf_consume(state, 1); op->is_reg_newline = true; break; default: - s->lex.lookbehind = NULL; + state->lex.lookbehind = NULL; pattern = uc_new_regexp(json_object_get_string(op->val), op->is_reg_icase, @@ -685,13 +684,13 @@ parse_regexp(struct uc_state *s) op->val = pattern; if (!pattern) { - uc_new_exception(s, op->off, "Syntax error: %s", err); + uc_new_exception(state, op->off, "Syntax error: %s", err); free(err); return 0; } - return uc_get_off(s, op); + return op - state->pool; } } @@ -781,46 +780,46 @@ is_numeric_char(struct uc_state *s, char c) } static uint32_t -parse_number(struct uc_state *s) +parse_number(struct uc_state *state) { uint32_t rv = 0; long long int n; char *ptr, *e; double d; - if (!buf_remaining(s) || !is_numeric_char(s, s->lex.bufstart[0])) { - lookbehind_append(s, "\0", 1); + if (!buf_remaining(state) || !is_numeric_char(state, state->lex.bufstart[0])) { + lookbehind_append(state, "\0", 1); - n = strtoll(s->lex.lookbehind, &e, 0); + n = strtoll(state->lex.lookbehind, &e, 0); if (*e == '.' || *e == 'e' || *e == 'E') { - d = strtod(s->lex.lookbehind, &e); + d = strtod(state->lex.lookbehind, &e); - if (e > s->lex.lookbehind && *e == 0) - rv = emit_op(s, s->source->off - (e - s->lex.lookbehind), T_DOUBLE, uc_new_double(d)); + if (e > state->lex.lookbehind && *e == 0) + rv = emit_op(state, state->source->off - (e - state->lex.lookbehind), T_DOUBLE, uc_new_double(d)); else - uc_new_exception(s, s->source->off - (s->lex.lookbehindlen - (e - s->lex.lookbehind) - 1), + uc_new_exception(state, state->source->off - (state->lex.lookbehindlen - (e - state->lex.lookbehind) - 1), "Syntax error: Invalid number literal"); } else if (*e == 0) { - rv = emit_op(s, s->source->off - (e - s->lex.lookbehind), T_NUMBER, xjs_new_int64(n)); - uc_get_op(s, rv)->is_overflow = (errno == ERANGE); + rv = emit_op(state, state->source->off - (e - state->lex.lookbehind), T_NUMBER, xjs_new_int64(n)); + OP(rv)->is_overflow = (errno == ERANGE); } else { - uc_new_exception(s, s->source->off - (s->lex.lookbehindlen - (e - s->lex.lookbehind) - 1), + uc_new_exception(state, state->source->off - (state->lex.lookbehindlen - (e - state->lex.lookbehind) - 1), "Syntax error: Invalid number literal"); } - lookbehind_reset(s); + lookbehind_reset(state); return rv; } - for (ptr = s->lex.bufstart; ptr < s->lex.bufend && is_numeric_char(s, *ptr); ptr++) + for (ptr = state->lex.bufstart; ptr < state->lex.bufend && is_numeric_char(state, *ptr); ptr++) ; - lookbehind_append(s, s->lex.bufstart, ptr - s->lex.bufstart); - buf_consume(s, ptr - s->lex.bufstart); + lookbehind_append(state, state->lex.bufstart, ptr - state->lex.bufstart); + buf_consume(state, ptr - state->lex.bufstart); return 0; } @@ -186,9 +186,8 @@ format_error_context(char **msg, size_t *msglen, struct uc_source *src, struct j } struct json_object * -uc_parse_error(struct uc_state *s, uint32_t off, uint64_t *tokens, int max_token) +uc_parse_error(struct uc_state *state, uint32_t off, uint64_t *tokens, int max_token) { - struct uc_op *op = uc_get_op(s, off); struct json_object *rv; size_t msglen = 0; bool first = true; @@ -210,8 +209,8 @@ uc_parse_error(struct uc_state *s, uint32_t off, uint64_t *tokens, int max_token } } - rv = uc_new_exception(s, - op ? op->off : s->lex.lastoff, + rv = uc_new_exception(state, + off ? OP_POS(off) : state->lex.lastoff, "Syntax error: Unexpected token\n%s", msg); free(msg); @@ -1574,10 +1573,9 @@ uc_printf(struct uc_state *s, uint32_t off, struct json_object *args) } static struct json_object * -uc_require_so(struct uc_state *s, uint32_t off, const char *path) +uc_require_so(struct uc_state *state, uint32_t off, const char *path) { void (*init)(const struct uc_ops *, struct uc_state *, struct json_object *); - struct uc_op *op = uc_get_op(s, off); struct uc_function fn = {}, *prev_fn; struct uc_source *src, *prev_src; struct json_object *scope; @@ -1591,32 +1589,34 @@ uc_require_so(struct uc_state *s, uint32_t off, const char *path) dlh = dlopen(path, RTLD_LAZY|RTLD_LOCAL); if (!dlh) - return uc_new_exception(s, op->off, "Unable to dlopen file %s: %s", path, dlerror()); + return uc_new_exception(state, OP_POS(off), + "Unable to dlopen file %s: %s", path, dlerror()); init = dlsym(dlh, "uc_module_init"); if (!init) - return uc_new_exception(s, op->off, "Module %s provides no 'uc_module_init' function", path); + return uc_new_exception(state, OP_POS(off), + "Module %s provides no 'uc_module_init' function", path); src = xalloc(sizeof(*src)); src->filename = xstrdup(path); - src->next = s->sources; + src->next = state->sources; fn.name = "require"; fn.source = src; - prev_fn = s->function; - s->function = &fn; + prev_fn = state->function; + state->function = &fn; - prev_src = s->source; - s->source = s->sources = src; + prev_src = state->source; + state->source = state->sources = src; scope = xjs_new_object(); - init(&ut, s, scope); + init(&ut, state, scope); - s->source = prev_src; - s->function = prev_fn; + state->source = prev_src; + state->function = prev_fn; return scope; } @@ -1629,7 +1629,7 @@ uc_execute_source(struct uc_state *s, struct uc_source *src, struct uc_scope *sc rv = uc_parse(s, src->fp); if (!uc_is_type(rv, T_EXCEPTION)) { - entry = uc_new_func(s, uc_get_op(s, s->main), scope ? scope : s->scope); + entry = uc_new_func(s, s->main, scope ? scope : s->scope); json_object_put(rv); rv = uc_invoke(s, s->main, NULL, entry, NULL); @@ -1641,9 +1641,8 @@ uc_execute_source(struct uc_state *s, struct uc_source *src, struct uc_scope *sc } static struct json_object * -uc_require_utpl(struct uc_state *s, uint32_t off, const char *path, struct uc_scope *scope) +uc_require_utpl(struct uc_state *state, uint32_t off, const char *path, struct uc_scope *scope) { - struct uc_op *op = uc_get_op(s, off); struct uc_function fn = {}, *prev_fn; struct uc_source *src, *prev_src; struct json_object *rv; @@ -1656,26 +1655,27 @@ uc_require_utpl(struct uc_state *s, uint32_t off, const char *path, struct uc_sc fp = fopen(path, "rb"); if (!fp) - return uc_new_exception(s, op->off, "Unable to open file %s: %s", path, strerror(errno)); + return uc_new_exception(state, OP_POS(off), + "Unable to open file %s: %s", path, strerror(errno)); src = xalloc(sizeof(*src)); src->fp = fp; src->filename = path ? xstrdup(path) : NULL; - src->next = s->sources; + src->next = state->sources; - prev_src = s->source; - s->source = s->sources = src; + prev_src = state->source; + state->source = state->sources = src; fn.name = "require"; fn.source = src; - prev_fn = s->function; - s->function = &fn; + prev_fn = state->function; + state->function = &fn; - rv = uc_execute_source(s, src, scope); + rv = uc_execute_source(state, src, scope); - s->function = prev_fn; - s->source = prev_src; + state->function = prev_fn; + state->source = prev_src; return rv; } @@ -1722,11 +1722,10 @@ invalid: } static struct json_object * -uc_require(struct uc_state *s, uint32_t off, struct json_object *args) +uc_require(struct uc_state *state, uint32_t off, struct json_object *args) { struct json_object *val = json_object_array_get_idx(args, 0); struct json_object *search, *se, *res; - struct uc_op *op = uc_get_op(s, off); struct uc_scope *sc, *scparent; size_t arridx, arrlen; const char *name; @@ -1735,7 +1734,7 @@ uc_require(struct uc_state *s, uint32_t off, struct json_object *args) return NULL; /* find root scope */ - for (sc = s->scope; sc; ) { + for (sc = state->scope; sc; ) { scparent = uc_parent_scope(sc); if (!scparent) @@ -1748,7 +1747,7 @@ uc_require(struct uc_state *s, uint32_t off, struct json_object *args) search = sc ? json_object_object_get(sc->scope, "REQUIRE_SEARCH_PATH") : NULL; if (!json_object_is_type(search, json_type_array)) - return uc_new_exception(s, op ? op->off : 0, + return uc_new_exception(state, off ? OP_POS(off) : 0, "Global require search path not set"); for (arridx = 0, arrlen = json_object_array_length(search); arridx < arrlen; arridx++) { @@ -1757,13 +1756,13 @@ uc_require(struct uc_state *s, uint32_t off, struct json_object *args) if (!json_object_is_type(se, json_type_string)) continue; - res = uc_require_path(s, off, json_object_get_string(se), name); + res = uc_require_path(state, off, json_object_get_string(se), name); if (res) return res; } - return uc_new_exception(s, op ? op->off : 0, + return uc_new_exception(state, off ? OP_POS(off) : 0, "No module named '%s' could be found", name); } @@ -2103,17 +2102,17 @@ uc_replace(struct uc_state *s, uint32_t off, struct json_object *args) } static struct json_object * -uc_json(struct uc_state *s, uint32_t off, struct json_object *args) +uc_json(struct uc_state *state, uint32_t off, struct json_object *args) { struct json_object *rv, *src = json_object_array_get_idx(args, 0); - struct uc_op *op = uc_get_op(s, off); struct json_tokener *tok = NULL; enum json_tokener_error err; const char *str; size_t len; if (!json_object_is_type(src, json_type_string)) - return uc_new_exception(s, op->off, "Passed value is not a string"); + return uc_new_exception(state, OP_POS(off), + "Passed value is not a string"); tok = xjs_new_tokener(); str = json_object_get_string(src); @@ -2124,16 +2123,19 @@ uc_json(struct uc_state *s, uint32_t off, struct json_object *args) if (err == json_tokener_continue) { json_object_put(rv); - rv = uc_new_exception(s, op->off, "Unexpected end of string in JSON data"); + rv = uc_new_exception(state, OP_POS(off), + "Unexpected end of string in JSON data"); } else if (err != json_tokener_success) { json_object_put(rv); - rv = uc_new_exception(s, op->off, "Failed to parse JSON string: %s", - json_tokener_error_desc(err)); + rv = uc_new_exception(state, OP_POS(off), + "Failed to parse JSON string: %s", + json_tokener_error_desc(err)); } else if (json_tokener_get_parse_end(tok) < len) { json_object_put(rv); - rv = uc_new_exception(s, op->off, "Trailing garbage after JSON data"); + rv = uc_new_exception(state, OP_POS(off), + "Trailing garbage after JSON data"); } json_tokener_free(tok); @@ -2175,36 +2177,38 @@ include_path(const char *curpath, const char *incpath) } static struct json_object * -uc_include(struct uc_state *s, uint32_t off, struct json_object *args) +uc_include(struct uc_state *state, uint32_t off, struct json_object *args) { struct json_object *rv, *path = json_object_array_get_idx(args, 0); struct json_object *scope = json_object_array_get_idx(args, 1); - struct uc_op *op = uc_get_op(s, off); struct uc_scope *sc; char *p; if (!json_object_is_type(path, json_type_string)) - return uc_new_exception(s, op->off, "Passed filename is not a string"); + return uc_new_exception(state, OP_POS(off), + "Passed filename is not a string"); if (scope && !json_object_is_type(scope, json_type_object)) - return uc_new_exception(s, op->off, "Passed scope value is not an object"); + return uc_new_exception(state, OP_POS(off), + "Passed scope value is not an object"); - p = include_path(s->callstack->function->source->filename, json_object_get_string(path)); + p = include_path(state->callstack->function->source->filename, json_object_get_string(path)); if (!p) - return uc_new_exception(s, op->off, "Include file not found"); + return uc_new_exception(state, OP_POS(off), + "Include file not found"); if (scope) { - sc = uc_new_scope(s, NULL); + sc = uc_new_scope(state, NULL); json_object_object_foreach(scope, key, val) json_object_object_add(sc->scope, key, json_object_get(val)); } else { - sc = s->scope; + sc = state->scope; } - rv = uc_require_utpl(s, off, p, sc); + rv = uc_require_utpl(state, off, p, sc); free(p); @@ -2226,11 +2230,10 @@ uc_warn(struct uc_state *s, uint32_t off, struct json_object *args) } static struct json_object * -uc_system(struct uc_state *s, uint32_t off, struct json_object *args) +uc_system(struct uc_state *state, uint32_t off, struct json_object *args) { struct json_object *cmdline = json_object_array_get_idx(args, 0); struct json_object *timeout = json_object_array_get_idx(args, 1); - struct uc_op *op = uc_get_op(s, off); sigset_t sigmask, sigomask; const char **arglist, *fn; struct timespec ts; @@ -2259,11 +2262,13 @@ uc_system(struct uc_state *s, uint32_t off, struct json_object *args) break; default: - return uc_new_exception(s, op->off, "Passed command is neither string nor array"); + return uc_new_exception(state, OP_POS(off), + "Passed command is neither string nor array"); } if (timeout && (!json_object_is_type(timeout, json_type_int) || json_object_get_int64(timeout) < 0)) - return uc_new_exception(s, op->off, "Invalid timeout specified"); + return uc_new_exception(state, OP_POS(off), + "Invalid timeout specified"); tms = timeout ? json_object_get_int64(timeout) : 0; @@ -2334,7 +2339,8 @@ fail: sigprocmask(SIG_SETMASK, &sigomask, NULL); free(arglist); - return uc_new_exception(s, op->off, "%s(): %s", fn, strerror(errno)); + return uc_new_exception(state, OP_POS(off), + "%s(): %s", fn, strerror(errno)); } const struct uc_ops ut = { @@ -53,30 +53,30 @@ print_usage(char *app) } #ifndef NDEBUG -static void dump(struct uc_state *s, uint32_t off, int level); +static void dump(struct uc_state *state, uint32_t off, int level); -static void dump_node(struct uc_op *op) { +static void dump_node(struct uc_state *state, uint32_t off) { const char *p; - switch (op->type) { + switch (OP_TYPE(off)) { case T_NUMBER: - printf("n%p [label=\"%"PRId64"\"];\n", op, json_object_get_int64(op->val)); + printf("n%u [label=\"%"PRId64"\"];\n", off, json_object_get_int64(OP_VAL(off))); break; case T_DOUBLE: - printf("n%p [label=\"%f\"];\n", op, json_object_get_double(op->val)); + printf("n%u [label=\"%f\"];\n", off, json_object_get_double(OP_VAL(off))); break; case T_BOOL: - printf("n%p [label=\"%s\"];\n", op, json_object_get_boolean(op->val) ? "true" : "false"); + printf("n%u [label=\"%s\"];\n", off, json_object_get_boolean(OP_VAL(off)) ? "true" : "false"); break; case T_STRING: case T_LABEL: case T_TEXT: - printf("n%p [label=\"%s<", op, uc_get_tokenname(op->type)); + printf("n%u [label=\"%s<", off, uc_get_tokenname(OP_TYPE(off))); - for (p = json_object_get_string(op->val); *p; p++) + for (p = json_object_get_string(OP_VAL(off)); *p; p++) switch (*p) { case '\n': printf("\\\n"); @@ -98,43 +98,43 @@ static void dump_node(struct uc_op *op) { break; default: - printf("n%p [label=\"%s", op, uc_get_tokenname(op->type)); + printf("n%u [label=\"%s", off, uc_get_tokenname(OP_TYPE(off))); - if (op->is_postfix) + if (OP_IS_POSTFIX(off)) printf(", postfix"); printf("\"];\n"); } } -static void dump(struct uc_state *s, uint32_t off, int level) { - struct uc_op *prev, *cur, *child; +static void dump(struct uc_state *state, uint32_t off, int level) { + uint32_t prev_off, cur_off, child_off; int i; if (level == 0) { printf("digraph G {\nmain [shape=box];\n"); } - for (prev = NULL, cur = uc_get_op(s, off); cur; prev = cur, cur = uc_get_op(s, cur->tree.next)) { - dump_node(cur); + for (prev_off = 0, cur_off = off; cur_off != 0; prev_off = cur_off, cur_off = OP_NEXT(cur_off)) { + dump_node(state, cur_off); - if (cur->type < __T_MAX) { - for (i = 0; i < ARRAY_SIZE(cur->tree.operand); i++) { - child = uc_get_op(s, cur->tree.operand[i]); + if (OP_TYPE(cur_off) < __T_MAX) { + for (i = 0; i < OPn_NUM; i++) { + child_off = OPn(cur_off, i); - if (cur->tree.operand[i]) { - dump(s, cur->tree.operand[i], level + 1); - printf("n%p -> n%p [label=\"op%d\"];\n", cur, child, i + 1); + if (child_off) { + dump(state, child_off, level + 1); + printf("n%u -> n%u [label=\"op%d\"];\n", cur_off, child_off, i + 1); } } } - if (prev) - printf("n%p -> n%p [style=dotted];\n", prev, cur); + if (prev_off) + printf("n%u -> n%u [style=dotted];\n", prev_off, cur_off); } if (level == 0) { - printf("main -> n%p [style=dotted];\n", uc_get_op(s, off)); + printf("main -> n%u [style=dotted];\n", off); printf("}\n"); } @@ -276,6 +276,9 @@ main(int argc, char **argv) state->lstrip_blocks = 1; state->trim_blocks = 1; + /* reserve opcode slot 0 */ + uc_new_op(state, 0, NULL, UINT32_MAX); + while ((opt = getopt(argc, argv, "dhlrSe:E:i:s:m:")) != -1) { switch (opt) { @@ -15,7 +15,7 @@ */ %token_type {uint32_t} -%extra_argument {struct uc_state *s} +%extra_argument {struct uc_state *state} %nonassoc T_LEXP T_REXP T_LSTM T_RSTM. @@ -59,55 +59,53 @@ #define YYNOERRORRECOVERY #define new_op(type, val, ...) \ - uc_new_op(s, type, val, ##__VA_ARGS__, UINT32_MAX) + uc_new_op(state, type, val, ##__VA_ARGS__, UINT32_MAX) #define wrap_op(op, ...) \ - uc_wrap_op(s, op, ##__VA_ARGS__, UINT32_MAX) + uc_wrap_op(state, op, ##__VA_ARGS__, UINT32_MAX) #define append_op(op1, op2) \ - uc_append_op(s, op1, op2) + uc_append_op(state, op1, op2) #define no_empty_obj(op) \ - uc_no_empty_obj(s, op) + uc_no_empty_obj(state, op) static inline uint32_t -uc_no_empty_obj(struct uc_state *s, uint32_t off) +uc_no_empty_obj(struct uc_state *state, uint32_t off) { - struct uc_op *op = uc_get_op(s, off); - - return (!op || op->type != T_LBRACE || op->tree.operand[0]) ? off : 0; + return (OP_TYPE(off) != T_LBRACE || OPn(off, 0)) ? off : 0; } static inline uint32_t -uc_add_else(struct uc_state *s, uint32_t off, uint32_t add) +uc_add_else(struct uc_state *state, uint32_t off, uint32_t add) { - struct uc_op *tail = uc_get_op(s, off); + uint32_t tail_off = off; - while (tail && tail->tree.operand[2]) - tail = uc_get_op(s, tail->tree.operand[2]); + while (OPn(tail_off, 2)) + tail_off = OPn(tail_off, 2); - tail->tree.operand[2] = add; + OPn(tail_off, 2) = add; return off; } static inline uint32_t -uc_expect_token(struct uc_state *s, uint32_t off, int token) +uc_expect_token(struct uc_state *state, uint32_t off, int token) { uint64_t tokens[(__T_MAX + 63) & -64] = {}; tokens[token / 64] |= ((uint64_t)1 << (token % 64)); - uc_parse_error(s, off, tokens, token); + uc_parse_error(state, off, tokens, token); return 0; } static inline uint32_t -_uc_check_op_seq_types(struct uc_state *s, uint32_t off, ...) +_uc_check_op_seq_types(struct uc_state *state, uint32_t off, ...) { uint64_t tokens[(__T_MAX + 63) & -64] = {}; - struct uc_op *arg = uc_get_op(s, off); - int token, max_token = 0; + int type, token, max_token = 0; + uint32_t arg_off; va_list ap; va_start(ap, off); @@ -119,28 +117,27 @@ _uc_check_op_seq_types(struct uc_state *s, uint32_t off, ...) va_end(ap); - while (arg) { - if (!(tokens[arg->type / 64] & ((uint64_t)1 << (arg->type % 64)))) { - uc_parse_error(s, off, tokens, max_token); + for (arg_off = off; arg_off != 0; arg_off = OP_NEXT(arg_off)) { + type = OP_TYPE(arg_off); + + if (!(tokens[type / 64] & ((uint64_t)1 << (type % 64)))) { + uc_parse_error(state, off, tokens, max_token); return 0; } - - arg = uc_get_op(s, arg->tree.next); } return off; } -#define uc_check_op_seq_types(s, off, ...) _uc_check_op_seq_types(s, off, __VA_ARGS__, 0) +#define uc_check_op_seq_types(state, off, ...) _uc_check_op_seq_types(state, off, __VA_ARGS__, 0) static inline uint32_t -uc_reject_local(struct uc_state *s, uint32_t off) +uc_reject_local(struct uc_state *state, uint32_t off) { - struct uc_op *op = uc_get_op(s, off); - - if (op->type == T_LOCAL) { - uc_new_exception(s, op->off, "Syntax error: Unexpected token\nDeclaration not allowed in this context"); + if (OP_TYPE(off) == T_LOCAL) { + uc_new_exception(state, OP_POS(off), + "Syntax error: Unexpected token\nDeclaration not allowed in this context"); return 0; } @@ -149,45 +146,43 @@ uc_reject_local(struct uc_state *s, uint32_t off) } static inline uint32_t -uc_check_for_in(struct uc_state *s, uint32_t off) +uc_check_for_in(struct uc_state *state, uint32_t off) { - struct uc_op *op = uc_get_op(s, off); - struct uc_op *arg; - uint32_t idx = 0; + uint32_t arg_off, idx = 0; - arg = (op->type == T_LOCAL) ? uc_get_op(s, op->tree.operand[0]) : op; + arg_off = (OP_TYPE(off) == T_LOCAL) ? OPn(off, 0) : off; - if (arg->type == T_LABEL) { - idx = uc_get_off(s, arg); + if (OP_TYPE(arg_off) == T_LABEL) { + idx = arg_off; - if (!arg->tree.next) { - uc_new_exception(s, arg->off + json_object_get_string_len(arg->val), + if (!OP_NEXT(arg_off)) { + uc_new_exception(state, OP_POS(arg_off) + json_object_get_string_len(OP_VAL(arg_off)), "Syntax error: Unexpected token\nExpecting ',' or 'in'"); return 0; } - arg = uc_get_op(s, arg->tree.next); + arg_off = OP_NEXT(arg_off); } - if (arg->type != T_IN || arg->tree.next || uc_get_op(s, arg->tree.operand[0])->type != T_LABEL) { - if (arg->type == T_IN && arg->tree.next) - arg = uc_get_op(s, arg->tree.next); + if (OP_TYPE(arg_off) != T_IN || OP_NEXT(arg_off) || OPn_TYPE(arg_off, 0) != T_LABEL) { + if (OP_TYPE(arg_off) == T_IN && OP_NEXT(arg_off)) + arg_off = OP_NEXT(arg_off); - uc_new_exception(s, arg->off, "Syntax error: Invalid for-in expression"); + uc_new_exception(state, OP_POS(arg_off), "Syntax error: Invalid for-in expression"); return 0; } /* transform T_LABEL->T_IN(T_LABEL, ...) into T_IN(T_LABEL->T_LABEL, ...) */ if (idx) { - uc_get_op(s, idx)->tree.next = 0; - arg->tree.operand[0] = append_op(idx, arg->tree.operand[0]); + OP_NEXT(idx) = 0; + OPn(arg_off, 0) = append_op(idx, OPn(arg_off, 0)); - if (op->type == T_LOCAL) - op->tree.operand[0] = uc_get_off(s, arg); + if (OP_TYPE(off) == T_LOCAL) + OPn(off, 0) = arg_off; else - off = uc_get_off(s, arg); + off = arg_off; } return off; @@ -206,12 +201,12 @@ uc_check_for_in(struct uc_state *s, uint32_t off) } } - uc_parse_error(s, TOKEN, tokens, max_token); + uc_parse_error(state, TOKEN, tokens, max_token); } -input ::= chunks(A). { s->main = new_op(T_FUNC, NULL, 0, 0, A); } -input ::= . { s->main = new_op(T_TEXT, xjs_new_string("")); s->main = new_op(T_FUNC, NULL, 0, 0, s->main); } +input ::= chunks(A). { state->main = new_op(T_FUNC, NULL, 0, 0, A); } +input ::= . { state->main = new_op(T_TEXT, xjs_new_string("")); state->main = new_op(T_FUNC, NULL, 0, 0, state->main); } chunks(A) ::= chunks(B) T_TEXT(C). { A = B ? append_op(B, C) : C; } chunks(A) ::= chunks(B) tplexp(C). { A = B ? append_op(B, C) : C; } @@ -249,13 +244,13 @@ sel_stmt(A) ::= T_IF(B) T_LPAREN exp(C) T_RPAREN stmt(D) T_ELSE stmt(E). sel_stmt(A) ::= T_IF(B) T_LPAREN exp(C) T_RPAREN stmt(D). [T_IF] { A = wrap_op(B, C, no_empty_obj(D)); } sel_stmt(A) ::= T_IF(B) T_LPAREN exp(C) T_RPAREN T_COLON chunks(D) sel_elifs(E) T_ELSE chunks(F) T_ENDIF. - { A = uc_add_else(s, wrap_op(B, C, D, E), F); } + { A = uc_add_else(state, wrap_op(B, C, D, E), F); } sel_stmt(A) ::= T_IF(B) T_LPAREN exp(C) T_RPAREN T_COLON chunks(D) T_ELSE chunks(E) T_ENDIF. { A = wrap_op(B, C, D, E); } sel_stmt(A) ::= T_IF(B) T_LPAREN exp(C) T_RPAREN T_COLON chunks(D) T_ENDIF. [T_IF] { A = wrap_op(B, C, D); } -sel_elifs(A) ::= sel_elifs(B) sel_elif(C). { A = uc_add_else(s, B, C); } +sel_elifs(A) ::= sel_elifs(B) sel_elif(C). { A = uc_add_else(state, B, C); } sel_elifs(A) ::= sel_elif(B). { A = B; } sel_elif(A) ::= T_ELIF(B) T_LPAREN exp(C) T_RPAREN T_COLON chunks(D). @@ -266,9 +261,9 @@ iter_stmt(A) ::= T_WHILE(B) T_LPAREN exp(C) T_RPAREN stmt(D). iter_stmt(A) ::= T_WHILE(B) T_LPAREN exp(C) T_RPAREN T_COLON chunks(D) T_ENDWHILE. { A = wrap_op(B, C, D); } iter_stmt(A) ::= T_FOR(B) paren_exp(C) stmt(D). - { A = wrap_op(B, uc_check_for_in(s, C), NULL, NULL, no_empty_obj(D)); uc_get_op(s, A)->is_for_in = 1; } + { A = wrap_op(B, uc_check_for_in(state, C), NULL, NULL, no_empty_obj(D)); OP(A)->is_for_in = 1; } iter_stmt(A) ::= T_FOR(B) paren_exp(C) T_COLON chunks(D) T_ENDFOR. - { A = wrap_op(B, uc_check_for_in(s, C), NULL, NULL, no_empty_obj(D)); uc_get_op(s, A)->is_for_in = 1; } + { A = wrap_op(B, uc_check_for_in(state, C), NULL, NULL, no_empty_obj(D)); OP(A)->is_for_in = 1; } iter_stmt(A) ::= T_FOR(B) T_LPAREN decl_or_exp(C) exp_stmt(D) T_RPAREN stmt(E). { A = wrap_op(B, C, D, NULL, no_empty_obj(E)); } iter_stmt(A) ::= T_FOR(B) T_LPAREN decl_or_exp(C) exp_stmt(D) exp(E) T_RPAREN stmt(F). @@ -311,8 +306,8 @@ switch_case(A) ::= T_CASE(B) exp(C) T_COLON stmts(D). { A = wrap_op(B, C, D); } switch_case(A) ::= T_CASE(B) exp(C) T_COLON. { A = wrap_op(B, C); } switch_case(A) ::= T_DEFAULT(B) T_COLON stmts(C). { A = wrap_op(B, C); } -args(A) ::= sargs(B) T_COMMA T_ELLIP T_LABEL(C). { A = append_op(B, C); uc_get_op(s, C)->is_ellip = 1; } -args(A) ::= T_ELLIP T_LABEL(B). { A = B; uc_get_op(s, B)->is_ellip = 1; } +args(A) ::= sargs(B) T_COMMA T_ELLIP T_LABEL(C). { A = append_op(B, C); OP(C)->is_ellip = 1; } +args(A) ::= T_ELLIP T_LABEL(B). { A = B; OP(B)->is_ellip = 1; } args(A) ::= sargs(B). { A = B; } sargs(A) ::= sargs(B) T_COMMA T_LABEL(C). { A = append_op(B, C); } @@ -327,7 +322,7 @@ ret_stmt(A) ::= T_RETURN(B) T_SCOL. { A = B; } break_stmt(A) ::= T_BREAK(B) T_SCOL. { A = B; } break_stmt(A) ::= T_CONTINUE(B) T_SCOL. { A = B; } -decl_stmt(A) ::= T_LOCAL(B) decls(C) T_SCOL. { A = wrap_op(B, uc_check_op_seq_types(s, C, T_ASSIGN, T_LABEL)); } +decl_stmt(A) ::= T_LOCAL(B) decls(C) T_SCOL. { A = wrap_op(B, uc_check_op_seq_types(state, C, T_ASSIGN, T_LABEL)); } decls(A) ::= decls(B) T_COMMA decl(C). { A = append_op(B, C); } decls(A) ::= decl(B). { A = B; } @@ -358,13 +353,13 @@ assign_exp(A) ::= unary_exp(B) T_ASBOR arrow_exp(C). { A = new_op(T_BOR, NULL, B assign_exp(A) ::= arrow_exp(B). { A = B; } arrow_exp(A) ::= unary_exp(B) T_ARROW(C) arrowfn_body(D). - { A = wrap_op(C, 0, uc_check_op_seq_types(s, B, T_LABEL), D); } + { A = wrap_op(C, 0, uc_check_op_seq_types(state, B, T_LABEL), D); } arrow_exp(A) ::= T_LPAREN T_RPAREN T_ARROW(C) arrowfn_body(D). { A = wrap_op(C, 0, 0, D); } arrow_exp(A) ::= T_LPAREN T_ELLIP T_LABEL(B) T_RPAREN T_ARROW(C) arrowfn_body(D). - { A = wrap_op(C, 0, B, D); uc_get_op(s, B)->is_ellip = 1; } + { A = wrap_op(C, 0, B, D); OP(B)->is_ellip = 1; } arrow_exp(A) ::= T_LPAREN exp(B) T_COMMA T_ELLIP T_LABEL(C) T_RPAREN T_ARROW(D) arrowfn_body(E). - { A = append_op(B, C); A = wrap_op(D, 0, uc_check_op_seq_types(s, A, T_LABEL), E); uc_get_op(s, C)->is_ellip = 1; } + { A = append_op(B, C); A = wrap_op(D, 0, uc_check_op_seq_types(state, A, T_LABEL), E); OP(C)->is_ellip = 1; } arrow_exp(A) ::= ternary_exp(B). { A = B; } ternary_exp(A) ::= or_exp(B) T_QMARK(C) assign_exp(D) T_COLON ternary_exp(E). @@ -420,14 +415,14 @@ unary_exp(A) ::= T_COMPL(B) unary_exp(C). { A = wrap_op(B, C); } unary_exp(A) ::= T_NOT(B) unary_exp(C). { A = wrap_op(B, C); } unary_exp(A) ::= postfix_exp(B). { A = B; } -postfix_exp(A) ::= unary_exp(B) T_INC(C). { A = wrap_op(C, B); uc_get_op(s, A)->is_postfix = 1; } -postfix_exp(A) ::= unary_exp(B) T_DEC(C). { A = wrap_op(C, B); uc_get_op(s, A)->is_postfix = 1; } +postfix_exp(A) ::= unary_exp(B) T_INC(C). { A = wrap_op(C, B); OP(A)->is_postfix = 1; } +postfix_exp(A) ::= unary_exp(B) T_DEC(C). { A = wrap_op(C, B); OP(A)->is_postfix = 1; } postfix_exp(A) ::= unary_exp(B) T_LPAREN(C) T_RPAREN. { A = wrap_op(C, B); } postfix_exp(A) ::= unary_exp(B) T_LPAREN(C) arg_exps(D) T_RPAREN. { A = wrap_op(C, B, D); } postfix_exp(A) ::= postfix_exp(B) T_DOT(C) T_LABEL(D). { A = wrap_op(C, B, D); } postfix_exp(A) ::= postfix_exp(B) T_LBRACK(C) exp(D) T_RBRACK. - { A = wrap_op(C, B, D); uc_get_op(s, A)->is_postfix = 1; } + { A = wrap_op(C, B, D); OP(A)->is_postfix = 1; } postfix_exp(A) ::= primary_exp(B). { A = B; } primary_exp(A) ::= T_BOOL(B). { A = B; } @@ -440,7 +435,7 @@ primary_exp(A) ::= T_NULL(B). { A = B; } primary_exp(A) ::= T_THIS(B). { A = B; } primary_exp(A) ::= array(B). { A = B; } primary_exp(A) ::= object(B). { A = B; } -primary_exp(A) ::= paren_exp(B). { A = uc_reject_local(s, B); } +primary_exp(A) ::= paren_exp(B). { A = uc_reject_local(state, B); } primary_exp(A) ::= T_FUNC(B) T_LPAREN T_RPAREN empty_object. { A = B; } primary_exp(A) ::= T_FUNC(B) T_LPAREN args(C) T_RPAREN empty_object. @@ -459,8 +454,8 @@ array(A) ::= T_LBRACK(B) items(C) T_RBRACK. { A = wrap_op(B, C); } items(A) ::= items(B) T_COMMA item(C). { A = append_op(B, C); } items(A) ::= item(B). { A = B; } -item(A) ::= T_ELLIP assign_exp(B). { A = uc_get_op(s, B)->tree.next ? new_op(T_COMMA, NULL, B) : B; uc_get_op(s, A)->is_ellip = 1; } -item(A) ::= assign_exp(B). { A = uc_get_op(s, B)->tree.next ? new_op(T_COMMA, NULL, B) : B; } +item(A) ::= T_ELLIP assign_exp(B). { A = OP_NEXT(B) ? new_op(T_COMMA, NULL, B) : B; OP(A)->is_ellip = 1; } +item(A) ::= assign_exp(B). { A = OP_NEXT(B) ? new_op(T_COMMA, NULL, B) : B; } object(A) ::= empty_object(B). { A = B; } object(A) ::= T_LBRACE(B) tuples(C) T_RBRACE. { A = wrap_op(B, C); } @@ -474,8 +469,8 @@ tuple(A) ::= T_LABEL(B) T_COLON exp(C). { A = wrap_op(B, C); } tuple(A) ::= T_STRING(B) T_COLON exp(C). { A = wrap_op(B, C); } tuple(A) ::= T_ELLIP(B) assign_exp(C). { A = wrap_op(B, C); } -arg_exps(A) ::= arg_exps(B) T_COMMA arg_exp(C). { A = append_op(B, C); uc_get_op(s, A)->is_list = 1; } -arg_exps(A) ::= arg_exp(B). { A = B; uc_get_op(s, A)->is_list = 1; } +arg_exps(A) ::= arg_exps(B) T_COMMA arg_exp(C). { A = append_op(B, C); OP(A)->is_list = 1; } +arg_exps(A) ::= arg_exp(B). { A = B; OP(A)->is_list = 1; } -arg_exp(A) ::= T_ELLIP assign_exp(B). { A = uc_get_op(s, B)->tree.next ? new_op(T_COMMA, NULL, B) : B; uc_get_op(s, A)->is_ellip = 1; } -arg_exp(A) ::= assign_exp(B). { A = uc_get_op(s, B)->tree.next ? new_op(T_COMMA, NULL, B) : B; } +arg_exp(A) ::= T_ELLIP assign_exp(B). { A = OP_NEXT(B) ? new_op(T_COMMA, NULL, B) : B; OP(A)->is_ellip = 1; } +arg_exp(A) ::= assign_exp(B). { A = OP_NEXT(B) ? new_op(T_COMMA, NULL, B) : B; } |