Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #ifndef V8_PARSING_PARSER_BASE_H | 5 #ifndef V8_PARSING_PARSER_BASE_H |
| 6 #define V8_PARSING_PARSER_BASE_H | 6 #define V8_PARSING_PARSER_BASE_H |
| 7 | 7 |
| 8 #include "src/ast/scopes.h" | 8 #include "src/ast/scopes.h" |
| 9 #include "src/bailout-reason.h" | 9 #include "src/bailout-reason.h" |
| 10 #include "src/base/hashmap.h" | 10 #include "src/base/hashmap.h" |
| (...skipping 1059 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1070 ExpressionClassifier* classifier, bool* ok); | 1070 ExpressionClassifier* classifier, bool* ok); |
| 1071 typename Traits::Type::ExpressionList ParseArguments( | 1071 typename Traits::Type::ExpressionList ParseArguments( |
| 1072 Scanner::Location* first_spread_pos, ExpressionClassifier* classifier, | 1072 Scanner::Location* first_spread_pos, ExpressionClassifier* classifier, |
| 1073 bool* ok) { | 1073 bool* ok) { |
| 1074 return ParseArguments(first_spread_pos, false, classifier, ok); | 1074 return ParseArguments(first_spread_pos, false, classifier, ok); |
| 1075 } | 1075 } |
| 1076 | 1076 |
| 1077 ExpressionT ParseAssignmentExpression(bool accept_IN, | 1077 ExpressionT ParseAssignmentExpression(bool accept_IN, |
| 1078 ExpressionClassifier* classifier, | 1078 ExpressionClassifier* classifier, |
| 1079 bool* ok); | 1079 bool* ok); |
| 1080 ExpressionT ParseTrivialAssignmentExpression(ExpressionClassifier* classifier, | |
| 1081 bool* ok); | |
| 1080 ExpressionT ParseYieldExpression(bool accept_IN, | 1082 ExpressionT ParseYieldExpression(bool accept_IN, |
| 1081 ExpressionClassifier* classifier, bool* ok); | 1083 ExpressionClassifier* classifier, bool* ok); |
| 1082 ExpressionT ParseTailCallExpression(ExpressionClassifier* classifier, | 1084 ExpressionT ParseTailCallExpression(ExpressionClassifier* classifier, |
| 1083 bool* ok); | 1085 bool* ok); |
| 1084 ExpressionT ParseConditionalExpression(bool accept_IN, | 1086 ExpressionT ParseConditionalExpression(bool accept_IN, |
| 1085 ExpressionClassifier* classifier, | 1087 ExpressionClassifier* classifier, |
| 1086 bool* ok); | 1088 bool* ok); |
| 1087 ExpressionT ParseBinaryExpression(int prec, bool accept_IN, | 1089 ExpressionT ParseBinaryExpression(int prec, bool accept_IN, |
| 1088 ExpressionClassifier* classifier, bool* ok); | 1090 ExpressionClassifier* classifier, bool* ok); |
| 1089 ExpressionT ParseUnaryExpression(ExpressionClassifier* classifier, bool* ok); | 1091 ExpressionT ParseUnaryExpression(ExpressionClassifier* classifier, bool* ok); |
| (...skipping 453 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1543 switch (peek()) { | 1545 switch (peek()) { |
| 1544 case Token::THIS: { | 1546 case Token::THIS: { |
| 1545 BindingPatternUnexpectedToken(classifier); | 1547 BindingPatternUnexpectedToken(classifier); |
| 1546 Consume(Token::THIS); | 1548 Consume(Token::THIS); |
| 1547 return this->ThisExpression(scope(), factory(), beg_pos); | 1549 return this->ThisExpression(scope(), factory(), beg_pos); |
| 1548 } | 1550 } |
| 1549 | 1551 |
| 1550 case Token::NULL_LITERAL: | 1552 case Token::NULL_LITERAL: |
| 1551 case Token::TRUE_LITERAL: | 1553 case Token::TRUE_LITERAL: |
| 1552 case Token::FALSE_LITERAL: | 1554 case Token::FALSE_LITERAL: |
| 1553 BindingPatternUnexpectedToken(classifier); | |
| 1554 return this->ExpressionFromLiteral(Next(), beg_pos, scanner(), factory()); | |
| 1555 case Token::SMI: | 1555 case Token::SMI: |
| 1556 case Token::NUMBER: | 1556 case Token::NUMBER: |
| 1557 BindingPatternUnexpectedToken(classifier); | 1557 BindingPatternUnexpectedToken(classifier); |
| 1558 return this->ExpressionFromLiteral(Next(), beg_pos, scanner(), factory()); | 1558 return this->ExpressionFromLiteral(Next(), beg_pos, scanner(), factory()); |
| 1559 | 1559 |
| 1560 case Token::ASYNC: | 1560 case Token::ASYNC: |
| 1561 if (allow_harmony_async_await() && | 1561 if (allow_harmony_async_await() && |
| 1562 !scanner()->HasAnyLineTerminatorAfterNext() && | 1562 !scanner()->HasAnyLineTerminatorAfterNext() && |
| 1563 PeekAhead() == Token::FUNCTION) { | 1563 PeekAhead() == Token::FUNCTION) { |
| 1564 Consume(Token::ASYNC); | 1564 Consume(Token::ASYNC); |
| (...skipping 705 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2270 | 2270 |
| 2271 return result; | 2271 return result; |
| 2272 } | 2272 } |
| 2273 | 2273 |
| 2274 // Precedence = 2 | 2274 // Precedence = 2 |
| 2275 template <class Traits> | 2275 template <class Traits> |
| 2276 typename ParserBase<Traits>::ExpressionT | 2276 typename ParserBase<Traits>::ExpressionT |
| 2277 ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN, | 2277 ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN, |
| 2278 ExpressionClassifier* classifier, | 2278 ExpressionClassifier* classifier, |
| 2279 bool* ok) { | 2279 bool* ok) { |
| 2280 // Try to parse a simple sub-grammar and early-out if successful. | |
| 2281 typename ParserBase<Traits>::ExpressionT trivial_result = | |
| 2282 this->ParseTrivialAssignmentExpression(classifier, ok); | |
| 2283 if (!Traits::IsEmptyExpression(trivial_result)) return trivial_result; | |
|
marja
2016/07/29 07:56:04
Ah right, since we have 2 expression types, this c
vogelheim
2016/08/09 11:26:08
Done. (2nd version)
| |
| 2284 | |
| 2280 // AssignmentExpression :: | 2285 // AssignmentExpression :: |
| 2281 // ConditionalExpression | 2286 // ConditionalExpression |
| 2282 // ArrowFunction | 2287 // ArrowFunction |
| 2283 // YieldExpression | 2288 // YieldExpression |
| 2284 // LeftHandSideExpression AssignmentOperator AssignmentExpression | 2289 // LeftHandSideExpression AssignmentOperator AssignmentExpression |
| 2285 bool is_destructuring_assignment = false; | 2290 bool is_destructuring_assignment = false; |
| 2286 int lhs_beg_pos = peek_position(); | 2291 int lhs_beg_pos = peek_position(); |
| 2287 | 2292 |
| 2288 if (peek() == Token::YIELD && is_generator()) { | 2293 if (peek() == Token::YIELD && is_generator()) { |
| 2289 return this->ParseYieldExpression(accept_IN, classifier, ok); | 2294 return this->ParseYieldExpression(accept_IN, classifier, ok); |
| 2290 } | 2295 } |
| 2291 | 2296 |
| 2292 FuncNameInferrer::State fni_state(fni_); | 2297 FuncNameInferrer::State fni_state(fni_); |
| 2293 ParserBase<Traits>::Checkpoint checkpoint(this); | 2298 ParserBase<Traits>::Checkpoint checkpoint(this); |
| 2294 ExpressionClassifier arrow_formals_classifier(this, | 2299 ExpressionClassifier arrow_formals_classifier(this, |
| 2295 classifier->duplicate_finder()); | 2300 classifier->duplicate_finder()); |
| 2296 | 2301 |
| 2297 bool is_async = allow_harmony_async_await() && peek() == Token::ASYNC && | 2302 bool is_async = allow_harmony_async_await() && peek() == Token::ASYNC && |
| 2298 !scanner()->HasAnyLineTerminatorAfterNext() && | 2303 !scanner()->HasAnyLineTerminatorAfterNext() && |
| 2299 IsValidArrowFormalParametersStart(PeekAhead()); | 2304 IsValidArrowFormalParametersStart(PeekAhead()); |
| 2300 | 2305 |
| 2301 bool parenthesized_formals = peek() == Token::LPAREN; | 2306 bool parenthesized_formals = peek() == Token::LPAREN; |
| 2302 if (!is_async && !parenthesized_formals) { | 2307 if (!is_async && !parenthesized_formals) { |
| 2303 ArrowFormalParametersUnexpectedToken(&arrow_formals_classifier); | 2308 ArrowFormalParametersUnexpectedToken(&arrow_formals_classifier); |
| 2304 } | 2309 } |
| 2305 ExpressionT expression = this->ParseConditionalExpression( | 2310 ExpressionT expression = this->ParseConditionalExpression( |
|
adamk
2016/07/28 17:51:55
What if, rather than putting ParseTrivialAssignmen
vogelheim
2016/08/09 11:26:08
Well... it would also do a lot of work that I'm no
adamk
2016/08/09 16:39:16
But we'd still be skipping the function calls, rig
| |
| 2306 accept_IN, &arrow_formals_classifier, CHECK_OK); | 2311 accept_IN, &arrow_formals_classifier, CHECK_OK); |
| 2307 | 2312 |
| 2308 if (is_async && peek_any_identifier() && PeekAhead() == Token::ARROW) { | 2313 if (is_async && peek_any_identifier() && PeekAhead() == Token::ARROW) { |
| 2309 // async Identifier => AsyncConciseBody | 2314 // async Identifier => AsyncConciseBody |
| 2310 IdentifierT name = | 2315 IdentifierT name = |
| 2311 ParseAndClassifyIdentifier(&arrow_formals_classifier, CHECK_OK); | 2316 ParseAndClassifyIdentifier(&arrow_formals_classifier, CHECK_OK); |
| 2312 expression = this->ExpressionFromIdentifier( | 2317 expression = this->ExpressionFromIdentifier( |
| 2313 name, position(), scanner()->location().end_pos, scope(), factory()); | 2318 name, position(), scanner()->location().end_pos, scope(), factory()); |
| 2314 } | 2319 } |
| 2315 | 2320 |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2458 if (is_destructuring_assignment) { | 2463 if (is_destructuring_assignment) { |
| 2459 result = factory()->NewRewritableExpression(result); | 2464 result = factory()->NewRewritableExpression(result); |
| 2460 Traits::QueueDestructuringAssignmentForRewriting(result); | 2465 Traits::QueueDestructuringAssignmentForRewriting(result); |
| 2461 } | 2466 } |
| 2462 | 2467 |
| 2463 return result; | 2468 return result; |
| 2464 } | 2469 } |
| 2465 | 2470 |
| 2466 template <class Traits> | 2471 template <class Traits> |
| 2467 typename ParserBase<Traits>::ExpressionT | 2472 typename ParserBase<Traits>::ExpressionT |
| 2473 ParserBase<Traits>::ParseTrivialAssignmentExpression( | |
| 2474 ExpressionClassifier* classifier, bool* ok) { | |
| 2475 // Parser shortcut: The following scope is a micro-optimization to reduce | |
|
adamk
2016/07/28 17:51:55
This can be rewritten now that it's in its own fun
vogelheim
2016/08/09 11:26:08
Done.
| |
| 2476 // parsing time. It should be functionally neutral and deliver either nullptr | |
| 2477 // or the same result as the canonical ParseAssignmentExpression. | |
| 2478 // When we encounter | |
| 2479 // [SMI|NUMBER|{NULL,TRUE,FALSE}_LITERAL|THIS|STRING|IDENTIFIER] | |
| 2480 // followed by | |
| 2481 // [COMMA|RPAREN|RBRACK|SEMICOLON] | |
| 2482 // then this will result in a single AST node. Instead of parsing this | |
| 2483 // 'properly' (a call chain 11-levels deep), we will just generate the | |
| 2484 // appropriate AST nodes right here. | |
| 2485 Token::Value peek_token = peek(); | |
| 2486 bool is_number = peek_token == Token::SMI || peek_token == Token::NUMBER; | |
| 2487 bool is_literal = peek_token == Token::NULL_LITERAL || | |
| 2488 peek_token == Token::TRUE_LITERAL || | |
| 2489 peek_token == Token::FALSE_LITERAL; | |
| 2490 bool is_string = peek_token == Token::STRING; | |
| 2491 bool is_identifier = peek_token == Token::IDENTIFIER; | |
| 2492 bool is_this = peek_token == Token::THIS; | |
| 2493 if (is_number || is_literal || is_string || is_identifier || is_this) { | |
| 2494 // PeekAhead() is expensive & may not always be called, so we only call it | |
| 2495 // after checking peek(). | |
| 2496 Token::Value peek_ahead = PeekAhead(); | |
| 2497 if (peek_ahead == Token::COMMA || peek_ahead == Token::RPAREN || | |
| 2498 peek_ahead == Token::SEMICOLON || peek_ahead == Token::RBRACK) { | |
| 2499 Scanner::Location pos = scanner()->peek_location(); | |
| 2500 if (is_string) { | |
| 2501 FuncNameInferrer::State fni_state(fni_); | |
| 2502 classifier->RecordBindingPatternError( | |
| 2503 pos, MessageTemplate::kUnexpectedTokenString); | |
| 2504 Consume(Token::STRING); | |
| 2505 return this->ExpressionFromString(pos.beg_pos, scanner(), factory()); | |
| 2506 } else if (is_this) { | |
| 2507 classifier->RecordBindingPatternError( | |
| 2508 pos, MessageTemplate::kUnexpectedToken, Token::Name(Token::THIS)); | |
| 2509 Consume(Token::THIS); | |
| 2510 return this->ThisExpression(scope(), factory(), pos.beg_pos); | |
| 2511 } else if (is_number) { | |
| 2512 classifier->RecordBindingPatternError( | |
| 2513 pos, MessageTemplate::kUnexpectedTokenNumber); | |
| 2514 Consume(peek_token); | |
| 2515 return this->ExpressionFromLiteral(peek_token, pos.beg_pos, scanner(), | |
| 2516 factory()); | |
| 2517 } else if (is_literal) { | |
| 2518 classifier->RecordBindingPatternError( | |
| 2519 pos, MessageTemplate::kUnexpectedToken, Token::Name(peek_token)); | |
| 2520 Consume(peek_token); | |
| 2521 return this->ExpressionFromLiteral(peek_token, pos.beg_pos, scanner(), | |
| 2522 factory()); | |
| 2523 } else if (is_identifier) { | |
| 2524 FuncNameInferrer::State fni_state(fni_); | |
| 2525 ExpressionClassifier arrow_formals_classifier( | |
| 2526 this, classifier->duplicate_finder()); | |
| 2527 IdentifierT name = | |
| 2528 ParseAndClassifyIdentifier(&arrow_formals_classifier, CHECK_OK); | |
| 2529 typename ParserBase<Traits>::ExpressionT shortcut_result = | |
| 2530 this->ExpressionFromIdentifier(name, pos.beg_pos, pos.end_pos, | |
| 2531 scope(), factory()); | |
| 2532 if (this->IsAssignableIdentifier(shortcut_result)) { | |
| 2533 arrow_formals_classifier.ForgiveAssignmentPatternError(); | |
| 2534 } | |
| 2535 classifier->Accumulate( | |
| 2536 &arrow_formals_classifier, | |
| 2537 ExpressionClassifier::StandardProductions | | |
| 2538 ExpressionClassifier::FormalParametersProductions | | |
| 2539 ExpressionClassifier::CoverInitializedNameProduction | | |
| 2540 ExpressionClassifier::AsyncArrowFormalParametersProduction | | |
| 2541 ExpressionClassifier::AsyncBindingPatternProduction, | |
| 2542 false); | |
| 2543 DCHECK(!Token::IsAssignmentOp(peek_ahead)); | |
| 2544 classifier->MergeNonPatterns(&arrow_formals_classifier); | |
| 2545 return shortcut_result; | |
| 2546 } else { | |
| 2547 UNREACHABLE(); | |
| 2548 } | |
| 2549 } | |
| 2550 } | |
| 2551 // No applicable shortcut found: Proceed w/ regular parsing. | |
| 2552 return this->EmptyExpression(); | |
| 2553 } | |
| 2554 | |
| 2555 template <class Traits> | |
| 2556 typename ParserBase<Traits>::ExpressionT | |
| 2468 ParserBase<Traits>::ParseYieldExpression(bool accept_IN, | 2557 ParserBase<Traits>::ParseYieldExpression(bool accept_IN, |
| 2469 ExpressionClassifier* classifier, | 2558 ExpressionClassifier* classifier, |
| 2470 bool* ok) { | 2559 bool* ok) { |
| 2471 // YieldExpression :: | 2560 // YieldExpression :: |
| 2472 // 'yield' ([no line terminator] '*'? AssignmentExpression)? | 2561 // 'yield' ([no line terminator] '*'? AssignmentExpression)? |
| 2473 int pos = peek_position(); | 2562 int pos = peek_position(); |
| 2474 classifier->RecordPatternError(scanner()->peek_location(), | 2563 classifier->RecordPatternError(scanner()->peek_location(), |
| 2475 MessageTemplate::kInvalidDestructuringTarget); | 2564 MessageTemplate::kInvalidDestructuringTarget); |
| 2476 classifier->RecordFormalParameterInitializerError( | 2565 classifier->RecordFormalParameterInitializerError( |
| 2477 scanner()->peek_location(), MessageTemplate::kYieldInParameter); | 2566 scanner()->peek_location(), MessageTemplate::kYieldInParameter); |
| (...skipping 1219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3697 has_seen_constructor_ = true; | 3786 has_seen_constructor_ = true; |
| 3698 return; | 3787 return; |
| 3699 } | 3788 } |
| 3700 } | 3789 } |
| 3701 | 3790 |
| 3702 | 3791 |
| 3703 } // namespace internal | 3792 } // namespace internal |
| 3704 } // namespace v8 | 3793 } // namespace v8 |
| 3705 | 3794 |
| 3706 #endif // V8_PARSING_PARSER_BASE_H | 3795 #endif // V8_PARSING_PARSER_BASE_H |
| OLD | NEW |