Skip to content

Commit 738d1f3

Browse files
Implement parse of for-in statement.
JerryScript-DCO-1.0-Signed-off-by: Evgeny Gavrin e.gavrin@samsung.com JerryScript-DCO-1.0-Signed-off-by: Ruben Ayrapetyan r.ayrapetyan@samsung.com
1 parent 476fbac commit 738d1f3

File tree

6 files changed

+508
-8
lines changed

6 files changed

+508
-8
lines changed

jerry-core/parser/js/opcodes-dumper.cpp

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -708,6 +708,23 @@ eval_ret_operand (void)
708708
return ret;
709709
} /* eval_ret_operand */
710710

711+
/**
712+
* Creates operand for taking iterator value (next property name)
713+
* from for-in opcode handler.
714+
*
715+
* @return constructed operand
716+
*/
717+
operand
718+
jsp_create_operand_for_in_special_reg (void)
719+
{
720+
operand ret;
721+
722+
ret.type = OPERAND_TMP;
723+
ret.data.uid = OPCODE_REG_SPECIAL_FOR_IN_PROPERTY_NAME;
724+
725+
return ret;
726+
} /* jsp_create_operand_for_in_special_reg */
727+
711728
bool
712729
operand_is_empty (operand op)
713730
{
@@ -2334,6 +2351,62 @@ dump_with_end (void)
23342351
serializer_dump_op_meta (create_op_meta_000 (opcode));
23352352
} /* dump_with_end */
23362353

