Skip to content

Commit

Permalink
Implement parse of for-in statement.
Browse files Browse the repository at this point in the history
JerryScript-DCO-1.0-Signed-off-by: Evgeny Gavrin [email protected]
JerryScript-DCO-1.0-Signed-off-by: Ruben Ayrapetyan [email protected]
  • Loading branch information
ruben-ayrapetyan committed Jun 26, 2015
1 parent 476fbac commit b474d0b
Show file tree
Hide file tree
Showing 6 changed files with 498 additions and 8 deletions.
73 changes: 73 additions & 0 deletions jerry-core/parser/js/opcodes-dumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -708,6 +708,23 @@ eval_ret_operand (void)
return ret;
} /* eval_ret_operand */

/**
* Creates operand for taking iterator value (next property name)
* from for-in opcode handler.
*
* @return constructed operand
*/
operand
jsp_create_operand_for_in_special_reg (void)
{
operand ret;

ret.type = OPERAND_TMP;
ret.data.uid = OPCODE_REG_SPECIAL_FOR_IN_PROPERTY_NAME;

return ret;
} /* jsp_create_operand_for_in_special_reg */

bool
operand_is_empty (operand op)
{
Expand Down Expand Up @@ -2334,6 +2351,62 @@ dump_with_end (void)
serializer_dump_op_meta (create_op_meta_000 (opcode));
} /* dump_with_end */

/**
* Dump template of 'for_in' instruction.
*
* Note:
* the instruction's flags field is written later (see also: rewrite_for_in).
*
* @return position of dumped instruction
*/
opcode_counter_t
dump_for_in_for_rewrite (operand op) /**< operand - result of evaluating Expression
* in for-in statement */
{
opcode_counter_t oc = serializer_get_current_opcode_counter ();

if (op.type == OPERAND_LITERAL)
{
const opcode_t opcode = getop_for_in (LITERAL_TO_REWRITE, INVALID_VALUE, INVALID_VALUE);
serializer_dump_op_meta (create_op_meta_100 (opcode, op.data.lit_id));
}
else
{
JERRY_ASSERT (op.type == OPERAND_TMP);

const opcode_t opcode = getop_for_in (op.data.uid, INVALID_VALUE, INVALID_VALUE);
serializer_dump_op_meta (create_op_meta_000 (opcode));
}

return oc;
} /* dump_for_in_for_rewrite */

/**
* Write position of 'for_in' block's end to specified 'for_in' instruction template,
* dumped earlier (see also: dump_for_in_for_rewrite).
*/
void
rewrite_for_in (opcode_counter_t oc) /**< opcode counter of the instruction template */
{
op_meta for_in_op_meta = serializer_get_op_meta (oc);

idx_t id1, id2;
split_opcode_counter (get_diff_from (oc), &id1, &id2);
for_in_op_meta.op.data.for_in.oc_idx_1 = id1;
for_in_op_meta.op.data.for_in.oc_idx_2 = id2;
serializer_rewrite_op_meta (oc, for_in_op_meta);
} /* rewrite_for_in */

/**
* Dump 'meta' instruction of 'end for_in' type
*/
void
dump_for_in_end (void)
{
const opcode_t opcode = getop_meta (OPCODE_META_TYPE_END_FOR_IN, INVALID_VALUE, INVALID_VALUE);
serializer_dump_op_meta (create_op_meta_000 (opcode));
} /* dump_for_in_end */

