Chromium Code Reviews| Index: src/parser.cc |
| diff --git a/src/parser.cc b/src/parser.cc |
| index 26771e4e347830c81c13377cbd24c7d1d5897213..7dff13d3fa918de2fea1ce8a983892579023d612 100644 |
| --- a/src/parser.cc |
| +++ b/src/parser.cc |
| @@ -14,7 +14,6 @@ |
| #include "src/compiler.h" |
| #include "src/messages.h" |
| #include "src/parser.h" |
| -#include "src/pattern-rewriter.h" |
| #include "src/preparser.h" |
| #include "src/runtime/runtime.h" |
| #include "src/scanner-character-streams.h" |
| @@ -2285,10 +2284,15 @@ Block* Parser::ParseVariableStatement(VariableDeclarationContext var_context, |
| // VariableStatement :: |
| // VariableDeclarations ';' |
| - const AstRawString* ignore; |
| - Block* result = ParseVariableDeclarations( |
| - var_context, nullptr, names, &ignore, nullptr, nullptr, CHECK_OK); |
| + DeclarationParsingResult parsing_result; |
| + ParseVariableDeclarations(var_context, &parsing_result, CHECK_OK); |
| ExpectSemicolon(CHECK_OK); |
| + Block* result = factory()->NewBlock(NULL, 1, true, parsing_result.decl.pos); |
| + for (auto decl : parsing_result.declarations) { |
| + decl.pattern.DeclareAndInitializeVariables( |
| + result, &parsing_result.decl, decl.initializer, names, CHECK_OK); |
| + } |
| + |
| return result; |
| } |
| @@ -2298,11 +2302,10 @@ Block* Parser::ParseVariableStatement(VariableDeclarationContext var_context, |
| // *out is untouched; in particular, it is the caller's responsibility |
| // to initialize it properly. This mechanism is used for the parsing |
| // of 'for-in' loops. |
| -Block* Parser::ParseVariableDeclarations( |
| - VariableDeclarationContext var_context, int* num_decl, |
| - ZoneList<const AstRawString*>* names, const AstRawString** out, |
| - Scanner::Location* first_initializer_loc, Scanner::Location* bindings_loc, |
| - bool* ok) { |
| +// TODO(dslomov): fix the comment |
| +void Parser::ParseVariableDeclarations(VariableDeclarationContext var_context, |
| + DeclarationParsingResult* parsing_result, |
| + bool* ok) { |
| // VariableDeclarations :: |
| // ('var' | 'const' | 'let') (Identifier ('=' AssignmentExpression)?)+[','] |
| // |
| @@ -2317,51 +2320,50 @@ Block* Parser::ParseVariableDeclarations( |
| // ConstBinding :: |
| // BindingPattern '=' AssignmentExpression |
| - PatternRewriter::DeclarationDescriptor decl; |
| - decl.parser = this; |
| - decl.pos = peek_position(); |
| - decl.mode = VAR; |
| + parsing_result->decl.parser = this; |
| + parsing_result->decl.pos = peek_position(); |
| + parsing_result->decl.mode = VAR; |
| // True if the binding needs initialization. 'let' and 'const' declared |
| // bindings are created uninitialized by their declaration nodes and |
| // need initialization. 'var' declared bindings are always initialized |
| // immediately by their declaration nodes. |
| - decl.needs_init = false; |
| - decl.is_const = false; |
| - decl.init_op = Token::INIT_VAR; |
| - decl.names = names; |
| + parsing_result->decl.needs_init = false; |
| + parsing_result->decl.is_const = false; |
| + parsing_result->decl.init_op = Token::INIT_VAR; |
| if (peek() == Token::VAR) { |
| if (is_strong(language_mode())) { |
| Scanner::Location location = scanner()->peek_location(); |
| ReportMessageAt(location, "strong_var"); |
| *ok = false; |
| - return NULL; |
| + return; |
| } |
| Consume(Token::VAR); |
| } else if (peek() == Token::CONST) { |
| Consume(Token::CONST); |
| if (is_sloppy(language_mode())) { |
| - decl.mode = CONST_LEGACY; |
| - decl.init_op = Token::INIT_CONST_LEGACY; |
| + parsing_result->decl.mode = CONST_LEGACY; |
| + parsing_result->decl.init_op = Token::INIT_CONST_LEGACY; |
| ++use_counts_[v8::Isolate::kLegacyConst]; |
| } else { |
| DCHECK(var_context != kStatement); |
| - decl.mode = CONST; |
| - decl.init_op = Token::INIT_CONST; |
| + parsing_result->decl.mode = CONST; |
| + parsing_result->decl.init_op = Token::INIT_CONST; |
| } |
| - decl.is_const = true; |
| - decl.needs_init = true; |
| + parsing_result->decl.is_const = true; |
| + parsing_result->decl.needs_init = true; |
| } else if (peek() == Token::LET && is_strict(language_mode())) { |
| Consume(Token::LET); |
| DCHECK(var_context != kStatement); |
| - decl.mode = LET; |
| - decl.needs_init = true; |
| - decl.init_op = Token::INIT_LET; |
| + parsing_result->decl.mode = LET; |
| + parsing_result->decl.needs_init = true; |
| + parsing_result->decl.init_op = Token::INIT_LET; |
| } else { |
| UNREACHABLE(); // by current callers |
| } |
| - decl.declaration_scope = DeclarationScope(decl.mode); |
| - decl.scope = scope_; |
| + parsing_result->decl.declaration_scope = |
| + DeclarationScope(parsing_result->decl.mode); |
| + parsing_result->decl.scope = scope_; |
| // The scope of a var/const declared variable anywhere inside a function |
| @@ -2375,9 +2377,6 @@ Block* Parser::ParseVariableDeclarations( |
| // behavior for code such as print(eval('var x = 7')), and for cosmetic |
| // reasons when pretty-printing. Also, unless an assignment (initialization) |
| // is inside an initializer block, it is ignored. |
| - // |
| - // Create new block with one expected declaration. |
| - decl.block = factory()->NewBlock(NULL, 1, true, decl.pos); |
| int nvars = 0; // the number of variables declared |
| int bindings_start = peek_position(); |
| const AstRawString* first_name = NULL; |
| @@ -2385,25 +2384,24 @@ Block* Parser::ParseVariableDeclarations( |
| do { |
| if (fni_ != NULL) fni_->Enter(); |
| - // Parse variable name. |
| + // Parse name. |
| if (nvars > 0) Consume(Token::COMMA); |
| PatternRewriter pattern_rewriter; |
| { |
| ExpressionClassifier pattern_classifier; |
| Token::Value next = peek(); |
| - Expression* pattern = |
| - ParsePrimaryExpression(&pattern_classifier, CHECK_OK); |
| - ValidateBindingPattern(&pattern_classifier, CHECK_OK); |
| - pattern_rewriter = PatternRewriter(&decl, pattern); |
| + Expression* pattern = ParsePrimaryExpression(&pattern_classifier, ok); |
| + if (!*ok) return; |
| + ValidateBindingPattern(&pattern_classifier, ok); |
| + if (!*ok) return; |
| + pattern_rewriter = PatternRewriter(pattern); |
| if (!allow_harmony_destructuring() && |
| !pattern_rewriter.IsSingleVariableBinding()) { |
| ReportUnexpectedToken(next); |
| *ok = false; |
| - return nullptr; |
| + return; |
| } |
| - |
| - // TODO(dslomov): unify |
| } |
| Scanner::Location variable_loc = scanner()->location(); |
| @@ -2416,26 +2414,27 @@ Block* Parser::ParseVariableDeclarations( |
| is_for_iteration_variable = |
| var_context == kForStatement && |
| (peek() == Token::IN || PeekContextualKeyword(CStrVector("of"))); |
| - if (is_for_iteration_variable && decl.mode == CONST) { |
| - decl.needs_init = false; |
| + if (is_for_iteration_variable && parsing_result->decl.mode == CONST) { |
| + parsing_result->decl.needs_init = false; |
| } |
| Expression* value = NULL; |
| - decl.pos = -1; |
| - decl.initializer_position = -1; |
| // Harmony consts have non-optional initializers. |
| if (peek() == Token::ASSIGN || |
| - (decl.mode == CONST && !is_for_iteration_variable)) { |
| - Expect(Token::ASSIGN, CHECK_OK); |
| - decl.pos = position(); |
| + (parsing_result->decl.mode == CONST && !is_for_iteration_variable)) { |
| + Expect(Token::ASSIGN, ok); |
|
arv (Not doing code reviews)
2015/05/13 16:29:29
Maybe add a macro for CHECK_OK_VOID?
Dmitry Lomov (no reviews)
2015/05/14 16:28:00
Considered this but decided against. Too many CHEC
|
| + if (!*ok) return; |
| + parsing_result->decl.pos = position(); |
| ExpressionClassifier classifier; |
| value = ParseAssignmentExpression(var_context != kForStatement, |
| - &classifier, CHECK_OK); |
| - ValidateExpression(&classifier, CHECK_OK); |
| + &classifier, ok); |
| + if (!*ok) return; |
| + ValidateExpression(&classifier, ok); |
| + if (!*ok) return; |
| variable_loc.end_pos = scanner()->location().end_pos; |
| - if (first_initializer_loc && !first_initializer_loc->IsValid()) { |
| - *first_initializer_loc = variable_loc; |
| + if (!parsing_result->first_initializer_loc.IsValid()) { |
| + parsing_result->first_initializer_loc = variable_loc; |
| } |
| // Don't infer if it is "a = function(){...}();"-like expression. |
| @@ -2448,31 +2447,27 @@ Block* Parser::ParseVariableDeclarations( |
| } |
| } |
| // End position of the initializer is after the assignment expression. |
| - decl.initializer_position = scanner()->location().end_pos; |
| + pattern_rewriter.set_initializer_position(scanner()->location().end_pos); |
| } else { |
| // End position of the initializer is after the variable. |
| - decl.initializer_position = position(); |
| + pattern_rewriter.set_initializer_position(position()); |
| } |
| // Make sure that 'const x' and 'let x' initialize 'x' to undefined. |
| - if (value == NULL && decl.needs_init) { |
| + if (value == NULL && parsing_result->decl.needs_init) { |
| value = GetLiteralUndefined(position()); |
| } |
| - pattern_rewriter.DeclareAndInitializeVariables(value, &nvars, CHECK_OK); |
| - |
| if (single_name && fni_ != NULL) fni_->Leave(); |
| + parsing_result->declarations.Add( |
| + DeclarationParsingResult::Declaration(pattern_rewriter, value)); |
| + nvars++; |
| } while (peek() == Token::COMMA); |
| - if (bindings_loc) { |
| - *bindings_loc = |
| - Scanner::Location(bindings_start, scanner()->location().end_pos); |
| - } |
| - |
| - if (num_decl) *num_decl = nvars; |
| - *out = first_name; |
| + parsing_result->bindings_loc = |
| + Scanner::Location(bindings_start, scanner()->location().end_pos); |
| - return decl.block; |
| + parsing_result->out = first_name; |
|
arv (Not doing code reviews)
2015/05/13 16:29:29
rename out?
Dmitry Lomov (no reviews)
2015/05/14 16:28:00
I did one better and removed it completely
|
| } |
| @@ -3239,7 +3234,6 @@ Statement* Parser::DesugarLexicalBindingsInForStatement( |
| Block* inner_block = factory()->NewBlock(NULL, names->length() + 4, false, |
| RelocInfo::kNoPosition); |
| ZoneList<Variable*> inner_vars(names->length(), zone()); |
| - |
| // For each let variable x: |
| // make statement: let/const x = temp_x. |
| VariableMode mode = is_const ? CONST : LET; |
| @@ -3255,6 +3249,7 @@ Statement* Parser::DesugarLexicalBindingsInForStatement( |
| proxy, temp_proxy, RelocInfo::kNoPosition); |
| Statement* assignment_statement = |
| factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition); |
| + DCHECK(init->position() != RelocInfo::kNoPosition); |
| proxy->var()->set_initializer_position(init->position()); |
| inner_block->AddStatement(assignment_statement, zone()); |
| } |
| @@ -3391,7 +3386,6 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, |
| Scope* saved_scope = scope_; |
| Scope* for_scope = NewScope(scope_, BLOCK_SCOPE); |
| scope_ = for_scope; |
| - |
| Expect(Token::FOR, CHECK_OK); |
| Expect(Token::LPAREN, CHECK_OK); |
| for_scope->set_start_position(scanner()->location().beg_pos); |
| @@ -3399,13 +3393,18 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, |
| if (peek() != Token::SEMICOLON) { |
| if (peek() == Token::VAR || |
| (peek() == Token::CONST && is_sloppy(language_mode()))) { |
| - const AstRawString* name = NULL; |
| - Scanner::Location first_initializer_loc = Scanner::Location::invalid(); |
| - Scanner::Location bindings_loc = Scanner::Location::invalid(); |
| - int num_decl; |
| - Block* variable_statement = ParseVariableDeclarations( |
| - kForStatement, &num_decl, nullptr, &name, &first_initializer_loc, |
| - &bindings_loc, CHECK_OK); |
| + DeclarationParsingResult parsing_result; |
| + ParseVariableDeclarations(kForStatement, &parsing_result, CHECK_OK); |
| + Block* variable_statement = |
| + factory()->NewBlock(NULL, 1, true, parsing_result.decl.pos); |
| + |
| + for (auto declaration : parsing_result.declarations) { |
| + declaration.pattern.DeclareAndInitializeVariables( |
| + variable_statement, &parsing_result.decl, declaration.initializer, |
| + nullptr, CHECK_OK); |
| + } |
| + |
| + int num_decl = parsing_result.declarations.length(); |
| bool accept_IN = num_decl >= 1; |
| bool accept_OF = true; |
| ForEachStatement::VisitMode mode; |
| @@ -3417,18 +3416,21 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, |
| if (num_decl != 1) { |
| const char* loop_type = |
| mode == ForEachStatement::ITERATE ? "for-of" : "for-in"; |
| - ParserTraits::ReportMessageAt( |
| - bindings_loc, "for_inof_loop_multi_bindings", loop_type); |
| + ParserTraits::ReportMessageAt(parsing_result.bindings_loc, |
| + "for_inof_loop_multi_bindings", |
| + loop_type); |
| *ok = false; |
| return nullptr; |
| } |
| - if (first_initializer_loc.IsValid() && |
| + if (parsing_result.first_initializer_loc.IsValid() && |
| (is_strict(language_mode()) || mode == ForEachStatement::ITERATE)) { |
| if (mode == ForEachStatement::ITERATE) { |
| - ReportMessageAt(first_initializer_loc, "for_of_loop_initializer"); |
| + ReportMessageAt(parsing_result.first_initializer_loc, |
| + "for_of_loop_initializer"); |
| } else { |
| // TODO(caitp): This should be an error in sloppy mode too. |
| - ReportMessageAt(first_initializer_loc, "for_in_loop_initializer"); |
| + ReportMessageAt(parsing_result.first_initializer_loc, |
| + "for_in_loop_initializer"); |
| } |
| *ok = false; |
| return nullptr; |
| @@ -3440,8 +3442,9 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, |
| Expression* enumerable = ParseExpression(true, CHECK_OK); |
| Expect(Token::RPAREN, CHECK_OK); |
| - VariableProxy* each = scope_->NewUnresolved( |
| - factory(), name, Variable::NORMAL, each_beg_pos, each_end_pos); |
| + VariableProxy* each = |
| + scope_->NewUnresolved(factory(), parsing_result.out, |
| + Variable::NORMAL, each_beg_pos, each_end_pos); |
| Statement* body = ParseSubStatement(NULL, CHECK_OK); |
| InitializeForEachStatement(loop, each, enumerable, body); |
| Block* result = |
| @@ -3460,13 +3463,19 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, |
| } else if ((peek() == Token::LET || peek() == Token::CONST) && |
| is_strict(language_mode())) { |
| is_const = peek() == Token::CONST; |
| - const AstRawString* name = NULL; |
| - Scanner::Location first_initializer_loc = Scanner::Location::invalid(); |
| - Scanner::Location bindings_loc = Scanner::Location::invalid(); |
| - int num_decl; |
| - Block* variable_statement = ParseVariableDeclarations( |
| - kForStatement, &num_decl, &lexical_bindings, &name, |
| - &first_initializer_loc, &bindings_loc, CHECK_OK); |
| + DeclarationParsingResult parsing_result; |
| + |
| + ParseVariableDeclarations(kForStatement, &parsing_result, CHECK_OK); |
|
arv (Not doing code reviews)
2015/05/13 16:29:29
Can this code be shared with the sloppy branch?
Dmitry Lomov (no reviews)
2015/05/14 16:28:00
Maybe in the next CL; I shared some.
|
| + Block* variable_statement = |
| + factory()->NewBlock(NULL, 1, true, parsing_result.decl.pos); |
| + DCHECK(parsing_result.decl.pos != RelocInfo::kNoPosition); |
| + |
| + for (auto declaration : parsing_result.declarations) { |
| + declaration.pattern.DeclareAndInitializeVariables( |
| + variable_statement, &parsing_result.decl, declaration.initializer, |
| + &lexical_bindings, CHECK_OK); |
| + } |
| + int num_decl = parsing_result.declarations.length(); |
| bool accept_IN = num_decl >= 1; |
| bool accept_OF = true; |
| ForEachStatement::VisitMode mode; |
| @@ -3478,17 +3487,20 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, |
| if (num_decl != 1) { |
| const char* loop_type = |
| mode == ForEachStatement::ITERATE ? "for-of" : "for-in"; |
| - ParserTraits::ReportMessageAt( |
| - bindings_loc, "for_inof_loop_multi_bindings", loop_type); |
| + ParserTraits::ReportMessageAt(parsing_result.bindings_loc, |
| + "for_inof_loop_multi_bindings", |
| + loop_type); |
| *ok = false; |
| return nullptr; |
| } |
| - if (first_initializer_loc.IsValid() && |
| + if (parsing_result.first_initializer_loc.IsValid() && |
| (is_strict(language_mode()) || mode == ForEachStatement::ITERATE)) { |
| if (mode == ForEachStatement::ITERATE) { |
| - ReportMessageAt(first_initializer_loc, "for_of_loop_initializer"); |
| + ReportMessageAt(parsing_result.first_initializer_loc, |
| + "for_of_loop_initializer"); |
| } else { |
| - ReportMessageAt(first_initializer_loc, "for_in_loop_initializer"); |
| + ReportMessageAt(parsing_result.first_initializer_loc, |
| + "for_in_loop_initializer"); |
| } |
| *ok = false; |
| return nullptr; |
| @@ -3522,8 +3534,9 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, |
| scope_ = for_scope; |
| Expect(Token::RPAREN, CHECK_OK); |
| - VariableProxy* each = scope_->NewUnresolved( |
| - factory(), name, Variable::NORMAL, each_beg_pos, each_end_pos); |
| + VariableProxy* each = |
| + scope_->NewUnresolved(factory(), parsing_result.out, |
| + Variable::NORMAL, each_beg_pos, each_end_pos); |
| Statement* body = ParseSubStatement(NULL, CHECK_OK); |
| Block* body_block = |
| factory()->NewBlock(NULL, 3, false, RelocInfo::kNoPosition); |