Commit db1de41a authored by marja's avatar marja Committed by Commit bot

[parser] Refactor ParseForStatement.

It was a scary function which handled all possible old-fashioned and
for-each statements at one go. Split it to multiple smaller functions
and made the top level logic clearer.

BUG=

Review-Url: https://codereview.chromium.org/2645353002
Cr-Commit-Position: refs/heads/master@{#42627}
parent f94c7e8f
...@@ -1302,6 +1302,20 @@ class ParserBase { ...@@ -1302,6 +1302,20 @@ class ParserBase {
bool* ok); bool* ok);
StatementT ParseTryStatement(bool* ok); StatementT ParseTryStatement(bool* ok);
StatementT ParseForStatement(ZoneList<const AstRawString*>* labels, bool* ok); StatementT ParseForStatement(ZoneList<const AstRawString*>* labels, bool* ok);
StatementT ParseForEachStatementWithDeclarations(
int stmt_pos, ForInfo* for_info, BlockState* for_state,
ZoneList<const AstRawString*>* labels, bool* ok);
StatementT ParseForEachStatementWithoutDeclarations(
int stmt_pos, ExpressionT expression, int lhs_beg_pos, int lhs_end_pos,
ForInfo* for_info, BlockState* for_state,
ZoneList<const AstRawString*>* labels, bool* ok);
// Parse a C-style for loop: 'for (<init>; <cond>; <step>) { ... }'
StatementT ParseStandardForLoop(int stmt_pos, StatementT init,
bool bound_names_are_lexical,
ForInfo* for_info, BlockState* for_state,
ZoneList<const AstRawString*>* labels,
bool* ok);
bool IsNextLetKeyword(); bool IsNextLetKeyword();
bool IsTrivialExpression(); bool IsTrivialExpression();
...@@ -5397,173 +5411,193 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement( ...@@ -5397,173 +5411,193 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement(
for_state.set_is_hidden(); for_state.set_is_hidden();
StatementT init = impl()->NullStatement(); StatementT init = impl()->NullStatement();
if (peek() != Token::SEMICOLON) {
// An initializer is present.
if (peek() == Token::VAR || peek() == Token::CONST ||
(peek() == Token::LET && IsNextLetKeyword())) {
// The initializer contains declarations.
ParseVariableDeclarations(kForStatement, &for_info.parsing_result,
nullptr, CHECK_OK);
bound_names_are_lexical =
IsLexicalVariableMode(for_info.parsing_result.descriptor.mode);
for_info.position = scanner()->location().beg_pos;
if (CheckInOrOf(&for_info.mode)) {
// Just one declaration followed by in/of.
if (for_info.parsing_result.declarations.length() != 1) {
impl()->ReportMessageAt(
for_info.parsing_result.bindings_loc,
MessageTemplate::kForInOfLoopMultiBindings,
ForEachStatement::VisitModeString(for_info.mode));
*ok = false;
return impl()->NullStatement();
}
if (for_info.parsing_result.first_initializer_loc.IsValid() &&
(is_strict(language_mode()) ||
for_info.mode == ForEachStatement::ITERATE ||
bound_names_are_lexical ||
!impl()->IsIdentifier(
for_info.parsing_result.declarations[0].pattern))) {
impl()->ReportMessageAt(
for_info.parsing_result.first_initializer_loc,
MessageTemplate::kForInOfLoopInitializer,
ForEachStatement::VisitModeString(for_info.mode));
*ok = false;
return impl()->NullStatement();
}
BlockT init_block = impl()->RewriteForVarInLegacy(for_info); if (peek() == Token::VAR || peek() == Token::CONST ||
(peek() == Token::LET && IsNextLetKeyword())) {
// The initializer contains declarations.
ParseVariableDeclarations(kForStatement, &for_info.parsing_result, nullptr,
CHECK_OK);
bound_names_are_lexical =
IsLexicalVariableMode(for_info.parsing_result.descriptor.mode);
for_info.position = scanner()->location().beg_pos;
if (CheckInOrOf(&for_info.mode)) {
return ParseForEachStatementWithDeclarations(stmt_pos, &for_info,
&for_state, labels, ok);
}
// One or more declaration not followed by in/of.
init = impl()->BuildInitializationBlock(
&for_info.parsing_result,
bound_names_are_lexical ? &for_info.bound_names : nullptr, CHECK_OK);
} else if (peek() != Token::SEMICOLON) {
// The initializer does not contain declarations.
int lhs_beg_pos = peek_position();
ExpressionClassifier classifier(this);
ExpressionT expression = ParseExpressionCoverGrammar(false, CHECK_OK);
int lhs_end_pos = scanner()->location().end_pos;
bool is_for_each = CheckInOrOf(&for_info.mode);
bool is_destructuring = is_for_each && (expression->IsArrayLiteral() ||
expression->IsObjectLiteral());
if (is_destructuring) {
ValidateAssignmentPattern(CHECK_OK);
} else {
impl()->RewriteNonPattern(CHECK_OK);
}
auto loop = if (is_for_each) {
factory()->NewForEachStatement(for_info.mode, labels, stmt_pos); return ParseForEachStatementWithoutDeclarations(
typename Types::Target target(this, loop); stmt_pos, expression, lhs_beg_pos, lhs_end_pos, &for_info, &for_state,
labels, ok);
}
// Initializer is just an expression.
init = factory()->NewExpressionStatement(expression, lhs_beg_pos);
}
int each_keyword_pos = scanner()->location().beg_pos; // Standard 'for' loop, we have parsed the initializer at this point.
return ParseStandardForLoop(stmt_pos, init, bound_names_are_lexical,
&for_info, &for_state, labels, ok);
}
ExpressionT enumerable = impl()->EmptyExpression(); template <typename Impl>
if (for_info.mode == ForEachStatement::ITERATE) { typename ParserBase<Impl>::StatementT
ExpressionClassifier classifier(this); ParserBase<Impl>::ParseForEachStatementWithDeclarations(
enumerable = ParseAssignmentExpression(true, CHECK_OK); int stmt_pos, ForInfo* for_info, BlockState* for_state,
impl()->RewriteNonPattern(CHECK_OK); ZoneList<const AstRawString*>* labels, bool* ok) {
} else { // Just one declaration followed by in/of.
enumerable = ParseExpression(true, CHECK_OK); if (for_info->parsing_result.declarations.length() != 1) {
} impl()->ReportMessageAt(for_info->parsing_result.bindings_loc,
MessageTemplate::kForInOfLoopMultiBindings,
ForEachStatement::VisitModeString(for_info->mode));
*ok = false;
return impl()->NullStatement();
}
if (for_info->parsing_result.first_initializer_loc.IsValid() &&
(is_strict(language_mode()) ||
for_info->mode == ForEachStatement::ITERATE ||
IsLexicalVariableMode(for_info->parsing_result.descriptor.mode) ||
!impl()->IsIdentifier(
for_info->parsing_result.declarations[0].pattern))) {
impl()->ReportMessageAt(for_info->parsing_result.first_initializer_loc,
MessageTemplate::kForInOfLoopInitializer,
ForEachStatement::VisitModeString(for_info->mode));
*ok = false;
return impl()->NullStatement();
}
Expect(Token::RPAREN, CHECK_OK); BlockT init_block = impl()->RewriteForVarInLegacy(*for_info);
StatementT final_loop = impl()->NullStatement(); auto loop = factory()->NewForEachStatement(for_info->mode, labels, stmt_pos);
{ typename Types::Target target(this, loop);
ReturnExprScope no_tail_calls(function_state_,
ReturnExprContext::kInsideForInOfBody);
BlockState block_state(zone(), &scope_state_);
block_state.set_start_position(scanner()->location().beg_pos);
StatementT body = ParseScopedStatement(nullptr, true, CHECK_OK);
BlockT body_block = impl()->NullBlock();
ExpressionT each_variable = impl()->EmptyExpression();
impl()->DesugarBindingInForEachStatement(&for_info, &body_block,
&each_variable, CHECK_OK);
body_block->statements()->Add(body, zone());
final_loop = impl()->InitializeForEachStatement(
loop, each_variable, enumerable, body_block, each_keyword_pos);
block_state.set_end_position(scanner()->location().end_pos);
body_block->set_scope(block_state.FinalizedBlockScope());
}
init_block = int each_keyword_pos = scanner()->location().beg_pos;
impl()->CreateForEachStatementTDZ(init_block, for_info, ok);
for_state.set_end_position(scanner()->location().end_pos); ExpressionT enumerable = impl()->EmptyExpression();
Scope* for_scope = for_state.FinalizedBlockScope(); if (for_info->mode == ForEachStatement::ITERATE) {
// Parsed for-in loop w/ variable declarations. ExpressionClassifier classifier(this);
if (!impl()->IsNullStatement(init_block)) { enumerable = ParseAssignmentExpression(true, CHECK_OK);
init_block->statements()->Add(final_loop, zone()); impl()->RewriteNonPattern(CHECK_OK);
init_block->set_scope(for_scope); } else {
return init_block; enumerable = ParseExpression(true, CHECK_OK);
} else { }
DCHECK_NULL(for_scope);
return final_loop;
}
} else {
// One or more declaration not followed by in/of.
init = impl()->BuildInitializationBlock(
&for_info.parsing_result,
bound_names_are_lexical ? &for_info.bound_names : nullptr,
CHECK_OK);
}
} else {
// The initializer does not contain declarations.
int lhs_beg_pos = peek_position();
ExpressionClassifier classifier(this);
ExpressionT expression = ParseExpressionCoverGrammar(false, CHECK_OK);
int lhs_end_pos = scanner()->location().end_pos;
bool is_for_each = CheckInOrOf(&for_info.mode); Expect(Token::RPAREN, CHECK_OK);
bool is_destructuring = is_for_each && (expression->IsArrayLiteral() ||
expression->IsObjectLiteral());
if (is_destructuring) { StatementT final_loop = impl()->NullStatement();
ValidateAssignmentPattern(CHECK_OK); {
} else { ReturnExprScope no_tail_calls(function_state_,
impl()->RewriteNonPattern(CHECK_OK); ReturnExprContext::kInsideForInOfBody);
} BlockState block_state(zone(), &scope_state_);
block_state.set_start_position(scanner()->location().beg_pos);
if (is_for_each) { StatementT body = ParseScopedStatement(nullptr, true, CHECK_OK);
// Initializer is reference followed by in/of.
if (!is_destructuring) {
expression = impl()->CheckAndRewriteReferenceExpression(
expression, lhs_beg_pos, lhs_end_pos,
MessageTemplate::kInvalidLhsInFor, kSyntaxError, CHECK_OK);
}
auto loop = BlockT body_block = impl()->NullBlock();
factory()->NewForEachStatement(for_info.mode, labels, stmt_pos); ExpressionT each_variable = impl()->EmptyExpression();
typename Types::Target target(this, loop); impl()->DesugarBindingInForEachStatement(for_info, &body_block,
&each_variable, CHECK_OK);
body_block->statements()->Add(body, zone());
final_loop = impl()->InitializeForEachStatement(
loop, each_variable, enumerable, body_block, each_keyword_pos);
int each_keyword_pos = scanner()->location().beg_pos; block_state.set_end_position(scanner()->location().end_pos);
body_block->set_scope(block_state.FinalizedBlockScope());
}
ExpressionT enumerable = impl()->EmptyExpression(); init_block = impl()->CreateForEachStatementTDZ(init_block, *for_info, ok);
if (for_info.mode == ForEachStatement::ITERATE) {
ExpressionClassifier classifier(this);
enumerable = ParseAssignmentExpression(true, CHECK_OK);
impl()->RewriteNonPattern(CHECK_OK);
} else {
enumerable = ParseExpression(true, CHECK_OK);
}
Expect(Token::RPAREN, CHECK_OK); for_state->set_end_position(scanner()->location().end_pos);
Scope* for_scope = for_state->FinalizedBlockScope();
// Parsed for-in loop w/ variable declarations.
if (!impl()->IsNullStatement(init_block)) {
init_block->statements()->Add(final_loop, zone());
init_block->set_scope(for_scope);
return init_block;
}
{ DCHECK_NULL(for_scope);
ReturnExprScope no_tail_calls(function_state_, return final_loop;
ReturnExprContext::kInsideForInOfBody); }
BlockState block_state(zone(), &scope_state_);
block_state.set_start_position(scanner()->location().beg_pos); template <typename Impl>
typename ParserBase<Impl>::StatementT
// For legacy compat reasons, give for loops similar treatment to ParserBase<Impl>::ParseForEachStatementWithoutDeclarations(
// if statements in allowing a function declaration for a body int stmt_pos, ExpressionT expression, int lhs_beg_pos, int lhs_end_pos,
StatementT body = ParseScopedStatement(nullptr, true, CHECK_OK); ForInfo* for_info, BlockState* for_state,
block_state.set_end_position(scanner()->location().end_pos); ZoneList<const AstRawString*>* labels, bool* ok) {
StatementT final_loop = impl()->InitializeForEachStatement( // Initializer is reference followed by in/of.
loop, expression, enumerable, body, each_keyword_pos); if (!expression->IsArrayLiteral() && !expression->IsObjectLiteral()) {
expression = impl()->CheckAndRewriteReferenceExpression(
Scope* for_scope = for_state.FinalizedBlockScope(); expression, lhs_beg_pos, lhs_end_pos, MessageTemplate::kInvalidLhsInFor,
DCHECK_NULL(for_scope); kSyntaxError, CHECK_OK);
USE(for_scope);
Scope* block_scope = block_state.FinalizedBlockScope();
DCHECK_NULL(block_scope);
USE(block_scope);
return final_loop;
}
} else {
// Initializer is just an expression.
init = factory()->NewExpressionStatement(expression, lhs_beg_pos);
}
}
} }
// Standard 'for' loop, we have parsed the initializer at this point. auto loop = factory()->NewForEachStatement(for_info->mode, labels, stmt_pos);
typename Types::Target target(this, loop);
int each_keyword_pos = scanner()->location().beg_pos;
ExpressionT enumerable = impl()->EmptyExpression();
if (for_info->mode == ForEachStatement::ITERATE) {
ExpressionClassifier classifier(this);
enumerable = ParseAssignmentExpression(true, CHECK_OK);
impl()->RewriteNonPattern(CHECK_OK);
} else {
enumerable = ParseExpression(true, CHECK_OK);
}
Expect(Token::RPAREN, CHECK_OK);
{
ReturnExprScope no_tail_calls(function_state_,
ReturnExprContext::kInsideForInOfBody);
BlockState block_state(zone(), &scope_state_);
block_state.set_start_position(scanner()->location().beg_pos);
// For legacy compat reasons, give for loops similar treatment to
// if statements in allowing a function declaration for a body
StatementT body = ParseScopedStatement(nullptr, true, CHECK_OK);
block_state.set_end_position(scanner()->location().end_pos);
StatementT final_loop = impl()->InitializeForEachStatement(
loop, expression, enumerable, body, each_keyword_pos);
Scope* for_scope = for_state->FinalizedBlockScope();
DCHECK_NULL(for_scope);
USE(for_scope);
Scope* block_scope = block_state.FinalizedBlockScope();
DCHECK_NULL(block_scope);
USE(block_scope);
return final_loop;
}
}
template <typename Impl>
typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStandardForLoop(
int stmt_pos, StatementT init, bool bound_names_are_lexical,
ForInfo* for_info, BlockState* for_state,
ZoneList<const AstRawString*>* labels, bool* ok) {
auto loop = factory()->NewForStatement(labels, stmt_pos); auto loop = factory()->NewForStatement(labels, stmt_pos);
typename Types::Target target(this, loop); typename Types::Target target(this, loop);
...@@ -5577,7 +5611,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement( ...@@ -5577,7 +5611,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement(
// for loop must be parsed in a new scope. // for loop must be parsed in a new scope.
Scope* inner_scope = scope(); Scope* inner_scope = scope();
// TODO(verwaest): Allocate this through a ScopeState as well. // TODO(verwaest): Allocate this through a ScopeState as well.
if (bound_names_are_lexical && for_info.bound_names.length() > 0) { if (bound_names_are_lexical && for_info->bound_names.length() > 0) {
inner_scope = NewScopeWithParent(inner_scope, BLOCK_SCOPE); inner_scope = NewScopeWithParent(inner_scope, BLOCK_SCOPE);
inner_scope->set_start_position(scanner()->location().beg_pos); inner_scope->set_start_position(scanner()->location().beg_pos);
} }
...@@ -5598,46 +5632,46 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement( ...@@ -5598,46 +5632,46 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement(
body = ParseScopedStatement(nullptr, true, CHECK_OK); body = ParseScopedStatement(nullptr, true, CHECK_OK);
} }
if (bound_names_are_lexical && for_info.bound_names.length() > 0) { if (bound_names_are_lexical && for_info->bound_names.length() > 0) {
auto result = impl()->DesugarLexicalBindingsInForStatement( auto result = impl()->DesugarLexicalBindingsInForStatement(
loop, init, cond, next, body, inner_scope, for_info, CHECK_OK); loop, init, cond, next, body, inner_scope, *for_info, CHECK_OK);
for_state.set_end_position(scanner()->location().end_pos); for_state->set_end_position(scanner()->location().end_pos);
return result; return result;
} else {
for_state.set_end_position(scanner()->location().end_pos);
Scope* for_scope = for_state.FinalizedBlockScope();
if (for_scope != nullptr) {
// Rewrite a for statement of the form
// for (const x = i; c; n) b
//
// into
//
// {
// const x = i;
// for (; c; n) b
// }
//
// or, desugar
// for (; c; n) b
// into
// {
// for (; c; n) b
// }
// just in case b introduces a lexical binding some other way, e.g., if b
// is a FunctionDeclaration.
BlockT block = factory()->NewBlock(nullptr, 2, false, kNoSourcePosition);
if (!impl()->IsNullStatement(init)) {
block->statements()->Add(init, zone());
}
block->statements()->Add(loop, zone());
block->set_scope(for_scope);
loop->Initialize(init, cond, next, body);
return block;
} else {
loop->Initialize(init, cond, next, body);
return loop;
}
} }
for_state->set_end_position(scanner()->location().end_pos);
Scope* for_scope = for_state->FinalizedBlockScope();
if (for_scope != nullptr) {
// Rewrite a for statement of the form
// for (const x = i; c; n) b
//
// into
//
// {
// const x = i;
// for (; c; n) b
// }
//
// or, desugar
// for (; c; n) b
// into
// {
// for (; c; n) b
// }
// just in case b introduces a lexical binding some other way, e.g., if b
// is a FunctionDeclaration.
BlockT block = factory()->NewBlock(nullptr, 2, false, kNoSourcePosition);
if (!impl()->IsNullStatement(init)) {
block->statements()->Add(init, zone());
}
block->statements()->Add(loop, zone());
block->set_scope(for_scope);
loop->Initialize(init, cond, next, body);
return block;
}
loop->Initialize(init, cond, next, body);
return loop;
} }
#undef CHECK_OK #undef CHECK_OK
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment