Skip to content

Commit

Permalink
Fix parse of simple for statement.
Browse files Browse the repository at this point in the history
Related issue: #156

JerryScript-DCO-1.0-Signed-off-by: Ruben Ayrapetyan [email protected]
  • Loading branch information
ruben-ayrapetyan committed Jun 25, 2015
1 parent 601f1ee commit f849cc6
Show file tree
Hide file tree
Showing 3 changed files with 240 additions and 109 deletions.
290 changes: 182 additions & 108 deletions jerry-core/parser/js/parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,67 @@ jsp_skip_braces (token_type brace_type) /**< type of the opening brace */
current_token_must_be (closing_bracket_type);
} /* jsp_skip_braces */

/**
* Find next token of specified type before the specified location
*
* Note:
* If skip_brace_blocks is true, every { should correspond to } brace before search end location,
* otherwise a syntax error is raised.
*
* @return true - if token was found (in the case, it is the current token,
* and lexer locus points to it),
* false - otherwise (in the case, lexer locus points to end_loc).
*/
static bool
jsp_find_next_token_before_the_locus (token_type token_to_find, /**< token to search for
* (except TOK_NEWLINE and TOK_EOF) */
locus end_loc, /**< location to search before */
bool skip_brace_blocks) /**< skip blocks, surrounded with { and } braces */
{
JERRY_ASSERT (token_to_find != TOK_NEWLINE
&& token_to_find != TOK_EOF);

while (tok.loc < end_loc)
{
if (skip_brace_blocks)
{
if (token_is (TOK_OPEN_BRACE))
{
jsp_skip_braces (TOK_OPEN_BRACE);

JERRY_ASSERT (token_is (TOK_CLOSE_BRACE));
skip_newlines ();

if (tok.loc >= end_loc)
{
lexer_seek (end_loc);
tok = lexer_next_token ();

return false;
}
}
else if (token_is (TOK_CLOSE_BRACE))
{
EMIT_ERROR ("Unmatched } brace");
}
}

if (token_is (token_to_find))
{
return true;
}
else
{
JERRY_ASSERT (!token_is (TOK_EOF));
}

skip_newlines ();
}

JERRY_ASSERT (tok.loc == end_loc);
return false;
} /* jsp_find_next_token_before_the_locus */

/* property_name
: Identifier
| Keyword
Expand Down Expand Up @@ -1726,88 +1787,146 @@ parse_variable_declaration (void)
(LT!* ',' LT!* variable_declaration)*
; */
static void
parse_variable_declaration_list (bool *several_decls)
parse_variable_declaration_list (void)
{
JERRY_ASSERT (is_keyword (KW_VAR));

while (true)
{
skip_newlines ();

parse_variable_declaration ();

skip_newlines ();
if (!token_is (TOK_COMMA))
{
lexer_save_token (tok);
return;
}

skip_newlines ();
if (several_decls)
{
*several_decls = true;
break;
}
}
}

/**
* Parse for statement
*
* See also:
* ECMA-262 v5, 12.6.3
*
* Note:
* Syntax:
* Initializer Condition Increment Body LoopEnd
* - for ([ExpressionNoIn]; [Expression]; [Expression]) Statement
* - for (var VariableDeclarationListNoIn; [Expression]; [Expression]) Statement
*
* Note:
* Layout of generated byte-code is the following:
* Initializer ([ExpressionNoIn] / VariableDeclarationListNoIn)
* Jump -> ConditionCheck
* NextIteration:
* Body (Statement)
* ContinueTarget:
* Increment ([Expression])
* ConditionCheck:
* Condition ([Expression])
* If Condition is evaluted to true, jump -> NextIteration
*/
static void
parse_plain_for (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_statement (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) */
locus for_body_statement_loc) /**< locus of loop body statement */
{
dump_jump_to_end_for_rewrite ();

// Skip till body
JERRY_ASSERT (token_is (TOK_SEMICOLON));
current_token_must_be (TOK_OPEN_PAREN);
skip_newlines ();
const locus cond_loc = tok.loc;
while (!token_is (TOK_SEMICOLON))

// Initializer
if (is_keyword (KW_VAR))
{
skip_newlines ();
parse_variable_declaration_list ();
skip_token ();
}
skip_newlines ();
const locus incr_loc = tok.loc;
while (!token_is (TOK_CLOSE_PAREN))
else if (!token_is (TOK_SEMICOLON))
{
skip_newlines ();
parse_expression (false, JSP_EVAL_RET_STORE_NOT_DUMP);
skip_token ();
}
else
{
// Initializer is empty
}

// Jump -> ConditionCheck
dump_jump_to_end_for_rewrite ();

dumper_set_next_interation_target ();

// Parse body
current_token_must_be (TOK_SEMICOLON);
skip_token ();

// Save Condition locus
const locus condition_loc = tok.loc;

if (!jsp_find_next_token_before_the_locus (TOK_SEMICOLON,
for_body_statement_loc,
true))
{
EMIT_ERROR ("Invalid for statement");
}

current_token_must_be (TOK_SEMICOLON);
skip_token ();

// Save Increment locus
const locus increment_loc = tok.loc;

// Body
lexer_seek (for_body_statement_loc);
skip_newlines ();

parse_statement (NULL);

const locus end_loc = tok.loc;
// 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 ());

lexer_seek (incr_loc);
skip_token ();
// Increment
lexer_seek (increment_loc);
skip_newlines ();

if (!token_is (TOK_CLOSE_PAREN))
{
parse_expression (true, JSP_EVAL_RET_STORE_NOT_DUMP);
}

current_token_must_be (TOK_CLOSE_PAREN);

// Setup ConditionCheck
rewrite_jump_to_end ();

lexer_seek (cond_loc);
skip_token ();
// Condition
lexer_seek (condition_loc);
skip_newlines ();

if (token_is (TOK_SEMICOLON))
{
dump_continue_iterations_check (empty_operand ());
}
else
{
const operand cond = parse_expression (true, JSP_EVAL_RET_STORE_NOT_DUMP);
operand cond = parse_expression (true, JSP_EVAL_RET_STORE_NOT_DUMP);
dump_continue_iterations_check (cond);
}

lexer_seek (end_loc);
skip_token ();
lexer_seek (loop_end_loc);
skip_newlines ();
if (tok.type != TOK_CLOSE_BRACE)
{
lexer_save_token (tok);
}
}
} /* jsp_parse_for_statement */

