diff options
-rw-r--r-- | ast.c | 165 | ||||
-rw-r--r-- | ast.h | 28 | ||||
-rw-r--r-- | eval.c | 293 | ||||
-rw-r--r-- | eval.h | 3 | ||||
-rw-r--r-- | lib.c | 63 | ||||
-rw-r--r-- | tests/02_runtime/05_closure_scope | 35 |
6 files changed, 344 insertions, 243 deletions
@@ -278,55 +278,154 @@ ut_new_regexp(const char *source, bool icase, bool newline, bool global, char ** return op->val; } +static void +func_free(struct json_object *v, void *ud) +{ + struct ut_op *op = ud; + struct ut_function *fn = op->tag.data; + + json_object_put(fn->args); + ut_release_scope(fn->parent_scope); + + free(op); +} + static int func_to_string(struct json_object *v, struct printbuf *pb, int level, int flags) { bool strict = (level > 0) || (flags & JSON_C_TO_STRING_STRICT); struct ut_op *op = json_object_get_userdata(v); - struct ut_op *base, *decl, *name, *args, *arg; - - /* find start of operand array */ - for (base = op; base && !base->is_first; base--) - ; - - decl = base + (op->tag.off ? op->tag.off - 1 : 0); - name = base + (decl->tree.operand[0] ? decl->tree.operand[0] - 1 : 0); - args = base + (decl->tree.operand[1] ? decl->tree.operand[1] - 1 : 0); + struct ut_function *fn = op->tag.data; + size_t i; sprintbuf(pb, "%sfunction%s%s(", strict ? "\"" : "", - (name != base) ? " " : "", - (name != base) ? json_object_get_string(name->val) : ""); - - for (arg = args; arg != base; arg = base + (arg->tree.next ? arg->tree.next - 1 : 0)) - sprintbuf(pb, "%s%s", - (arg != args) ? ", " : "", - json_object_get_string(arg->val)); + fn->name ? " " : "", + fn->name ? fn->name : ""); + + if (fn->args) { + for (i = 0; i < json_object_array_length(fn->args); i++) { + sprintbuf(pb, "%s%s", + i ? ", " : "", + json_object_get_string(json_object_array_get_idx(fn->args, i))); + } + } return sprintbuf(pb, ") { ... }%s", strict ? "\"" : ""); } +#define ALIGN(x) (((x) + sizeof(size_t) - 1) & -sizeof(size_t)) + struct json_object * -ut_new_func(struct ut_op *decl) +ut_new_func(struct ut_state *s, struct ut_op *decl, struct ut_scope *scope) { struct json_object *val = xjs_new_object(); - struct ut_op *op = xalloc(sizeof(*op)); - struct ut_op *base; + struct ut_op *op, *name, *args, *arg; + struct ut_function *fn; + size_t sz; + + sz = ALIGN(sizeof(*op)) + ALIGN(sizeof(*fn)); - /* find start of operand array */ - for (base = decl; base && !base->is_first; base--) - ; + name = ut_get_op(s, decl->tree.operand[0]); + args = ut_get_op(s, decl->tree.operand[1]); + + if (name) + sz += ALIGN(json_object_get_string_len(name->val) + 1); + + op = xalloc(sz); + + fn = (void *)op + ALIGN(sizeof(*op)); + fn->entry = decl->tree.operand[2]; + + if (name) { + fn->name = (char *)fn + ALIGN(sizeof(*fn)); + strcpy(fn->name, json_object_get_string(name->val)); + } + + if (args) { + fn->args = xjs_new_array(); + + for (arg = args; arg; arg = ut_get_op(s, arg->tree.next)) + json_object_array_add(fn->args, json_object_get(arg->val)); + } + + fn->parent_scope = ut_acquire_scope(scope); op->val = val; op->type = T_FUNC; - op->tag.off = (decl - base) + 1; + op->tag.data = fn; - json_object_set_serializer(val, func_to_string, op, obj_free); + json_object_set_serializer(val, func_to_string, op, func_free); return op->val; } static void +scope_free(struct json_object *v, void *ud) +{ + struct ut_scope *sc = ud; + + if (sc->parent) { + ut_release_scope(json_object_get_userdata(sc->parent)); + sc->parent = NULL; + } + + sc->scope = NULL; +} + +void +ut_release_scope(struct ut_scope *sc) +{ + if (sc->refs == 0) + abort(); + + sc->refs--; + + if (sc->refs == 0) { + json_object_put(sc->scope); + sc->scope = NULL; + + if (sc->parent) { + ut_release_scope(json_object_get_userdata(sc->parent)); + sc->parent = NULL; + } + } +} + +struct ut_scope * +ut_acquire_scope(struct ut_scope *sc) +{ + sc->refs++; + + return sc; +} + +struct ut_scope * +ut_new_scope(struct ut_state *s, struct ut_scope *parent) +{ + struct ut_scope *sc; + + sc = xalloc(sizeof(*sc)); + sc->scope = xjs_new_object(); + + if (parent) + sc->parent = ut_acquire_scope(parent)->scope; + + json_object_set_userdata(sc->scope, sc, scope_free); + + sc->next = s->scopelist; + s->scopelist = sc; + + return ut_acquire_scope(sc); +} + +struct ut_scope * +ut_parent_scope(struct ut_scope *scope) +{ + return json_object_get_userdata(scope->parent); +} + +static void ut_reset(struct ut_state *s) { s->semicolon_emitted = false; @@ -343,16 +442,12 @@ ut_reset(struct ut_state *s) void ut_free(struct ut_state *s) { + struct ut_scope *sc, *sc_next; size_t n; if (s) { json_object_put(s->ctx); - while (s->stack.off > 0) - json_object_put(s->stack.scope[--s->stack.off]); - - free(s->stack.scope); - for (n = 0; n < s->poolsize; n++) json_object_put(s->pool[n].val); @@ -367,6 +462,18 @@ ut_free(struct ut_state *s) while (ut_ext_types_count > 0) json_object_put(ut_ext_types[--ut_ext_types_count].proto); + json_object_put(s->rval); + + for (sc = s->scopelist; sc; sc = sc->next) { + json_object_put(sc->scope); + sc->scope = NULL; + } + + for (sc = s->scopelist; sc; sc = sc_next) { + sc_next = sc->next; + free(sc); + } + free(ut_ext_types); free(s->filename); free(s); @@ -81,6 +81,19 @@ struct ut_op { }; }; +struct ut_scope { + struct ut_scope *next; + struct json_object *scope, *ctx, *parent; + size_t refs; +}; + +struct ut_function { + char *name; + struct json_object *args; + struct ut_scope *scope, *parent_scope; + uint32_t entry; +}; + struct ut_state { struct ut_op *pool; uint32_t poolsize; @@ -103,12 +116,8 @@ struct ut_state { char *regexp_error; } info; } error; - struct { - struct json_object **scope; - uint8_t size; - uint8_t off; - } stack; - struct json_object *ctx; + struct ut_scope *scopelist, *scope; + struct json_object *ctx, *rval; char *filename; }; @@ -137,12 +146,17 @@ uint32_t ut_append_op(struct ut_state *s, uint32_t a, uint32_t b); enum ut_error_type ut_parse(struct ut_state *s, const char *expr); void ut_free(struct ut_state *s); -struct json_object *ut_new_func(struct ut_op *decl); +struct json_object *ut_new_func(struct ut_state *s, struct ut_op *decl, struct ut_scope *scope); struct json_object *ut_new_object(struct json_object *proto); struct json_object *ut_new_double(double v); struct json_object *ut_new_null(void); struct json_object *ut_new_regexp(const char *source, bool icase, bool newline, bool global, char **err); +struct ut_scope *ut_new_scope(struct ut_state *s, struct ut_scope *parent); +struct ut_scope *ut_parent_scope(struct ut_scope *scope); +struct ut_scope *ut_acquire_scope(struct ut_scope *scope); +void ut_release_scope(struct ut_scope *scope); + bool ut_register_extended_type(const char *name, struct json_object *proto, void (*freefn)(void *)); struct json_object *ut_set_extended_type(struct json_object *v, const char *name, void *data); void **ut_get_extended_type(struct json_object *val, const char *name); @@ -166,45 +166,6 @@ ut_cast_number(struct json_object *v, int64_t *n, double *d) } static struct json_object * -ut_getscope(struct ut_state *state, uint8_t depth) -{ - if (depth >= state->stack.off) - return NULL; - - return state->stack.scope[state->stack.off - depth - 1]; -} - -static struct json_object * -ut_addscope(struct ut_state *state, uint32_t decl) -{ - struct json_object *scope; - - if (state->stack.off >= 255) - return ut_exception(state, decl, "Runtime error: Too much recursion"); - - if (state->stack.off >= state->stack.size) { - state->stack.scope = xrealloc(state->stack.scope, (state->stack.size + 1) * sizeof(*state->stack.scope)); - state->stack.size++; - } - - scope = ut_new_object(NULL); - state->stack.scope[state->stack.off++] = scope; - - return scope; -} - -void -ut_putval(struct json_object *val) -{ - struct ut_op *tag = json_object_get_userdata(val); - - if (tag && tag->val != val) - json_object_put(tag->val); - - json_object_put(val); -} - -static struct json_object * ut_execute_op(struct ut_state *state, uint32_t off); static struct json_object * @@ -288,8 +249,8 @@ ut_getref(struct ut_state *state, uint32_t off, struct json_object **key) struct ut_op *op = ut_get_op(state, off); uint32_t off1 = op ? op->tree.operand[0] : 0; uint32_t off2 = op ? op->tree.operand[1] : 0; - struct json_object *val, *scope, *next; - uint8_t i; + struct ut_scope *sc, *next; + struct json_object *val; if (key) *key = NULL; @@ -313,14 +274,13 @@ ut_getref(struct ut_state *state, uint32_t off, struct json_object **key) return ut_execute_op(state, off1); } else if (op && op->type == T_LABEL) { - i = 0; - scope = ut_getscope(state, i); + sc = state->scope; while (true) { - if (json_object_object_get_ex(scope, json_object_get_string(op->val), NULL)) + if (json_object_object_get_ex(sc->scope, json_object_get_string(op->val), NULL)) break; - next = ut_getscope(state, ++i); + next = ut_parent_scope(sc); if (!next) { if (state->strict_declarations) { @@ -332,13 +292,13 @@ ut_getref(struct ut_state *state, uint32_t off, struct json_object **key) break; } - scope = next; + sc = next; } if (key) *key = json_object_get(op->val); - return json_object_get(scope); + return json_object_get(sc->scope); } else { if (key) @@ -484,8 +444,8 @@ ut_execute_assign(struct ut_state *state, uint32_t off) if (!ut_is_type(val, T_EXCEPTION)) ut_setval(scope, key, val); - ut_putval(scope); - ut_putval(key); + json_object_put(scope); + json_object_put(key); return val; } @@ -506,7 +466,7 @@ ut_execute_local(struct ut_state *state, uint32_t off) if (ut_is_type(val, T_EXCEPTION)) return val; - rv = ut_setval(ut_getscope(state, 0), label->val, val); + rv = ut_setval(state->scope->scope, label->val, val); } as = ut_get_op(state, as->tree.next); @@ -524,7 +484,7 @@ ut_test_condition(struct ut_state *state, uint32_t off) struct json_object *val = ut_execute_op_sequence(state, off); bool istrue = ut_val_is_truish(val); - ut_putval(val); + json_object_put(val); return istrue; } @@ -580,10 +540,10 @@ ut_execute_for(struct ut_state *state, uint32_t off) if (ut_is_type(val, T_EXCEPTION)) return val; - scope = local ? ut_getscope(state, 0) : ut_getref(state, ut_get_off(state, ivar), NULL); + scope = local ? state->scope->scope : ut_getref(state, ut_get_off(state, ivar), NULL); if (ut_is_type(scope, T_EXCEPTION)) { - ut_putval(val); + json_object_put(val); return scope; } @@ -594,7 +554,7 @@ ut_execute_for(struct ut_state *state, uint32_t off) item = json_object_array_get_idx(val, arridx); ut_setval(scope, ivar->val, item); - ut_putval(rv); + json_object_put(rv); rv = ut_execute_op_sequence(state, ut_get_off(state, body)); tag = json_object_get_userdata(rv); @@ -602,13 +562,13 @@ ut_execute_for(struct ut_state *state, uint32_t off) switch (tag ? tag->type : 0) { case T_RETURN: case T_EXCEPTION: - ut_putval(val); + json_object_put(val); return rv; case T_BREAK: - ut_putval(val); - ut_putval(rv); + json_object_put(val); + json_object_put(rv); return NULL; } @@ -617,7 +577,7 @@ ut_execute_for(struct ut_state *state, uint32_t off) else if (json_object_is_type(val, json_type_object)) { json_object_object_foreach(val, key, item) { ut_setval(scope, ivar->val, xjs_new_string(key)); - ut_putval(rv); + json_object_put(rv); rv = ut_execute_op_sequence(state, ut_get_off(state, body)); tag = json_object_get_userdata(rv); @@ -625,21 +585,21 @@ ut_execute_for(struct ut_state *state, uint32_t off) switch (tag ? tag->type : 0) { case T_RETURN: case T_EXCEPTION: - ut_putval(val); + json_object_put(val); return rv; case T_BREAK: - ut_putval(val); - ut_putval(rv); + json_object_put(val); + json_object_put(rv); return NULL; } } } - ut_putval(val); - ut_putval(rv); + json_object_put(val); + json_object_put(rv); return NULL; } @@ -650,11 +610,11 @@ ut_execute_for(struct ut_state *state, uint32_t off) if (ut_is_type(val, T_EXCEPTION)) return val; - ut_putval(val); + json_object_put(val); } while (test ? ut_test_condition(state, ut_get_off(state, test)) : true) { - ut_putval(rv); + json_object_put(rv); rv = ut_execute_op_sequence(state, ut_get_off(state, body)); tag = json_object_get_userdata(rv); @@ -665,7 +625,7 @@ ut_execute_for(struct ut_state *state, uint32_t off) return rv; case T_BREAK: - ut_putval(rv); + json_object_put(rv); return NULL; } @@ -674,16 +634,16 @@ ut_execute_for(struct ut_state *state, uint32_t off) val = ut_execute_op_sequence(state, ut_get_off(state, incr)); if (ut_is_type(val, T_EXCEPTION)) { - ut_putval(rv); + json_object_put(rv); return val; } - ut_putval(val); + json_object_put(val); } } - ut_putval(rv); + json_object_put(rv); return NULL; } @@ -699,7 +659,7 @@ ut_execute_while(struct ut_state *state, uint32_t off) bool cond; while (1) { - ut_putval(rv); + json_object_put(rv); v = test ? ut_execute_op_sequence(state, test) : NULL; cond = test ? ut_val_is_truish(v) : true; @@ -707,7 +667,7 @@ ut_execute_while(struct ut_state *state, uint32_t off) if (ut_is_type(v, T_EXCEPTION)) return v; - ut_putval(v); + json_object_put(v); if (!cond) return NULL; @@ -721,13 +681,13 @@ ut_execute_while(struct ut_state *state, uint32_t off) return rv; case T_BREAK: - ut_putval(rv); + json_object_put(rv); return NULL; } } - ut_putval(rv); + json_object_put(rv); return NULL; } @@ -740,7 +700,7 @@ ut_execute_and_or(struct ut_state *state, uint32_t off) int i; for (i = 0; i < ARRAY_SIZE(op->tree.operand) && op->tree.operand[i]; i++) { - ut_putval(val); + json_object_put(val); val = ut_execute_op(state, op->tree.operand[i]); @@ -833,7 +793,7 @@ _ut_get_operands(struct ut_state *state, struct ut_op *op, size_t n, struct json if (ut_is_type(v[i], T_EXCEPTION)) { for (j = 0; j < i; j++) - ut_putval(v[j]); + json_object_put(v[j]); return v[i]; } @@ -858,8 +818,8 @@ ut_execute_rel(struct ut_state *state, uint32_t off) rv = xjs_new_boolean(ut_cmp(op->type, v[0], v[1])); - ut_putval(v[0]); - ut_putval(v[1]); + json_object_put(v[0]); + json_object_put(v[1]); return rv; } @@ -917,8 +877,8 @@ ut_execute_equality(struct ut_state *state, uint32_t off) equal = ut_eq(v[0], v[1]); rv = xjs_new_boolean((op->type == T_EQS) ? equal : !equal); - ut_putval(v[0]); - ut_putval(v[1]); + json_object_put(v[0]); + json_object_put(v[1]); return rv; } @@ -950,8 +910,8 @@ ut_execute_in(struct ut_state *state, uint32_t off) found = json_object_object_get_ex(v[1], key, NULL); } - ut_putval(v[0]); - ut_putval(v[1]); + json_object_put(v[0]); + json_object_put(v[1]); return xjs_new_boolean(found); } @@ -972,21 +932,21 @@ ut_execute_inc_dec(struct ut_state *state, uint32_t off) val = ut_getval(scope, key); - ut_putval(scope); - ut_putval(key); + json_object_put(scope); + json_object_put(key); if (ut_cast_number(val, &n, &d) == json_type_double) nval = ut_new_double(d + (op->type == T_INC ? 1.0 : -1.0)); else nval = xjs_new_int64(n + (op->type == T_INC ? 1 : -1)); - ut_putval(ut_setval(scope, key, nval)); + json_object_put(ut_setval(scope, key, nval)); /* postfix inc/dec, return old val */ if (op->is_postfix) return val; - ut_putval(val); + json_object_put(val); return json_object_get(nval); } @@ -1037,12 +997,12 @@ ut_execute_object(struct ut_state *state, uint32_t off) } struct json_object * -ut_invoke(struct ut_state *state, uint32_t off, struct json_object *scope, +ut_invoke(struct ut_state *state, uint32_t off, struct json_object *this, struct json_object *func, struct json_object *argvals) { struct ut_op *tag = json_object_get_userdata(func); - struct ut_op *arg, *decl; - struct json_object *s, *rv = NULL; + struct json_object *rv = NULL; + struct ut_function *fn; size_t arridx; ut_c_fn *cfn; @@ -1056,59 +1016,47 @@ ut_invoke(struct ut_state *state, uint32_t off, struct json_object *scope, return cfn ? cfn(state, off, argvals) : NULL; } - decl = ut_get_op(state, tag->tag.off); - arg = ut_get_op(state, decl ? decl->tree.operand[1] : 0); - - s = scope ? scope : ut_addscope(state, ut_get_off(state, decl)); - - if (!json_object_is_type(s, json_type_object)) - return s; - - for (arridx = 0; arg; arridx++, arg = ut_get_op(state, arg->tree.next)) - ut_setval(s, arg->val, argvals ? json_object_array_get_idx(argvals, arridx) : NULL); + fn = tag->tag.data; + fn->scope = ut_new_scope(state, fn->parent_scope); + fn->scope->ctx = json_object_get(this ? this : state->ctx); - /* store the function "this" context in the proto member of the scope tag structure */ - tag = json_object_get_userdata(s); + ut_release_scope(state->scope); + state->scope = ut_acquire_scope(fn->scope); - if (tag) - tag->tag.proto = json_object_get(state->ctx); + if (fn->args) + for (arridx = 0; arridx < json_object_array_length(fn->args); arridx++) + ut_setval(fn->scope->scope, json_object_array_get_idx(fn->args, arridx), + argvals ? json_object_array_get_idx(argvals, arridx) : NULL); - rv = ut_execute_op_sequence(state, decl->tree.operand[2]); + rv = ut_execute_op_sequence(state, fn->entry); tag = json_object_get_userdata(rv); switch (tag ? tag->type : 0) { case T_BREAK: case T_CONTINUE: - ut_putval(rv); + json_object_put(rv); rv = ut_exception(state, ut_get_off(state, tag), "Syntax error: %s statement must be inside loop", tokennames[tag->type]); break; case T_RETURN: - /* handle magic null */ - if (json_object_is_type(rv, json_type_boolean)) { - if (!strcmp(json_object_get_string(rv), "null")) { - ut_putval(rv); - rv = NULL; - } - } - + json_object_put(rv); + rv = json_object_get(state->rval); break; } - /* we left the function, remove the "this" context from the scope tag structure */ - tag = json_object_get_userdata(s); + /* we left the function, pop the function scope... */ + ut_release_scope(state->scope); + state->scope = ut_acquire_scope(ut_parent_scope(fn->scope)); - if (tag) { - json_object_put(tag->tag.proto); - tag->tag.proto = NULL; - } + /* ... and remove the "this" context... */ + json_object_put(fn->scope->ctx); + fn->scope->ctx = NULL; - if (!scope) { - state->stack.scope[--state->stack.off] = NULL; - json_object_put(s); - } + /* ... and reset the function scope */ + ut_release_scope(fn->scope); + fn->scope = NULL; return rv; } @@ -1141,8 +1089,8 @@ ut_execute_call(struct ut_state *state, uint32_t off) rv = ut_invoke(state, off, NULL, v[0], v[1]); } - ut_putval(v[0]); - ut_putval(v[1]); + json_object_put(v[0]); + json_object_put(v[1]); return rv; } @@ -1195,7 +1143,7 @@ ut_execute_exp(struct ut_state *state, uint32_t off) break; } - ut_putval(val); + json_object_put(val); return NULL; } @@ -1214,7 +1162,7 @@ ut_execute_unary_plus_minus(struct ut_state *state, uint32_t off) t = ut_cast_number(v[0], &n, &d); - ut_putval(v[0]); + json_object_put(v[0]); switch (t) { case json_type_int: @@ -1258,8 +1206,8 @@ ut_execute_arith(struct ut_state *state, uint32_t off) rv = xjs_new_string(s); - ut_putval(v[0]); - ut_putval(v[1]); + json_object_put(v[0]); + json_object_put(v[1]); free(s); return rv; @@ -1268,8 +1216,8 @@ ut_execute_arith(struct ut_state *state, uint32_t off) t1 = ut_cast_number(v[0], &n1, &d1); t2 = ut_cast_number(v[1], &n2, &d2); - ut_putval(v[0]); - ut_putval(v[1]); + json_object_put(v[0]); + json_object_put(v[1]); if (t1 == json_type_double || t2 == json_type_double) { d1 = (t1 == json_type_double) ? d1 : (double)n1; @@ -1339,8 +1287,8 @@ ut_execute_bitop(struct ut_state *state, uint32_t off) if (ut_cast_number(v[1], &n2, &d) == json_type_double) n2 = isnan(d) ? 0 : (int64_t)d; - ut_putval(v[0]); - ut_putval(v[1]); + json_object_put(v[0]); + json_object_put(v[1]); switch (op->type) { case T_LSHIFT: @@ -1384,7 +1332,7 @@ ut_execute_compl(struct ut_state *state, uint32_t off) if (ut_cast_number(v[0], &n, &d) == json_type_double) n = isnan(d) ? 0 : (int64_t)d; - ut_putval(v[0]); + json_object_put(v[0]); return xjs_new_int64(~n); } @@ -1393,16 +1341,18 @@ static struct json_object * ut_execute_return(struct ut_state *state, uint32_t off) { struct ut_op *op = ut_get_op(state, off); - struct json_object *v[1]; + struct json_object *v[1], *rv; ut_get_operands(state, op, v); - if (!v[0]) - v[0] = ut_new_null(); + json_object_put(state->rval); + state->rval = v[0]; + + rv = xjs_new_boolean(false); - json_object_set_userdata(v[0], op, NULL); + json_object_set_userdata(rv, op, NULL); - return v[0]; + return rv; } static struct json_object * @@ -1420,7 +1370,7 @@ static struct json_object * ut_execute_function(struct ut_state *state, uint32_t off) { struct ut_op *op = ut_get_op(state, off); - struct json_object *obj = ut_new_func(op); + struct json_object *obj = ut_new_func(state, op, state->scope); return obj; } @@ -1428,7 +1378,7 @@ ut_execute_function(struct ut_state *state, uint32_t off) static struct json_object * ut_execute_this(struct ut_state *state, uint32_t off) { - return json_object_get(ut_getproto(ut_getscope(state, 0))); + return json_object_get(state->scope->ctx); } static struct json_object * @@ -1441,12 +1391,12 @@ ut_execute_try_catch(struct ut_state *state, uint32_t off) if (ut_is_type(rv, T_EXCEPTION)) { if (op->tree.operand[1]) - ut_putval(ut_setval(ut_getscope(state, 0), ut_get_child(state, off, 1)->val, + json_object_put(ut_setval(state->scope->scope, ut_get_child(state, off, 1)->val, xjs_new_string(json_object_get_string(rv)))); memset(&state->error, 0, sizeof(state->error)); - ut_putval(rv); + json_object_put(rv); rv = ut_execute_op_sequence(state, op->tree.operand[2]); } @@ -1459,7 +1409,7 @@ ut_match_case(struct ut_state *state, struct json_object *v, struct ut_op *Case) struct json_object *caseval = ut_execute_op_sequence(state, Case->tree.operand[0]); bool rv = ut_eq(v, caseval); - ut_putval(caseval); + json_object_put(caseval); return rv; } @@ -1480,7 +1430,7 @@ ut_execute_switch_case(struct ut_state *state, uint32_t off) /* remember default case and throw on dupes */ if (Case->type == T_DEFAULT) { if (Default) { - ut_putval(v[0]); + json_object_put(v[0]); return ut_exception(state, ut_get_off(state, Case), "Syntax error: more than one switch default case"); @@ -1502,7 +1452,7 @@ ut_execute_switch_case(struct ut_state *state, uint32_t off) Case != NULL; Case = ut_get_op(state, Case->tree.next)) { - ut_putval(rv); + json_object_put(rv); if (Case == Default) rv = ut_execute_op_sequence(state, Default->tree.operand[0]); @@ -1510,13 +1460,13 @@ ut_execute_switch_case(struct ut_state *state, uint32_t off) rv = ut_execute_op_sequence(state, Case->tree.operand[1]); if (ut_is_type(rv, T_BREAK)) { - ut_putval(rv); + json_object_put(rv); rv = NULL; break; } } - ut_putval(v[0]); + json_object_put(v[0]); return rv; } @@ -1544,7 +1494,7 @@ ut_execute_op(struct ut_state *state, uint32_t off) val = ut_execute_function(state, off); if (op1) - ut_setval(ut_getscope(state, 0), op1->val, val); + ut_setval(state->scope->scope, op1->val, val); return val; @@ -1562,7 +1512,7 @@ ut_execute_op(struct ut_state *state, uint32_t off) case T_LABEL: scope = ut_getref(state, off, &key); - ut_putval(state->ctx); + json_object_put(state->ctx); state->ctx = NULL; if (state->strict_declarations && scope == NULL) { @@ -1572,23 +1522,23 @@ ut_execute_op(struct ut_state *state, uint32_t off) } val = ut_getval(scope, key); - ut_putval(scope); - ut_putval(key); + json_object_put(scope); + json_object_put(key); return val; case T_DOT: scope = ut_getref_required(state, off, &key); - ut_putval(state->ctx); + json_object_put(state->ctx); state->ctx = json_object_get(scope); if (!key) return scope; val = ut_getval(scope, key); - ut_putval(scope); - ut_putval(key); + json_object_put(scope); + json_object_put(key); return val; @@ -1597,15 +1547,15 @@ ut_execute_op(struct ut_state *state, uint32_t off) if (op->is_postfix) { scope = ut_getref_required(state, off, &key); - ut_putval(state->ctx); + json_object_put(state->ctx); state->ctx = json_object_get(scope); if (!key) return scope; val = ut_getval(scope, key); - ut_putval(scope); - ut_putval(key); + json_object_put(scope); + json_object_put(key); return val; } @@ -1700,7 +1650,7 @@ ut_execute_op_sequence(struct ut_state *state, uint32_t off) struct ut_op *op = NULL; while (off) { - ut_putval(v); + json_object_put(v); v = ut_execute_op(state, off); tag = v ? json_object_get_userdata(v) : NULL; @@ -1761,7 +1711,7 @@ enum ut_error_type ut_run(struct ut_state *state, struct json_object *env, struct json_object *modules) { struct ut_op *op = ut_get_op(state, state->main); - struct json_object *entry, *scope, *args, *rv; + struct json_object *entry, *args, *rv; size_t i; if (!op || op->type != T_FUNC) { @@ -1770,25 +1720,18 @@ ut_run(struct ut_state *state, struct json_object *env, struct json_object *modu return UT_ERROR_EXCEPTION; } - entry = ut_execute_function(state, state->main); - - if (!entry) - return UT_ERROR_EXCEPTION; - - scope = ut_addscope(state, state->main); - - if (!json_object_is_type(scope, json_type_object)) - return UT_ERROR_EXCEPTION; - + state->scope = ut_new_scope(state, NULL); state->ctx = NULL; + entry = ut_execute_function(state, state->main); + if (env) { json_object_object_foreach(env, key, val) - ut_register_variable(scope, key, json_object_get(val)); + ut_register_variable(state->scope->scope, key, json_object_get(val)); } - ut_globals_init(state, scope); - ut_lib_init(state, scope); + ut_globals_init(state, state->scope->scope); + ut_lib_init(state, state->scope->scope); args = xjs_new_array(); @@ -1797,13 +1740,13 @@ ut_run(struct ut_state *state, struct json_object *env, struct json_object *modu json_object_array_put_idx(args, 0, json_object_get(json_object_array_get_idx(modules, i))); rv = ut_invoke(state, 0, NULL, - json_object_object_get(scope, "require"), + json_object_object_get(state->scope->scope, "require"), args); if (ut_is_type(rv, T_EXCEPTION)) goto out; - ut_register_variable(scope, + ut_register_variable(state->scope->scope, json_object_get_string(json_object_array_get_idx(modules, i)), rv); } @@ -1814,6 +1757,8 @@ ut_run(struct ut_state *state, struct json_object *env, struct json_object *modu rv = ut_invoke(state, state->main, NULL, entry, args); out: + ut_release_scope(state->scope); + json_object_put(entry); json_object_put(args); json_object_put(rv); @@ -27,9 +27,6 @@ __attribute__((format(printf, 3, 0))) struct json_object * ut_exception(struct ut_state *state, uint32_t op, const char *fmt, ...); -void -ut_putval(struct json_object *val); - bool ut_cmp(int how, struct json_object *v1, struct json_object *v2); @@ -527,7 +527,7 @@ ut_delete(struct ut_state *s, uint32_t off, struct json_object *args) return NULL; for (arrlen = json_object_array_length(args), arridx = 1; arridx < arrlen; arridx++) { - ut_putval(rv); + json_object_put(rv); key = json_object_get_string(json_object_array_get_idx(args, arridx)); rv = json_object_get(json_object_object_get(obj, key ? key : "null")); @@ -600,10 +600,10 @@ ut_filter(struct ut_state *s, uint32_t off, struct json_object *args) if (ut_val_is_truish(rv)) json_object_array_add(arr, json_object_get(json_object_array_get_idx(obj, arridx))); - ut_putval(rv); + json_object_put(rv); } - ut_putval(cmpargs); + json_object_put(cmpargs); return arr; } @@ -758,7 +758,7 @@ ut_map(struct ut_state *s, uint32_t off, struct json_object *args) json_object_array_add(arr, ut_invoke(s, off, NULL, func, cmpargs)); } - ut_putval(cmpargs); + json_object_put(cmpargs); return arr; } @@ -875,7 +875,7 @@ sort_fn(const void *k1, const void *k2) rv = ut_invoke(sort_ctx.s, sort_ctx.off, NULL, sort_ctx.fn, sort_ctx.args); ret = !ut_val_is_truish(rv); - ut_putval(rv); + json_object_put(rv); return ret; } @@ -897,7 +897,7 @@ ut_sort(struct ut_state *s, uint32_t off, struct json_object *args) } json_object_array_sort(arr, sort_fn); - ut_putval(sort_ctx.args); + json_object_put(sort_ctx.args); return json_object_get(arr); } @@ -1489,9 +1489,9 @@ ut_require_so(struct ut_state *s, uint32_t off, const char *path) } static struct json_object * -ut_require_utpl(struct ut_state *s, uint32_t off, const char *path, struct json_object *scope) +ut_require_utpl(struct ut_state *s, uint32_t off, const char *path, struct ut_scope *scope) { - struct json_object *ex, *sc, *entry, *rv; + struct json_object *ex, *entry, *rv; char *source, *msg; struct stat st; FILE *sfile; @@ -1519,15 +1519,13 @@ ut_require_utpl(struct ut_state *s, uint32_t off, const char *path, struct json_ return ex; } - sc = scope ? scope : xjs_new_object(); - - entry = ut_new_func(ut_get_op(s, s->main)); + entry = ut_new_func(s, ut_get_op(s, s->main), scope ? scope : s->scope); - rv = ut_invoke(s, off, sc, entry, NULL); + rv = ut_invoke(s, off, NULL, entry, NULL); if (ut_is_type(rv, T_EXCEPTION)) { msg = ut_format_error(s, source); - ut_putval(rv); + json_object_put(rv); rv = ut_exception(s, off, "%s", msg); free(msg); } @@ -1536,9 +1534,6 @@ ut_require_utpl(struct ut_state *s, uint32_t off, const char *path, struct json_ json_object_put(entry); - if (sc != scope) - json_object_put(sc); - return rv; } @@ -1593,14 +1588,25 @@ ut_require(struct ut_state *s, 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 ut_scope *sc, *scparent; size_t arridx, arrlen; const char *name; if (!json_object_is_type(val, json_type_string)) return NULL; + /* find root scope */ + for (sc = s->scope; sc; ) { + scparent = ut_parent_scope(sc); + + if (!scparent) + break; + + sc = scparent; + } + name = json_object_get_string(val); - search = json_object_object_get(s->stack.scope[0], "REQUIRE_SEARCH_PATH"); + search = sc ? json_object_object_get(sc->scope, "REQUIRE_SEARCH_PATH") : NULL; if (!json_object_is_type(search, json_type_array)) return ut_exception(s, off, "Global require search path not set"); @@ -2028,8 +2034,7 @@ ut_include(struct ut_state *s, 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 json_object *prev_scope; - size_t prev_stack_offset; + struct ut_scope *sc; char *p, *filename; if (!json_object_is_type(path, json_type_string)) @@ -2044,28 +2049,26 @@ ut_include(struct ut_state *s, uint32_t off, struct json_object *args) return ut_exception(s, off, "Include file not found"); if (scope) { - prev_stack_offset = s->stack.off; - prev_scope = s->stack.scope[0]; + sc = ut_new_scope(s, NULL); - s->stack.scope[0] = json_object_get(scope); - s->stack.off = 1; + json_object_object_foreach(scope, key, val) + json_object_object_add(sc->scope, key, json_object_get(val)); + } + else { + sc = s->scope; } filename = s->filename; s->filename = p; - rv = ut_require_utpl(s, off, p, s->stack.scope[s->stack.off - 1]); + rv = ut_require_utpl(s, off, p, sc); s->filename = filename; free(p); - if (scope) { - s->stack.scope[0] = prev_scope; - s->stack.off = prev_stack_offset; - - json_object_put(scope); - } + if (scope) + json_object_put(sc->scope); if (ut_is_type(rv, T_EXCEPTION)) return rv; diff --git a/tests/02_runtime/05_closure_scope b/tests/02_runtime/05_closure_scope new file mode 100644 index 0000000..40f9245 --- /dev/null +++ b/tests/02_runtime/05_closure_scope @@ -0,0 +1,35 @@ +Testing closure scopes. + + +1. Ensure that the declaring scope is retained in functions. + +-- Expect stdout -- +Make function with x=1 +Make function with x=2 +Make function with x=3 +x is 1 +x is 2 +x is 3 +-- End -- + +-- Testcase -- +{% + local count=0; + + function a() { + local x = ++count; + print("Make function with x=", x, "\n"); + return function() { + print("x is ", x, "\n"); + }; + } + + local fn1 = a(); + local fn2 = a(); + local fn3 = a(); + + fn1(); + fn2(); + fn3(); +%} +-- End -- |