Index: src/parsing/parser-base.h |
diff --git a/src/parsing/parser-base.h b/src/parsing/parser-base.h |
index eade9a7402a4b7200e286d8b1f9067bbe6a88e5e..7db2d4a7f44a08315332472fd467c269b4ee3077 100644 |
--- a/src/parsing/parser-base.h |
+++ b/src/parsing/parser-base.h |
@@ -1302,6 +1302,20 @@ class ParserBase { |
bool* ok); |
StatementT ParseTryStatement(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 IsTrivialExpression(); |
@@ -5380,173 +5394,193 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement( |
for_state.set_is_hidden(); |
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 = |
- factory()->NewForEachStatement(for_info.mode, labels, stmt_pos); |
- typename Types::Target target(this, loop); |
+ if (is_for_each) { |
+ return ParseForEachStatementWithoutDeclarations( |
+ 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(); |
- if (for_info.mode == ForEachStatement::ITERATE) { |
- ExpressionClassifier classifier(this); |
- enumerable = ParseAssignmentExpression(true, CHECK_OK); |
- impl()->RewriteNonPattern(CHECK_OK); |
- } else { |
- enumerable = ParseExpression(true, CHECK_OK); |
- } |
+template <typename Impl> |
+typename ParserBase<Impl>::StatementT |
+ParserBase<Impl>::ParseForEachStatementWithDeclarations( |
+ int stmt_pos, ForInfo* for_info, BlockState* for_state, |
+ ZoneList<const AstRawString*>* labels, bool* ok) { |
+ // 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 || |
+ 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(); |
- { |
- 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()); |
- } |
+ auto loop = factory()->NewForEachStatement(for_info->mode, labels, stmt_pos); |
+ typename Types::Target target(this, loop); |
- init_block = |
- impl()->CreateForEachStatementTDZ(init_block, for_info, ok); |
+ int each_keyword_pos = scanner()->location().beg_pos; |
- 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; |
- } 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; |
+ 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); |
+ } |
- bool is_for_each = CheckInOrOf(&for_info.mode); |
- bool is_destructuring = is_for_each && (expression->IsArrayLiteral() || |
- expression->IsObjectLiteral()); |
+ Expect(Token::RPAREN, CHECK_OK); |
- if (is_destructuring) { |
- ValidateAssignmentPattern(CHECK_OK); |
- } else { |
- impl()->RewriteNonPattern(CHECK_OK); |
- } |
+ StatementT final_loop = impl()->NullStatement(); |
+ { |
+ ReturnExprScope no_tail_calls(function_state_, |
+ ReturnExprContext::kInsideForInOfBody); |
+ BlockState block_state(zone(), &scope_state_); |
+ block_state.set_start_position(scanner()->location().beg_pos); |
- if (is_for_each) { |
- // 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); |
- } |
+ StatementT body = ParseScopedStatement(nullptr, true, CHECK_OK); |
- auto loop = |
- factory()->NewForEachStatement(for_info.mode, labels, stmt_pos); |
- typename Types::Target target(this, loop); |
+ 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); |
- 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(); |
- if (for_info.mode == ForEachStatement::ITERATE) { |
- ExpressionClassifier classifier(this); |
- enumerable = ParseAssignmentExpression(true, CHECK_OK); |
- impl()->RewriteNonPattern(CHECK_OK); |
- } else { |
- enumerable = ParseExpression(true, CHECK_OK); |
- } |
+ init_block = impl()->CreateForEachStatementTDZ(init_block, *for_info, 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; |
+ } |
- { |
- 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; |
- } |
- } else { |
- // Initializer is just an expression. |
- init = factory()->NewExpressionStatement(expression, lhs_beg_pos); |
- } |
- } |
+ DCHECK_NULL(for_scope); |
+ return final_loop; |
+} |
+ |
+template <typename Impl> |
+typename ParserBase<Impl>::StatementT |
+ParserBase<Impl>::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) { |
+ // Initializer is reference followed by in/of. |
+ if (!expression->IsArrayLiteral() && !expression->IsObjectLiteral()) { |
+ expression = impl()->CheckAndRewriteReferenceExpression( |
+ expression, lhs_beg_pos, lhs_end_pos, MessageTemplate::kInvalidLhsInFor, |
+ kSyntaxError, CHECK_OK); |
} |
- // 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); |
typename Types::Target target(this, loop); |
@@ -5560,7 +5594,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement( |
// for loop must be parsed in a new scope. |
Scope* inner_scope = scope(); |
// 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->set_start_position(scanner()->location().beg_pos); |
} |
@@ -5581,46 +5615,46 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement( |
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( |
- loop, init, cond, next, body, inner_scope, for_info, CHECK_OK); |
- for_state.set_end_position(scanner()->location().end_pos); |
+ loop, init, cond, next, body, inner_scope, *for_info, CHECK_OK); |
+ for_state->set_end_position(scanner()->location().end_pos); |
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 |