From db1de41a62dc90dd853e0e73d941d72fae4ca8f1 Mon Sep 17 00:00:00 2001 From: marja Date: Tue, 24 Jan 2017 02:17:02 -0800 Subject: [PATCH] [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} --- src/parsing/parser-base.h | 432 ++++++++++++++++++++------------------ 1 file changed, 233 insertions(+), 199 deletions(-) diff --git a/src/parsing/parser-base.h b/src/parsing/parser-base.h index 3f894e74f1..b89cbee9b6 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* labels, bool* ok); + StatementT ParseForEachStatementWithDeclarations( + int stmt_pos, ForInfo* for_info, BlockState* for_state, + ZoneList* 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* labels, bool* ok); + + // Parse a C-style for loop: 'for (; ; ) { ... }' + StatementT ParseStandardForLoop(int stmt_pos, StatementT init, + bool bound_names_are_lexical, + ForInfo* for_info, BlockState* for_state, + ZoneList* labels, + bool* ok); bool IsNextLetKeyword(); bool IsTrivialExpression(); @@ -5397,173 +5411,193 @@ typename ParserBase::StatementT ParserBase::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(); - } + 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; - BlockT init_block = impl()->RewriteForVarInLegacy(for_info); - - 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); - - 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()); - } - - init_block = - impl()->CreateForEachStatementTDZ(init_block, for_info, 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; - } 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); - bool is_destructuring = is_for_each && (expression->IsArrayLiteral() || - expression->IsObjectLiteral()); - - if (is_destructuring) { - ValidateAssignmentPattern(CHECK_OK); - } else { - impl()->RewriteNonPattern(CHECK_OK); - } - - 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); - } - - 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; - } - } else { - // Initializer is just an expression. - init = factory()->NewExpressionStatement(expression, lhs_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); + } + + 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); } // 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); +} + +template +typename ParserBase::StatementT +ParserBase::ParseForEachStatementWithDeclarations( + int stmt_pos, ForInfo* for_info, BlockState* for_state, + ZoneList* 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(); + } + + BlockT init_block = impl()->RewriteForVarInLegacy(*for_info); + + 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); + + 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()); + } + + init_block = impl()->CreateForEachStatementTDZ(init_block, *for_info, 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); + return final_loop; +} + +template +typename ParserBase::StatementT +ParserBase::ParseForEachStatementWithoutDeclarations( + int stmt_pos, ExpressionT expression, int lhs_beg_pos, int lhs_end_pos, + ForInfo* for_info, BlockState* for_state, + ZoneList* 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); + } + + 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 ParserBase::StatementT ParserBase::ParseStandardForLoop( + int stmt_pos, StatementT init, bool bound_names_are_lexical, + ForInfo* for_info, BlockState* for_state, + ZoneList* labels, bool* ok) { auto loop = factory()->NewForStatement(labels, stmt_pos); typename Types::Target target(this, loop); @@ -5577,7 +5611,7 @@ typename ParserBase::StatementT ParserBase::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); } @@ -5598,46 +5632,46 @@ typename ParserBase::StatementT ParserBase::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