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 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
119 | 119 |
120 | 120 |
121 // ---------------------------------------------------------------------------- | 121 // ---------------------------------------------------------------------------- |
122 // The CHECK_OK macro is a convenient macro to enforce error | 122 // The CHECK_OK macro is a convenient macro to enforce error |
123 // handling for functions that may fail (by returning !*ok). | 123 // handling for functions that may fail (by returning !*ok). |
124 // | 124 // |
125 // CAUTION: This macro appends extra statements after a call, | 125 // CAUTION: This macro appends extra statements after a call, |
126 // thus it must never be used where only a single statement | 126 // thus it must never be used where only a single statement |
127 // is correct (e.g. an if statement branch w/o braces)! | 127 // is correct (e.g. an if statement branch w/o braces)! |
128 | 128 |
129 #define CHECK_OK_CUSTOM(x) ok); \ | 129 #define CHECK_OK_CUSTOM(x, ...) ok); \ |
130 if (!*ok) return impl()->x(); \ | 130 if (!*ok) return impl()->x(__VA_ARGS__); \ |
131 ((void)0 | 131 ((void)0 |
132 #define DUMMY ) // to make indentation work | 132 #define DUMMY ) // to make indentation work |
133 #undef DUMMY | 133 #undef DUMMY |
134 | 134 |
135 // Used in functions where the return type is ExpressionT. | 135 // Used in functions where the return type is ExpressionT. |
136 #define CHECK_OK CHECK_OK_CUSTOM(EmptyExpression) | 136 #define CHECK_OK CHECK_OK_CUSTOM(EmptyExpression) |
137 | 137 |
138 // Common base class template shared between parser and pre-parser. | 138 // Common base class template shared between parser and pre-parser. |
139 // The Impl parameter is the actual class of the parser/pre-parser, | 139 // The Impl parameter is the actual class of the parser/pre-parser, |
140 // following the Curiously Recurring Template Pattern (CRTP). | 140 // following the Curiously Recurring Template Pattern (CRTP). |
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
266 | 266 |
267 uintptr_t stack_limit() const { return stack_limit_; } | 267 uintptr_t stack_limit() const { return stack_limit_; } |
268 | 268 |
269 void set_stack_limit(uintptr_t stack_limit) { stack_limit_ = stack_limit; } | 269 void set_stack_limit(uintptr_t stack_limit) { stack_limit_ = stack_limit; } |
270 | 270 |
271 Zone* zone() const { return zone_; } | 271 Zone* zone() const { return zone_; } |
272 | 272 |
273 protected: | 273 protected: |
274 friend class v8::internal::ExpressionClassifier<ParserTypes<Impl>>; | 274 friend class v8::internal::ExpressionClassifier<ParserTypes<Impl>>; |
275 | 275 |
| 276 // clang-format off |
276 enum AllowRestrictedIdentifiers { | 277 enum AllowRestrictedIdentifiers { |
277 kAllowRestrictedIdentifiers, | 278 kAllowRestrictedIdentifiers, |
278 kDontAllowRestrictedIdentifiers | 279 kDontAllowRestrictedIdentifiers |
279 }; | 280 }; |
280 | 281 |
281 enum Mode { | 282 enum Mode { |
282 PARSE_LAZILY, | 283 PARSE_LAZILY, |
283 PARSE_EAGERLY | 284 PARSE_EAGERLY |
284 }; | 285 }; |
285 | 286 |
| 287 enum LazyParsingResult { |
| 288 kLazyParsingComplete, |
| 289 kLazyParsingAborted |
| 290 }; |
| 291 |
286 enum VariableDeclarationContext { | 292 enum VariableDeclarationContext { |
287 kStatementListItem, | 293 kStatementListItem, |
288 kStatement, | 294 kStatement, |
289 kForStatement | 295 kForStatement |
290 }; | 296 }; |
| 297 // clang-format on |
291 | 298 |
292 class Checkpoint; | 299 class Checkpoint; |
293 class ObjectLiteralCheckerBase; | 300 class ObjectLiteralCheckerBase; |
294 | 301 |
295 // --------------------------------------------------------------------------- | 302 // --------------------------------------------------------------------------- |
296 // ScopeState and its subclasses implement the parser's scope stack. | 303 // ScopeState and its subclasses implement the parser's scope stack. |
297 // ScopeState keeps track of the current scope, and the outer ScopeState. The | 304 // ScopeState keeps track of the current scope, and the outer ScopeState. The |
298 // parser's scope_state_ points to the top ScopeState. ScopeState's | 305 // parser's scope_state_ points to the top ScopeState. ScopeState's |
299 // constructor push on the scope stack and the destructors pop. BlockState and | 306 // constructor push on the scope stack and the destructors pop. BlockState and |
300 // FunctionState are used to hold additional per-block and per-function state. | 307 // FunctionState are used to hold additional per-block and per-function state. |
(...skipping 477 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
778 return; | 785 return; |
779 } | 786 } |
780 if (scanner()->HasAnyLineTerminatorBeforeNext() || | 787 if (scanner()->HasAnyLineTerminatorBeforeNext() || |
781 tok == Token::RBRACE || | 788 tok == Token::RBRACE || |
782 tok == Token::EOS) { | 789 tok == Token::EOS) { |
783 return; | 790 return; |
784 } | 791 } |
785 Expect(Token::SEMICOLON, ok); | 792 Expect(Token::SEMICOLON, ok); |
786 } | 793 } |
787 | 794 |
788 // A dummy function, just useful as an argument to CHECK_OK_CUSTOM. | 795 // Dummy functions, just useful as arguments to CHECK_OK_CUSTOM. |
789 static void Void() {} | 796 static void Void() {} |
| 797 template <typename T> |
| 798 static T Return(T result) { |
| 799 return result; |
| 800 } |
790 | 801 |
791 bool is_any_identifier(Token::Value token) { | 802 bool is_any_identifier(Token::Value token) { |
792 return token == Token::IDENTIFIER || token == Token::ENUM || | 803 return token == Token::IDENTIFIER || token == Token::ENUM || |
793 token == Token::AWAIT || token == Token::ASYNC || | 804 token == Token::AWAIT || token == Token::ASYNC || |
794 token == Token::FUTURE_STRICT_RESERVED_WORD || token == Token::LET || | 805 token == Token::FUTURE_STRICT_RESERVED_WORD || token == Token::LET || |
795 token == Token::STATIC || token == Token::YIELD; | 806 token == Token::STATIC || token == Token::YIELD; |
796 } | 807 } |
797 bool peek_any_identifier() { return is_any_identifier(peek()); } | 808 bool peek_any_identifier() { return is_any_identifier(peek()); } |
798 | 809 |
799 bool CheckContextualKeyword(Vector<const char> keyword) { | 810 bool CheckContextualKeyword(Vector<const char> keyword) { |
(...skipping 13 matching lines...) Expand all Loading... |
813 const char* full_name, int pos, bool* ok); | 824 const char* full_name, int pos, bool* ok); |
814 | 825 |
815 void ExpectContextualKeyword(Vector<const char> keyword, bool* ok) { | 826 void ExpectContextualKeyword(Vector<const char> keyword, bool* ok) { |
816 Expect(Token::IDENTIFIER, CHECK_OK_CUSTOM(Void)); | 827 Expect(Token::IDENTIFIER, CHECK_OK_CUSTOM(Void)); |
817 if (!scanner()->is_literal_contextual_keyword(keyword)) { | 828 if (!scanner()->is_literal_contextual_keyword(keyword)) { |
818 ReportUnexpectedToken(scanner()->current_token()); | 829 ReportUnexpectedToken(scanner()->current_token()); |
819 *ok = false; | 830 *ok = false; |
820 } | 831 } |
821 } | 832 } |
822 | 833 |
823 bool CheckInOrOf(ForEachStatement::VisitMode* visit_mode, bool* ok) { | 834 bool CheckInOrOf(ForEachStatement::VisitMode* visit_mode) { |
824 if (Check(Token::IN)) { | 835 if (Check(Token::IN)) { |
825 *visit_mode = ForEachStatement::ENUMERATE; | 836 *visit_mode = ForEachStatement::ENUMERATE; |
826 return true; | 837 return true; |
827 } else if (CheckContextualKeyword(CStrVector("of"))) { | 838 } else if (CheckContextualKeyword(CStrVector("of"))) { |
828 *visit_mode = ForEachStatement::ITERATE; | 839 *visit_mode = ForEachStatement::ITERATE; |
829 return true; | 840 return true; |
830 } | 841 } |
831 return false; | 842 return false; |
832 } | 843 } |
833 | 844 |
(...skipping 2643 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3477 bool* ok) { | 3488 bool* ok) { |
3478 if (peek() == Token::ARROW && scanner_->HasAnyLineTerminatorBeforeNext()) { | 3489 if (peek() == Token::ARROW && scanner_->HasAnyLineTerminatorBeforeNext()) { |
3479 // ASI inserts `;` after arrow parameters if a line terminator is found. | 3490 // ASI inserts `;` after arrow parameters if a line terminator is found. |
3480 // `=> ...` is never a valid expression, so report as syntax error. | 3491 // `=> ...` is never a valid expression, so report as syntax error. |
3481 // If next token is not `=>`, it's a syntax error anyways. | 3492 // If next token is not `=>`, it's a syntax error anyways. |
3482 ReportUnexpectedTokenAt(scanner_->peek_location(), Token::ARROW); | 3493 ReportUnexpectedTokenAt(scanner_->peek_location(), Token::ARROW); |
3483 *ok = false; | 3494 *ok = false; |
3484 return impl()->EmptyExpression(); | 3495 return impl()->EmptyExpression(); |
3485 } | 3496 } |
3486 | 3497 |
3487 typename Types::StatementList body; | 3498 typename Types::StatementList body = impl()->NullStatementList(); |
3488 int num_parameters = formal_parameters.scope->num_parameters(); | 3499 int num_parameters = formal_parameters.scope->num_parameters(); |
3489 int materialized_literal_count = -1; | 3500 int materialized_literal_count = -1; |
3490 int expected_property_count = -1; | 3501 int expected_property_count = -1; |
3491 | 3502 |
3492 FunctionKind arrow_kind = is_async ? kAsyncArrowFunction : kArrowFunction; | 3503 FunctionKind arrow_kind = is_async ? kAsyncArrowFunction : kArrowFunction; |
| 3504 FunctionLiteral::EagerCompileHint eager_compile_hint = |
| 3505 FunctionLiteral::kShouldLazyCompile; |
| 3506 bool should_be_used_once_hint = false; |
3493 { | 3507 { |
3494 FunctionState function_state(&function_state_, &scope_state_, | 3508 FunctionState function_state(&function_state_, &scope_state_, |
3495 formal_parameters.scope, arrow_kind); | 3509 formal_parameters.scope, arrow_kind); |
3496 | 3510 |
3497 function_state.SkipMaterializedLiterals( | 3511 function_state.SkipMaterializedLiterals( |
3498 formal_parameters.materialized_literals_count); | 3512 formal_parameters.materialized_literals_count); |
3499 | 3513 |
3500 impl()->ReindexLiterals(formal_parameters); | 3514 impl()->ReindexLiterals(formal_parameters); |
3501 | 3515 |
3502 Expect(Token::ARROW, CHECK_OK); | 3516 Expect(Token::ARROW, CHECK_OK); |
3503 | 3517 |
3504 if (peek() == Token::LBRACE) { | 3518 if (peek() == Token::LBRACE) { |
3505 // Multiple statement body | 3519 // Multiple statement body |
3506 Consume(Token::LBRACE); | 3520 Consume(Token::LBRACE); |
3507 DCHECK_EQ(scope(), formal_parameters.scope); | 3521 DCHECK_EQ(scope(), formal_parameters.scope); |
3508 bool is_lazily_parsed = (mode() == PARSE_LAZILY && | 3522 bool is_lazily_parsed = (mode() == PARSE_LAZILY && |
3509 formal_parameters.scope->AllowsLazyParsing()); | 3523 formal_parameters.scope->AllowsLazyParsing()); |
3510 if (is_lazily_parsed) { | 3524 if (is_lazily_parsed) { |
3511 body = impl()->NewStatementList(0); | 3525 Scanner::BookmarkScope bookmark(scanner()); |
3512 impl()->SkipLazyFunctionBody(&materialized_literal_count, | 3526 bool may_abort = bookmark.Set(); |
3513 &expected_property_count, CHECK_OK); | 3527 LazyParsingResult result = impl()->SkipLazyFunctionBody( |
| 3528 &materialized_literal_count, &expected_property_count, may_abort, |
| 3529 CHECK_OK); |
| 3530 |
3514 if (formal_parameters.materialized_literals_count > 0) { | 3531 if (formal_parameters.materialized_literals_count > 0) { |
3515 materialized_literal_count += | 3532 materialized_literal_count += |
3516 formal_parameters.materialized_literals_count; | 3533 formal_parameters.materialized_literals_count; |
3517 } | 3534 } |
3518 } else { | 3535 |
| 3536 if (result == kLazyParsingAborted) { |
| 3537 bookmark.Reset(); |
| 3538 // Trigger eager (re-)parsing, just below this block. |
| 3539 is_lazily_parsed = false; |
| 3540 |
| 3541 // This is probably an initialization function. Inform the compiler it |
| 3542 // should also eager-compile this function, and that we expect it to |
| 3543 // be used once. |
| 3544 eager_compile_hint = FunctionLiteral::kShouldEagerCompile; |
| 3545 should_be_used_once_hint = true; |
| 3546 } |
| 3547 } |
| 3548 if (!is_lazily_parsed) { |
3519 body = impl()->ParseEagerFunctionBody( | 3549 body = impl()->ParseEagerFunctionBody( |
3520 impl()->EmptyIdentifier(), kNoSourcePosition, formal_parameters, | 3550 impl()->EmptyIdentifier(), kNoSourcePosition, formal_parameters, |
3521 arrow_kind, FunctionLiteral::kAnonymousExpression, CHECK_OK); | 3551 arrow_kind, FunctionLiteral::kAnonymousExpression, CHECK_OK); |
3522 materialized_literal_count = | 3552 materialized_literal_count = |
3523 function_state.materialized_literal_count(); | 3553 function_state.materialized_literal_count(); |
3524 expected_property_count = function_state.expected_property_count(); | 3554 expected_property_count = function_state.expected_property_count(); |
3525 } | 3555 } |
3526 } else { | 3556 } else { |
3527 // Single-expression body | 3557 // Single-expression body |
3528 int pos = position(); | 3558 int pos = position(); |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3569 } | 3599 } |
3570 impl()->CheckConflictingVarDeclarations(formal_parameters.scope, CHECK_OK); | 3600 impl()->CheckConflictingVarDeclarations(formal_parameters.scope, CHECK_OK); |
3571 | 3601 |
3572 impl()->RewriteDestructuringAssignments(); | 3602 impl()->RewriteDestructuringAssignments(); |
3573 } | 3603 } |
3574 | 3604 |
3575 FunctionLiteralT function_literal = factory()->NewFunctionLiteral( | 3605 FunctionLiteralT function_literal = factory()->NewFunctionLiteral( |
3576 impl()->EmptyIdentifierString(), formal_parameters.scope, body, | 3606 impl()->EmptyIdentifierString(), formal_parameters.scope, body, |
3577 materialized_literal_count, expected_property_count, num_parameters, | 3607 materialized_literal_count, expected_property_count, num_parameters, |
3578 FunctionLiteral::kNoDuplicateParameters, | 3608 FunctionLiteral::kNoDuplicateParameters, |
3579 FunctionLiteral::kAnonymousExpression, | 3609 FunctionLiteral::kAnonymousExpression, eager_compile_hint, arrow_kind, |
3580 FunctionLiteral::kShouldLazyCompile, arrow_kind, | |
3581 formal_parameters.scope->start_position()); | 3610 formal_parameters.scope->start_position()); |
3582 | 3611 |
3583 function_literal->set_function_token_position( | 3612 function_literal->set_function_token_position( |
3584 formal_parameters.scope->start_position()); | 3613 formal_parameters.scope->start_position()); |
| 3614 if (should_be_used_once_hint) { |
| 3615 function_literal->set_should_be_used_once_hint(); |
| 3616 } |
3585 | 3617 |
3586 if (fni_ != NULL) impl()->InferFunctionName(fni_, function_literal); | 3618 if (fni_ != NULL) impl()->InferFunctionName(fni_, function_literal); |
3587 | 3619 |
3588 return function_literal; | 3620 return function_literal; |
3589 } | 3621 } |
3590 | 3622 |
3591 template <typename Impl> | 3623 template <typename Impl> |
3592 typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseTemplateLiteral( | 3624 typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseTemplateLiteral( |
3593 ExpressionT tag, int start, bool* ok) { | 3625 ExpressionT tag, int start, bool* ok) { |
3594 // A TemplateLiteral is made up of 0 or more TEMPLATE_SPAN tokens (literal | 3626 // A TemplateLiteral is made up of 0 or more TEMPLATE_SPAN tokens (literal |
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3726 void ParserBase<Impl>::CheckDestructuringElement(ExpressionT expression, | 3758 void ParserBase<Impl>::CheckDestructuringElement(ExpressionT expression, |
3727 int begin, int end) { | 3759 int begin, int end) { |
3728 if (!IsValidPattern(expression) && !expression->IsAssignment() && | 3760 if (!IsValidPattern(expression) && !expression->IsAssignment() && |
3729 !IsValidReferenceExpression(expression)) { | 3761 !IsValidReferenceExpression(expression)) { |
3730 classifier()->RecordAssignmentPatternError( | 3762 classifier()->RecordAssignmentPatternError( |
3731 Scanner::Location(begin, end), | 3763 Scanner::Location(begin, end), |
3732 MessageTemplate::kInvalidDestructuringTarget); | 3764 MessageTemplate::kInvalidDestructuringTarget); |
3733 } | 3765 } |
3734 } | 3766 } |
3735 | 3767 |
3736 | |
3737 #undef CHECK_OK | 3768 #undef CHECK_OK |
3738 #undef CHECK_OK_CUSTOM | 3769 #undef CHECK_OK_CUSTOM |
3739 | 3770 |
3740 template <typename Impl> | 3771 template <typename Impl> |
3741 void ParserBase<Impl>::ObjectLiteralChecker::CheckProperty( | 3772 void ParserBase<Impl>::ObjectLiteralChecker::CheckProperty( |
3742 Token::Value property, PropertyKind type, MethodKind method_type, | 3773 Token::Value property, PropertyKind type, MethodKind method_type, |
3743 bool* ok) { | 3774 bool* ok) { |
3744 DCHECK(!IsStaticMethod(method_type)); | 3775 DCHECK(!IsStaticMethod(method_type)); |
3745 DCHECK(!IsSpecialMethod(method_type) || | 3776 DCHECK(!IsSpecialMethod(method_type) || |
3746 type == PropertyKind::kMethodProperty); | 3777 type == PropertyKind::kMethodProperty); |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3792 has_seen_constructor_ = true; | 3823 has_seen_constructor_ = true; |
3793 return; | 3824 return; |
3794 } | 3825 } |
3795 } | 3826 } |
3796 | 3827 |
3797 | 3828 |
3798 } // namespace internal | 3829 } // namespace internal |
3799 } // namespace v8 | 3830 } // namespace v8 |
3800 | 3831 |
3801 #endif // V8_PARSING_PARSER_BASE_H | 3832 #endif // V8_PARSING_PARSER_BASE_H |
OLD | NEW |