static void
parse_for_in (jsp_label_t *outermost_stmt_label_p) /**< outermost (first) label, corresponding to
Expand All @@ -1819,92 +1938,48 @@ parse_for_in (jsp_label_t *outermost_stmt_label_p) /**< outermost (first) label,
EMIT_SORRY ("'for in' loops are not supported yet");
}

/* for_statement
: 'for' LT!* '(' (LT!* for_statement_initialiser_part)? LT!* ';'
(LT!* expression)? LT!* ';' (LT!* expression)? LT!* ')' LT!* statement
;
for_statement_initialiser_part
: expression
| 'var' LT!* variable_declaration_list
;
for_in_statement
: 'for' LT!* '(' LT!* for_in_statement_initialiser_part LT!* 'in'
LT!* expression LT!* ')' LT!* statement
;
for_in_statement_initialiser_part
: left_hand_side_expression
| 'var' LT!* variable_declaration
;*/

/**
* Parse for/for-in statements
*
* See also:
* ECMA-262 v5, 12.6.3 and 12.6.4
*/
static void
parse_for_or_for_in_statement (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_or_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) */
{
assert_keyword (KW_FOR);
token_after_newlines_must_be (TOK_OPEN_PAREN);

skip_newlines ();
if (token_is (TOK_SEMICOLON))
{
parse_plain_for (outermost_stmt_label_p);
return;
}
/* Both for_statement_initialiser_part and for_in_statement_initialiser_part
contains 'var'. Check it first. */
if (is_keyword (KW_VAR))
{
bool several_decls = false;
skip_newlines ();
parse_variable_declaration_list (&several_decls);
if (several_decls)
{
token_after_newlines_must_be (TOK_SEMICOLON);
parse_plain_for (outermost_stmt_label_p);
return;
}
else
{
skip_newlines ();
if (token_is (TOK_SEMICOLON))
{
parse_plain_for (outermost_stmt_label_p);
return;
}
else if (is_keyword (KW_IN))
{
parse_for_in (outermost_stmt_label_p);
return;
}
else
{
EMIT_ERROR ("Expected either ';' or 'in' token");
}
}
}
locus for_open_paren_loc, for_body_statement_loc;

/* expression contains left_hand_side_expression. */
parse_expression (false, JSP_EVAL_RET_STORE_NOT_DUMP);
for_open_paren_loc = tok.loc;

jsp_skip_braces (TOK_OPEN_PAREN);
skip_newlines ();
if (token_is (TOK_SEMICOLON))
{
parse_plain_for (outermost_stmt_label_p);
return;
}
else if (is_keyword (KW_IN))

for_body_statement_loc = tok.loc;

lexer_seek (for_open_paren_loc);
tok = lexer_next_token ();

bool is_plain_for = jsp_find_next_token_before_the_locus (TOK_SEMICOLON,
for_body_statement_loc,
true);
lexer_seek (for_open_paren_loc);
tok = lexer_next_token ();

if (is_plain_for)
{
parse_for_in (outermost_stmt_label_p);
return;
jsp_parse_for_statement (outermost_stmt_label_p, for_body_statement_loc);
}
else
{
EMIT_ERROR ("Expected either ';' or 'in' token");
parse_for_in (outermost_stmt_label_p);
}
}
} /* jsp_parse_for_or_for_in_statement */

static operand
parse_expression_inside_parens (void)
Expand Down Expand Up @@ -2318,7 +2393,7 @@ parse_iterational_statement (jsp_label_t *outermost_named_stmt_label_p) /**< out
else
{
JERRY_ASSERT (is_keyword (KW_FOR));
parse_for_or_for_in_statement (outermost_stmt_label_p);
jsp_parse_for_or_for_in_statement (outermost_stmt_label_p);
}

jsp_label_rewrite_jumps_and_pop (&label,
Expand Down Expand Up @@ -2412,8 +2487,7 @@ parse_statement (jsp_label_t *outermost_stmt_label_p) /**< outermost (first) lab
}
if (is_keyword (KW_VAR))
{
skip_newlines ();
parse_variable_declaration_list (NULL);
parse_variable_declaration_list ();
return;
}
if (is_keyword (KW_FUNCTION))
Expand Down
Loading

0 comments on commit f849cc6

Please sign in to comment.