void
dump_try_for_rewrite (void)
{
Expand Down
5 changes: 5 additions & 0 deletions jerry-core/parser/js/opcodes-dumper.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ typedef enum __attr_packed___
operand empty_operand (void);
operand literal_operand (lit_cpointer_t);
operand eval_ret_operand (void);
operand jsp_create_operand_for_in_special_reg (void);
bool operand_is_empty (operand);

void dumper_init (void);
Expand Down Expand Up @@ -209,6 +210,10 @@ opcode_counter_t dump_with_for_rewrite (operand);
void rewrite_with (opcode_counter_t);
void dump_with_end (void);

opcode_counter_t dump_for_in_for_rewrite (operand);
void rewrite_for_in (opcode_counter_t);
void dump_for_in_end (void);

void dump_try_for_rewrite (void);
void rewrite_try (void);
void dump_catch_for_rewrite (operand);
Expand Down
179 changes: 171 additions & 8 deletions jerry-core/parser/js/parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1763,7 +1763,7 @@ parse_expression (bool in_allowed, /**< flag indicating if 'in' is allowed insid
initialiser
: '=' LT!* assignment_expression
; */
static void
static operand
parse_variable_declaration (void)
{
current_token_must_be (TOK_NAME);
Expand All @@ -1780,6 +1780,8 @@ parse_variable_declaration (void)
{
lexer_save_token (tok);
}

return name;
}

/* variable_declaration_list
Expand Down Expand Up @@ -1928,15 +1930,176 @@ jsp_parse_for_statement (jsp_label_t *outermost_stmt_label_p, /**< outermost (fi
}
} /* jsp_parse_for_statement */

/**
* Parse VariableDeclarationNoIn / LeftHandSideExpression (iterator part) of for-in statement
*
* See also:
* jsp_parse_for_in_statement
*
* @return true - if iterator consists of base and property name,
* false - otherwise, iterator consists of an identifier name (without base).
*/
static bool
jsp_parse_for_in_statement_iterator (operand *base_p, /**< out: base value of member expression, if any,
* empty operand - otherwise */
operand *identifier_p) /**< out: property name (if base value is not empty),
* identifier - otherwise */
{
JERRY_ASSERT (base_p != NULL);
JERRY_ASSERT (identifier_p != NULL);

if (is_keyword (KW_VAR))
{
skip_newlines ();

*base_p = empty_operand ();
*identifier_p = parse_variable_declaration ();

return false;
}
else
{
operand base, identifier;

/*
* FIXME:
* Remove evaluation of last part of identifier chain
*/
operand i = parse_left_hand_side_expression (&base, &identifier);

if (operand_is_empty (base))
{
*base_p = empty_operand ();
*identifier_p = i;

return false;
}
else
{
*base_p = base;
*identifier_p = identifier;

return true;
}
}
} /* jsp_parse_for_in_statement_iterator */

/**
* Parse for-in statement
*
* See also:
* ECMA-262 v5, 12.6.4
*
* Note:
* Syntax:
* Iterator Collection Body LoopEnd
* - for ( LeftHandSideExpression in Expression) Statement
* - for (var VariableDeclarationNoIn in Expression) Statement
*
* Note:
* Layout of generate byte-code is the following:
* tmp <- Collection (Expression)
* for_in instruction (tmp, opcode counter of for-in end mark)
* {
* Assignment of OPCODE_REG_SPECIAL_FOR_IN_PROPERTY_NAME to
* Iterator (VariableDeclarationNoIn / LeftHandSideExpression)
* }
* Body (Statement)
* ContinueTarget:
* meta (OPCODE_META_TYPE_END_FOR_IN)
*/
static void
parse_for_in (jsp_label_t *outermost_stmt_label_p) /**< outermost (first) label, corresponding to
* the statement (or NULL, if there are no named
* labels associated with the statement) */
jsp_parse_for_in_statement (jsp_label_t *outermost_stmt_label_p, /**< outermost (first) label,
* corresponding to the statement
* (or NULL, if there are no name
* labels associated with the statement) */
locus for_body_statement_loc) /**< locus of loop body statement */
{
(void) outermost_stmt_label_p;
jsp_label_raise_nested_jumpable_border ();

EMIT_SORRY ("'for in' loops are not supported yet");
}
current_token_must_be (TOK_OPEN_PAREN);
skip_newlines ();

// Save Iterator location
locus iterator_loc = tok.loc;

while (tok.loc < for_body_statement_loc)
{
if (jsp_find_next_token_before_the_locus (TOK_KEYWORD,
for_body_statement_loc,
true))
{
if (is_keyword (KW_IN))
{
break;
}
else
{
skip_token ();
}
}
else
{
EMIT_ERROR ("Invalid for statement");
}
}

JERRY_ASSERT (is_keyword (KW_IN));
skip_newlines ();

// Collection
operand collection = parse_expression (true, JSP_EVAL_RET_STORE_NOT_DUMP);
current_token_must_be (TOK_CLOSE_PAREN);
skip_token ();

// Dump for-in instruction
opcode_counter_t for_in_oc = dump_for_in_for_rewrite (collection);

// Dump assignment VariableDeclarationNoIn / LeftHandSideExpression <- OPCODE_REG_SPECIAL_FOR_IN_PROPERTY_NAME
lexer_seek (iterator_loc);
tok = lexer_next_token ();

operand iterator_base, iterator_identifier, for_in_special_reg;
for_in_special_reg = jsp_create_operand_for_in_special_reg ();

if (jsp_parse_for_in_statement_iterator (&iterator_base, &iterator_identifier))
{
dump_prop_setter (iterator_base, iterator_identifier, for_in_special_reg);
}
else
{
JERRY_ASSERT (operand_is_empty (iterator_base));
dump_variable_assignment (iterator_identifier, for_in_special_reg);
}

// Body
lexer_seek (for_body_statement_loc);
tok = lexer_next_token ();

parse_statement (NULL);

// Save LoopEnd locus
const locus loop_end_loc = tok.loc;

// Setup ContinueTarget
jsp_label_setup_continue_target (outermost_stmt_label_p,
serializer_get_current_opcode_counter ());

// Write position of for-in end to for_in instruction
rewrite_for_in (for_in_oc);

// Dump meta (OPCODE_META_TYPE_END_FOR_IN)
dump_for_in_end ();

lexer_seek (loop_end_loc);
tok = lexer_next_token ();
if (tok.type != TOK_CLOSE_BRACE)
{
lexer_save_token (tok);
}

jsp_label_remove_nested_jumpable_border ();
} /* jsp_parse_for_in_statement */

/**
* Parse for/for-in statements
Expand Down Expand Up @@ -1977,7 +2140,7 @@ jsp_parse_for_or_for_in_statement (jsp_label_t *outermost_stmt_label_p) /**< out
}
else
{
parse_for_in (outermost_stmt_label_p);
jsp_parse_for_in_statement (outermost_stmt_label_p, for_body_statement_loc);
}
} /* jsp_parse_for_or_for_in_statement */

Expand Down
1 change: 1 addition & 0 deletions jerry-core/parser/js/scopes-tree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,7 @@ generate_opcode (scopes_tree tree, opcode_counter_t opc_index, lit_id_hash_table
case OPCODE (obj_decl):
case OPCODE (this_binding):
case OPCODE (with):
case OPCODE (for_in):
case OPCODE (throw_value):
case OPCODE (is_true_jmp_up):
case OPCODE (is_true_jmp_down):
Expand Down
6 changes: 6 additions & 0 deletions jerry-core/vm/pretty-printer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ pp_op_meta (const opcode_t *opcodes_p,
PP_OP (delete_prop, "%s = delete %s.%s;");
PP_OP (typeof, "%s = typeof %s;");
PP_OP (with, "with (%s);");
PP_OP (for_in, "for_in (%s);");
case NAME_TO_ID (is_true_jmp_up): printf ("if (%s) goto %d;", VAR (1), oc - OC (2, 3)); break;
case NAME_TO_ID (is_false_jmp_up): printf ("if (%s == false) goto %d;", VAR (1), oc - OC (2, 3)); break;
case NAME_TO_ID (is_true_jmp_down): printf ("if (%s) goto %d;", VAR (1), oc + OC (2, 3)); break;
Expand Down Expand Up @@ -554,6 +555,11 @@ pp_op_meta (const opcode_t *opcodes_p,
printf ("end with;");
break;
}
case OPCODE_META_TYPE_END_FOR_IN:
{
printf ("end for-in;");
break;
}
case OPCODE_META_TYPE_FUNCTION_END:
{
printf ("function end: %d;", oc + OC (2, 3));
Expand Down
Loading

0 comments on commit b474d0b

Please sign in to comment.