| 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
|
|
|