2354+
/**
2355+
* Dump template of 'for_in' instruction.
2356+
*
2357+
* Note:
2358+
* the instruction's flags field is written later (see also: rewrite_for_in).
2359+
*
2360+
* @return position of dumped instruction
2361+
*/
2362+
opcode_counter_t
2363+
dump_for_in_for_rewrite (operand op) /**< operand - result of evaluating Expression
2364+
* in for-in statement */
2365+
{
2366+
opcode_counter_t oc = serializer_get_current_opcode_counter ();
2367+
2368+
if (op.type == OPERAND_LITERAL)
2369+
{
2370+
const opcode_t opcode = getop_for_in (LITERAL_TO_REWRITE, INVALID_VALUE, INVALID_VALUE);
2371+
serializer_dump_op_meta (create_op_meta_100 (opcode, op.data.lit_id));
2372+
}
2373+
else
2374+
{
2375+
JERRY_ASSERT (op.type == OPERAND_TMP);
2376+
2377+
const opcode_t opcode = getop_for_in (op.data.uid, INVALID_VALUE, INVALID_VALUE);
2378+
serializer_dump_op_meta (create_op_meta_000 (opcode));
2379+
}
2380+
2381+
return oc;
2382+
} /* dump_for_in_for_rewrite */
2383+
2384+
/**
2385+
* Write position of 'for_in' block's end to specified 'for_in' instruction template,
2386+
* dumped earlier (see also: dump_for_in_for_rewrite).
2387+
*/
2388+
void
2389+
rewrite_for_in (opcode_counter_t oc) /**< opcode counter of the instruction template */
2390+
{
2391+
op_meta for_in_op_meta = serializer_get_op_meta (oc);
2392+
2393+
idx_t id1, id2;
2394+
split_opcode_counter (get_diff_from (oc), &id1, &id2);
2395+
for_in_op_meta.op.data.for_in.oc_idx_1 = id1;
2396+
for_in_op_meta.op.data.for_in.oc_idx_2 = id2;
2397+
serializer_rewrite_op_meta (oc, for_in_op_meta);
2398+
} /* rewrite_for_in */
2399+
2400+
/**
2401+
* Dump 'meta' instruction of 'end for_in' type
2402+
*/
2403+
void
2404+
dump_for_in_end (void)
2405+
{
2406+
const opcode_t opcode = getop_meta (OPCODE_META_TYPE_END_FOR_IN, INVALID_VALUE, INVALID_VALUE);
2407+
serializer_dump_op_meta (create_op_meta_000 (opcode));
2408+
} /* dump_for_in_end */
2409+
23372410
void
23382411
dump_try_for_rewrite (void)
23392412
{

jerry-core/parser/js/opcodes-dumper.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ typedef enum __attr_packed___
4949
operand empty_operand (void);
5050
operand literal_operand (lit_cpointer_t);
5151
operand eval_ret_operand (void);
52+
operand jsp_create_operand_for_in_special_reg (void);
5253
bool operand_is_empty (operand);
5354

5455
void dumper_init (void);
@@ -209,6 +210,10 @@ opcode_counter_t dump_with_for_rewrite (operand);
209210
void rewrite_with (opcode_counter_t);
210211
void dump_with_end (void);
211212

213+
opcode_counter_t dump_for_in_for_rewrite (operand);
214+
void rewrite_for_in (opcode_counter_t);
215+
void dump_for_in_end (void);
216+
212217
void dump_try_for_rewrite (void);
213218
void rewrite_try (void);
214219
void dump_catch_for_rewrite (operand);

jerry-core/parser/js/parser.cpp

Lines changed: 171 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1763,7 +1763,7 @@ parse_expression (bool in_allowed, /**< flag indicating if 'in' is allowed insid
17631763
initialiser
17641764
: '=' LT!* assignment_expression
17651765
; */
1766-
static void
1766+
static operand
17671767
parse_variable_declaration (void)
17681768
{
17691769
current_token_must_be (TOK_NAME);
@@ -1780,6 +1780,8 @@ parse_variable_declaration (void)
17801780
{
17811781
lexer_save_token (tok);
17821782
}
1783+
1784+
return name;
17831785
}
17841786

17851787
/* variable_declaration_list
@@ -1928,15 +1930,176 @@ jsp_parse_for_statement (jsp_label_t *outermost_stmt_label_p, /**< outermost (fi
19281930
}
19291931
} /* jsp_parse_for_statement */
19301932

1933+
/**
1934+
* Parse VariableDeclarationNoIn / LeftHandSideExpression (iterator part) of for-in statement
1935+
*
1936+
* See also:
1937+
* jsp_parse_for_in_statement
1938+
*
1939+
* @return true - if iterator consists of base and property name,
1940+
* false - otherwise, iterator consists of an identifier name (without base).
1941+
*/
1942+
static bool
1943+
jsp_parse_for_in_statement_iterator (operand *base_p, /**< out: base value of member expression, if any,
1944+
* empty operand - otherwise */
1945+
operand *identifier_p) /**< out: property name (if base value is not empty),
1946+
* identifier - otherwise */
1947+
{
1948+
JERRY_ASSERT (base_p != NULL);
1949+
JERRY_ASSERT (identifier_p != NULL);
1950+
1951+
if (is_keyword (KW_VAR))
1952+
{
1953+
skip_newlines ();
1954+
1955+
*base_p = empty_operand ();
1956+
*identifier_p = parse_variable_declaration ();
1957+
1958+
return false;
1959+
}
1960+
else
1961+
{
1962+
operand base, identifier;
1963+
1964+
/*
1965+
* FIXME:
1966+
* Remove evaluation of last part of identifier chain
1967+
*/
1968+
operand i = parse_left_hand_side_expression (&base, &identifier);
1969+
1970+
if (operand_is_empty (base))
1971+
{
1972+
*base_p = empty_operand ();
1973+
*identifier_p = i;
1974+
1975+
return false;
1976+
}
1977+
else
1978+
{
1979+
*base_p = base;
1980+
*identifier_p = identifier;
1981+
1982+
return true;
1983+
}
1984+
}
1985+
} /* jsp_parse_for_in_statement_iterator */
1986+
1987+
/**
1988+
* Parse for-in statement
1989+
*
1990+
* See also:
1991+
* ECMA-262 v5, 12.6.4
1992+
*
1993+
* Note:
1994+
* Syntax:
1995+
* Iterator Collection Body LoopEnd
1996+
* - for ( LeftHandSideExpression in Expression) Statement
1997+
* - for (var VariableDeclarationNoIn in Expression) Statement
1998+
*
1999+
* Note:
2000+
* Layout of generate byte-code is the following:
2001+
* tmp <- Collection (Expression)
2002+
* for_in instruction (tmp, opcode counter of for-in end mark)
2003+
* {
2004+
* Assignment of OPCODE_REG_SPECIAL_FOR_IN_PROPERTY_NAME to
2005+
* Iterator (VariableDeclarationNoIn / LeftHandSideExpression)
2006+
* }
2007+
* Body (Statement)
2008+
* ContinueTarget:
2009+
* meta (OPCODE_META_TYPE_END_FOR_IN)
2010+
*/
19312011
static void
1932-
parse_for_in (jsp_label_t *outermost_stmt_label_p) /**< outermost (first) label, corresponding to
1933-
* the statement (or NULL, if there are no named
1934-
* labels associated with the statement) */
2012+
jsp_parse_for_in_statement (jsp_label_t *outermost_stmt_label_p, /**< outermost (first) label,
2013+
* corresponding to the statement
2014+
* (or NULL, if there are no name
2015+
* labels associated with the statement) */
2016+
locus for_body_statement_loc) /**< locus of loop body statement */
19352017
{
1936-
(void) outermost_stmt_label_p;
2018+
jsp_label_raise_nested_jumpable_border ();
19372019

1938-
EMIT_SORRY ("'for in' loops are not supported yet");
1939-
}
2020+
current_token_must_be (TOK_OPEN_PAREN);
2021+
skip_newlines ();
2022+
2023+
// Save Iterator location
2024+
locus iterator_loc = tok.loc;
2025+
2026+
while (tok.loc < for_body_statement_loc)
2027+
{
2028+
if (jsp_find_next_token_before_the_locus (TOK_KEYWORD,
2029+
for_body_statement_loc,
2030+
true))
2031+
{
2032+
if (is_keyword (KW_IN))
2033+
{
2034+
break;
2035+
}
2036+
else
2037+
{
2038+
skip_token ();
2039+
}
2040+
}
2041+
else
2042+
{
2043+
EMIT_ERROR ("Invalid for statement");
2044+
}
2045+
}
2046+
2047+
JERRY_ASSERT (is_keyword (KW_IN));
2048+
skip_newlines ();
2049+
2050+
// Collection
2051+
operand collection = parse_expression (true, JSP_EVAL_RET_STORE_NOT_DUMP);
2052+
current_token_must_be (TOK_CLOSE_PAREN);
2053+
skip_token ();
2054+
2055+
// Dump for-in instruction
2056+
opcode_counter_t for_in_oc = dump_for_in_for_rewrite (collection);
2057+
2058+
// Dump assignment VariableDeclarationNoIn / LeftHandSideExpression <- OPCODE_REG_SPECIAL_FOR_IN_PROPERTY_NAME
2059+
lexer_seek (iterator_loc);
2060+
tok = lexer_next_token ();
2061+
2062+
operand iterator_base, iterator_identifier, for_in_special_reg;
2063+
for_in_special_reg = jsp_create_operand_for_in_special_reg ();
2064+
2065+
if (jsp_parse_for_in_statement_iterator (&iterator_base, &iterator_identifier))
2066+
{
2067+
dump_prop_setter (iterator_base, iterator_identifier, for_in_special_reg);
2068+
}
2069+
else
2070+
{
2071+
JERRY_ASSERT (operand_is_empty (iterator_base));
2072+
dump_variable_assignment (iterator_identifier, for_in_special_reg);
2073+
}
2074+
2075+
// Body
2076+
lexer_seek (for_body_statement_loc);
2077+
tok = lexer_next_token ();
2078+
2079+
parse_statement (NULL);
2080+
2081+
// Save LoopEnd locus
2082+
const locus loop_end_loc = tok.loc;
2083+
2084+
// Setup ContinueTarget
2085+
jsp_label_setup_continue_target (outermost_stmt_label_p,
2086+
serializer_get_current_opcode_counter ());
2087+
2088+
// Write position of for-in end to for_in instruction
2089+
rewrite_for_in (for_in_oc);
2090+
2091+
// Dump meta (OPCODE_META_TYPE_END_FOR_IN)
2092+
dump_for_in_end ();
2093+
2094+
lexer_seek (loop_end_loc);
2095+
tok = lexer_next_token ();
2096+
if (tok.type != TOK_CLOSE_BRACE)
2097+
{
2098+
lexer_save_token (tok);
2099+
}
2100+
2101+
jsp_label_remove_nested_jumpable_border ();
2102+
} /* jsp_parse_for_in_statement */
19402103

19412104
/**
19422105
* Parse for/for-in statements
@@ -1977,7 +2140,7 @@ jsp_parse_for_or_for_in_statement (jsp_label_t *outermost_stmt_label_p) /**< out
19772140
}
19782141
else
19792142
{
1980-
parse_for_in (outermost_stmt_label_p);
2143+
jsp_parse_for_in_statement (outermost_stmt_label_p, for_body_statement_loc);
19812144
}
19822145
} /* jsp_parse_for_or_for_in_statement */
19832146

jerry-core/parser/js/scopes-tree.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,7 @@ generate_opcode (scopes_tree tree, opcode_counter_t opc_index, lit_id_hash_table
305305
case OPCODE (obj_decl):
306306
case OPCODE (this_binding):
307307
case OPCODE (with):
308+
case OPCODE (for_in):
308309
case OPCODE (throw_value):
309310
case OPCODE (is_true_jmp_up):
310311
case OPCODE (is_true_jmp_down):

jerry-core/vm/pretty-printer.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@ pp_op_meta (const opcode_t *opcodes_p,
232232
PP_OP (delete_prop, "%s = delete %s.%s;");
233233
PP_OP (typeof, "%s = typeof %s;");
234234
PP_OP (with, "with (%s);");
235+
PP_OP (for_in, "for_in (%s);");
235236
case NAME_TO_ID (is_true_jmp_up): printf ("if (%s) goto %d;", VAR (1), oc - OC (2, 3)); break;
236237
case NAME_TO_ID (is_false_jmp_up): printf ("if (%s == false) goto %d;", VAR (1), oc - OC (2, 3)); break;
237238
case NAME_TO_ID (is_true_jmp_down): printf ("if (%s) goto %d;", VAR (1), oc + OC (2, 3)); break;
@@ -554,6 +555,11 @@ pp_op_meta (const opcode_t *opcodes_p,
554555
printf ("end with;");
555556
break;
556557
}
558+
case OPCODE_META_TYPE_END_FOR_IN:
559+
{
560+
printf ("end for-in;");
561+
break;
562+
}
557563
case OPCODE_META_TYPE_FUNCTION_END:
558564
{
559565
printf ("function end: %d;", oc + OC (2, 3));

0 commit comments

Comments
 (0)