diff options
-rw-r--r-- | ast.h | 1 | ||||
-rw-r--r-- | eval.c | 25 | ||||
-rw-r--r-- | parser.y | 22 |
3 files changed, 34 insertions, 14 deletions
@@ -56,6 +56,7 @@ struct ut_op { uint16_t is_op:1; uint16_t is_overflow:1; uint16_t is_postfix:1; + uint16_t is_for_in:1; uint32_t off; struct json_object *val; union { @@ -525,29 +525,42 @@ ut_execute_if(struct ut_state *state, uint32_t off) static struct json_object * ut_execute_for(struct ut_state *state, uint32_t off) { - struct json_object *ivar, *val, *item, *rv = NULL; + struct json_object *scope, *val, *item, *rv = NULL; + struct ut_op *loop = ut_get_op(state, off); struct ut_op *init = ut_get_child(state, off, 0); struct ut_op *test = ut_get_child(state, off, 1); struct ut_op *incr = ut_get_child(state, off, 2); struct ut_op *body = ut_get_child(state, off, 3); - struct ut_op *tag; + struct ut_op *ivar, *tag; size_t arridx, arrlen; + bool local = false; /* for (x in ...) loop variant */ - if (init != NULL && test == NULL && incr == NULL) { + if (loop->is_for_in) { + if (init->type == T_LOCAL) { + local = true; + init = ut_get_op(state, init->tree.operand[0]); + } + if (init->type != T_IN) return ut_exception(state, ut_get_off(state, init), "Syntax error: missing ';' after for loop initializer"); - ivar = ut_get_op(state, init->tree.operand[0])->val; + ivar = ut_get_op(state, init->tree.operand[0]); + + if (!ivar || ivar->type != T_LABEL) + return ut_exception(state, ut_get_off(state, init), + "Syntax error: invalid for-in left-hand side"); + val = ut_execute_op(state, init->tree.operand[1]); + scope = local ? ut_getscope(state, 0) : ut_getref(state, ut_get_off(state, ivar), NULL); if (json_object_is_type(val, json_type_array)) { for (arridx = 0, arrlen = json_object_array_length(val); arridx < arrlen; arridx++) { item = json_object_array_get_idx(val, arridx); - ut_setval(ut_getscope(state, 0), ivar, item); + ut_setval(scope, ivar->val, item); ut_putval(rv); rv = ut_execute_op_sequence(state, ut_get_off(state, body)); @@ -570,7 +583,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(ut_getscope(state, 0), ivar, json_object_new_string(key)); + ut_setval(scope, ivar->val, json_object_new_string(key)); ut_putval(rv); rv = ut_execute_op_sequence(state, ut_get_off(state, body)); @@ -139,17 +139,17 @@ iter_stmt(A) ::= T_WHILE(B) T_LPAREN exp(C) T_RPAREN stmt(D). { A = wrap_op(B, C, no_empty_obj(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) T_LPAREN exp(C) T_RPAREN stmt(D). - { A = wrap_op(B, C, NULL, NULL, no_empty_obj(D)); } -iter_stmt(A) ::= T_FOR(B) T_LPAREN exp(C) T_RPAREN T_COLON chunks(D) T_ENDFOR. - { A = wrap_op(B, C, NULL, NULL, no_empty_obj(D)); } -iter_stmt(A) ::= T_FOR(B) T_LPAREN exp_stmt(C) exp_stmt(D) T_RPAREN stmt(E). +iter_stmt(A) ::= T_FOR(B) T_LPAREN for_in_exp(C) T_RPAREN stmt(D). + { A = wrap_op(B, C, NULL, NULL, no_empty_obj(D)); ut_get_op(s, A)->is_for_in = 1; } +iter_stmt(A) ::= T_FOR(B) T_LPAREN for_in_exp(C) T_RPAREN T_COLON chunks(D) T_ENDFOR. + { A = wrap_op(B, C, NULL, NULL, no_empty_obj(D)); ut_get_op(s, 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 exp_stmt(C) exp_stmt(D) exp(E) T_RPAREN stmt(F). +iter_stmt(A) ::= T_FOR(B) T_LPAREN decl_or_exp(C) exp_stmt(D) exp(E) T_RPAREN stmt(F). { A = wrap_op(B, C, D, E, no_empty_obj(F)); } -iter_stmt(A) ::= T_FOR(B) T_LPAREN exp_stmt(C) exp_stmt(D) T_RPAREN T_COLON chunks(E) T_ENDFOR. +iter_stmt(A) ::= T_FOR(B) T_LPAREN decl_or_exp(C) exp_stmt(D) T_RPAREN T_COLON chunks(E) T_ENDFOR. { A = wrap_op(B, C, D, NULL, E); } -iter_stmt(A) ::= T_FOR(B) T_LPAREN exp_stmt(C) exp_stmt(D) exp(E) T_RPAREN T_COLON chunks(F) T_ENDFOR. +iter_stmt(A) ::= T_FOR(B) T_LPAREN decl_or_exp(C) exp_stmt(D) exp(E) T_RPAREN T_COLON chunks(F) T_ENDFOR. { A = wrap_op(B, C, D, E, F); } func_stmt(A) ::= T_FUNC(B) T_LABEL(C) T_LPAREN T_RPAREN cpd_stmt(D). @@ -168,6 +168,12 @@ func_stmt(A) ::= T_FUNC(B) T_LABEL(C) T_LPAREN args(D) T_RPAREN T_COLON chunks(E args(A) ::= args(B) T_COMMA T_LABEL(C). { A = append_op(B, C); } args(A) ::= T_LABEL(B). { A = B; } +for_in_exp(A) ::= rel_exp(B). { A = B; } +for_in_exp(A) ::= T_LOCAL(B) rel_exp(C). { A = wrap_op(B, C); } + +decl_or_exp(A) ::= exp_stmt(B). { A = B; } +decl_or_exp(A) ::= decl_stmt(B). { A = B; } + ret_stmt(A) ::= T_RETURN(B) exp(C) T_SCOL. { A = wrap_op(B, C); } ret_stmt(A) ::= T_RETURN(B) T_SCOL. { A = B; } |