summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--ast.h1
-rw-r--r--eval.c25
-rw-r--r--parser.y22
3 files changed, 34 insertions, 14 deletions
diff --git a/ast.h b/ast.h
index f65a91f..3466beb 100644
--- a/ast.h
+++ b/ast.h
@@ -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 {
diff --git a/eval.c b/eval.c
index db67fa2..b9c9907 100644
--- a/eval.c
+++ b/eval.c
@@ -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));
diff --git a/parser.y b/parser.y
index c2d447b..9a83fc0 100644
--- a/parser.y
+++ b/parser.y
@@ -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; }