Fix parse of simple for statement.

Related issue: #156

JerryScript-DCO-1.0-Signed-off-by: Ruben Ayrapetyan r.ayrapetyan@samsung.com
This commit is contained in:
Ruben Ayrapetyan
2015-06-24 21:39:14 +03:00
parent 601f1eea58
commit f849cc6283
3 changed files with 240 additions and 109 deletions
+182 -108
View File
@@ -220,6 +220,67 @@ jsp_skip_braces (token_type brace_type) /**< type of the opening brace */
current_token_must_be (closing_bracket_type); current_token_must_be (closing_bracket_type);
} /* jsp_skip_braces */ } /* 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 /* property_name
: Identifier : Identifier
| Keyword | Keyword
@@ -1726,88 +1787,146 @@ parse_variable_declaration (void)
(LT!* ',' LT!* variable_declaration)* (LT!* ',' LT!* variable_declaration)*
; */ ; */
static void static void
parse_variable_declaration_list (bool *several_decls) parse_variable_declaration_list (void)
{ {
JERRY_ASSERT (is_keyword (KW_VAR));
while (true) while (true)
{ {
skip_newlines ();
parse_variable_declaration (); parse_variable_declaration ();
skip_newlines (); skip_newlines ();
if (!token_is (TOK_COMMA)) if (!token_is (TOK_COMMA))
{ {
lexer_save_token (tok); lexer_save_token (tok);
return; break;
}
skip_newlines ();
if (several_decls)
{
*several_decls = true;
} }
} }
} }
/**
* 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 static void
parse_plain_for (jsp_label_t *outermost_stmt_label_p) /**< outermost (first) label, corresponding to 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 * the statement (or NULL, if there are no named
* labels associated with the statement) */ * labels associated with the statement) */
locus for_body_statement_loc) /**< locus of loop body statement */
{ {
dump_jump_to_end_for_rewrite (); current_token_must_be (TOK_OPEN_PAREN);
skip_newlines ();
// Skip till body // Initializer
JERRY_ASSERT (token_is (TOK_SEMICOLON)); if (is_keyword (KW_VAR))
skip_newlines ();
const locus cond_loc = tok.loc;
while (!token_is (TOK_SEMICOLON))
{ {
skip_newlines (); parse_variable_declaration_list ();
skip_token ();
} }
skip_newlines (); else if (!token_is (TOK_SEMICOLON))
const locus incr_loc = tok.loc;
while (!token_is (TOK_CLOSE_PAREN))
{ {
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 (); 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 (); skip_newlines ();
parse_statement (NULL); 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, jsp_label_setup_continue_target (outermost_stmt_label_p,
serializer_get_current_opcode_counter ()); serializer_get_current_opcode_counter ());
lexer_seek (incr_loc); // Increment
skip_token (); lexer_seek (increment_loc);
skip_newlines ();
if (!token_is (TOK_CLOSE_PAREN)) if (!token_is (TOK_CLOSE_PAREN))
{ {
parse_expression (true, JSP_EVAL_RET_STORE_NOT_DUMP); parse_expression (true, JSP_EVAL_RET_STORE_NOT_DUMP);
} }
current_token_must_be (TOK_CLOSE_PAREN);
// Setup ConditionCheck
rewrite_jump_to_end (); rewrite_jump_to_end ();
lexer_seek (cond_loc); // Condition
skip_token (); lexer_seek (condition_loc);
skip_newlines ();
if (token_is (TOK_SEMICOLON)) if (token_is (TOK_SEMICOLON))
{ {
dump_continue_iterations_check (empty_operand ()); dump_continue_iterations_check (empty_operand ());
} }
else 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); dump_continue_iterations_check (cond);
} }
lexer_seek (end_loc); lexer_seek (loop_end_loc);
skip_token (); skip_newlines ();
if (tok.type != TOK_CLOSE_BRACE) if (tok.type != TOK_CLOSE_BRACE)
{ {
lexer_save_token (tok); lexer_save_token (tok);
} }
} } /* jsp_parse_for_statement */
static void static void
parse_for_in (jsp_label_t *outermost_stmt_label_p) /**< outermost (first) label, corresponding to parse_for_in (jsp_label_t *outermost_stmt_label_p) /**< outermost (first) label, corresponding to
@@ -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"); EMIT_SORRY ("'for in' loops are not supported yet");
} }
/* for_statement /**
: 'for' LT!* '(' (LT!* for_statement_initialiser_part)? LT!* ';' * Parse for/for-in statements
(LT!* expression)? LT!* ';' (LT!* expression)? LT!* ')' LT!* statement *
; * See also:
* ECMA-262 v5, 12.6.3 and 12.6.4
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
;*/
static void static void
parse_for_or_for_in_statement (jsp_label_t *outermost_stmt_label_p) /**< outermost (first) label, corresponding to jsp_parse_for_or_for_in_statement (jsp_label_t *outermost_stmt_label_p) /**< outermost (first) label,
* the statement (or NULL, if there are no named * corresponding to the statement
* labels associated with the statement) */ * (or NULL, if there are no name
* labels associated with the statement) */
{ {
assert_keyword (KW_FOR); assert_keyword (KW_FOR);
token_after_newlines_must_be (TOK_OPEN_PAREN); token_after_newlines_must_be (TOK_OPEN_PAREN);
skip_newlines (); locus for_open_paren_loc, for_body_statement_loc;
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");
}
}
}
/* expression contains left_hand_side_expression. */ for_open_paren_loc = tok.loc;
parse_expression (false, JSP_EVAL_RET_STORE_NOT_DUMP);
jsp_skip_braces (TOK_OPEN_PAREN);
skip_newlines (); skip_newlines ();
if (token_is (TOK_SEMICOLON))
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_plain_for (outermost_stmt_label_p); jsp_parse_for_statement (outermost_stmt_label_p, for_body_statement_loc);
return;
}
else if (is_keyword (KW_IN))
{
parse_for_in (outermost_stmt_label_p);
return;
} }
else else
{ {
EMIT_ERROR ("Expected either ';' or 'in' token"); parse_for_in (outermost_stmt_label_p);
} }
} } /* jsp_parse_for_or_for_in_statement */
static operand static operand
parse_expression_inside_parens (void) parse_expression_inside_parens (void)
@@ -2318,7 +2393,7 @@ parse_iterational_statement (jsp_label_t *outermost_named_stmt_label_p) /**< out
else else
{ {
JERRY_ASSERT (is_keyword (KW_FOR)); 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, jsp_label_rewrite_jumps_and_pop (&label,
@@ -2412,8 +2487,7 @@ parse_statement (jsp_label_t *outermost_stmt_label_p) /**< outermost (first) lab
} }
if (is_keyword (KW_VAR)) if (is_keyword (KW_VAR))
{ {
skip_newlines (); parse_variable_declaration_list ();
parse_variable_declaration_list (NULL);
return; return;
} }
if (is_keyword (KW_FUNCTION)) if (is_keyword (KW_FUNCTION))
+39 -1
View File
@@ -1,4 +1,5 @@
// Copyright 2014 Samsung Electronics Co., Ltd. // Copyright 2014-2015 Samsung Electronics Co., Ltd.
// Copyright 2015 University of Szeged.
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
@@ -12,15 +13,18 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
// 1.
var i = 0; var i = 0;
for (; i < 100; i++) { for (; i < 100; i++) {
} }
assert(i == 100); assert(i == 100);
// 2.
for (var j = 0; j < 100; j++) { for (var j = 0; j < 100; j++) {
} }
assert(j == 100); assert(j == 100);
// 3.
for (i = 0; ; ) { for (i = 0; ; ) {
if (i == 100) { if (i == 100) {
break; break;
@@ -30,6 +34,7 @@ for (i = 0; ; ) {
} }
assert(i == 100); assert(i == 100);
// 4.
for (i = 0; i < 10; i++) { for (i = 0; i < 10; i++) {
for (j = 0; j < 10; j++) { for (j = 0; j < 10; j++) {
} }
@@ -38,3 +43,36 @@ assert(i != 100);
assert(j != 100); assert(j != 100);
assert(i == 10); assert(i == 10);
assert(j == 10); assert(j == 10);
// 5.
s = '';
for (
var i = {x: 0};
i.x < 2
;
i.x++
)
{
s += i.x;
}
assert (s === '01');
// 6.
s = '';
for (
var i = {x: 0};
i.x < 2
;
i.x++
)
{
s += i.x;
}
assert (s === '01');
+19
View File
@@ -0,0 +1,19 @@
// Copyright 2015 Samsung Electronics Co., Ltd.
// Copyright 2015 University of Szeged.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
function dec(x) { return x - 1 };
for (var i = 5; i > 0; i = dec(i)) {}
for (var i = 11; i = dec (i); i--) {}
for (var i = dec (12); i > 0; i--) {}