Chromium Code Reviews| Index: src/parsing/parser-base.h |
| diff --git a/src/parsing/parser-base.h b/src/parsing/parser-base.h |
| index eade9a7402a4b7200e286d8b1f9067bbe6a88e5e..bb538851ef5466c01fb499d935a964a0efbddcaf 100644 |
| --- a/src/parsing/parser-base.h |
| +++ b/src/parsing/parser-base.h |
| @@ -1302,6 +1302,18 @@ 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); |
| + |
| + StatementT ParseStandardForLoop(StatementT init, int stmt_pos, |
|
adamk
2017/01/23 18:46:27
Can you give this a little comment that illustrate
marja
2017/01/24 09:37:29
Done.
|
| + ForInfo* for_info, BlockState* for_state, |
| + ZoneList<const AstRawString*>* labels, |
| + bool* ok); |
| bool IsNextLetKeyword(); |
| bool IsTrivialExpression(); |
| @@ -5370,7 +5382,6 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement( |
| ZoneList<const AstRawString*>* labels, bool* ok) { |
| int stmt_pos = peek_position(); |
| ForInfo for_info(this); |
| - bool bound_names_are_lexical = false; |
| // Create an in-between scope for let-bound iteration variables. |
| BlockState for_state(zone(), &scope_state_); |
| @@ -5380,173 +5391,192 @@ 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); |
| + 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. |
| + bool bound_names_are_lexical = |
| + IsLexicalVariableMode(for_info.parsing_result.descriptor.mode); |
| + 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(init, stmt_pos, &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( |
| + StatementT init, int stmt_pos, 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 +5590,9 @@ 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) { |
| + bool bound_names_are_lexical = |
| + IsLexicalVariableMode(for_info->parsing_result.descriptor.mode); |
| + 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 +5613,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 |