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

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);
} /* 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
@ -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 ();
current_token_must_be (TOK_OPEN_PAREN);
skip_newlines ();
// Skip till body
JERRY_ASSERT (token_is (TOK_SEMICOLON));
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
@ -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))
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);
return;
}
else if (is_keyword (KW_IN))
{
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)
@ -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,
@ -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))

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");
// 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
// limitations under the License.
// 1.
var i = 0;
for (; i < 100; i++) {
}
assert(i == 100);
// 2.
for (var j = 0; j < 100; j++) {
}
assert(j == 100);
// 3.
for (i = 0; ; ) {
if (i == 100) {
break;
@ -30,6 +34,7 @@ for (i = 0; ; ) {
}
assert(i == 100);
// 4.
for (i = 0; i < 10; i++) {
for (j = 0; j < 10; j++) {
}
@ -38,3 +43,36 @@ assert(i != 100);
assert(j != 100);
assert(i == 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');

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--) {}