Chromium Code Reviews| Index: src/parser.cc |
| diff --git a/src/parser.cc b/src/parser.cc |
| index b9d2c2f9e7df66c6e5e0feebf727001aac2915be..ee0f7dc6804848109197ed9878835d791e3d77f4 100644 |
| --- a/src/parser.cc |
| +++ b/src/parser.cc |
| @@ -2295,8 +2295,8 @@ const AstRawString* Parser::DeclarationParsingResult::SingleName() const { |
| Block* Parser::DeclarationParsingResult::BuildInitializationBlock( |
| ZoneList<const AstRawString*>* names, bool* ok) { |
| - Block* result = |
| - descriptor.parser->factory()->NewBlock(NULL, 1, true, descriptor.pos); |
| + Block* result = descriptor.parser->factory()->NewBlock( |
| + NULL, 1, true, descriptor.declaration_pos); |
| for (auto declaration : declarations) { |
| PatternRewriter::DeclareAndInitializeVariables( |
| result, &descriptor, &declaration, names, CHECK_OK); |
| @@ -2350,7 +2350,8 @@ void Parser::ParseVariableDeclarations(VariableDeclarationContext var_context, |
| // BindingPattern '=' AssignmentExpression |
| parsing_result->descriptor.parser = this; |
| - parsing_result->descriptor.pos = peek_position(); |
| + parsing_result->descriptor.declaration_pos = peek_position(); |
| + parsing_result->descriptor.initialization_pos = peek_position(); |
| parsing_result->descriptor.mode = VAR; |
| // True if the binding needs initialization. 'let' and 'const' declared |
| // bindings are created uninitialized by their declaration nodes and |
| @@ -3417,11 +3418,10 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, |
| bool is_let_identifier_expression = false; |
| DeclarationParsingResult parsing_result; |
| if (peek() != Token::SEMICOLON) { |
| - if (peek() == Token::VAR || |
| - (peek() == Token::CONST && is_sloppy(language_mode()))) { |
| + if (peek() == Token::VAR || peek() == Token::CONST || |
| + (peek() == Token::LET && is_strict(language_mode()))) { |
| ParseVariableDeclarations(kForStatement, &parsing_result, CHECK_OK); |
| - Block* variable_statement = |
| - parsing_result.BuildInitializationBlock(nullptr, CHECK_OK); |
| + is_const = parsing_result.descriptor.mode == CONST; |
| int num_decl = parsing_result.declarations.length(); |
| bool accept_IN = num_decl >= 1; |
| @@ -3454,124 +3454,100 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, |
| *ok = false; |
| return nullptr; |
| } |
| - ForEachStatement* loop = |
| - factory()->NewForEachStatement(mode, labels, stmt_pos); |
| - Target target(&this->target_stack_, loop); |
| - Expression* enumerable = ParseExpression(true, CHECK_OK); |
| - Expect(Token::RPAREN, CHECK_OK); |
| - |
| - VariableProxy* each = |
| - scope_->NewUnresolved(factory(), parsing_result.SingleName(), |
| - Variable::NORMAL, each_beg_pos, each_end_pos); |
| - Statement* body = ParseSubStatement(NULL, CHECK_OK); |
| - InitializeForEachStatement(loop, each, enumerable, body); |
| - Block* result = |
| - factory()->NewBlock(NULL, 2, false, RelocInfo::kNoPosition); |
| - result->AddStatement(variable_statement, zone()); |
| - result->AddStatement(loop, zone()); |
| - scope_ = saved_scope; |
| - for_scope->set_end_position(scanner()->location().end_pos); |
| - for_scope = for_scope->FinalizeBlockScope(); |
| - DCHECK(for_scope == NULL); |
| - // Parsed for-in loop w/ variable/const declaration. |
| - return result; |
| - } else { |
| - init = variable_statement; |
| - } |
| - } else if ((peek() == Token::LET || peek() == Token::CONST) && |
| - is_strict(language_mode())) { |
| - is_const = peek() == Token::CONST; |
| - ParseVariableDeclarations(kForStatement, &parsing_result, CHECK_OK); |
| - DCHECK(parsing_result.descriptor.pos != RelocInfo::kNoPosition); |
| - |
| - int num_decl = parsing_result.declarations.length(); |
| - bool accept_IN = num_decl >= 1; |
| - bool accept_OF = true; |
| - ForEachStatement::VisitMode mode; |
| - int each_beg_pos = scanner()->location().beg_pos; |
| - int each_end_pos = scanner()->location().end_pos; |
| - |
| - if (accept_IN && CheckInOrOf(accept_OF, &mode, ok)) { |
| - if (!*ok) return nullptr; |
| - if (num_decl != 1) { |
| - const char* loop_type = |
| - mode == ForEachStatement::ITERATE ? "for-of" : "for-in"; |
| - ParserTraits::ReportMessageAt( |
| - parsing_result.bindings_loc, |
| - MessageTemplate::kForInOfLoopMultiBindings, loop_type); |
| - *ok = false; |
| - return nullptr; |
| - } |
| - if (parsing_result.first_initializer_loc.IsValid() && |
| - (is_strict(language_mode()) || mode == ForEachStatement::ITERATE)) { |
| - if (mode == ForEachStatement::ITERATE) { |
| - ReportMessageAt(parsing_result.first_initializer_loc, |
| - MessageTemplate::kForOfLoopInitializer); |
| - } else { |
| - ReportMessageAt(parsing_result.first_initializer_loc, |
| - MessageTemplate::kForInLoopInitializer); |
| - } |
| - *ok = false; |
| - return nullptr; |
| + DCHECK(parsing_result.declarations.length() == 1); |
| + Block* init_block = nullptr; |
| + |
| + // special case for legacy for (var/const x =.... in) |
|
rossberg
2015/05/21 17:18:04
Does this actually work with const? You are doing
Dmitry Lomov (no reviews)
2015/05/21 17:22:01
It should only work for legacy const and it does (
|
| + if (is_sloppy(language_mode()) && |
| + !IsLexicalVariableMode(parsing_result.descriptor.mode) && |
| + parsing_result.declarations[0].initializer != nullptr) { |
|
rossberg
2015/05/21 17:18:04
Don't you need to also check that the LHS is a sim
Dmitry Lomov (no reviews)
2015/05/21 17:22:01
No this is done in the parser (see tests in test-p
|
| + VariableProxy* single_var = scope_->NewUnresolved( |
| + factory(), parsing_result.SingleName(), Variable::NORMAL, |
| + each_beg_pos, each_end_pos); |
| + init_block = factory()->NewBlock( |
| + nullptr, 2, true, parsing_result.descriptor.declaration_pos); |
| + init_block->AddStatement( |
| + factory()->NewExpressionStatement( |
| + factory()->NewAssignment( |
| + Token::ASSIGN, single_var, |
| + parsing_result.declarations[0].initializer, |
| + RelocInfo::kNoPosition), |
| + RelocInfo::kNoPosition), |
| + zone()); |
| } |
| - // Rewrite a for-in statement of the form |
| + |
| + // Rewrite a for-in/of statement of the form |
| // |
| - // for (let/const x in e) b |
| + // for (let/const/var x in/of e) b |
| // |
| // into |
| // |
| // <let x' be a temporary variable> |
| - // for (x' in e) { |
| - // let/const x; |
| + // for (x' in/of e) { |
| + // let/const/var x; |
| // x = x'; |
| // b; |
| // } |
| - // TODO(keuchel): Move the temporary variable to the block scope, after |
| - // implementing stack allocated block scoped variables. |
| Variable* temp = scope_->DeclarationScope()->NewTemporary( |
| ast_value_factory()->dot_for_string()); |
| - VariableProxy* temp_proxy = |
| - factory()->NewVariableProxy(temp, each_beg_pos, each_end_pos); |
| ForEachStatement* loop = |
| factory()->NewForEachStatement(mode, labels, stmt_pos); |
| Target target(&this->target_stack_, loop); |
| - // The expression does not see the loop variable. |
| + // The expression does not see the lexical loop variables. |
| scope_ = saved_scope; |
| Expression* enumerable = ParseExpression(true, CHECK_OK); |
| scope_ = for_scope; |
| Expect(Token::RPAREN, CHECK_OK); |
| Statement* body = ParseSubStatement(NULL, CHECK_OK); |
| + |
| Block* body_block = |
| factory()->NewBlock(NULL, 3, false, RelocInfo::kNoPosition); |
| - auto each_initialization_block = factory()->NewBlock( |
| - nullptr, 1, true, parsing_result.descriptor.pos); |
| + auto each_initialization_block = |
| + factory()->NewBlock(nullptr, 1, true, RelocInfo::kNoPosition); |
| { |
| DCHECK(parsing_result.declarations.length() == 1); |
| DeclarationParsingResult::Declaration decl = |
| parsing_result.declarations[0]; |
| - decl.initializer = temp_proxy; |
| + auto descriptor = parsing_result.descriptor; |
| + descriptor.declaration_pos = RelocInfo::kNoPosition; |
| + decl.initializer = factory()->NewVariableProxy(temp); |
| + |
| PatternRewriter::DeclareAndInitializeVariables( |
| - each_initialization_block, &parsing_result.descriptor, &decl, |
| - &lexical_bindings, CHECK_OK); |
| + each_initialization_block, &descriptor, &decl, |
| + IsLexicalVariableMode(descriptor.mode) ? &lexical_bindings |
| + : nullptr, |
| + CHECK_OK); |
| } |
| body_block->AddStatement(each_initialization_block, zone()); |
| body_block->AddStatement(body, zone()); |
| + VariableProxy* temp_proxy = |
| + factory()->NewVariableProxy(temp, each_beg_pos, each_end_pos); |
| InitializeForEachStatement(loop, temp_proxy, enumerable, body_block); |
| scope_ = saved_scope; |
| for_scope->set_end_position(scanner()->location().end_pos); |
| for_scope = for_scope->FinalizeBlockScope(); |
| - body_block->set_scope(for_scope); |
| - // Parsed for-in loop w/ let declaration. |
| - return loop; |
| + if (for_scope != nullptr) { |
| + body_block->set_scope(for_scope); |
| + } |
| + // Parsed for-in loop w/ variable declarations. |
| + if (init_block != nullptr) { |
| + init_block->AddStatement(loop, zone()); |
| + return init_block; |
| + } else { |
| + return loop; |
| + } |
| } else { |
| - init = parsing_result.BuildInitializationBlock(&lexical_bindings, |
| - CHECK_OK); |
| + init = parsing_result.BuildInitializationBlock( |
| + IsLexicalVariableMode(parsing_result.descriptor.mode) |
| + ? &lexical_bindings |
| + : nullptr, |
| + CHECK_OK); |
| } |
| } else { |
| Scanner::Location lhs_location = scanner()->peek_location(); |
| @@ -3579,9 +3555,9 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, |
| ForEachStatement::VisitMode mode; |
| bool accept_OF = expression->IsVariableProxy(); |
| is_let_identifier_expression = |
| - expression->IsVariableProxy() && |
| - expression->AsVariableProxy()->raw_name() == |
| - ast_value_factory()->let_string(); |
| + expression->IsVariableProxy() && |
| + expression->AsVariableProxy()->raw_name() == |
| + ast_value_factory()->let_string(); |
| if (CheckInOrOf(accept_OF, &mode, ok)) { |
| if (!*ok) return nullptr; |