diff options
author | Michaël Zasso <targos@protonmail.com> | 2019-03-12 09:01:49 +0100 |
---|---|---|
committer | Michaël Zasso <targos@protonmail.com> | 2019-03-14 18:49:21 +0100 |
commit | 7b48713334469818661fe276cf571de9c7899f2d (patch) | |
tree | 4dbda49ac88db76ce09dc330a0cb587e68e139ba /deps/v8/src/parsing/parser-base.h | |
parent | 8549ac09b256666cf5275224ec58fab9939ff32e (diff) | |
download | android-node-v8-7b48713334469818661fe276cf571de9c7899f2d.tar.gz android-node-v8-7b48713334469818661fe276cf571de9c7899f2d.tar.bz2 android-node-v8-7b48713334469818661fe276cf571de9c7899f2d.zip |
deps: update V8 to 7.3.492.25
PR-URL: https://github.com/nodejs/node/pull/25852
Reviewed-By: Ujjwal Sharma <usharma1998@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Ali Ijaz Sheikh <ofrobots@google.com>
Diffstat (limited to 'deps/v8/src/parsing/parser-base.h')
-rw-r--r-- | deps/v8/src/parsing/parser-base.h | 4704 |
1 files changed, 2104 insertions, 2600 deletions
diff --git a/deps/v8/src/parsing/parser-base.h b/deps/v8/src/parsing/parser-base.h index bfb056e0c8..33c165cd92 100644 --- a/deps/v8/src/parsing/parser-base.h +++ b/deps/v8/src/parsing/parser-base.h @@ -18,11 +18,12 @@ #include "src/counters.h" #include "src/globals.h" #include "src/log.h" -#include "src/messages.h" -#include "src/parsing/expression-classifier.h" +#include "src/message-template.h" +#include "src/parsing/expression-scope.h" #include "src/parsing/func-name-inferrer.h" #include "src/parsing/scanner.h" #include "src/parsing/token.h" +#include "src/pointer-with-payload.h" #include "src/zone/zone-chunk-list.h" namespace v8 { @@ -39,6 +40,8 @@ enum AllowLabelledFunctionStatement { kDisallowLabelledFunctionStatement, }; +enum ParsingArrowHeadFlag { kCertainlyNotArrowHead, kMaybeArrowHead }; + enum class ParseFunctionFlag : uint8_t { kIsNormal = 0, kIsGenerator = 1 << 0, @@ -74,77 +77,39 @@ struct FormalParametersBase { // Stack-allocated scope to collect source ranges from the parser. class SourceRangeScope final { public: - enum PositionKind { - POSITION_BEG, - POSITION_END, - PEEK_POSITION_BEG, - PEEK_POSITION_END, - }; - - SourceRangeScope(Scanner* scanner, SourceRange* range, - PositionKind pre_kind = PEEK_POSITION_BEG, - PositionKind post_kind = POSITION_END) - : scanner_(scanner), range_(range), post_kind_(post_kind) { - range_->start = GetPosition(pre_kind); + SourceRangeScope(const Scanner* scanner, SourceRange* range) + : scanner_(scanner), range_(range) { + range_->start = scanner->peek_location().beg_pos; DCHECK_NE(range_->start, kNoSourcePosition); + DCHECK_EQ(range_->end, kNoSourcePosition); } - ~SourceRangeScope() { Finalize(); } - - const SourceRange& Finalize() { - if (is_finalized_) return *range_; - is_finalized_ = true; - range_->end = GetPosition(post_kind_); + ~SourceRangeScope() { + DCHECK_EQ(kNoSourcePosition, range_->end); + range_->end = scanner_->location().end_pos; DCHECK_NE(range_->end, kNoSourcePosition); - return *range_; } private: - int32_t GetPosition(PositionKind kind) { - switch (kind) { - case POSITION_BEG: - return scanner_->location().beg_pos; - case POSITION_END: - return scanner_->location().end_pos; - case PEEK_POSITION_BEG: - return scanner_->peek_location().beg_pos; - case PEEK_POSITION_END: - return scanner_->peek_location().end_pos; - default: - UNREACHABLE(); - } - } - - Scanner* scanner_; + const Scanner* scanner_; SourceRange* range_; - PositionKind post_kind_; - bool is_finalized_ = false; DISALLOW_IMPLICIT_CONSTRUCTORS(SourceRangeScope); }; // ---------------------------------------------------------------------------- -// The CHECK_OK macro is a convenient macro to enforce error -// handling for functions that may fail (by returning !*ok). +// The RETURN_IF_PARSE_ERROR macro is a convenient macro to enforce error +// handling for functions that may fail (by returning if there was an parser +// error). // -// CAUTION: This macro appends extra statements after a call, -// thus it must never be used where only a single statement -// is correct (e.g. an if statement branch w/o braces)! - -#define CHECK_OK_CUSTOM(x, ...) ok); \ - if (!*ok) return impl()->x(__VA_ARGS__); \ - ((void)0 -#define DUMMY ) // to make indentation work -#undef DUMMY - -// Used in functions where the return type is ExpressionT. -#define CHECK_OK CHECK_OK_CUSTOM(NullExpression) +// Usage: +// foo = ParseFoo(); // may fail +// RETURN_IF_PARSE_ERROR +// +// SAFE_USE(foo); -#define CHECK_OK_VOID ok); \ - if (!*ok) return; \ - ((void)0 -#define DUMMY ) // to make indentation work -#undef DUMMY +#define RETURN_IF_PARSE_ERROR \ + if (has_error()) return impl()->NullStatement(); // Common base class template shared between parser and pre-parser. // The Impl parameter is the actual class of the parser/pre-parser, @@ -217,8 +182,10 @@ enum class ParsePropertyKind : uint8_t { kAccessorSetter, kValue, kShorthand, + kAssign, kMethod, kClassField, + kShorthandOrClassField, kSpread, kNotSet }; @@ -228,25 +195,43 @@ class ParserBase { public: // Shorten type names defined by ParserTypes<Impl>. typedef ParserTypes<Impl> Types; - typedef typename Types::Identifier IdentifierT; - typedef typename Types::Expression ExpressionT; - typedef typename Types::FunctionLiteral FunctionLiteralT; - typedef typename Types::ObjectLiteralProperty ObjectLiteralPropertyT; + typedef typename v8::internal::ExpressionScope<Types> ExpressionScope; + typedef typename v8::internal::ExpressionParsingScope<Types> + ExpressionParsingScope; + typedef typename v8::internal::AccumulationScope<Types> AccumulationScope; + typedef typename v8::internal::ArrowHeadParsingScope<Types> + ArrowHeadParsingScope; + typedef typename v8::internal::VariableDeclarationParsingScope<Types> + VariableDeclarationParsingScope; + typedef typename v8::internal::ParameterDeclarationParsingScope<Types> + ParameterDeclarationParsingScope; + + // Return types for traversing functions. + typedef typename Types::Block BlockT; + typedef typename Types::BreakableStatement BreakableStatementT; typedef typename Types::ClassLiteralProperty ClassLiteralPropertyT; - typedef typename Types::Suspend SuspendExpressionT; - typedef typename Types::RewritableExpression RewritableExpressionT; + typedef typename Types::ClassPropertyList ClassPropertyListT; + typedef typename Types::Expression ExpressionT; typedef typename Types::ExpressionList ExpressionListT; typedef typename Types::FormalParameters FormalParametersT; + typedef typename Types::ForStatement ForStatementT; + typedef typename Types::FunctionLiteral FunctionLiteralT; + typedef typename Types::Identifier IdentifierT; + typedef typename Types::IterationStatement IterationStatementT; + typedef typename Types::ObjectLiteralProperty ObjectLiteralPropertyT; + typedef typename Types::ObjectPropertyList ObjectPropertyListT; typedef typename Types::Statement StatementT; typedef typename Types::StatementList StatementListT; - typedef typename Types::Block BlockT; - typedef typename Types::ForStatement ForStatementT; - typedef typename v8::internal::ExpressionClassifier<Types> - ExpressionClassifier; + typedef typename Types::Suspend SuspendExpressionT; + // For constructing objects returned by the traversing functions. + typedef typename Types::Factory FactoryT; + // Other implementation-specific tasks. typedef typename Types::FuncNameInferrer FuncNameInferrer; typedef typename Types::FuncNameInferrer::State FuncNameInferrerState; typedef typename Types::SourceRange SourceRange; typedef typename Types::SourceRangeScope SourceRangeScope; + typedef typename Types::Target TargetT; + typedef typename Types::TargetScope TargetScopeT; // All implementation-specific methods must be called through this. Impl* impl() { return static_cast<Impl*>(this); } @@ -261,7 +246,7 @@ class ParserBase { original_scope_(nullptr), function_state_(nullptr), extension_(extension), - fni_(ast_value_factory, zone), + fni_(ast_value_factory), ast_value_factory_(ast_value_factory), ast_node_factory_(ast_value_factory, zone), runtime_call_stats_(runtime_call_stats), @@ -271,34 +256,38 @@ class ParserBase { stack_limit_(stack_limit), pending_error_handler_(pending_error_handler), zone_(zone), - classifier_(nullptr), + expression_scope_(nullptr), scanner_(scanner), - default_eager_compile_hint_(FunctionLiteral::kShouldLazyCompile), function_literal_id_(0), script_id_(script_id), + default_eager_compile_hint_(FunctionLiteral::kShouldLazyCompile), allow_natives_(false), - allow_harmony_do_expressions_(false), allow_harmony_public_fields_(false), allow_harmony_static_fields_(false), allow_harmony_dynamic_import_(false), allow_harmony_import_meta_(false), allow_harmony_private_fields_(false), - allow_eval_cache_(true) {} + allow_harmony_private_methods_(false), + allow_eval_cache_(true) { + pointer_buffer_.reserve(32); + variable_buffer_.reserve(32); + } #define ALLOW_ACCESSORS(name) \ bool allow_##name() const { return allow_##name##_; } \ void set_allow_##name(bool allow) { allow_##name##_ = allow; } ALLOW_ACCESSORS(natives); - ALLOW_ACCESSORS(harmony_do_expressions); ALLOW_ACCESSORS(harmony_public_fields); ALLOW_ACCESSORS(harmony_static_fields); ALLOW_ACCESSORS(harmony_dynamic_import); ALLOW_ACCESSORS(harmony_import_meta); + ALLOW_ACCESSORS(harmony_private_methods); ALLOW_ACCESSORS(eval_cache); #undef ALLOW_ACCESSORS + V8_INLINE bool has_error() const { return scanner()->has_parser_error(); } bool allow_harmony_numeric_separator() const { return scanner()->allow_harmony_numeric_separator(); } @@ -326,6 +315,10 @@ class ParserBase { return default_eager_compile_hint_; } + int loop_nesting_depth() const { + return function_state_->loop_nesting_depth(); + } + int GetNextFunctionLiteralId() { return ++function_literal_id_; } int GetLastFunctionLiteralId() const { return function_literal_id_; } @@ -340,14 +333,9 @@ class ParserBase { Zone* zone() const { return zone_; } protected: - friend class v8::internal::ExpressionClassifier<ParserTypes<Impl>>; - - enum AllowRestrictedIdentifiers { - kAllowRestrictedIdentifiers, - kDontAllowRestrictedIdentifiers - }; - - enum LazyParsingResult { kLazyParsingComplete, kLazyParsingAborted }; + friend class v8::internal::ExpressionScope<ParserTypes<Impl>>; + friend class v8::internal::ExpressionParsingScope<ParserTypes<Impl>>; + friend class v8::internal::ArrowHeadParsingScope<ParserTypes<Impl>>; enum VariableDeclarationContext { kStatementListItem, @@ -356,7 +344,6 @@ class ParserBase { }; class ClassLiteralChecker; - class ObjectLiteralChecker; // --------------------------------------------------------------------------- // BlockState and FunctionState implement the parser's scope stack. @@ -403,33 +390,6 @@ class ParserBase { FunctionKind kind() const { return scope()->function_kind(); } - void RewindDestructuringAssignments(int pos) { - destructuring_assignments_to_rewrite_.Rewind(pos); - } - - void AdoptDestructuringAssignmentsFromParentState(int pos) { - const auto& outer_assignments = - outer_function_state_->destructuring_assignments_to_rewrite_; - DCHECK_GE(outer_assignments.size(), pos); - auto it = outer_assignments.begin(); - it.Advance(pos); - for (; it != outer_assignments.end(); ++it) { - auto expr = *it; - expr->set_scope(scope_); - destructuring_assignments_to_rewrite_.push_back(expr); - } - outer_function_state_->RewindDestructuringAssignments(pos); - } - - const ZoneChunkList<RewritableExpressionT>& - destructuring_assignments_to_rewrite() const { - return destructuring_assignments_to_rewrite_; - } - - ZoneList<typename ExpressionClassifier::Error>* GetReportedErrorList() { - return &reported_errors_; - } - bool next_function_is_likely_called() const { return next_function_is_likely_called_; } @@ -450,41 +410,50 @@ class ParserBase { class FunctionOrEvalRecordingScope { public: explicit FunctionOrEvalRecordingScope(FunctionState* state) - : state_(state) { - prev_value_ = state->contains_function_or_eval_; + : state_and_prev_value_(state, state->contains_function_or_eval_) { state->contains_function_or_eval_ = false; } ~FunctionOrEvalRecordingScope() { - bool found = state_->contains_function_or_eval_; + bool found = state_and_prev_value_->contains_function_or_eval_; if (!found) { - state_->contains_function_or_eval_ = prev_value_; + state_and_prev_value_->contains_function_or_eval_ = + state_and_prev_value_.GetPayload(); } } private: - FunctionState* state_; - bool prev_value_; + PointerWithPayload<FunctionState, bool, 1> state_and_prev_value_; }; - private: - void AddDestructuringAssignment(RewritableExpressionT expr) { - destructuring_assignments_to_rewrite_.push_back(expr); - } + class LoopScope { + public: + explicit LoopScope(FunctionState* function_state) + : function_state_(function_state) { + function_state_->loop_nesting_depth_++; + } + ~LoopScope() { function_state_->loop_nesting_depth_--; } + + private: + FunctionState* function_state_; + }; + + int loop_nesting_depth() const { return loop_nesting_depth_; } + + private: // Properties count estimation. int expected_property_count_; // How many suspends are needed for this function. int suspend_count_; + // How deeply nested we currently are in this function. + int loop_nesting_depth_ = 0; + FunctionState** function_state_stack_; FunctionState* outer_function_state_; DeclarationScope* scope_; - ZoneChunkList<RewritableExpressionT> destructuring_assignments_to_rewrite_; - - ZoneList<typename ExpressionClassifier::Error> reported_errors_; - // A reason, if any, why this function should not be optimized. BailoutReason dont_optimize_reason_; @@ -503,12 +472,10 @@ class ParserBase { }; struct DeclarationDescriptor { - enum Kind { NORMAL, PARAMETER, FOR_EACH }; - Scope* scope; VariableMode mode; + VariableKind kind; int declaration_pos; int initialization_pos; - Kind declaration_kind; }; struct DeclarationParsingResult { @@ -538,18 +505,12 @@ class ParserBase { struct CatchInfo { public: explicit CatchInfo(ParserBase* parser) - : name(parser->impl()->NullIdentifier()), - pattern(parser->impl()->NullExpression()), - scope(nullptr), - init_block(parser->impl()->NullStatement()), - inner_block(parser->impl()->NullStatement()), - bound_names(1, parser->zone()) {} - IdentifierT name; + : pattern(parser->impl()->NullExpression()), + variable(nullptr), + scope(nullptr) {} ExpressionT pattern; + Variable* variable; Scope* scope; - BlockT init_block; - BlockT inner_block; - ZonePtrList<const AstRawString> bound_names; }; struct ForInfo { @@ -578,29 +539,102 @@ class ParserBase { has_name_static_property(false), has_static_computed_names(false), has_static_class_fields(false), - has_instance_class_fields(false), + has_instance_members(false), is_anonymous(false), static_fields_scope(nullptr), - instance_fields_scope(nullptr), + instance_members_scope(nullptr), computed_field_count(0) {} Variable* variable; ExpressionT extends; - typename Types::ClassPropertyList properties; - typename Types::ClassPropertyList static_fields; - typename Types::ClassPropertyList instance_fields; + ClassPropertyListT properties; + ClassPropertyListT static_fields; + ClassPropertyListT instance_fields; FunctionLiteralT constructor; bool has_seen_constructor; bool has_name_static_property; bool has_static_computed_names; bool has_static_class_fields; - bool has_instance_class_fields; + bool has_instance_members; bool is_anonymous; DeclarationScope* static_fields_scope; - DeclarationScope* instance_fields_scope; + DeclarationScope* instance_members_scope; int computed_field_count; }; + enum class PropertyPosition { kObjectLiteral, kClassLiteral }; + struct ParsePropertyInfo { + public: + explicit ParsePropertyInfo(ParserBase* parser, + AccumulationScope* accumulation_scope = nullptr) + : accumulation_scope(accumulation_scope), + name(parser->impl()->NullIdentifier()), + position(PropertyPosition::kClassLiteral), + function_flags(ParseFunctionFlag::kIsNormal), + kind(ParsePropertyKind::kNotSet), + is_computed_name(false), + is_private(false), + is_static(false), + is_rest(false) {} + + bool ParsePropertyKindFromToken(Token::Value token) { + // This returns true, setting the property kind, iff the given token is + // one which must occur after a property name, indicating that the + // previous token was in fact a name and not a modifier (like the "get" in + // "get x"). + switch (token) { + case Token::COLON: + kind = ParsePropertyKind::kValue; + return true; + case Token::COMMA: + kind = ParsePropertyKind::kShorthand; + return true; + case Token::RBRACE: + kind = ParsePropertyKind::kShorthandOrClassField; + return true; + case Token::ASSIGN: + kind = ParsePropertyKind::kAssign; + return true; + case Token::LPAREN: + kind = ParsePropertyKind::kMethod; + return true; + case Token::MUL: + case Token::SEMICOLON: + kind = ParsePropertyKind::kClassField; + return true; + default: + break; + } + return false; + } + + AccumulationScope* accumulation_scope; + IdentifierT name; + PropertyPosition position; + ParseFunctionFlags function_flags; + ParsePropertyKind kind; + bool is_computed_name; + bool is_private; + bool is_static; + bool is_rest; + }; + + ClassLiteralProperty::Kind ClassPropertyKindFor(ParsePropertyKind kind) { + switch (kind) { + case ParsePropertyKind::kAccessorGetter: + return ClassLiteralProperty::GETTER; + case ParsePropertyKind::kAccessorSetter: + return ClassLiteralProperty::SETTER; + case ParsePropertyKind::kMethod: + return ClassLiteralProperty::METHOD; + case ParsePropertyKind::kClassField: + return ClassLiteralProperty::FIELD; + default: + // Only returns for deterministic kinds + UNREACHABLE(); + } + } + const AstRawString* ClassFieldVariableName(AstValueFactory* ast_value_factory, int index) { std::string name = ".class-field-" + std::to_string(index); @@ -667,6 +701,22 @@ class ParserBase { return scope()->GetClosureScope(); } + VariableProxy* NewRawVariable(const AstRawString* name, int pos) { + return factory()->ast_node_factory()->NewVariableProxy( + name, NORMAL_VARIABLE, pos); + } + + VariableProxy* NewUnresolved(const AstRawString* name) { + return scope()->NewUnresolved(factory()->ast_node_factory(), name, + scanner()->location().beg_pos); + } + + VariableProxy* NewUnresolved(const AstRawString* name, int begin_pos, + VariableKind kind = NORMAL_VARIABLE) { + return scope()->NewUnresolved(factory()->ast_node_factory(), name, + begin_pos, kind); + } + Scanner* scanner() const { return scanner_; } AstValueFactory* ast_value_factory() const { return ast_value_factory_; } int position() const { return scanner_->location().beg_pos; } @@ -676,14 +726,18 @@ class ParserBase { bool stack_overflow() const { return pending_error_handler()->stack_overflow(); } - void set_stack_overflow() { pending_error_handler()->set_stack_overflow(); } + void set_stack_overflow() { + scanner_->set_parser_error(); + pending_error_handler()->set_stack_overflow(); + } + void CheckStackOverflow() { + // Any further calls to Next or peek will return the illegal token. + if (GetCurrentStackPosition() < stack_limit_) set_stack_overflow(); + } int script_id() { return script_id_; } void set_script_id(int id) { script_id_ = id; } - V8_INLINE Token::Value peek() { - if (stack_overflow()) return Token::ILLEGAL; - return scanner()->peek(); - } + V8_INLINE Token::Value peek() { return scanner()->peek(); } // Returns the position past the following semicolon (if it exists), and the // position past the end of the current token otherwise. @@ -691,33 +745,19 @@ class ParserBase { return (peek() == Token::SEMICOLON) ? peek_end_position() : end_position(); } - V8_INLINE Token::Value PeekAhead() { - if (stack_overflow()) return Token::ILLEGAL; - return scanner()->PeekAhead(); - } + V8_INLINE Token::Value PeekAhead() { return scanner()->PeekAhead(); } - V8_INLINE Token::Value Next() { - if (stack_overflow()) return Token::ILLEGAL; - { - if (GetCurrentStackPosition() < stack_limit_) { - // Any further calls to Next or peek will return the illegal token. - // The current call must return the next token, which might already - // have been peek'ed. - set_stack_overflow(); - } - } - return scanner()->Next(); - } + V8_INLINE Token::Value Next() { return scanner()->Next(); } - void Consume(Token::Value token) { - Token::Value next = Next(); + V8_INLINE void Consume(Token::Value token) { + Token::Value next = scanner()->Next(); USE(next); USE(token); - DCHECK_EQ(next, token); + DCHECK_IMPLIES(!has_error(), next == token); } - bool Check(Token::Value token) { - Token::Value next = peek(); + V8_INLINE bool Check(Token::Value token) { + Token::Value next = scanner()->peek(); if (next == token) { Consume(next); return true; @@ -725,28 +765,26 @@ class ParserBase { return false; } - void Expect(Token::Value token, bool* ok) { + void Expect(Token::Value token) { Token::Value next = Next(); - if (next != token) { + if (V8_UNLIKELY(next != token)) { ReportUnexpectedToken(next); - *ok = false; } } - void ExpectSemicolon(bool* ok) { + void ExpectSemicolon() { // Check for automatic semicolon insertion according to // the rules given in ECMA-262, section 7.9, page 21. Token::Value tok = peek(); - if (tok == Token::SEMICOLON) { + if (V8_LIKELY(tok == Token::SEMICOLON)) { Next(); return; } - if (scanner()->HasLineTerminatorBeforeNext() || tok == Token::RBRACE || - tok == Token::EOS) { + if (V8_LIKELY(scanner()->HasLineTerminatorBeforeNext() || + Token::IsAutoSemicolon(tok))) { return; } - *ok = false; if (scanner()->current_token() == Token::AWAIT && !is_async_function()) { ReportMessageAt(scanner()->location(), MessageTemplate::kAwaitNotInAsyncFunction, kSyntaxError); @@ -756,38 +794,28 @@ class ParserBase { ReportUnexpectedToken(Next()); } - // Dummy functions, just useful as arguments to CHECK_OK_CUSTOM. - static void Void() {} - template <typename T> - static T Return(T result) { - return result; - } - bool peek_any_identifier() { return Token::IsAnyIdentifier(peek()); } - bool CheckContextualKeyword(Token::Value token) { - if (PeekContextualKeyword(token)) { + bool PeekContextualKeyword(const AstRawString* name) { + return peek() == Token::IDENTIFIER && + scanner()->NextSymbol(ast_value_factory()) == name; + } + + bool CheckContextualKeyword(const AstRawString* name) { + if (PeekContextualKeyword(name)) { Consume(Token::IDENTIFIER); return true; } return false; } - bool PeekContextualKeyword(Token::Value token) { - DCHECK(Token::IsContextualKeyword(token)); - return peek() == Token::IDENTIFIER && - scanner()->next_contextual_token() == token; - } - - void ExpectMetaProperty(Token::Value property_name, const char* full_name, - int pos, bool* ok); + void ExpectMetaProperty(const AstRawString* property_name, + const char* full_name, int pos); - void ExpectContextualKeyword(Token::Value token, bool* ok) { - DCHECK(Token::IsContextualKeyword(token)); - Expect(Token::IDENTIFIER, CHECK_OK_CUSTOM(Void)); - if (scanner()->current_contextual_token() != token) { + void ExpectContextualKeyword(const AstRawString* name) { + Expect(Token::IDENTIFIER); + if (V8_UNLIKELY(scanner()->CurrentSymbol(ast_value_factory()) != name)) { ReportUnexpectedToken(scanner()->current_token()); - *ok = false; } } @@ -795,7 +823,7 @@ class ParserBase { if (Check(Token::IN)) { *visit_mode = ForEachStatement::ENUMERATE; return true; - } else if (CheckContextualKeyword(Token::OF)) { + } else if (CheckContextualKeyword(ast_value_factory()->of_string())) { *visit_mode = ForEachStatement::ITERATE; return true; } @@ -803,23 +831,23 @@ class ParserBase { } bool PeekInOrOf() { - return peek() == Token::IN || PeekContextualKeyword(Token::OF); + return peek() == Token::IN || + PeekContextualKeyword(ast_value_factory()->of_string()); } // Checks whether an octal literal was last seen between beg_pos and end_pos. // Only called for strict mode strings. - void CheckStrictOctalLiteral(int beg_pos, int end_pos, bool* ok) { + void CheckStrictOctalLiteral(int beg_pos, int end_pos) { Scanner::Location octal = scanner()->octal_position(); if (octal.IsValid() && beg_pos <= octal.beg_pos && octal.end_pos <= end_pos) { - MessageTemplate::Template message = scanner()->octal_message(); + MessageTemplate message = scanner()->octal_message(); DCHECK_NE(message, MessageTemplate::kNone); impl()->ReportMessageAt(octal, message); scanner()->clear_octal_position(); if (message == MessageTemplate::kStrictDecimalWithLeadingZero) { impl()->CountUsage(v8::Isolate::kDecimalWithLeadingZeroInStrictMode); } - *ok = false; } } @@ -827,29 +855,29 @@ class ParserBase { // appears in the current template literal token. In the presence of such, // either returns false or reports an error, depending on should_throw. // Otherwise returns true. - inline bool CheckTemplateEscapes(bool should_throw, bool* ok) { - DCHECK(scanner()->current_token() == Token::TEMPLATE_SPAN || - scanner()->current_token() == Token::TEMPLATE_TAIL); - if (!scanner()->has_invalid_template_escape()) { - return true; - } + inline bool CheckTemplateEscapes(bool should_throw) { + DCHECK(Token::IsTemplate(scanner()->current_token())); + if (!scanner()->has_invalid_template_escape()) return true; // Handle error case(s) if (should_throw) { impl()->ReportMessageAt(scanner()->invalid_template_escape_location(), scanner()->invalid_template_escape_message()); - *ok = false; } - return false; + scanner()->clear_invalid_template_escape_message(); + return should_throw; } - void CheckDestructuringElement(ExpressionT element, int beg_pos, int end_pos); + ExpressionT ParsePossibleDestructuringSubPattern(AccumulationScope* scope); + void ClassifyParameter(IdentifierT parameter, int beg_pos, int end_pos); + void ClassifyArrowParameter(AccumulationScope* accumulation_scope, + int position, ExpressionT parameter); // Checking the name of a function literal. This has to be done after parsing // the function, since the function can declare itself strict. void CheckFunctionName(LanguageMode language_mode, IdentifierT function_name, FunctionNameValidity function_name_validity, - const Scanner::Location& function_name_loc, bool* ok) { + const Scanner::Location& function_name_loc) { if (impl()->IsNull(function_name)) return; if (function_name_validity == kSkipFunctionNameCheck) return; // The function name needs to be checked in strict mode. @@ -858,24 +886,15 @@ class ParserBase { if (impl()->IsEvalOrArguments(function_name)) { impl()->ReportMessageAt(function_name_loc, MessageTemplate::kStrictEvalArguments); - *ok = false; return; } if (function_name_validity == kFunctionNameIsStrictReserved) { impl()->ReportMessageAt(function_name_loc, MessageTemplate::kUnexpectedStrictReserved); - *ok = false; return; } } - // Determine precedence of given token. - static int Precedence(Token::Value token, bool accept_IN) { - if (token == Token::IN && !accept_IN) - return 0; // 0 precedence will terminate binary expression parsing - return Token::Precedence(token); - } - typename Types::Factory* factory() { return &ast_node_factory_; } DeclarationScope* GetReceiverScope() const { @@ -907,405 +926,280 @@ class ParserBase { } // Report syntax errors. - void ReportMessage(MessageTemplate::Template message) { + V8_NOINLINE void ReportMessage(MessageTemplate message) { Scanner::Location source_location = scanner()->location(); impl()->ReportMessageAt(source_location, message, static_cast<const char*>(nullptr), kSyntaxError); } template <typename T> - void ReportMessage(MessageTemplate::Template message, T arg, - ParseErrorType error_type = kSyntaxError) { + V8_NOINLINE void ReportMessage(MessageTemplate message, T arg, + ParseErrorType error_type = kSyntaxError) { Scanner::Location source_location = scanner()->location(); impl()->ReportMessageAt(source_location, message, arg, error_type); } - void ReportMessageAt(Scanner::Location location, - MessageTemplate::Template message, - ParseErrorType error_type) { + V8_NOINLINE void ReportMessageAt(Scanner::Location location, + MessageTemplate message, + ParseErrorType error_type) { impl()->ReportMessageAt(location, message, static_cast<const char*>(nullptr), error_type); } - void GetUnexpectedTokenMessage( - Token::Value token, MessageTemplate::Template* message, - Scanner::Location* location, const char** arg, - MessageTemplate::Template default_ = MessageTemplate::kUnexpectedToken); + V8_NOINLINE void ReportUnexpectedToken(Token::Value token); - void ReportUnexpectedToken(Token::Value token); - void ReportUnexpectedTokenAt( - Scanner::Location location, Token::Value token, - MessageTemplate::Template message = MessageTemplate::kUnexpectedToken); - - void ReportClassifierError( - const typename ExpressionClassifier::Error& error) { - if (classifier()->does_error_reporting()) { - impl()->ReportMessageAt(error.location, error.message, error.arg); - } else { - impl()->ReportUnidentifiableError(); - } + void ValidateFormalParameters(LanguageMode language_mode, + const FormalParametersT& parameters, + bool allow_duplicates) { + if (!allow_duplicates) parameters.ValidateDuplicate(impl()); + if (is_strict(language_mode)) parameters.ValidateStrictMode(impl()); } - void ValidateExpression(bool* ok) { - if (!classifier()->is_valid_expression()) { - ReportClassifierError(classifier()->expression_error()); - *ok = false; - } + V8_INLINE IdentifierT ParseAndClassifyIdentifier(Token::Value token); + // Parses an identifier or a strict mode future reserved word. Allows passing + // in function_kind for the case of parsing the identifier in a function + // expression, where the relevant "function_kind" bit is of the function being + // parsed, not the containing function. + V8_INLINE IdentifierT ParseIdentifier(FunctionKind function_kind); + V8_INLINE IdentifierT ParseIdentifier() { + return ParseIdentifier(function_state_->kind()); } + // Same as above but additionally disallows 'eval' and 'arguments' in strict + // mode. + IdentifierT ParseNonRestrictedIdentifier(); - void ValidateFormalParameterInitializer(bool* ok) { - if (!classifier()->is_valid_formal_parameter_initializer()) { - ReportClassifierError(classifier()->formal_parameter_initializer_error()); - *ok = false; - } - } + V8_INLINE IdentifierT ParsePropertyName(); - void ValidateBindingPattern(bool* ok) { - if (!classifier()->is_valid_binding_pattern()) { - ReportClassifierError(classifier()->binding_pattern_error()); - *ok = false; - } - } + ExpressionT ParsePropertyOrPrivatePropertyName(); - void ValidateAssignmentPattern(bool* ok) { - if (!classifier()->is_valid_assignment_pattern()) { - ReportClassifierError(classifier()->assignment_pattern_error()); - *ok = false; - } - } + ExpressionT ParseRegExpLiteral(); - void ValidateFormalParameters(LanguageMode language_mode, - bool allow_duplicates, bool* ok) { - if (!allow_duplicates && - !classifier()->is_valid_formal_parameter_list_without_duplicates()) { - ReportClassifierError(classifier()->duplicate_formal_parameter_error()); - *ok = false; - } else if (is_strict(language_mode) && - !classifier()->is_valid_strict_mode_formal_parameters()) { - ReportClassifierError(classifier()->strict_mode_formal_parameter_error()); - *ok = false; - } - } - - bool IsValidArrowFormalParametersStart(Token::Value token) { - return Token::IsAnyIdentifier(token) || token == Token::LPAREN; - } - - void ValidateArrowFormalParameters(ExpressionT expr, - bool parenthesized_formals, bool is_async, - bool* ok) { - if (classifier()->is_valid_binding_pattern()) { - // A simple arrow formal parameter: IDENTIFIER => BODY. - if (!impl()->IsIdentifier(expr)) { - impl()->ReportMessageAt(scanner()->location(), - MessageTemplate::kUnexpectedToken, - Token::String(scanner()->current_token())); - *ok = false; - } - } else if (!classifier()->is_valid_arrow_formal_parameters()) { - // If after parsing the expr, we see an error but the expression is - // neither a valid binding pattern nor a valid parenthesized formal - // parameter list, show the "arrow formal parameters" error if the formals - // started with a parenthesis, and the binding pattern error otherwise. - const typename ExpressionClassifier::Error& error = - parenthesized_formals ? classifier()->arrow_formal_parameters_error() - : classifier()->binding_pattern_error(); - ReportClassifierError(error); - *ok = false; - } - if (is_async && !classifier()->is_valid_async_arrow_formal_parameters()) { - const typename ExpressionClassifier::Error& error = - classifier()->async_arrow_formal_parameters_error(); - ReportClassifierError(error); - *ok = false; - } - } - - void ValidateLetPattern(bool* ok) { - if (!classifier()->is_valid_let_pattern()) { - ReportClassifierError(classifier()->let_pattern_error()); - *ok = false; - } - } - - void BindingPatternUnexpectedToken() { - MessageTemplate::Template message = MessageTemplate::kUnexpectedToken; - const char* arg; - Scanner::Location location = scanner()->peek_location(); - GetUnexpectedTokenMessage(peek(), &message, &location, &arg); - classifier()->RecordBindingPatternError(location, message, arg); - } - - void ArrowFormalParametersUnexpectedToken() { - MessageTemplate::Template message = MessageTemplate::kUnexpectedToken; - const char* arg; - Scanner::Location location = scanner()->peek_location(); - GetUnexpectedTokenMessage(peek(), &message, &location, &arg); - classifier()->RecordArrowFormalParametersError(location, message, arg); - } - - // Recursive descent functions. - // All ParseXXX functions take as the last argument an *ok parameter - // which is set to false if parsing failed; it is unchanged otherwise. - // By making the 'exception handling' explicit, we are forced to check - // for failure at the call sites. The family of CHECK_OK* macros can - // be useful for this. - - // Parses an identifier that is valid for the current scope, in particular it - // fails on strict mode future reserved keywords in a strict scope. If - // allow_eval_or_arguments is kAllowEvalOrArguments, we allow "eval" or - // "arguments" as identifier even in strict mode (this is needed in cases like - // "var foo = eval;"). - IdentifierT ParseIdentifier(AllowRestrictedIdentifiers, bool* ok); - IdentifierT ParseAndClassifyIdentifier(bool* ok); - // Parses an identifier or a strict mode future reserved word, and indicate - // whether it is strict mode future reserved. Allows passing in function_kind - // for the case of parsing the identifier in a function expression, where the - // relevant "function_kind" bit is of the function being parsed, not the - // containing function. - IdentifierT ParseIdentifierOrStrictReservedWord(FunctionKind function_kind, - bool* is_strict_reserved, - bool* is_await, bool* ok); - IdentifierT ParseIdentifierOrStrictReservedWord(bool* is_strict_reserved, - bool* is_await, bool* ok) { - return ParseIdentifierOrStrictReservedWord( - function_state_->kind(), is_strict_reserved, is_await, ok); - } - - V8_INLINE IdentifierT ParseIdentifierName(bool* ok); - - ExpressionT ParseIdentifierNameOrPrivateName(bool* ok); - - ExpressionT ParseRegExpLiteral(bool* ok); - - ExpressionT ParseBindingPattern(bool* ok); - ExpressionT ParsePrimaryExpression(bool* is_async, bool* ok); - - // Use when parsing an expression that is known to not be a pattern or part - // of a pattern. - V8_INLINE ExpressionT ParseExpression(bool* ok); - - // This method does not wrap the parsing of the expression inside a - // new expression classifier; it uses the top-level classifier instead. - // It should be used whenever we're parsing something with the "cover" - // grammar that recognizes both patterns and non-patterns (which roughly - // corresponds to what's inside the parentheses generated by the symbol + ExpressionT ParseBindingPattern(); + ExpressionT ParsePrimaryExpression(); + + // Use when parsing an expression that is known to not be a pattern or part of + // a pattern. + V8_INLINE ExpressionT ParseExpression(); + V8_INLINE ExpressionT ParseAssignmentExpression(); + + // These methods do not wrap the parsing of the expression inside a new + // expression_scope; they use the outer expression_scope instead. They should + // be used whenever we're parsing something with the "cover" grammar that + // recognizes both patterns and non-patterns (which roughly corresponds to + // what's inside the parentheses generated by the symbol // "CoverParenthesizedExpressionAndArrowParameterList" in the ES 2017 // specification). - ExpressionT ParseExpressionCoverGrammar(bool accept_IN, bool* ok); + ExpressionT ParseExpressionCoverGrammar(); + ExpressionT ParseAssignmentExpressionCoverGrammar(); + + ExpressionT ParseArrowParametersWithRest(ExpressionListT* list, + AccumulationScope* scope); - ExpressionT ParseArrayLiteral(bool* ok); + ExpressionT ParseArrayLiteral(); inline static bool IsAccessor(ParsePropertyKind kind) { return IsInRange(kind, ParsePropertyKind::kAccessorGetter, ParsePropertyKind::kAccessorSetter); } - ExpressionT ParsePropertyName(IdentifierT* name, ParsePropertyKind* kind, - ParseFunctionFlags* flags, - bool* is_computed_name, bool* ok); - ExpressionT ParseObjectLiteral(bool* ok); + ExpressionT ParseProperty(ParsePropertyInfo* prop_info); + ExpressionT ParseObjectLiteral(); ClassLiteralPropertyT ParseClassPropertyDefinition( - ClassLiteralChecker* checker, ClassInfo* class_info, - IdentifierT* property_name, bool has_extends, bool* is_computed_name, - ClassLiteralProperty::Kind* property_kind, bool* is_static, bool* ok); - ExpressionT ParseClassFieldInitializer(ClassInfo* class_info, int beg_pos, - bool is_static, bool* ok); + ClassInfo* class_info, ParsePropertyInfo* prop_info, bool has_extends); + void CheckClassFieldName(IdentifierT name, bool is_static); + void CheckClassMethodName(IdentifierT name, ParsePropertyKind type, + ParseFunctionFlags flags, bool is_static, + bool* has_seen_constructor); + ExpressionT ParseMemberInitializer(ClassInfo* class_info, int beg_pos, + bool is_static); ObjectLiteralPropertyT ParseObjectPropertyDefinition( - ObjectLiteralChecker* checker, bool* is_computed_name, - bool* is_rest_property, bool* ok); - ExpressionListT ParseArguments(Scanner::Location* first_spread_pos, - bool maybe_arrow, - bool* is_simple_parameter_list, bool* ok); - ExpressionListT ParseArguments(Scanner::Location* first_spread_pos, - bool* ok) { - bool is_simple = true; - return ParseArguments(first_spread_pos, false, &is_simple, ok); - } - - ExpressionT ParseAssignmentExpression(bool accept_IN, bool* ok); - ExpressionT ParseYieldExpression(bool accept_IN, bool* ok); - V8_INLINE ExpressionT ParseConditionalExpression(bool accept_IN, bool* ok); - ExpressionT ParseConditionalContinuation(ExpressionT expression, - bool accept_IN, int pos, bool* ok); - ExpressionT ParseBinaryExpression(int prec, bool accept_IN, bool* ok); - ExpressionT ParseUnaryOpExpression(bool* ok); - ExpressionT ParseAwaitExpression(bool* ok); - ExpressionT ParsePrefixExpression(bool* ok); - V8_INLINE ExpressionT ParseUnaryExpression(bool* ok); - V8_INLINE ExpressionT ParsePostfixExpression(bool* ok); - V8_INLINE ExpressionT ParseLeftHandSideExpression(bool* ok); - ExpressionT ParseMemberWithPresentNewPrefixesExpression(bool* is_async, - bool* ok); - V8_INLINE ExpressionT ParseMemberWithNewPrefixesExpression(bool* is_async, - bool* ok); - V8_INLINE ExpressionT ParseMemberExpression(bool* is_async, bool* ok); - V8_INLINE ExpressionT ParseMemberExpressionContinuation( - ExpressionT expression, bool* is_async, bool* ok); - - // `rewritable_length`: length of the destructuring_assignments_to_rewrite() - // queue in the parent function state, prior to parsing of formal parameters. - // If the arrow function is lazy, any items added during formal parameter - // parsing are removed from the queue. - ExpressionT ParseArrowFunctionLiteral(bool accept_IN, - const FormalParametersT& parameters, - int rewritable_length, bool* ok); - void ParseAsyncFunctionBody(Scope* scope, StatementListT body, bool* ok); - ExpressionT ParseAsyncFunctionLiteral(bool* ok); + ParsePropertyInfo* prop_info, bool* has_seen_proto); + void ParseArguments( + ExpressionListT* args, bool* has_spread, + ParsingArrowHeadFlag maybe_arrow = kCertainlyNotArrowHead); + + ExpressionT ParseYieldExpression(); + V8_INLINE ExpressionT ParseConditionalExpression(); + ExpressionT ParseConditionalContinuation(ExpressionT expression, int pos); + ExpressionT ParseBinaryContinuation(ExpressionT x, int prec, int prec1); + V8_INLINE ExpressionT ParseBinaryExpression(int prec); + ExpressionT ParseUnaryOrPrefixExpression(); + ExpressionT ParseAwaitExpression(); + V8_INLINE ExpressionT ParseUnaryExpression(); + V8_INLINE ExpressionT ParsePostfixExpression(); + V8_INLINE ExpressionT ParseLeftHandSideExpression(); + ExpressionT ParseLeftHandSideContinuation(ExpressionT expression); + ExpressionT ParseMemberWithPresentNewPrefixesExpression(); + V8_INLINE ExpressionT ParseMemberWithNewPrefixesExpression(); + ExpressionT ParseFunctionExpression(); + V8_INLINE ExpressionT ParseMemberExpression(); + V8_INLINE ExpressionT + ParseMemberExpressionContinuation(ExpressionT expression) { + if (!Token::IsMember(peek())) return expression; + return DoParseMemberExpressionContinuation(expression); + } + ExpressionT DoParseMemberExpressionContinuation(ExpressionT expression); + + ExpressionT ParseArrowFunctionLiteral(const FormalParametersT& parameters); + void ParseAsyncFunctionBody(Scope* scope, StatementListT* body); + ExpressionT ParseAsyncFunctionLiteral(); ExpressionT ParseClassLiteral(IdentifierT name, Scanner::Location class_name_location, bool name_is_strict_reserved, - int class_token_pos, bool* ok); - ExpressionT ParseTemplateLiteral(ExpressionT tag, int start, bool tagged, - bool* ok); - ExpressionT ParseSuperExpression(bool is_new, bool* ok); - ExpressionT ParseImportExpressions(bool* ok); - ExpressionT ParseNewTargetExpression(bool* ok); - - V8_INLINE void ParseFormalParameter(FormalParametersT* parameters, bool* ok); - void ParseFormalParameterList(FormalParametersT* parameters, bool* ok); + int class_token_pos); + ExpressionT ParseTemplateLiteral(ExpressionT tag, int start, bool tagged); + ExpressionT ParseSuperExpression(bool is_new); + ExpressionT ParseImportExpressions(); + ExpressionT ParseNewTargetExpression(); + + V8_INLINE void ParseFormalParameter(FormalParametersT* parameters); + void ParseFormalParameterList(FormalParametersT* parameters); void CheckArityRestrictions(int param_count, FunctionKind function_type, bool has_rest, int formals_start_pos, - int formals_end_pos, bool* ok); + int formals_end_pos); - BlockT ParseVariableDeclarations(VariableDeclarationContext var_context, - DeclarationParsingResult* parsing_result, - ZonePtrList<const AstRawString>* names, - bool* ok); + void ParseVariableDeclarations(VariableDeclarationContext var_context, + DeclarationParsingResult* parsing_result, + ZonePtrList<const AstRawString>* names); StatementT ParseAsyncFunctionDeclaration( - ZonePtrList<const AstRawString>* names, bool default_export, bool* ok); - StatementT ParseFunctionDeclaration(bool* ok); + ZonePtrList<const AstRawString>* names, bool default_export); + StatementT ParseFunctionDeclaration(); StatementT ParseHoistableDeclaration(ZonePtrList<const AstRawString>* names, - bool default_export, bool* ok); + bool default_export); StatementT ParseHoistableDeclaration(int pos, ParseFunctionFlags flags, ZonePtrList<const AstRawString>* names, - bool default_export, bool* ok); + bool default_export); StatementT ParseClassDeclaration(ZonePtrList<const AstRawString>* names, - bool default_export, bool* ok); - StatementT ParseNativeDeclaration(bool* ok); + bool default_export); + StatementT ParseNativeDeclaration(); // Whether we're parsing a single-expression arrow function or something else. enum class FunctionBodyType { kExpression, kBlock }; // Consumes the ending }. - void ParseFunctionBody(StatementListT result, IdentifierT function_name, + void ParseFunctionBody(StatementListT* body, IdentifierT function_name, int pos, const FormalParametersT& parameters, FunctionKind kind, FunctionLiteral::FunctionType function_type, - FunctionBodyType body_type, bool accept_IN, bool* ok); - - // Under some circumstances, we allow preparsing to abort if the preparsed - // function is "long and trivial", and fully parse instead. Our current - // definition of "long and trivial" is: - // - over kLazyParseTrialLimit statements - // - all starting with an identifier (i.e., no if, for, while, etc.) - static const int kLazyParseTrialLimit = 200; + FunctionBodyType body_type); // TODO(nikolaos, marja): The first argument should not really be passed // by value. The method is expected to add the parsed statements to the // list. This works because in the case of the parser, StatementListT is // a pointer whereas the preparser does not really modify the body. - V8_INLINE void ParseStatementList(StatementListT body, Token::Value end_token, - bool* ok) { - LazyParsingResult result = ParseStatementList(body, end_token, false, ok); - USE(result); - DCHECK_EQ(result, kLazyParsingComplete); - } - V8_INLINE LazyParsingResult ParseStatementList(StatementListT body, - Token::Value end_token, - bool may_abort, bool* ok); - StatementT ParseStatementListItem(bool* ok); + V8_INLINE void ParseStatementList(StatementListT* body, + Token::Value end_token); + StatementT ParseStatementListItem(); StatementT ParseStatement(ZonePtrList<const AstRawString>* labels, - ZonePtrList<const AstRawString>* own_labels, - bool* ok) { + ZonePtrList<const AstRawString>* own_labels) { return ParseStatement(labels, own_labels, - kDisallowLabelledFunctionStatement, ok); + kDisallowLabelledFunctionStatement); } StatementT ParseStatement(ZonePtrList<const AstRawString>* labels, ZonePtrList<const AstRawString>* own_labels, - AllowLabelledFunctionStatement allow_function, - bool* ok); - BlockT ParseBlock(ZonePtrList<const AstRawString>* labels, bool* ok); + AllowLabelledFunctionStatement allow_function); + BlockT ParseBlock(ZonePtrList<const AstRawString>* labels); // Parse a SubStatement in strict mode, or with an extra block scope in // sloppy mode to handle // ES#sec-functiondeclarations-in-ifstatement-statement-clauses - StatementT ParseScopedStatement(ZonePtrList<const AstRawString>* labels, - bool* ok); + StatementT ParseScopedStatement(ZonePtrList<const AstRawString>* labels); StatementT ParseVariableStatement(VariableDeclarationContext var_context, - ZonePtrList<const AstRawString>* names, - bool* ok); + ZonePtrList<const AstRawString>* names); // Magical syntax support. - ExpressionT ParseV8Intrinsic(bool* ok); + ExpressionT ParseV8Intrinsic(); - ExpressionT ParseDoExpression(bool* ok); - - StatementT ParseDebuggerStatement(bool* ok); + StatementT ParseDebuggerStatement(); StatementT ParseExpressionOrLabelledStatement( ZonePtrList<const AstRawString>* labels, ZonePtrList<const AstRawString>* own_labels, - AllowLabelledFunctionStatement allow_function, bool* ok); - StatementT ParseIfStatement(ZonePtrList<const AstRawString>* labels, - bool* ok); - StatementT ParseContinueStatement(bool* ok); - StatementT ParseBreakStatement(ZonePtrList<const AstRawString>* labels, - bool* ok); - StatementT ParseReturnStatement(bool* ok); - StatementT ParseWithStatement(ZonePtrList<const AstRawString>* labels, - bool* ok); + AllowLabelledFunctionStatement allow_function); + StatementT ParseIfStatement(ZonePtrList<const AstRawString>* labels); + StatementT ParseContinueStatement(); + StatementT ParseBreakStatement(ZonePtrList<const AstRawString>* labels); + StatementT ParseReturnStatement(); + StatementT ParseWithStatement(ZonePtrList<const AstRawString>* labels); StatementT ParseDoWhileStatement(ZonePtrList<const AstRawString>* labels, - ZonePtrList<const AstRawString>* own_labels, - bool* ok); + ZonePtrList<const AstRawString>* own_labels); StatementT ParseWhileStatement(ZonePtrList<const AstRawString>* labels, - ZonePtrList<const AstRawString>* own_labels, - bool* ok); - StatementT ParseThrowStatement(bool* ok); - StatementT ParseSwitchStatement(ZonePtrList<const AstRawString>* labels, - bool* ok); - V8_INLINE StatementT ParseTryStatement(bool* ok); + ZonePtrList<const AstRawString>* own_labels); + StatementT ParseThrowStatement(); + StatementT ParseSwitchStatement(ZonePtrList<const AstRawString>* labels); + V8_INLINE StatementT ParseTryStatement(); StatementT ParseForStatement(ZonePtrList<const AstRawString>* labels, - ZonePtrList<const AstRawString>* own_labels, - bool* ok); + ZonePtrList<const AstRawString>* own_labels); StatementT ParseForEachStatementWithDeclarations( int stmt_pos, ForInfo* for_info, ZonePtrList<const AstRawString>* labels, - ZonePtrList<const AstRawString>* own_labels, Scope* inner_block_scope, - bool* ok); + ZonePtrList<const AstRawString>* own_labels, Scope* inner_block_scope); StatementT ParseForEachStatementWithoutDeclarations( int stmt_pos, ExpressionT expression, int lhs_beg_pos, int lhs_end_pos, ForInfo* for_info, ZonePtrList<const AstRawString>* labels, - ZonePtrList<const AstRawString>* own_labels, bool* ok); + ZonePtrList<const AstRawString>* own_labels); // Parse a C-style for loop: 'for (<init>; <cond>; <next>) { ... }' // "for (<init>;" is assumed to have been parser already. ForStatementT ParseStandardForLoop( int stmt_pos, ZonePtrList<const AstRawString>* labels, ZonePtrList<const AstRawString>* own_labels, ExpressionT* cond, - StatementT* next, StatementT* body, bool* ok); + StatementT* next, StatementT* body); // Same as the above, but handles those cases where <init> is a // lexical variable declaration. StatementT ParseStandardForLoopWithLexicalDeclarations( int stmt_pos, StatementT init, ForInfo* for_info, ZonePtrList<const AstRawString>* labels, - ZonePtrList<const AstRawString>* own_labels, bool* ok); - StatementT ParseForAwaitStatement(ZonePtrList<const AstRawString>* labels, - ZonePtrList<const AstRawString>* own_labels, - bool* ok); + ZonePtrList<const AstRawString>* own_labels); + StatementT ParseForAwaitStatement( + ZonePtrList<const AstRawString>* labels, + ZonePtrList<const AstRawString>* own_labels); + + V8_INLINE bool IsLet(const AstRawString* identifier) const { + return identifier == ast_value_factory()->let_string(); + } + + void DesugarBindingInForEachStatement(ForInfo* for_info, BlockT* body_block, + ExpressionT* each_variable) { + // Annex B.3.5 prohibits the form + // `try {} catch(e) { for (var e of {}); }` + // So if we are parsing a statement like `for (var ... of ...)` + // we need to walk up the scope chain and look for catch scopes + // which have a simple binding, then compare their binding against + // all of the names declared in the init of the for-of we're + // parsing. + bool is_for_var_of = + for_info->mode == ForEachStatement::ITERATE && + for_info->parsing_result.descriptor.mode == VariableMode::kVar; + + if (is_for_var_of) { + Scope* scope = this->scope(); + while (scope != nullptr && !scope->is_declaration_scope()) { + if (scope->is_catch_scope()) { + auto name = scope->catch_variable()->raw_name(); + // If it's a simple binding and the name is declared in the for loop. + if (name != ast_value_factory()->dot_catch_string() && + for_info->bound_names.Contains(name)) { + impl()->ReportMessageAt(for_info->parsing_result.bindings_loc, + MessageTemplate::kVarRedeclaration, name); + } + } + scope = scope->outer_scope(); + } + } + + impl()->DesugarBindingInForEachStatement(for_info, body_block, + each_variable); + } bool IsNextLetKeyword(); - bool IsTrivialExpression(); // Checks if the expression is a valid reference expression (e.g., on the // left-hand side of assignments). Although ruled out by ECMA as early errors, // we allow calls for web compatibility and rewrite them to a runtime throw. - ExpressionT CheckAndRewriteReferenceExpression( - ExpressionT expression, int beg_pos, int end_pos, - MessageTemplate::Template message, bool* ok); - ExpressionT CheckAndRewriteReferenceExpression( - ExpressionT expression, int beg_pos, int end_pos, - MessageTemplate::Template message, ParseErrorType type, bool* ok); + ExpressionT RewriteInvalidReferenceExpression( + ExpressionT expression, int beg_pos, int end_pos, MessageTemplate message, + ParseErrorType type = kReferenceError); bool IsValidReferenceExpression(ExpressionT expression); @@ -1318,33 +1212,6 @@ class ParserBase { return true; } - bool IsValidPattern(ExpressionT expression) { - return expression->IsObjectLiteral() || expression->IsArrayLiteral(); - } - - // Due to hoisting, the value of a 'var'-declared variable may actually change - // even if the code contains only the "initial" assignment, namely when that - // assignment occurs inside a loop. For example: - // - // let i = 10; - // do { var x = i } while (i--): - // - // As a simple and very conservative approximation of this, we explicitly mark - // as maybe-assigned any non-lexical variable whose initializing "declaration" - // does not syntactically occur in the function scope. (In the example above, - // it occurs in a block scope.) - // - // Note that non-lexical variables include temporaries, which may also get - // assigned inside a loop due to the various rewritings that the parser - // performs. - // - // This also handles marking of loop variables in for-in and for-of loops, - // as determined by declaration_kind. - // - static void MarkLoopVariableAsAssigned( - Scope* scope, Variable* var, - typename DeclarationDescriptor::Kind declaration_kind); - FunctionKind FunctionKindForImpl(bool is_method, ParseFunctionFlags flags) { static const FunctionKind kFunctionKinds[][2][2] = { { @@ -1422,106 +1289,64 @@ class ParserBase { return factory()->NewReturnStatement(expr, pos, end_pos); } - // Validation per ES6 object literals. - class ObjectLiteralChecker { - public: - explicit ObjectLiteralChecker(ParserBase* parser) - : parser_(parser), has_seen_proto_(false) {} + ModuleDescriptor* module() const { + return scope()->AsModuleScope()->module(); + } + Scope* scope() const { return scope_; } - void CheckDuplicateProto(Token::Value property); + // Stack of expression expression_scopes. + // The top of the stack is always pointed to by expression_scope(). + V8_INLINE ExpressionScope* expression_scope() const { + DCHECK_NOT_NULL(expression_scope_); + return expression_scope_; + } - private: - bool IsProto() const { - return this->scanner()->CurrentMatchesContextualEscaped( - Token::PROTO_UNDERSCORED); + class AcceptINScope final { + public: + AcceptINScope(ParserBase* parser, bool accept_IN) + : parser_(parser), previous_accept_IN_(parser->accept_IN_) { + parser_->accept_IN_ = accept_IN; } - ParserBase* parser() const { return parser_; } - Scanner* scanner() const { return parser_->scanner(); } + ~AcceptINScope() { parser_->accept_IN_ = previous_accept_IN_; } + private: ParserBase* parser_; - bool has_seen_proto_; + bool previous_accept_IN_; }; - // Validation per ES6 class literals. - class ClassLiteralChecker { + class ParameterParsingScope { public: - explicit ClassLiteralChecker(ParserBase* parser) - : parser_(parser), has_seen_constructor_(false) {} - - void CheckClassMethodName(Token::Value property, ParsePropertyKind type, - ParseFunctionFlags flags, bool is_static, - bool* ok); - void CheckClassFieldName(bool is_static, bool* ok); - - private: - bool IsConstructor() { - return this->scanner()->CurrentMatchesContextualEscaped( - Token::CONSTRUCTOR); - } - bool IsPrivateConstructor() { - return this->scanner()->CurrentMatchesContextualEscaped( - Token::PRIVATE_CONSTRUCTOR); - } - bool IsPrototype() { - return this->scanner()->CurrentMatchesContextualEscaped(Token::PROTOTYPE); + ParameterParsingScope(Impl* parser, FormalParametersT* parameters) + : parser_(parser), parent_parameters_(parser_->parameters_) { + parser_->parameters_ = parameters; } - ParserBase* parser() const { return parser_; } - Scanner* scanner() const { return parser_->scanner(); } + ~ParameterParsingScope() { parser_->parameters_ = parent_parameters_; } - ParserBase* parser_; - bool has_seen_constructor_; + private: + Impl* parser_; + FormalParametersT* parent_parameters_; }; - ModuleDescriptor* module() const { - return scope()->AsModuleScope()->module(); - } - Scope* scope() const { return scope_; } - - // Stack of expression classifiers. - // The top of the stack is always pointed to by classifier(). - V8_INLINE ExpressionClassifier* classifier() const { - DCHECK_NOT_NULL(classifier_); - return classifier_; - } - - // Accumulates the classifier that is on top of the stack (inner) to - // the one that is right below (outer) and pops the inner. - V8_INLINE void Accumulate(unsigned productions) { - DCHECK_NOT_NULL(classifier_); - ExpressionClassifier* previous = classifier_->previous(); - DCHECK_NOT_NULL(previous); - previous->Accumulate(classifier_, productions); - classifier_ = previous; - } + class FunctionBodyParsingScope { + public: + explicit FunctionBodyParsingScope(Impl* parser) + : parser_(parser), expression_scope_(parser_->expression_scope_) { + parser_->expression_scope_ = nullptr; + } - V8_INLINE void AccumulateNonBindingPatternErrors() { - this->Accumulate(ExpressionClassifier::AllProductions & - ~(ExpressionClassifier::BindingPatternProduction | - ExpressionClassifier::LetPatternProduction)); - } + ~FunctionBodyParsingScope() { + parser_->expression_scope_ = expression_scope_; + } - // Pops and discards the classifier that is on top of the stack - // without accumulating. - V8_INLINE void DiscardExpressionClassifier() { - DCHECK_NOT_NULL(classifier_); - classifier_->Discard(); - classifier_ = classifier_->previous(); - } + private: + Impl* parser_; + ExpressionScope* expression_scope_; + }; - // Accumulate errors that can be arbitrarily deep in an expression. - // These correspond to the ECMAScript spec's 'Contains' operation - // on productions. This includes: - // - // - YieldExpression is disallowed in arrow parameters in a generator. - // - AwaitExpression is disallowed in arrow parameters in an async function. - // - AwaitExpression is disallowed in async arrow parameters. - // - V8_INLINE void AccumulateFormalParameterContainmentErrors() { - Accumulate(ExpressionClassifier::FormalParameterInitializerProduction | - ExpressionClassifier::AsyncArrowFormalParametersProduction); - } + std::vector<void*>* pointer_buffer() { return &pointer_buffer_; } + std::vector<void*>* variable_buffer() { return &variable_buffer_; } // Parser base's protected field members. @@ -1543,22 +1368,60 @@ class ParserBase { private: Zone* zone_; - ExpressionClassifier* classifier_; + ExpressionScope* expression_scope_; - Scanner* scanner_; + std::vector<void*> pointer_buffer_; + std::vector<void*> variable_buffer_; - FunctionLiteral::EagerCompileHint default_eager_compile_hint_; + Scanner* scanner_; int function_literal_id_; int script_id_; + FunctionLiteral::EagerCompileHint default_eager_compile_hint_; + + // This struct is used to move information about the next arrow function from + // the place where the arrow head was parsed to where the body will be parsed. + // Nothing can be parsed between the head and the body, so it will be consumed + // immediately after it's produced. + // Preallocating the struct as part of the parser minimizes the cost of + // supporting arrow functions on non-arrow expressions. + struct NextArrowFunctionInfo { + Scanner::Location strict_parameter_error_location = + Scanner::Location::invalid(); + MessageTemplate strict_parameter_error_message = MessageTemplate::kNone; + DeclarationScope* scope = nullptr; + + bool HasInitialState() const { return scope == nullptr; } + + void Reset() { + scope = nullptr; + ClearStrictParameterError(); + DCHECK(HasInitialState()); + } + + // Tracks strict-mode parameter violations of sloppy-mode arrow heads in + // case the function ends up becoming strict mode. Only one global place to + // track this is necessary since arrow functions with none-simple parameters + // cannot become strict-mode later on. + void ClearStrictParameterError() { + strict_parameter_error_location = Scanner::Location::invalid(); + strict_parameter_error_message = MessageTemplate::kNone; + } + }; + + FormalParametersT* parameters_; + NextArrowFunctionInfo next_arrow_function_info_; + + bool accept_IN_ = true; + bool allow_natives_; - bool allow_harmony_do_expressions_; bool allow_harmony_public_fields_; bool allow_harmony_static_fields_; bool allow_harmony_dynamic_import_; bool allow_harmony_import_meta_; bool allow_harmony_private_fields_; + bool allow_harmony_private_methods_; bool allow_eval_cache_; }; @@ -1572,8 +1435,6 @@ ParserBase<Impl>::FunctionState::FunctionState( function_state_stack_(function_state_stack), outer_function_state_(*function_state_stack), scope_(scope), - destructuring_assignments_to_rewrite_(scope->zone()), - reported_errors_(16, scope->zone()), dont_optimize_reason_(BailoutReason::kNoReason), next_function_is_likely_called_(false), previous_function_was_likely_called_(false), @@ -1592,218 +1453,109 @@ ParserBase<Impl>::FunctionState::~FunctionState() { } template <typename Impl> -void ParserBase<Impl>::GetUnexpectedTokenMessage( - Token::Value token, MessageTemplate::Template* message, - Scanner::Location* location, const char** arg, - MessageTemplate::Template default_) { - *arg = nullptr; - switch (token) { - case Token::EOS: - *message = MessageTemplate::kUnexpectedEOS; - break; - case Token::SMI: - case Token::NUMBER: - case Token::BIGINT: - *message = MessageTemplate::kUnexpectedTokenNumber; - break; - case Token::STRING: - *message = MessageTemplate::kUnexpectedTokenString; - break; - case Token::PRIVATE_NAME: - case Token::IDENTIFIER: - *message = MessageTemplate::kUnexpectedTokenIdentifier; - break; - case Token::AWAIT: - case Token::ENUM: - *message = MessageTemplate::kUnexpectedReserved; - break; - case Token::LET: - case Token::STATIC: - case Token::YIELD: - case Token::FUTURE_STRICT_RESERVED_WORD: - *message = is_strict(language_mode()) - ? MessageTemplate::kUnexpectedStrictReserved - : MessageTemplate::kUnexpectedTokenIdentifier; - break; - case Token::TEMPLATE_SPAN: - case Token::TEMPLATE_TAIL: - *message = MessageTemplate::kUnexpectedTemplateString; - break; - case Token::ESCAPED_STRICT_RESERVED_WORD: - case Token::ESCAPED_KEYWORD: - *message = MessageTemplate::kInvalidEscapedReservedWord; - break; - case Token::ILLEGAL: - if (scanner()->has_error()) { - *message = scanner()->error(); - *location = scanner()->error_location(); - } else { - *message = MessageTemplate::kInvalidOrUnexpectedToken; - } - break; - case Token::REGEXP_LITERAL: - *message = MessageTemplate::kUnexpectedTokenRegExp; - break; - default: - const char* name = Token::String(token); - DCHECK_NOT_NULL(name); - *arg = name; - break; - } -} - -template <typename Impl> void ParserBase<Impl>::ReportUnexpectedToken(Token::Value token) { - return ReportUnexpectedTokenAt(scanner_->location(), token); -} - -template <typename Impl> -void ParserBase<Impl>::ReportUnexpectedTokenAt( - Scanner::Location source_location, Token::Value token, - MessageTemplate::Template message) { - const char* arg; - GetUnexpectedTokenMessage(token, &message, &source_location, &arg); - impl()->ReportMessageAt(source_location, message, arg); -} - -template <typename Impl> -typename ParserBase<Impl>::IdentifierT ParserBase<Impl>::ParseIdentifier( - AllowRestrictedIdentifiers allow_restricted_identifiers, bool* ok) { - ExpressionClassifier classifier(this); - auto result = ParseAndClassifyIdentifier(CHECK_OK_CUSTOM(NullIdentifier)); - - if (allow_restricted_identifiers == kDontAllowRestrictedIdentifiers) { - ValidateAssignmentPattern(CHECK_OK_CUSTOM(NullIdentifier)); - ValidateBindingPattern(CHECK_OK_CUSTOM(NullIdentifier)); - } - - return result; + return impl()->ReportUnexpectedTokenAt(scanner_->location(), token); } template <typename Impl> typename ParserBase<Impl>::IdentifierT -ParserBase<Impl>::ParseAndClassifyIdentifier(bool* ok) { - Token::Value next = Next(); +ParserBase<Impl>::ParseAndClassifyIdentifier(Token::Value next) { + DCHECK_EQ(scanner()->current_token(), next); STATIC_ASSERT(Token::IDENTIFIER + 1 == Token::ASYNC); - if (IsInRange(next, Token::IDENTIFIER, Token::ASYNC)) { + if (V8_LIKELY(IsInRange(next, Token::IDENTIFIER, Token::ASYNC))) { IdentifierT name = impl()->GetSymbol(); - - // When this function is used to read a formal parameter, we don't always - // know whether the function is going to be strict or sloppy. Indeed for - // arrow functions we don't always know that the identifier we are reading - // is actually a formal parameter. Therefore besides the errors that we - // must detect because we know we're in strict mode, we also record any - // error that we might make in the future once we know the language mode. - if (impl()->IsEvalOrArguments(name)) { - if (impl()->IsArguments(name) && scope()->ShouldBanArguments()) { - ReportMessage(MessageTemplate::kArgumentsDisallowedInInitializer); - *ok = false; - return impl()->NullIdentifier(); - } - - classifier()->RecordStrictModeFormalParameterError( - scanner()->location(), MessageTemplate::kStrictEvalArguments); - if (is_strict(language_mode())) { - classifier()->RecordBindingPatternError( - scanner()->location(), MessageTemplate::kStrictEvalArguments); - } + if (V8_UNLIKELY(impl()->IsArguments(name) && + scope()->ShouldBanArguments())) { + ReportMessage(MessageTemplate::kArgumentsDisallowedInInitializer); + return impl()->EmptyIdentifierString(); } + return name; + } - if (classifier()->duplicate_finder() != nullptr && - scanner()->IsDuplicateSymbol(classifier()->duplicate_finder(), - ast_value_factory())) { - classifier()->RecordDuplicateFormalParameterError(scanner()->location()); - } + if (!Token::IsValidIdentifier(next, language_mode(), is_generator(), + parsing_module_ || is_async_function())) { + ReportUnexpectedToken(next); + return impl()->EmptyIdentifierString(); + } - return name; - } else if (next == Token::AWAIT && !parsing_module_ && !is_async_function()) { - classifier()->RecordAsyncArrowFormalParametersError( + if (next == Token::AWAIT) { + expression_scope()->RecordAsyncArrowParametersError( scanner()->location(), MessageTemplate::kAwaitBindingIdentifier); return impl()->GetSymbol(); - } else if (is_sloppy(language_mode()) && - (Token::IsStrictReservedWord(next) || - (next == Token::YIELD && !is_generator()))) { - classifier()->RecordStrictModeFormalParameterError( - scanner()->location(), MessageTemplate::kUnexpectedStrictReserved); - if (scanner()->IsLet()) { - classifier()->RecordLetPatternError( - scanner()->location(), MessageTemplate::kLetInLexicalBinding); - } - return impl()->GetSymbol(); - } else { - ReportUnexpectedToken(next); - *ok = false; - return impl()->NullIdentifier(); } + + DCHECK(Token::IsStrictReservedWord(next)); + expression_scope()->RecordStrictModeParameterError( + scanner()->location(), MessageTemplate::kUnexpectedStrictReserved); + return impl()->GetSymbol(); } template <class Impl> -typename ParserBase<Impl>::IdentifierT -ParserBase<Impl>::ParseIdentifierOrStrictReservedWord( - FunctionKind function_kind, bool* is_strict_reserved, bool* is_await, - bool* ok) { +typename ParserBase<Impl>::IdentifierT ParserBase<Impl>::ParseIdentifier( + FunctionKind function_kind) { Token::Value next = Next(); - if (next == Token::IDENTIFIER || (next == Token::AWAIT && !parsing_module_ && - !IsAsyncFunction(function_kind)) || - next == Token::ASYNC) { - *is_strict_reserved = false; - *is_await = next == Token::AWAIT; - } else if (Token::IsStrictReservedWord(next) || - (next == Token::YIELD && !IsGeneratorFunction(function_kind))) { - *is_strict_reserved = true; - } else { + + if (!Token::IsValidIdentifier( + next, language_mode(), IsGeneratorFunction(function_kind), + parsing_module_ || IsAsyncFunction(function_kind))) { ReportUnexpectedToken(next); - *ok = false; - return impl()->NullIdentifier(); + return impl()->EmptyIdentifierString(); } return impl()->GetSymbol(); } template <typename Impl> -typename ParserBase<Impl>::IdentifierT ParserBase<Impl>::ParseIdentifierName( - bool* ok) { - Token::Value next = Next(); - if (!Token::IsAnyIdentifier(next) && next != Token::ESCAPED_KEYWORD && - !Token::IsKeyword(next)) { - ReportUnexpectedToken(next); - *ok = false; - return impl()->NullIdentifier(); +typename ParserBase<Impl>::IdentifierT +ParserBase<Impl>::ParseNonRestrictedIdentifier() { + IdentifierT result = ParseIdentifier(); + + if (is_strict(language_mode()) && + V8_UNLIKELY(impl()->IsEvalOrArguments(result))) { + impl()->ReportMessageAt(scanner()->location(), + MessageTemplate::kStrictEvalArguments); } - return impl()->GetSymbol(); + return result; +} + +template <typename Impl> +typename ParserBase<Impl>::IdentifierT ParserBase<Impl>::ParsePropertyName() { + Token::Value next = Next(); + if (V8_LIKELY(Token::IsPropertyName(next))) return impl()->GetSymbol(); + + ReportUnexpectedToken(next); + return impl()->EmptyIdentifierString(); } template <typename Impl> typename ParserBase<Impl>::ExpressionT -ParserBase<Impl>::ParseIdentifierNameOrPrivateName(bool* ok) { +ParserBase<Impl>::ParsePropertyOrPrivatePropertyName() { int pos = position(); IdentifierT name; ExpressionT key; - if (allow_harmony_private_fields() && peek() == Token::PRIVATE_NAME) { - Consume(Token::PRIVATE_NAME); + Token::Value next = Next(); + if (V8_LIKELY(Token::IsPropertyName(next))) { name = impl()->GetSymbol(); - auto key_proxy = - impl()->ExpressionFromIdentifier(name, pos, InferName::kNo); - key_proxy->set_is_private_field(); - key = key_proxy; - } else { - name = ParseIdentifierName(CHECK_OK); key = factory()->NewStringLiteral(name, pos); + } else if (allow_harmony_private_fields() && next == Token::PRIVATE_NAME) { + name = impl()->GetSymbol(); + key = impl()->ExpressionFromIdentifier(name, pos, InferName::kNo); + } else { + ReportUnexpectedToken(next); + return impl()->FailureExpression(); } impl()->PushLiteralName(name); return key; } template <typename Impl> -typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseRegExpLiteral( - bool* ok) { +typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseRegExpLiteral() { int pos = peek_position(); if (!scanner()->ScanRegExpPattern()) { Next(); ReportMessage(MessageTemplate::kUnterminatedRegExp); - *ok = false; - return impl()->NullExpression(); + return impl()->FailureExpression(); } IdentifierT js_pattern = impl()->GetNextSymbol(); @@ -1811,8 +1563,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseRegExpLiteral( if (flags.IsNothing()) { Next(); ReportMessage(MessageTemplate::kMalformedRegExpFlags); - *ok = false; - return impl()->NullExpression(); + return impl()->FailureExpression(); } int js_flags = flags.FromJust(); Next(); @@ -1820,8 +1571,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseRegExpLiteral( } template <typename Impl> -typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseBindingPattern( - bool* ok) { +typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseBindingPattern() { // Pattern :: // Identifier // ArrayLiteral @@ -1832,29 +1582,35 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseBindingPattern( ExpressionT result; if (Token::IsAnyIdentifier(token)) { - IdentifierT name = ParseAndClassifyIdentifier(CHECK_OK); - result = impl()->ExpressionFromIdentifier(name, beg_pos); - } else { - classifier()->RecordNonSimpleParameter(); - - if (token == Token::LBRACK) { - result = ParseArrayLiteral(CHECK_OK); - } else if (token == Token::LBRACE) { - result = ParseObjectLiteral(CHECK_OK); - } else { - ReportUnexpectedToken(Next()); - *ok = false; - return impl()->NullExpression(); + IdentifierT name = ParseAndClassifyIdentifier(Next()); + if (V8_UNLIKELY(is_strict(language_mode()) && + impl()->IsEvalOrArguments(name))) { + impl()->ReportMessageAt(scanner()->location(), + MessageTemplate::kStrictEvalArguments); + return impl()->FailureExpression(); } + return impl()->ExpressionFromIdentifier(name, beg_pos); + } + + CheckStackOverflow(); + + if (token == Token::LBRACK) { + result = ParseArrayLiteral(); + } else if (token == Token::LBRACE) { + result = ParseObjectLiteral(); + } else { + ReportUnexpectedToken(Next()); + return impl()->FailureExpression(); } - ValidateBindingPattern(CHECK_OK); return result; } template <typename Impl> -typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePrimaryExpression( - bool* is_async, bool* ok) { +typename ParserBase<Impl>::ExpressionT +ParserBase<Impl>::ParsePrimaryExpression() { + CheckStackOverflow(); + // PrimaryExpression :: // 'this' // 'null' @@ -1874,136 +1630,115 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePrimaryExpression( int beg_pos = peek_position(); Token::Value token = peek(); - switch (token) { - case Token::THIS: { - BindingPatternUnexpectedToken(); - Consume(Token::THIS); - return impl()->ThisExpression(beg_pos); + + if (Token::IsAnyIdentifier(token)) { + Consume(token); + + FunctionKind kind = FunctionKind::kArrowFunction; + + if (V8_UNLIKELY(token == Token::ASYNC && + !scanner()->HasLineTerminatorBeforeNext())) { + // async function ... + if (peek() == Token::FUNCTION) return ParseAsyncFunctionLiteral(); + + // async Identifier => ... + if (peek_any_identifier() && PeekAhead() == Token::ARROW) { + token = Next(); + beg_pos = position(); + kind = FunctionKind::kAsyncArrowFunction; + } } - case Token::NULL_LITERAL: - case Token::TRUE_LITERAL: - case Token::FALSE_LITERAL: - case Token::SMI: - case Token::NUMBER: - case Token::BIGINT: { - // Ensure continuous enum range. - DCHECK(Token::IsLiteral(token)); - BindingPatternUnexpectedToken(); - return impl()->ExpressionFromLiteral(Next(), beg_pos); - } - case Token::STRING: { - DCHECK(Token::IsLiteral(token)); - BindingPatternUnexpectedToken(); - Consume(Token::STRING); - return impl()->ExpressionFromString(beg_pos); + if (V8_UNLIKELY(peek() == Token::ARROW)) { + ArrowHeadParsingScope parsing_scope(impl(), kind); + IdentifierT name = ParseAndClassifyIdentifier(token); + ClassifyParameter(name, beg_pos, end_position()); + ExpressionT result = + impl()->ExpressionFromIdentifier(name, beg_pos, InferName::kNo); + next_arrow_function_info_.scope = parsing_scope.ValidateAndCreateScope(); + return result; } - case Token::ASYNC: - if (!scanner()->HasLineTerminatorAfterNext() && - PeekAhead() == Token::FUNCTION) { - BindingPatternUnexpectedToken(); - Consume(Token::ASYNC); - return ParseAsyncFunctionLiteral(ok); - } - // CoverCallExpressionAndAsyncArrowHead - *is_async = true; - V8_FALLTHROUGH; - case Token::IDENTIFIER: - case Token::LET: - case Token::STATIC: - case Token::YIELD: - case Token::AWAIT: - case Token::FUTURE_STRICT_RESERVED_WORD: - case Token::ESCAPED_STRICT_RESERVED_WORD: { - // Ensure continuous enum range. - DCHECK(IsInRange(token, Token::IDENTIFIER, - Token::ESCAPED_STRICT_RESERVED_WORD)); - // Using eval or arguments in this context is OK even in strict mode. - IdentifierT name = ParseAndClassifyIdentifier(CHECK_OK); - return impl()->ExpressionFromIdentifier(name, beg_pos); + IdentifierT name = ParseAndClassifyIdentifier(token); + return impl()->ExpressionFromIdentifier(name, beg_pos); + } + + if (Token::IsLiteral(token)) { + return impl()->ExpressionFromLiteral(Next(), beg_pos); + } + + switch (token) { + case Token::THIS: { + Consume(Token::THIS); + return impl()->ThisExpression(beg_pos); } case Token::ASSIGN_DIV: case Token::DIV: - classifier()->RecordBindingPatternError( - scanner()->peek_location(), MessageTemplate::kUnexpectedTokenRegExp); - return ParseRegExpLiteral(ok); + return ParseRegExpLiteral(); case Token::LBRACK: - return ParseArrayLiteral(ok); + return ParseArrayLiteral(); case Token::LBRACE: - return ParseObjectLiteral(ok); + return ParseObjectLiteral(); case Token::LPAREN: { - // Arrow function formal parameters are either a single identifier or a - // list of BindingPattern productions enclosed in parentheses. - // Parentheses are not valid on the LHS of a BindingPattern, so we use - // the is_valid_binding_pattern() check to detect multiple levels of - // parenthesization. - bool pattern_error = !classifier()->is_valid_binding_pattern(); - classifier()->RecordPatternError(scanner()->peek_location(), - MessageTemplate::kUnexpectedToken, - Token::String(Token::LPAREN)); - if (pattern_error) ArrowFormalParametersUnexpectedToken(); Consume(Token::LPAREN); if (Check(Token::RPAREN)) { - // ()=>x. The continuation that looks for the => is in - // ParseAssignmentExpression. - classifier()->RecordExpressionError(scanner()->location(), - MessageTemplate::kUnexpectedToken, - Token::String(Token::RPAREN)); + // ()=>x. The continuation that consumes the => is in + // ParseAssignmentExpressionCoverGrammar. + if (peek() != Token::ARROW) ReportUnexpectedToken(Token::RPAREN); + next_arrow_function_info_.scope = + NewFunctionScope(FunctionKind::kArrowFunction); return factory()->NewEmptyParentheses(beg_pos); } + Scope::Snapshot scope_snapshot(scope()); + ArrowHeadParsingScope maybe_arrow(impl(), FunctionKind::kArrowFunction); // Heuristically try to detect immediately called functions before // seeing the call parentheses. if (peek() == Token::FUNCTION || (peek() == Token::ASYNC && PeekAhead() == Token::FUNCTION)) { function_state_->set_next_function_is_likely_called(); } - ExpressionT expr = ParseExpressionCoverGrammar(true, CHECK_OK); - Expect(Token::RPAREN, ok); + AcceptINScope scope(this, true); + ExpressionT expr = ParseExpressionCoverGrammar(); + expr->mark_parenthesized(); + Expect(Token::RPAREN); + + if (peek() == Token::ARROW) { + next_arrow_function_info_.scope = maybe_arrow.ValidateAndCreateScope(); + scope_snapshot.Reparent(next_arrow_function_info_.scope); + } else { + maybe_arrow.ValidateExpression(); + } + return expr; } case Token::CLASS: { - BindingPatternUnexpectedToken(); Consume(Token::CLASS); int class_token_pos = position(); IdentifierT name = impl()->NullIdentifier(); bool is_strict_reserved_name = false; Scanner::Location class_name_location = Scanner::Location::invalid(); if (peek_any_identifier()) { - bool is_await = false; - name = ParseIdentifierOrStrictReservedWord(&is_strict_reserved_name, - &is_await, CHECK_OK); + name = ParseAndClassifyIdentifier(Next()); class_name_location = scanner()->location(); - if (is_await) { - classifier()->RecordAsyncArrowFormalParametersError( - scanner()->location(), MessageTemplate::kAwaitBindingIdentifier); - } + is_strict_reserved_name = + Token::IsStrictReservedWord(scanner()->current_token()); } return ParseClassLiteral(name, class_name_location, - is_strict_reserved_name, class_token_pos, ok); + is_strict_reserved_name, class_token_pos); } case Token::TEMPLATE_SPAN: case Token::TEMPLATE_TAIL: - BindingPatternUnexpectedToken(); - return ParseTemplateLiteral(impl()->NullExpression(), beg_pos, false, ok); + return ParseTemplateLiteral(impl()->NullExpression(), beg_pos, false); case Token::MOD: if (allow_natives() || extension_ != nullptr) { - BindingPatternUnexpectedToken(); - return ParseV8Intrinsic(ok); - } - break; - - case Token::DO: - if (allow_harmony_do_expressions()) { - BindingPatternUnexpectedToken(); - return ParseDoExpression(ok); + return ParseV8Intrinsic(); } break; @@ -2012,72 +1747,49 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePrimaryExpression( } ReportUnexpectedToken(Next()); - *ok = false; - return impl()->NullExpression(); + return impl()->FailureExpression(); } template <typename Impl> -typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseExpression( - bool* ok) { - ExpressionClassifier classifier(this); - ExpressionT result = ParseExpressionCoverGrammar(true, CHECK_OK); - ValidateExpression(ok); +typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseExpression() { + ExpressionParsingScope expression_scope(impl()); + AcceptINScope scope(this, true); + ExpressionT result = ParseExpressionCoverGrammar(); + expression_scope.ValidateExpression(); return result; } template <typename Impl> typename ParserBase<Impl>::ExpressionT -ParserBase<Impl>::ParseExpressionCoverGrammar(bool accept_IN, bool* ok) { +ParserBase<Impl>::ParseAssignmentExpression() { + ExpressionParsingScope expression_scope(impl()); + ExpressionT result = ParseAssignmentExpressionCoverGrammar(); + expression_scope.ValidateExpression(); + return result; +} + +template <typename Impl> +typename ParserBase<Impl>::ExpressionT +ParserBase<Impl>::ParseExpressionCoverGrammar() { // Expression :: // AssignmentExpression // Expression ',' AssignmentExpression - ExpressionT result = impl()->NullExpression(); + ExpressionListT list(pointer_buffer()); + ExpressionT expression; + AccumulationScope accumulation_scope(expression_scope()); while (true) { - int comma_pos = position(); - ExpressionClassifier binding_classifier(this); - ExpressionT right; - if (Check(Token::ELLIPSIS)) { - // 'x, y, ...z' in CoverParenthesizedExpressionAndArrowParameterList only - // as the formal parameters of'(x, y, ...z) => foo', and is not itself a - // valid expression. - classifier()->RecordExpressionError(scanner()->location(), - MessageTemplate::kUnexpectedToken, - Token::String(Token::ELLIPSIS)); - int ellipsis_pos = position(); - int pattern_pos = peek_position(); - ExpressionT pattern = ParseBindingPattern(CHECK_OK); - if (peek() == Token::ASSIGN) { - ReportMessage(MessageTemplate::kRestDefaultInitializer); - *ok = false; - return result; - } - right = factory()->NewSpread(pattern, ellipsis_pos, pattern_pos); - } else { - right = ParseAssignmentExpression(accept_IN, CHECK_OK); - } - // No need to accumulate binding pattern-related errors, since - // an Expression can't be a binding pattern anyway. - AccumulateNonBindingPatternErrors(); - if (!impl()->IsIdentifier(right)) classifier()->RecordNonSimpleParameter(); - if (impl()->IsNull(result)) { - // First time through the loop. - result = right; - } else if (impl()->CollapseNaryExpression(&result, right, Token::COMMA, - comma_pos, - SourceRange::Empty())) { - // Do nothing, "result" is already updated. - } else { - result = - factory()->NewBinaryOperation(Token::COMMA, result, right, comma_pos); + if (V8_UNLIKELY(peek() == Token::ELLIPSIS)) { + return ParseArrowParametersWithRest(&list, &accumulation_scope); } - if (!Check(Token::COMMA)) break; + int expr_pos = peek_position(); + expression = ParseAssignmentExpressionCoverGrammar(); - if (right->IsSpread()) { - classifier()->RecordArrowFormalParametersError( - scanner()->location(), MessageTemplate::kParamAfterRest); - } + ClassifyArrowParameter(&accumulation_scope, expr_pos, expression); + list.Add(expression); + + if (!Check(Token::COMMA)) break; if (peek() == Token::RPAREN && PeekAhead() == Token::ARROW) { // a trailing comma is allowed at the end of an arrow parameter list @@ -2092,19 +1804,64 @@ ParserBase<Impl>::ParseExpressionCoverGrammar(bool accept_IN, bool* ok) { } } - return result; + // Return the single element if the list is empty. We need to do this because + // callers of this function care about the type of the result if there was + // only a single assignment expression. The preparser would lose this + // information otherwise. + if (list.length() == 1) return expression; + return impl()->ExpressionListToExpression(list); } template <typename Impl> -typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseArrayLiteral( - bool* ok) { +typename ParserBase<Impl>::ExpressionT +ParserBase<Impl>::ParseArrowParametersWithRest( + typename ParserBase<Impl>::ExpressionListT* list, + AccumulationScope* accumulation_scope) { + Consume(Token::ELLIPSIS); + + Scanner::Location ellipsis = scanner()->location(); + int pattern_pos = peek_position(); + ExpressionT pattern = ParseBindingPattern(); + ClassifyArrowParameter(accumulation_scope, pattern_pos, pattern); + + expression_scope()->RecordNonSimpleParameter(); + + if (V8_UNLIKELY(peek() == Token::ASSIGN)) { + ReportMessage(MessageTemplate::kRestDefaultInitializer); + return impl()->FailureExpression(); + } + + ExpressionT spread = + factory()->NewSpread(pattern, ellipsis.beg_pos, pattern_pos); + if (V8_UNLIKELY(peek() == Token::COMMA)) { + ReportMessage(MessageTemplate::kParamAfterRest); + return impl()->FailureExpression(); + } + + // 'x, y, ...z' in CoverParenthesizedExpressionAndArrowParameterList only + // as the formal parameters of'(x, y, ...z) => foo', and is not itself a + // valid expression. + if (peek() != Token::RPAREN || PeekAhead() != Token::ARROW) { + impl()->ReportUnexpectedTokenAt(ellipsis, Token::ELLIPSIS); + return impl()->FailureExpression(); + } + + list->Add(spread); + return impl()->ExpressionListToExpression(*list); +} + +template <typename Impl> +typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseArrayLiteral() { // ArrayLiteral :: // '[' Expression? (',' Expression?)* ']' int pos = peek_position(); - ExpressionListT values = impl()->NewExpressionList(4); + ExpressionListT values(pointer_buffer()); int first_spread_index = -1; Consume(Token::LBRACK); + + AccumulationScope accumulation_scope(expression_scope()); + while (!Check(Token::RBRACK)) { ExpressionT elem; if (peek() == Token::COMMA) { @@ -2112,115 +1869,80 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseArrayLiteral( } else if (Check(Token::ELLIPSIS)) { int start_pos = position(); int expr_pos = peek_position(); - ExpressionT argument = ParseAssignmentExpression(true, CHECK_OK); + AcceptINScope scope(this, true); + ExpressionT argument = + ParsePossibleDestructuringSubPattern(&accumulation_scope); elem = factory()->NewSpread(argument, start_pos, expr_pos); if (first_spread_index < 0) { - first_spread_index = values->length(); + first_spread_index = values.length(); } if (argument->IsAssignment()) { - classifier()->RecordPatternError( + expression_scope()->RecordPatternError( Scanner::Location(start_pos, end_position()), MessageTemplate::kInvalidDestructuringTarget); - } else { - CheckDestructuringElement(argument, start_pos, end_position()); } if (peek() == Token::COMMA) { - classifier()->RecordPatternError( + expression_scope()->RecordPatternError( Scanner::Location(start_pos, end_position()), MessageTemplate::kElementAfterRest); } } else { - int beg_pos = peek_position(); - elem = ParseAssignmentExpression(true, CHECK_OK); - CheckDestructuringElement(elem, beg_pos, end_position()); + AcceptINScope scope(this, true); + elem = ParsePossibleDestructuringSubPattern(&accumulation_scope); } - values->Add(elem, zone_); + values.Add(elem); if (peek() != Token::RBRACK) { - Expect(Token::COMMA, CHECK_OK); + Expect(Token::COMMA); + if (elem->IsFailureExpression()) return elem; } } return factory()->NewArrayLiteral(values, first_spread_index, pos); } -inline bool ParsePropertyKindFromToken(Token::Value token, - ParsePropertyKind* kind) { - // This returns true, setting the property kind, iff the given token is one - // which must occur after a property name, indicating that the previous token - // was in fact a name and not a modifier (like the "get" in "get x"). - switch (token) { - case Token::COLON: - *kind = ParsePropertyKind::kValue; - return true; - case Token::COMMA: - case Token::RBRACE: - case Token::ASSIGN: - *kind = ParsePropertyKind::kShorthand; - return true; - case Token::LPAREN: - *kind = ParsePropertyKind::kMethod; - return true; - case Token::MUL: - case Token::SEMICOLON: - *kind = ParsePropertyKind::kClassField; - return true; - case Token::PRIVATE_NAME: - *kind = ParsePropertyKind::kClassField; - return true; - default: - break; - } - return false; -} - -inline bool ParseAsAccessor(Token::Value token, Token::Value contextual_token, - ParsePropertyKind* kind) { - if (ParsePropertyKindFromToken(token, kind)) return false; - - if (contextual_token == Token::GET) { - *kind = ParsePropertyKind::kAccessorGetter; - } else if (contextual_token == Token::SET) { - *kind = ParsePropertyKind::kAccessorSetter; - } else { - return false; - } - - return true; -} - template <class Impl> -typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePropertyName( - IdentifierT* name, ParsePropertyKind* kind, ParseFunctionFlags* flags, - bool* is_computed_name, bool* ok) { - DCHECK_EQ(ParsePropertyKind::kNotSet, *kind); - DCHECK_EQ(*flags, ParseFunctionFlag::kIsNormal); - DCHECK(!*is_computed_name); +typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseProperty( + ParsePropertyInfo* prop_info) { + DCHECK_EQ(prop_info->kind, ParsePropertyKind::kNotSet); + DCHECK_EQ(prop_info->function_flags, ParseFunctionFlag::kIsNormal); + DCHECK(!prop_info->is_computed_name); if (Check(Token::ASYNC)) { Token::Value token = peek(); - if ((token != Token::MUL && ParsePropertyKindFromToken(token, kind)) || + if ((token != Token::MUL && prop_info->ParsePropertyKindFromToken(token)) || scanner()->HasLineTerminatorBeforeNext()) { - *name = impl()->GetSymbol(); - impl()->PushLiteralName(*name); - return factory()->NewStringLiteral(*name, position()); + prop_info->name = impl()->GetSymbol(); + impl()->PushLiteralName(prop_info->name); + return factory()->NewStringLiteral(prop_info->name, position()); } - *flags = ParseFunctionFlag::kIsAsync; - *kind = ParsePropertyKind::kMethod; + prop_info->function_flags = ParseFunctionFlag::kIsAsync; + prop_info->kind = ParsePropertyKind::kMethod; } if (Check(Token::MUL)) { - *flags |= ParseFunctionFlag::kIsGenerator; - *kind = ParsePropertyKind::kMethod; - } - - if (*kind == ParsePropertyKind::kNotSet && Check(Token::IDENTIFIER) && - !ParseAsAccessor(peek(), scanner()->current_contextual_token(), kind)) { - *name = impl()->GetSymbol(); - impl()->PushLiteralName(*name); - return factory()->NewStringLiteral(*name, position()); + prop_info->function_flags |= ParseFunctionFlag::kIsGenerator; + prop_info->kind = ParsePropertyKind::kMethod; + } + + if (prop_info->kind == ParsePropertyKind::kNotSet && + Check(Token::IDENTIFIER)) { + IdentifierT symbol = impl()->GetSymbol(); + if (!prop_info->ParsePropertyKindFromToken(peek())) { + if (impl()->IdentifierEquals(symbol, ast_value_factory()->get_string())) { + prop_info->kind = ParsePropertyKind::kAccessorGetter; + } else if (impl()->IdentifierEquals(symbol, + ast_value_factory()->set_string())) { + prop_info->kind = ParsePropertyKind::kAccessorSetter; + } + } + if (!IsAccessor(prop_info->kind)) { + prop_info->name = symbol; + impl()->PushLiteralName(prop_info->name); + return factory()->NewStringLiteral(prop_info->name, position()); + } } int pos = peek_position(); @@ -2237,10 +1959,27 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePropertyName( bool is_array_index; uint32_t index; switch (peek()) { + case Token::PRIVATE_NAME: + prop_info->is_private = true; + is_array_index = false; + Consume(Token::PRIVATE_NAME); + if (prop_info->kind == ParsePropertyKind::kNotSet) { + prop_info->ParsePropertyKindFromToken(peek()); + } + prop_info->name = impl()->GetSymbol(); + if (prop_info->position == PropertyPosition::kObjectLiteral || + (!allow_harmony_private_methods() && + (IsAccessor(prop_info->kind) || + prop_info->kind == ParsePropertyKind::kMethod))) { + ReportUnexpectedToken(Next()); + return impl()->FailureExpression(); + } + break; + case Token::STRING: Consume(Token::STRING); - *name = impl()->GetSymbol(); - is_array_index = impl()->IsArrayIndex(*name, &index); + prop_info->name = impl()->GetSymbol(); + is_array_index = impl()->IsArrayIndex(prop_info->name, &index); break; case Token::SMI: @@ -2248,82 +1987,76 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePropertyName( index = scanner()->smi_value(); is_array_index = true; // Token::SMI were scanned from their canonical representation. - *name = impl()->GetSymbol(); + prop_info->name = impl()->GetSymbol(); break; case Token::NUMBER: { Consume(Token::NUMBER); - *name = impl()->GetNumberAsSymbol(); - is_array_index = impl()->IsArrayIndex(*name, &index); + prop_info->name = impl()->GetNumberAsSymbol(); + is_array_index = impl()->IsArrayIndex(prop_info->name, &index); break; } case Token::LBRACK: { - *name = impl()->NullIdentifier(); - *is_computed_name = true; + prop_info->name = impl()->NullIdentifier(); + prop_info->is_computed_name = true; Consume(Token::LBRACK); - ExpressionClassifier computed_name_classifier(this); - ExpressionT expression = ParseAssignmentExpression(true, CHECK_OK); - ValidateExpression(CHECK_OK); - AccumulateFormalParameterContainmentErrors(); - Expect(Token::RBRACK, CHECK_OK); - if (*kind == ParsePropertyKind::kNotSet) { - ParsePropertyKindFromToken(peek(), kind); + AcceptINScope scope(this, true); + ExpressionT expression = ParseAssignmentExpression(); + Expect(Token::RBRACK); + if (prop_info->kind == ParsePropertyKind::kNotSet) { + prop_info->ParsePropertyKindFromToken(peek()); } return expression; } case Token::ELLIPSIS: - if (*kind == ParsePropertyKind::kNotSet) { - *name = impl()->NullIdentifier(); + if (prop_info->kind == ParsePropertyKind::kNotSet) { + prop_info->name = impl()->NullIdentifier(); Consume(Token::ELLIPSIS); - ExpressionT expression = ParseAssignmentExpression(true, CHECK_OK); - *kind = ParsePropertyKind::kSpread; - - if (!impl()->IsIdentifier(expression)) { - classifier()->RecordBindingPatternError( - scanner()->location(), + AcceptINScope scope(this, true); + int start_pos = peek_position(); + ExpressionT expression = + ParsePossibleDestructuringSubPattern(prop_info->accumulation_scope); + prop_info->kind = ParsePropertyKind::kSpread; + + if (!IsValidReferenceExpression(expression)) { + expression_scope()->RecordDeclarationError( + Scanner::Location(start_pos, end_position()), MessageTemplate::kInvalidRestBindingPattern); - } - - if (!expression->IsValidReferenceExpression()) { - classifier()->RecordAssignmentPatternError( - scanner()->location(), + expression_scope()->RecordPatternError( + Scanner::Location(start_pos, end_position()), MessageTemplate::kInvalidRestAssignmentPattern); } if (peek() != Token::RBRACE) { - classifier()->RecordPatternError(scanner()->location(), - MessageTemplate::kElementAfterRest); + expression_scope()->RecordPatternError( + scanner()->location(), MessageTemplate::kElementAfterRest); } return expression; } V8_FALLTHROUGH; default: - *name = ParseIdentifierName(CHECK_OK); + prop_info->name = ParsePropertyName(); is_array_index = false; break; } - if (*kind == ParsePropertyKind::kNotSet) { - ParsePropertyKindFromToken(peek(), kind); + if (prop_info->kind == ParsePropertyKind::kNotSet) { + prop_info->ParsePropertyKindFromToken(peek()); } - impl()->PushLiteralName(*name); + impl()->PushLiteralName(prop_info->name); return is_array_index ? factory()->NewNumberLiteral(index, pos) - : factory()->NewStringLiteral(*name, pos); + : factory()->NewStringLiteral(prop_info->name, pos); } template <typename Impl> typename ParserBase<Impl>::ClassLiteralPropertyT -ParserBase<Impl>::ParseClassPropertyDefinition( - ClassLiteralChecker* checker, ClassInfo* class_info, IdentifierT* name, - bool has_extends, bool* is_computed_name, - ClassLiteralProperty::Kind* property_kind, bool* is_static, bool* ok) { +ParserBase<Impl>::ParseClassPropertyDefinition(ClassInfo* class_info, + ParsePropertyInfo* prop_info, + bool has_extends) { DCHECK_NOT_NULL(class_info); - ParseFunctionFlags function_flags = ParseFunctionFlag::kIsNormal; - *is_static = false; - *property_kind = ClassLiteralProperty::METHOD; - ParsePropertyKind kind = ParsePropertyKind::kNotSet; + DCHECK_EQ(prop_info->position, PropertyPosition::kClassLiteral); Token::Value name_token = peek(); DCHECK_IMPLIES(name_token == Token::PRIVATE_NAME, @@ -2331,48 +2064,39 @@ ParserBase<Impl>::ParseClassPropertyDefinition( int property_beg_pos = scanner()->peek_location().beg_pos; int name_token_position = property_beg_pos; - *name = impl()->NullIdentifier(); ExpressionT name_expression; if (name_token == Token::STATIC) { Consume(Token::STATIC); name_token_position = scanner()->peek_location().beg_pos; if (peek() == Token::LPAREN) { - kind = ParsePropertyKind::kMethod; - *name = impl()->GetSymbol(); // TODO(bakkot) specialize on 'static' - name_expression = factory()->NewStringLiteral(*name, position()); + prop_info->kind = ParsePropertyKind::kMethod; + // TODO(bakkot) specialize on 'static' + prop_info->name = impl()->GetSymbol(); + name_expression = + factory()->NewStringLiteral(prop_info->name, position()); } else if (peek() == Token::ASSIGN || peek() == Token::SEMICOLON || peek() == Token::RBRACE) { - *name = impl()->GetSymbol(); // TODO(bakkot) specialize on 'static' - name_expression = factory()->NewStringLiteral(*name, position()); - } else if (peek() == Token::PRIVATE_NAME) { - DCHECK(allow_harmony_private_fields()); - // TODO(gsathya): Make a better error message for this. - ReportUnexpectedToken(Next()); - *ok = false; - return impl()->NullLiteralProperty(); - } else { - *is_static = true; + // TODO(bakkot) specialize on 'static' + prop_info->name = impl()->GetSymbol(); name_expression = - ParsePropertyName(name, &kind, &function_flags, is_computed_name, - CHECK_OK_CUSTOM(NullLiteralProperty)); + factory()->NewStringLiteral(prop_info->name, position()); + } else { + prop_info->is_static = true; + name_expression = ParseProperty(prop_info); } - } else if (name_token == Token::PRIVATE_NAME) { - Consume(Token::PRIVATE_NAME); - *name = impl()->GetSymbol(); - name_expression = factory()->NewStringLiteral(*name, position()); } else { - name_expression = - ParsePropertyName(name, &kind, &function_flags, is_computed_name, - CHECK_OK_CUSTOM(NullLiteralProperty)); + name_expression = ParseProperty(prop_info); } - if (!class_info->has_name_static_property && *is_static && - impl()->IsName(*name)) { + if (!class_info->has_name_static_property && prop_info->is_static && + impl()->IsName(prop_info->name)) { class_info->has_name_static_property = true; } - switch (kind) { + switch (prop_info->kind) { + case ParsePropertyKind::kAssign: case ParsePropertyKind::kClassField: + case ParsePropertyKind::kShorthandOrClassField: case ParsePropertyKind::kNotSet: // This case is a name followed by a name // or other property. Here we have to // assume that's an uninitialized field @@ -2381,34 +2105,33 @@ ParserBase<Impl>::ParseClassPropertyDefinition( // semicolon. If not, there will be a // syntax error after parsing the first // name as an uninitialized field. - case ParsePropertyKind::kShorthand: - case ParsePropertyKind::kValue: if (allow_harmony_public_fields() || allow_harmony_private_fields()) { - *property_kind = name_token == Token::PRIVATE_NAME - ? ClassLiteralProperty::PRIVATE_FIELD - : ClassLiteralProperty::PUBLIC_FIELD; - if (*is_static && !allow_harmony_static_fields()) { + prop_info->kind = ParsePropertyKind::kClassField; + DCHECK_IMPLIES(prop_info->is_computed_name, !prop_info->is_private); + + if (prop_info->is_static && !allow_harmony_static_fields()) { ReportUnexpectedToken(Next()); - *ok = false; return impl()->NullLiteralProperty(); } - if (!*is_computed_name) { - checker->CheckClassFieldName(*is_static, - CHECK_OK_CUSTOM(NullLiteralProperty)); + + if (!prop_info->is_computed_name) { + CheckClassFieldName(prop_info->name, prop_info->is_static); } - ExpressionT initializer = - ParseClassFieldInitializer(class_info, property_beg_pos, *is_static, - CHECK_OK_CUSTOM(NullLiteralProperty)); - ExpectSemicolon(CHECK_OK_CUSTOM(NullLiteralProperty)); + + ExpressionT initializer = ParseMemberInitializer( + class_info, property_beg_pos, prop_info->is_static); + ExpectSemicolon(); + ClassLiteralPropertyT result = factory()->NewClassLiteralProperty( - name_expression, initializer, *property_kind, *is_static, - *is_computed_name); - impl()->SetFunctionNameFromPropertyName(result, *name); + name_expression, initializer, ClassLiteralProperty::FIELD, + prop_info->is_static, prop_info->is_computed_name, + prop_info->is_private); + impl()->SetFunctionNameFromPropertyName(result, prop_info->name); + return result; } else { ReportUnexpectedToken(Next()); - *ok = false; return impl()->NullLiteralProperty(); } @@ -2421,89 +2144,89 @@ ParserBase<Impl>::ParseClassPropertyDefinition( // async '*' PropertyName '(' StrictFormalParameters ')' // '{' FunctionBody '}' - if (!*is_computed_name) { - checker->CheckClassMethodName(name_token, ParsePropertyKind::kMethod, - function_flags, *is_static, - CHECK_OK_CUSTOM(NullLiteralProperty)); + if (!prop_info->is_computed_name) { + CheckClassMethodName(prop_info->name, ParsePropertyKind::kMethod, + prop_info->function_flags, prop_info->is_static, + &class_info->has_seen_constructor); } - FunctionKind kind = MethodKindFor(function_flags); + FunctionKind kind = MethodKindFor(prop_info->function_flags); - if (!*is_static && impl()->IsConstructor(*name)) { + if (!prop_info->is_static && impl()->IsConstructor(prop_info->name)) { class_info->has_seen_constructor = true; kind = has_extends ? FunctionKind::kDerivedConstructor : FunctionKind::kBaseConstructor; } ExpressionT value = impl()->ParseFunctionLiteral( - *name, scanner()->location(), kSkipFunctionNameCheck, kind, + prop_info->name, scanner()->location(), kSkipFunctionNameCheck, kind, name_token_position, FunctionLiteral::kAccessorOrMethod, - language_mode(), nullptr, CHECK_OK_CUSTOM(NullLiteralProperty)); + language_mode(), nullptr); - *property_kind = ClassLiteralProperty::METHOD; ClassLiteralPropertyT result = factory()->NewClassLiteralProperty( - name_expression, value, *property_kind, *is_static, - *is_computed_name); - impl()->SetFunctionNameFromPropertyName(result, *name); + name_expression, value, ClassLiteralProperty::METHOD, + prop_info->is_static, prop_info->is_computed_name, + prop_info->is_private); + impl()->SetFunctionNameFromPropertyName(result, prop_info->name); return result; } case ParsePropertyKind::kAccessorGetter: case ParsePropertyKind::kAccessorSetter: { - DCHECK_EQ(function_flags, ParseFunctionFlag::kIsNormal); - bool is_get = kind == ParsePropertyKind::kAccessorGetter; + DCHECK_EQ(prop_info->function_flags, ParseFunctionFlag::kIsNormal); + bool is_get = prop_info->kind == ParsePropertyKind::kAccessorGetter; - if (!*is_computed_name) { - checker->CheckClassMethodName(name_token, kind, - ParseFunctionFlag::kIsNormal, *is_static, - CHECK_OK_CUSTOM(NullLiteralProperty)); + if (!prop_info->is_computed_name) { + CheckClassMethodName(prop_info->name, prop_info->kind, + ParseFunctionFlag::kIsNormal, prop_info->is_static, + &class_info->has_seen_constructor); // Make sure the name expression is a string since we need a Name for // Runtime_DefineAccessorPropertyUnchecked and since we can determine // this statically we can skip the extra runtime check. - name_expression = - factory()->NewStringLiteral(*name, name_expression->position()); + name_expression = factory()->NewStringLiteral( + prop_info->name, name_expression->position()); } FunctionKind kind = is_get ? FunctionKind::kGetterFunction : FunctionKind::kSetterFunction; FunctionLiteralT value = impl()->ParseFunctionLiteral( - *name, scanner()->location(), kSkipFunctionNameCheck, kind, + prop_info->name, scanner()->location(), kSkipFunctionNameCheck, kind, name_token_position, FunctionLiteral::kAccessorOrMethod, - language_mode(), nullptr, CHECK_OK_CUSTOM(NullLiteralProperty)); + language_mode(), nullptr); - *property_kind = + ClassLiteralProperty::Kind property_kind = is_get ? ClassLiteralProperty::GETTER : ClassLiteralProperty::SETTER; ClassLiteralPropertyT result = factory()->NewClassLiteralProperty( - name_expression, value, *property_kind, *is_static, - *is_computed_name); + name_expression, value, property_kind, prop_info->is_static, + prop_info->is_computed_name, prop_info->is_private); const AstRawString* prefix = is_get ? ast_value_factory()->get_space_string() : ast_value_factory()->set_space_string(); - impl()->SetFunctionNameFromPropertyName(result, *name, prefix); + impl()->SetFunctionNameFromPropertyName(result, prop_info->name, prefix); return result; } + case ParsePropertyKind::kValue: + case ParsePropertyKind::kShorthand: case ParsePropertyKind::kSpread: - ReportUnexpectedTokenAt( + impl()->ReportUnexpectedTokenAt( Scanner::Location(name_token_position, name_expression->position()), name_token); - *ok = false; return impl()->NullLiteralProperty(); } UNREACHABLE(); } template <typename Impl> -typename ParserBase<Impl>::ExpressionT -ParserBase<Impl>::ParseClassFieldInitializer(ClassInfo* class_info, int beg_pos, - bool is_static, bool* ok) { - DeclarationScope* initializer_scope = is_static - ? class_info->static_fields_scope - : class_info->instance_fields_scope; +typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseMemberInitializer( + ClassInfo* class_info, int beg_pos, bool is_static) { + DeclarationScope* initializer_scope = + is_static ? class_info->static_fields_scope + : class_info->instance_members_scope; if (initializer_scope == nullptr) { initializer_scope = - NewFunctionScope(FunctionKind::kClassFieldsInitializerFunction); + NewFunctionScope(FunctionKind::kClassMembersInitializerFunction); // TODO(gsathya): Make scopes be non contiguous. initializer_scope->set_start_position(beg_pos); initializer_scope->SetLanguageMode(LanguageMode::kStrict); @@ -2513,11 +2236,9 @@ ParserBase<Impl>::ParseClassFieldInitializer(ClassInfo* class_info, int beg_pos, if (Check(Token::ASSIGN)) { FunctionState initializer_state(&function_state_, &scope_, initializer_scope); - ExpressionClassifier expression_classifier(this); - initializer = - ParseAssignmentExpression(true, CHECK_OK_CUSTOM(NullExpression)); - ValidateExpression(CHECK_OK_CUSTOM(NullExpression)); + AcceptINScope scope(this, true); + initializer = ParseAssignmentExpression(); } else { initializer = factory()->NewUndefinedLiteral(kNoSourcePosition); } @@ -2527,8 +2248,8 @@ ParserBase<Impl>::ParseClassFieldInitializer(ClassInfo* class_info, int beg_pos, class_info->static_fields_scope = initializer_scope; class_info->has_static_class_fields = true; } else { - class_info->instance_fields_scope = initializer_scope; - class_info->has_instance_class_fields = true; + class_info->instance_members_scope = initializer_scope; + class_info->has_instance_members = true; } return initializer; @@ -2536,30 +2257,25 @@ ParserBase<Impl>::ParseClassFieldInitializer(ClassInfo* class_info, int beg_pos, template <typename Impl> typename ParserBase<Impl>::ObjectLiteralPropertyT -ParserBase<Impl>::ParseObjectPropertyDefinition(ObjectLiteralChecker* checker, - bool* is_computed_name, - bool* is_rest_property, - bool* ok) { - ParseFunctionFlags function_flags = ParseFunctionFlag::kIsNormal; - ParsePropertyKind kind = ParsePropertyKind::kNotSet; - - IdentifierT name = impl()->NullIdentifier(); +ParserBase<Impl>::ParseObjectPropertyDefinition(ParsePropertyInfo* prop_info, + bool* has_seen_proto) { + DCHECK_EQ(prop_info->position, PropertyPosition::kObjectLiteral); Token::Value name_token = peek(); - int next_beg_pos = peek_position(); - int next_end_pos = peek_end_position(); + Scanner::Location next_loc = scanner()->peek_location(); - ExpressionT name_expression = - ParsePropertyName(&name, &kind, &function_flags, is_computed_name, - CHECK_OK_CUSTOM(NullLiteralProperty)); + ExpressionT name_expression = ParseProperty(prop_info); + IdentifierT name = prop_info->name; + ParseFunctionFlags function_flags = prop_info->function_flags; + ParsePropertyKind kind = prop_info->kind; - switch (kind) { + switch (prop_info->kind) { case ParsePropertyKind::kSpread: DCHECK_EQ(function_flags, ParseFunctionFlag::kIsNormal); - DCHECK(!*is_computed_name); + DCHECK(!prop_info->is_computed_name); DCHECK_EQ(Token::ELLIPSIS, name_token); - *is_computed_name = true; - *is_rest_property = true; + prop_info->is_computed_name = true; + prop_info->is_rest = true; return factory()->NewObjectLiteralProperty( factory()->NewTheHoleLiteral(), name_expression, @@ -2568,21 +2284,27 @@ ParserBase<Impl>::ParseObjectPropertyDefinition(ObjectLiteralChecker* checker, case ParsePropertyKind::kValue: { DCHECK_EQ(function_flags, ParseFunctionFlag::kIsNormal); - if (!*is_computed_name) { - checker->CheckDuplicateProto(name_token); + if (!prop_info->is_computed_name && + impl()->IdentifierEquals(name, ast_value_factory()->proto_string())) { + if (*has_seen_proto) { + expression_scope()->RecordExpressionError( + scanner()->location(), MessageTemplate::kDuplicateProto); + } + *has_seen_proto = true; } Consume(Token::COLON); - int beg_pos = peek_position(); + AcceptINScope scope(this, true); ExpressionT value = - ParseAssignmentExpression(true, CHECK_OK_CUSTOM(NullLiteralProperty)); - CheckDestructuringElement(value, beg_pos, end_position()); + ParsePossibleDestructuringSubPattern(prop_info->accumulation_scope); ObjectLiteralPropertyT result = factory()->NewObjectLiteralProperty( - name_expression, value, *is_computed_name); + name_expression, value, prop_info->is_computed_name); impl()->SetFunctionNameFromPropertyName(result, name); return result; } + case ParsePropertyKind::kAssign: + case ParsePropertyKind::kShorthandOrClassField: case ParsePropertyKind::kShorthand: { // PropertyDefinition // IdentifierReference @@ -2592,56 +2314,43 @@ ParserBase<Impl>::ParseObjectPropertyDefinition(ObjectLiteralChecker* checker, // IdentifierReference Initializer? DCHECK_EQ(function_flags, ParseFunctionFlag::kIsNormal); - if (!Token::IsIdentifier(name_token, language_mode(), - this->is_generator(), - parsing_module_ || is_async_function())) { + if (!Token::IsValidIdentifier(name_token, language_mode(), is_generator(), + parsing_module_ || is_async_function())) { ReportUnexpectedToken(Next()); - *ok = false; return impl()->NullLiteralProperty(); } - DCHECK(!*is_computed_name); - - if (classifier()->duplicate_finder() != nullptr && - scanner()->IsDuplicateSymbol(classifier()->duplicate_finder(), - ast_value_factory())) { - classifier()->RecordDuplicateFormalParameterError( - scanner()->location()); - } - - if (impl()->IsEvalOrArguments(name) && is_strict(language_mode())) { - classifier()->RecordBindingPatternError( - scanner()->location(), MessageTemplate::kStrictEvalArguments); - } + DCHECK(!prop_info->is_computed_name); if (name_token == Token::LET) { - classifier()->RecordLetPatternError( + expression_scope()->RecordLexicalDeclarationError( scanner()->location(), MessageTemplate::kLetInLexicalBinding); } if (name_token == Token::AWAIT) { DCHECK(!is_async_function()); - classifier()->RecordAsyncArrowFormalParametersError( - Scanner::Location(next_beg_pos, next_end_pos), - MessageTemplate::kAwaitBindingIdentifier); + expression_scope()->RecordAsyncArrowParametersError( + next_loc, MessageTemplate::kAwaitBindingIdentifier); + } + ExpressionT lhs = + impl()->ExpressionFromIdentifier(name, next_loc.beg_pos); + if (!IsAssignableIdentifier(lhs)) { + expression_scope()->RecordPatternError( + next_loc, MessageTemplate::kStrictEvalArguments); } - ExpressionT lhs = impl()->ExpressionFromIdentifier(name, next_beg_pos); - CheckDestructuringElement(lhs, next_beg_pos, next_end_pos); ExpressionT value; if (peek() == Token::ASSIGN) { Consume(Token::ASSIGN); - ExpressionClassifier rhs_classifier(this); - ExpressionT rhs = ParseAssignmentExpression( - true, CHECK_OK_CUSTOM(NullLiteralProperty)); - ValidateExpression(CHECK_OK_CUSTOM(NullLiteralProperty)); - AccumulateFormalParameterContainmentErrors(); - value = factory()->NewAssignment(Token::ASSIGN, lhs, rhs, - kNoSourcePosition); - classifier()->RecordExpressionError( - Scanner::Location(next_beg_pos, end_position()), + { + AcceptINScope scope(this, true); + ExpressionT rhs = ParseAssignmentExpression(); + value = factory()->NewAssignment(Token::ASSIGN, lhs, rhs, + kNoSourcePosition); + impl()->SetFunctionNameFromIdentifierRef(rhs, lhs); + } + expression_scope()->RecordExpressionError( + Scanner::Location(next_loc.beg_pos, end_position()), MessageTemplate::kInvalidCoverInitializedName); - - impl()->SetFunctionNameFromIdentifierRef(rhs, lhs); } else { value = lhs; } @@ -2657,20 +2366,20 @@ ParserBase<Impl>::ParseObjectPropertyDefinition(ObjectLiteralChecker* checker, // PropertyName '(' StrictFormalParameters ')' '{' FunctionBody '}' // '*' PropertyName '(' StrictFormalParameters ')' '{' FunctionBody '}' - classifier()->RecordPatternError( - Scanner::Location(next_beg_pos, end_position()), + expression_scope()->RecordPatternError( + Scanner::Location(next_loc.beg_pos, end_position()), MessageTemplate::kInvalidDestructuringTarget); FunctionKind kind = MethodKindFor(function_flags); ExpressionT value = impl()->ParseFunctionLiteral( name, scanner()->location(), kSkipFunctionNameCheck, kind, - next_beg_pos, FunctionLiteral::kAccessorOrMethod, language_mode(), - nullptr, CHECK_OK_CUSTOM(NullLiteralProperty)); + next_loc.beg_pos, FunctionLiteral::kAccessorOrMethod, language_mode(), + nullptr); ObjectLiteralPropertyT result = factory()->NewObjectLiteralProperty( name_expression, value, ObjectLiteralProperty::COMPUTED, - *is_computed_name); + prop_info->is_computed_name); impl()->SetFunctionNameFromPropertyName(result, name); return result; } @@ -2680,11 +2389,11 @@ ParserBase<Impl>::ParseObjectPropertyDefinition(ObjectLiteralChecker* checker, DCHECK_EQ(function_flags, ParseFunctionFlag::kIsNormal); bool is_get = kind == ParsePropertyKind::kAccessorGetter; - classifier()->RecordPatternError( - Scanner::Location(next_beg_pos, end_position()), + expression_scope()->RecordPatternError( + Scanner::Location(next_loc.beg_pos, end_position()), MessageTemplate::kInvalidDestructuringTarget); - if (!*is_computed_name) { + if (!prop_info->is_computed_name) { // Make sure the name expression is a string since we need a Name for // Runtime_DefineAccessorPropertyUnchecked and since we can determine // this statically we can skip the extra runtime check. @@ -2697,14 +2406,14 @@ ParserBase<Impl>::ParseObjectPropertyDefinition(ObjectLiteralChecker* checker, FunctionLiteralT value = impl()->ParseFunctionLiteral( name, scanner()->location(), kSkipFunctionNameCheck, kind, - next_beg_pos, FunctionLiteral::kAccessorOrMethod, language_mode(), - nullptr, CHECK_OK_CUSTOM(NullLiteralProperty)); + next_loc.beg_pos, FunctionLiteral::kAccessorOrMethod, language_mode(), + nullptr); ObjectLiteralPropertyT result = factory()->NewObjectLiteralProperty( name_expression, value, is_get ? ObjectLiteralProperty::GETTER : ObjectLiteralProperty::SETTER, - *is_computed_name); + prop_info->is_computed_name); const AstRawString* prefix = is_get ? ast_value_factory()->get_space_string() : ast_value_factory()->set_space_string(); @@ -2715,42 +2424,41 @@ ParserBase<Impl>::ParseObjectPropertyDefinition(ObjectLiteralChecker* checker, case ParsePropertyKind::kClassField: case ParsePropertyKind::kNotSet: ReportUnexpectedToken(Next()); - *ok = false; return impl()->NullLiteralProperty(); } UNREACHABLE(); } template <typename Impl> -typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseObjectLiteral( - bool* ok) { +typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseObjectLiteral() { // ObjectLiteral :: // '{' (PropertyDefinition (',' PropertyDefinition)* ','? )? '}' int pos = peek_position(); - typename Types::ObjectPropertyList properties = - impl()->NewObjectPropertyList(4); + ObjectPropertyListT properties(pointer_buffer()); int number_of_boilerplate_properties = 0; bool has_computed_names = false; bool has_rest_property = false; - ObjectLiteralChecker checker(this); + bool has_seen_proto = false; Consume(Token::LBRACE); + AccumulationScope accumulation_scope(expression_scope()); while (!Check(Token::RBRACE)) { FuncNameInferrerState fni_state(&fni_); - bool is_computed_name = false; - bool is_rest_property = false; - ObjectLiteralPropertyT property = ParseObjectPropertyDefinition( - &checker, &is_computed_name, &is_rest_property, CHECK_OK); + ParsePropertyInfo prop_info(this, &accumulation_scope); + prop_info.position = PropertyPosition::kObjectLiteral; + ObjectLiteralPropertyT property = + ParseObjectPropertyDefinition(&prop_info, &has_seen_proto); + if (impl()->IsNull(property)) return impl()->FailureExpression(); - if (is_computed_name) { + if (prop_info.is_computed_name) { has_computed_names = true; } - if (is_rest_property) { + if (prop_info.is_rest) { has_rest_property = true; } @@ -2760,11 +2468,10 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseObjectLiteral( number_of_boilerplate_properties++; } - properties->Add(property, zone()); + properties.Add(property); if (peek() != Token::RBRACE) { - // Need {} because of the CHECK_OK macro. - Expect(Token::COMMA, CHECK_OK); + Expect(Token::COMMA); } fni_.Infer(); @@ -2775,8 +2482,8 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseObjectLiteral( // this runtime function. Here, we make sure that the number of // properties is less than number of arguments allowed for a runtime // call. - if (has_rest_property && properties->length() > Code::kMaxArguments) { - this->classifier()->RecordPatternError(Scanner::Location(pos, position()), + if (has_rest_property && properties.length() > Code::kMaxArguments) { + expression_scope()->RecordPatternError(Scanner::Location(pos, position()), MessageTemplate::kTooManyArguments); } @@ -2785,78 +2492,61 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseObjectLiteral( } template <typename Impl> -typename ParserBase<Impl>::ExpressionListT ParserBase<Impl>::ParseArguments( - Scanner::Location* first_spread_arg_loc, bool maybe_arrow, - bool* is_simple_parameter_list, bool* ok) { +void ParserBase<Impl>::ParseArguments( + typename ParserBase<Impl>::ExpressionListT* args, bool* has_spread, + ParsingArrowHeadFlag maybe_arrow) { // Arguments :: // '(' (AssignmentExpression)*[','] ')' - Scanner::Location spread_arg = Scanner::Location::invalid(); - ExpressionListT result = impl()->NewExpressionList(4); - Expect(Token::LPAREN, CHECK_OK_CUSTOM(NullExpressionList)); + *has_spread = false; + Consume(Token::LPAREN); + AccumulationScope accumulation_scope(expression_scope()); + while (peek() != Token::RPAREN) { int start_pos = peek_position(); bool is_spread = Check(Token::ELLIPSIS); int expr_pos = peek_position(); - ExpressionT argument = - ParseAssignmentExpression(true, CHECK_OK_CUSTOM(NullExpressionList)); - if (!impl()->IsIdentifier(argument)) *is_simple_parameter_list = false; + AcceptINScope scope(this, true); + ExpressionT argument = ParseAssignmentExpressionCoverGrammar(); - if (!maybe_arrow) { - ValidateExpression(CHECK_OK_CUSTOM(NullExpressionList)); + if (V8_UNLIKELY(maybe_arrow == kMaybeArrowHead)) { + ClassifyArrowParameter(&accumulation_scope, expr_pos, argument); + if (is_spread) { + expression_scope()->RecordNonSimpleParameter(); + if (argument->IsAssignment()) { + expression_scope()->RecordAsyncArrowParametersError( + scanner()->location(), MessageTemplate::kRestDefaultInitializer); + } + if (peek() == Token::COMMA) { + expression_scope()->RecordAsyncArrowParametersError( + scanner()->peek_location(), MessageTemplate::kParamAfterRest); + } + } } if (is_spread) { - *is_simple_parameter_list = false; - if (!spread_arg.IsValid()) { - spread_arg.beg_pos = start_pos; - spread_arg.end_pos = peek_position(); - } - if (argument->IsAssignment()) { - classifier()->RecordAsyncArrowFormalParametersError( - scanner()->location(), MessageTemplate::kRestDefaultInitializer); - } + *has_spread = true; argument = factory()->NewSpread(argument, start_pos, expr_pos); } - result->Add(argument, zone_); - - if (peek() != Token::COMMA) break; - - Next(); - - if (argument->IsSpread()) { - classifier()->RecordAsyncArrowFormalParametersError( - scanner()->location(), MessageTemplate::kParamAfterRest); - } + args->Add(argument); + if (!Check(Token::COMMA)) break; } - if (result->length() > Code::kMaxArguments) { + if (args->length() > Code::kMaxArguments) { ReportMessage(MessageTemplate::kTooManyArguments); - *ok = false; - return impl()->NullExpressionList(); + return; } Scanner::Location location = scanner_->location(); - if (Token::RPAREN != Next()) { + if (!Check(Token::RPAREN)) { impl()->ReportMessageAt(location, MessageTemplate::kUnterminatedArgList); - *ok = false; - return impl()->NullExpressionList(); - } - *first_spread_arg_loc = spread_arg; - - if (!maybe_arrow || peek() != Token::ARROW) { - if (maybe_arrow) { - ValidateExpression(CHECK_OK_CUSTOM(NullExpressionList)); - } } - - return result; } // Precedence = 2 template <typename Impl> typename ParserBase<Impl>::ExpressionT -ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN, bool* ok) { +ParserBase<Impl>::ParseAssignmentExpressionCoverGrammar() { // AssignmentExpression :: // ConditionalExpression // ArrowFunction @@ -2865,188 +2555,120 @@ ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN, bool* ok) { int lhs_beg_pos = peek_position(); if (peek() == Token::YIELD && is_generator()) { - return ParseYieldExpression(accept_IN, ok); + return ParseYieldExpression(); } FuncNameInferrerState fni_state(&fni_); - ExpressionClassifier arrow_formals_classifier( - this, classifier()->duplicate_finder()); - Scope::Snapshot scope_snapshot(scope()); - int rewritable_length = static_cast<int>( - function_state_->destructuring_assignments_to_rewrite().size()); + DCHECK_IMPLIES(!has_error(), next_arrow_function_info_.HasInitialState()); - bool is_async = peek() == Token::ASYNC && - !scanner()->HasLineTerminatorAfterNext() && - IsValidArrowFormalParametersStart(PeekAhead()); + ExpressionT expression = ParseConditionalExpression(); - bool parenthesized_formals = peek() == Token::LPAREN; - if (!is_async && !parenthesized_formals) { - ArrowFormalParametersUnexpectedToken(); - } - - // Parse a simple, faster sub-grammar (primary expression) if it's evident - // that we have only a trivial expression to parse. - ExpressionT expression; - if (IsTrivialExpression()) { - expression = ParsePrimaryExpression(&is_async, CHECK_OK); - } else { - expression = ParseConditionalExpression(accept_IN, CHECK_OK); - } + Token::Value op = peek(); - if (is_async && impl()->IsIdentifier(expression) && peek_any_identifier() && - PeekAhead() == Token::ARROW) { - // async Identifier => AsyncConciseBody - IdentifierT name = ParseAndClassifyIdentifier(CHECK_OK); - expression = - impl()->ExpressionFromIdentifier(name, position(), InferName::kNo); - // Remove `async` keyword from inferred name stack. - fni_.RemoveAsyncKeywordFromEnd(); - } - - if (peek() == Token::ARROW) { - Scanner::Location arrow_loc = scanner()->peek_location(); - ValidateArrowFormalParameters(expression, parenthesized_formals, is_async, - CHECK_OK); - // This reads strangely, but is correct: it checks whether any - // sub-expression of the parameter list failed to be a valid formal - // parameter initializer. Since YieldExpressions are banned anywhere - // in an arrow parameter list, this is correct. - // TODO(adamk): Rename "FormalParameterInitializerError" to refer to - // "YieldExpression", which is its only use. - ValidateFormalParameterInitializer(CHECK_OK); + if (!Token::IsArrowOrAssignmentOp(op)) return expression; + // Arrow functions. + if (V8_UNLIKELY(op == Token::ARROW)) { Scanner::Location loc(lhs_beg_pos, end_position()); - DeclarationScope* scope = - NewFunctionScope(is_async ? FunctionKind::kAsyncArrowFunction - : FunctionKind::kArrowFunction); - // Because the arrow's parameters were parsed in the outer scope, - // we need to fix up the scope chain appropriately. - scope_snapshot.Reparent(scope); - - FormalParametersT parameters(scope); - if (!classifier()->is_simple_parameter_list()) { - scope->SetHasNonSimpleParameters(); - parameters.is_simple = false; + if (!impl()->IsIdentifier(expression) && !expression->is_parenthesized()) { + impl()->ReportMessageAt( + Scanner::Location(expression->position(), position()), + MessageTemplate::kMalformedArrowFunParamList); + return impl()->FailureExpression(); } + DeclarationScope* scope = next_arrow_function_info_.scope; scope->set_start_position(lhs_beg_pos); - Scanner::Location duplicate_loc = Scanner::Location::invalid(); - impl()->DeclareArrowFunctionFormalParameters(¶meters, expression, loc, - &duplicate_loc, CHECK_OK); - if (duplicate_loc.IsValid()) { - classifier()->RecordDuplicateFormalParameterError(duplicate_loc); - } - expression = ParseArrowFunctionLiteral(accept_IN, parameters, - rewritable_length, CHECK_OK); - Accumulate(ExpressionClassifier::AsyncArrowFormalParametersProduction); - classifier()->RecordPatternError(arrow_loc, - MessageTemplate::kUnexpectedToken, - Token::String(Token::ARROW)); - fni_.Infer(); - - return expression; - } + FormalParametersT parameters(scope); + parameters.set_strict_parameter_error( + next_arrow_function_info_.strict_parameter_error_location, + next_arrow_function_info_.strict_parameter_error_message); + parameters.is_simple = scope->has_simple_parameters(); + next_arrow_function_info_.Reset(); - // "expression" was not itself an arrow function parameter list, but it might - // form part of one. Propagate speculative formal parameter error locations - // (including those for binding patterns, since formal parameters can - // themselves contain binding patterns). - unsigned productions = ExpressionClassifier::AllProductions & - ~ExpressionClassifier::ArrowFormalParametersProduction; + impl()->DeclareArrowFunctionFormalParameters(¶meters, expression, loc); - // Parenthesized identifiers and property references are allowed as part - // of a larger assignment pattern, even though parenthesized patterns - // themselves are not allowed, e.g., "[(x)] = []". Only accumulate - // assignment pattern errors if the parsed expression is more complex. - if (IsValidReferenceExpression(expression)) { - productions &= ~ExpressionClassifier::AssignmentPatternProduction; - } + expression = ParseArrowFunctionLiteral(parameters); - const bool is_destructuring_assignment = - IsValidPattern(expression) && peek() == Token::ASSIGN; - if (is_destructuring_assignment) { - // This is definitely not an expression so don't accumulate - // expression-related errors. - productions &= ~ExpressionClassifier::ExpressionProduction; + return expression; } - Accumulate(productions); - if (!Token::IsAssignmentOp(peek())) return expression; - - if (is_destructuring_assignment) { - ValidateAssignmentPattern(CHECK_OK); + if (V8_LIKELY(impl()->IsAssignableIdentifier(expression))) { + if (expression->is_parenthesized()) { + expression_scope()->RecordDeclarationError( + Scanner::Location(lhs_beg_pos, end_position()), + MessageTemplate::kInvalidDestructuringTarget); + } + expression_scope()->MarkIdentifierAsAssigned(); + } else if (expression->IsProperty()) { + expression_scope()->RecordDeclarationError( + Scanner::Location(lhs_beg_pos, end_position()), + MessageTemplate::kInvalidPropertyBindingPattern); + } else if (expression->IsPattern() && op == Token::ASSIGN) { + // Destructuring assignmment. + if (expression->is_parenthesized()) { + expression_scope()->RecordPatternError( + Scanner::Location(lhs_beg_pos, end_position()), + MessageTemplate::kInvalidDestructuringTarget); + } + expression_scope()->ValidateAsPattern(expression, lhs_beg_pos, + end_position()); } else { - expression = CheckAndRewriteReferenceExpression( + DCHECK(!IsValidReferenceExpression(expression)); + expression = RewriteInvalidReferenceExpression( expression, lhs_beg_pos, end_position(), - MessageTemplate::kInvalidLhsInAssignment, CHECK_OK); + MessageTemplate::kInvalidLhsInAssignment); } - impl()->MarkExpressionAsAssigned(expression); + Consume(op); + int op_position = position(); - Token::Value op = Next(); // Get assignment operator. - if (op != Token::ASSIGN) { - classifier()->RecordPatternError(scanner()->location(), - MessageTemplate::kUnexpectedToken, - Token::String(op)); - } - int pos = position(); - - ExpressionClassifier rhs_classifier(this); + ExpressionT right = ParseAssignmentExpression(); - ExpressionT right = ParseAssignmentExpression(accept_IN, CHECK_OK); - ValidateExpression(CHECK_OK); - AccumulateFormalParameterContainmentErrors(); - - // We try to estimate the set of properties set by constructors. We define a - // new property whenever there is an assignment to a property of 'this'. We - // should probably only add properties if we haven't seen them - // before. Otherwise we'll probably overestimate the number of properties. - if (op == Token::ASSIGN && impl()->IsThisProperty(expression)) { - function_state_->AddProperty(); - } - - impl()->CheckAssigningFunctionLiteralToProperty(expression, right); + if (op == Token::ASSIGN) { + // We try to estimate the set of properties set by constructors. We define a + // new property whenever there is an assignment to a property of 'this'. We + // should probably only add properties if we haven't seen them before. + // Otherwise we'll probably overestimate the number of properties. + if (impl()->IsThisProperty(expression)) function_state_->AddProperty(); + + impl()->CheckAssigningFunctionLiteralToProperty(expression, right); + + // Check if the right hand side is a call to avoid inferring a + // name if we're dealing with "a = function(){...}();"-like + // expression. + if (right->IsCall() || right->IsCallNew()) { + fni_.RemoveLastFunction(); + } else { + fni_.Infer(); + } - // Check if the right hand side is a call to avoid inferring a - // name if we're dealing with "a = function(){...}();"-like - // expression. - if (op == Token::ASSIGN && !right->IsCall() && !right->IsCallNew()) { - fni_.Infer(); + impl()->SetFunctionNameFromIdentifierRef(right, expression); } else { + expression_scope()->RecordPatternError( + Scanner::Location(lhs_beg_pos, end_position()), + MessageTemplate::kInvalidDestructuringTarget); fni_.RemoveLastFunction(); } - if (op == Token::ASSIGN) { - impl()->SetFunctionNameFromIdentifierRef(right, expression); - } - - DCHECK_NE(op, Token::INIT); - ExpressionT result = factory()->NewAssignment(op, expression, right, pos); - - if (is_destructuring_assignment) { - DCHECK_NE(op, Token::ASSIGN_EXP); - auto rewritable = factory()->NewRewritableExpression(result, scope()); - impl()->QueueDestructuringAssignmentForRewriting(rewritable); - result = rewritable; - } - - return result; + return factory()->NewAssignment(op, expression, right, op_position); } template <typename Impl> -typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseYieldExpression( - bool accept_IN, bool* ok) { +typename ParserBase<Impl>::ExpressionT +ParserBase<Impl>::ParseYieldExpression() { // YieldExpression :: // 'yield' ([no line terminator] '*'? AssignmentExpression)? int pos = peek_position(); - classifier()->RecordPatternError( - scanner()->peek_location(), MessageTemplate::kInvalidDestructuringTarget); - classifier()->RecordFormalParameterInitializerError( + expression_scope()->RecordParameterInitializerError( scanner()->peek_location(), MessageTemplate::kYieldInParameter); - Expect(Token::YIELD, CHECK_OK); + Consume(Token::YIELD); + + CheckStackOverflow(); + // The following initialization is necessary. ExpressionT expression = impl()->NullExpression(); bool delegating = false; // yield* @@ -3069,8 +2691,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseYieldExpression( // Delegating yields require an RHS; fall through. V8_FALLTHROUGH; default: - expression = ParseAssignmentExpression(accept_IN, CHECK_OK); - ValidateExpression(CHECK_OK); + expression = ParseAssignmentExpressionCoverGrammar(); break; } } @@ -3099,80 +2720,65 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseYieldExpression( // Precedence = 3 template <typename Impl> typename ParserBase<Impl>::ExpressionT -ParserBase<Impl>::ParseConditionalExpression(bool accept_IN, - bool* ok) { +ParserBase<Impl>::ParseConditionalExpression() { // ConditionalExpression :: // LogicalOrExpression // LogicalOrExpression '?' AssignmentExpression ':' AssignmentExpression int pos = peek_position(); // We start using the binary expression parser for prec >= 4 only! - ExpressionT expression = ParseBinaryExpression(4, accept_IN, CHECK_OK); + ExpressionT expression = ParseBinaryExpression(4); return peek() == Token::CONDITIONAL - ? ParseConditionalContinuation(expression, accept_IN, pos, ok) + ? ParseConditionalContinuation(expression, pos) : expression; } template <typename Impl> typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseConditionalContinuation(ExpressionT expression, - bool accept_IN, int pos, - bool* ok) { + int pos) { SourceRange then_range, else_range; - ValidateExpression(CHECK_OK); - BindingPatternUnexpectedToken(); - ArrowFormalParametersUnexpectedToken(); ExpressionT left; { SourceRangeScope range_scope(scanner(), &then_range); Consume(Token::CONDITIONAL); - ExpressionClassifier classifier(this); // In parsing the first assignment expression in conditional // expressions we always accept the 'in' keyword; see ECMA-262, // section 11.12, page 58. - left = ParseAssignmentExpression(true, CHECK_OK); - AccumulateNonBindingPatternErrors(); + AcceptINScope scope(this, true); + left = ParseAssignmentExpression(); } - ValidateExpression(CHECK_OK); ExpressionT right; { SourceRangeScope range_scope(scanner(), &else_range); - Expect(Token::COLON, CHECK_OK); - ExpressionClassifier classifier(this); - right = ParseAssignmentExpression(accept_IN, CHECK_OK); - AccumulateNonBindingPatternErrors(); + Expect(Token::COLON); + right = ParseAssignmentExpression(); } - ValidateExpression(CHECK_OK); ExpressionT expr = factory()->NewConditional(expression, left, right, pos); impl()->RecordConditionalSourceRange(expr, then_range, else_range); return expr; } - // Precedence >= 4 template <typename Impl> -typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseBinaryExpression( - int prec, bool accept_IN, bool* ok) { - DCHECK_GE(prec, 4); - SourceRange right_range; - ExpressionT x = ParseUnaryExpression(CHECK_OK); - for (int prec1 = Precedence(peek(), accept_IN); prec1 >= prec; prec1--) { +typename ParserBase<Impl>::ExpressionT +ParserBase<Impl>::ParseBinaryContinuation(ExpressionT x, int prec, int prec1) { + do { // prec1 >= 4 - while (Precedence(peek(), accept_IN) == prec1) { - ValidateExpression(CHECK_OK); - BindingPatternUnexpectedToken(); - ArrowFormalParametersUnexpectedToken(); - - SourceRangeScope right_range_scope(scanner(), &right_range); - Token::Value op = Next(); - int pos = position(); - - const bool is_right_associative = op == Token::EXP; - const int next_prec = is_right_associative ? prec1 : prec1 + 1; - ExpressionT y = ParseBinaryExpression(next_prec, accept_IN, CHECK_OK); - right_range_scope.Finalize(); - ValidateExpression(CHECK_OK); + while (Token::Precedence(peek(), accept_IN_) == prec1) { + SourceRange right_range; + int pos = peek_position(); + ExpressionT y; + Token::Value op; + { + SourceRangeScope right_range_scope(scanner(), &right_range); + op = Next(); + + const bool is_right_associative = op == Token::EXP; + const int next_prec = is_right_associative ? prec1 : prec1 + 1; + y = ParseBinaryExpression(next_prec); + } // For now we distinguish between comparisons and other binary // operations. (We could combine the two and get rid of this @@ -3200,16 +2806,28 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseBinaryExpression( } } } - } + --prec1; + } while (prec1 >= prec); + return x; } +// Precedence >= 4 template <typename Impl> -typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseUnaryOpExpression( - bool* ok) { - BindingPatternUnexpectedToken(); - ArrowFormalParametersUnexpectedToken(); +typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseBinaryExpression( + int prec) { + DCHECK_GE(prec, 4); + ExpressionT x = ParseUnaryExpression(); + int prec1 = Token::Precedence(peek(), accept_IN_); + if (prec1 >= prec) { + return ParseBinaryContinuation(x, prec, prec1); + } + return x; +} +template <typename Impl> +typename ParserBase<Impl>::ExpressionT +ParserBase<Impl>::ParseUnaryOrPrefixExpression() { Token::Value op = Next(); int pos = position(); @@ -3218,66 +2836,64 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseUnaryOpExpression( function_state_->set_next_function_is_likely_called(); } - ExpressionT expression = ParseUnaryExpression(CHECK_OK); - ValidateExpression(CHECK_OK); + CheckStackOverflow(); + + int expression_position = peek_position(); + ExpressionT expression = ParseUnaryExpression(); + + if (Token::IsUnaryOp(op)) { + if (op == Token::DELETE) { + if (impl()->IsIdentifier(expression) && is_strict(language_mode())) { + // "delete identifier" is a syntax error in strict mode. + ReportMessage(MessageTemplate::kStrictDelete); + return impl()->FailureExpression(); + } - if (op == Token::DELETE) { - if (impl()->IsIdentifier(expression) && is_strict(language_mode())) { - // "delete identifier" is a syntax error in strict mode. - ReportMessage(MessageTemplate::kStrictDelete); - *ok = false; - return impl()->NullExpression(); + if (impl()->IsPropertyWithPrivateFieldKey(expression)) { + ReportMessage(MessageTemplate::kDeletePrivateField); + return impl()->FailureExpression(); + } } - if (impl()->IsPropertyWithPrivateFieldKey(expression)) { - ReportMessage(MessageTemplate::kDeletePrivateField); - *ok = false; - return impl()->NullExpression(); + if (peek() == Token::EXP) { + impl()->ReportMessageAt( + Scanner::Location(pos, peek_end_position()), + MessageTemplate::kUnexpectedTokenUnaryExponentiation); + return impl()->FailureExpression(); } - } - if (peek() == Token::EXP) { - ReportUnexpectedToken(Next()); - *ok = false; - return impl()->NullExpression(); + // Allow the parser's implementation to rewrite the expression. + return impl()->BuildUnaryExpression(expression, op, pos); } - // Allow the parser's implementation to rewrite the expression. - return impl()->BuildUnaryExpression(expression, op, pos); -} + DCHECK(Token::IsCountOp(op)); -template <typename Impl> -typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePrefixExpression( - bool* ok) { - BindingPatternUnexpectedToken(); - ArrowFormalParametersUnexpectedToken(); - Token::Value op = Next(); - int beg_pos = peek_position(); - ExpressionT expression = ParseUnaryExpression(CHECK_OK); - expression = CheckAndRewriteReferenceExpression( - expression, beg_pos, end_position(), - MessageTemplate::kInvalidLhsInPrefixOp, CHECK_OK); - impl()->MarkExpressionAsAssigned(expression); - ValidateExpression(CHECK_OK); + if (V8_LIKELY(IsValidReferenceExpression(expression))) { + if (impl()->IsIdentifier(expression)) { + expression_scope()->MarkIdentifierAsAssigned(); + } + } else { + expression = RewriteInvalidReferenceExpression( + expression, expression_position, end_position(), + MessageTemplate::kInvalidLhsInPrefixOp); + } return factory()->NewCountOperation(op, true /* prefix */, expression, position()); } template <typename Impl> -typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseAwaitExpression( - bool* ok) { - classifier()->RecordFormalParameterInitializerError( +typename ParserBase<Impl>::ExpressionT +ParserBase<Impl>::ParseAwaitExpression() { + expression_scope()->RecordParameterInitializerError( scanner()->peek_location(), MessageTemplate::kAwaitExpressionFormalParameter); int await_pos = peek_position(); Consume(Token::AWAIT); - ExpressionT value = ParseUnaryExpression(CHECK_OK); + CheckStackOverflow(); - classifier()->RecordBindingPatternError( - Scanner::Location(await_pos, end_position()), - MessageTemplate::kInvalidDestructuringTarget); + ExpressionT value = ParseUnaryExpression(); ExpressionT expr = factory()->NewAwait(value, await_pos); function_state_->AddSuspend(); @@ -3286,8 +2902,8 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseAwaitExpression( } template <typename Impl> -typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseUnaryExpression( - bool* ok) { +typename ParserBase<Impl>::ExpressionT +ParserBase<Impl>::ParseUnaryExpression() { // UnaryExpression :: // PostfixExpression // 'delete' UnaryExpression @@ -3302,31 +2918,30 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseUnaryExpression( // [+Await] AwaitExpression[?Yield] Token::Value op = peek(); - if (Token::IsUnaryOp(op)) return ParseUnaryOpExpression(ok); - if (Token::IsCountOp(op)) return ParsePrefixExpression(ok); + if (Token::IsUnaryOrCountOp(op)) return ParseUnaryOrPrefixExpression(); if (is_async_function() && op == Token::AWAIT) { - return ParseAwaitExpression(ok); + return ParseAwaitExpression(); } - return ParsePostfixExpression(ok); + return ParsePostfixExpression(); } template <typename Impl> -typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePostfixExpression( - bool* ok) { +typename ParserBase<Impl>::ExpressionT +ParserBase<Impl>::ParsePostfixExpression() { // PostfixExpression :: // LeftHandSideExpression ('++' | '--')? int lhs_beg_pos = peek_position(); - ExpressionT expression = ParseLeftHandSideExpression(CHECK_OK); + ExpressionT expression = ParseLeftHandSideExpression(); if (!scanner()->HasLineTerminatorBeforeNext() && Token::IsCountOp(peek())) { - BindingPatternUnexpectedToken(); - ArrowFormalParametersUnexpectedToken(); - - expression = CheckAndRewriteReferenceExpression( - expression, lhs_beg_pos, end_position(), - MessageTemplate::kInvalidLhsInPostfixOp, CHECK_OK); - impl()->MarkExpressionAsAssigned(expression); - ValidateExpression(CHECK_OK); + if (V8_UNLIKELY(!IsValidReferenceExpression(expression))) { + expression = RewriteInvalidReferenceExpression( + expression, lhs_beg_pos, end_position(), + MessageTemplate::kInvalidLhsInPostfixOp); + } + if (impl()->IsIdentifier(expression)) { + expression_scope()->MarkIdentifierAsAssigned(); + } Token::Value next = Next(); expression = @@ -3340,36 +2955,83 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePostfixExpression( template <typename Impl> typename ParserBase<Impl>::ExpressionT -ParserBase<Impl>::ParseLeftHandSideExpression(bool* ok) { +ParserBase<Impl>::ParseLeftHandSideExpression() { // LeftHandSideExpression :: // (NewExpression | MemberExpression) ... - bool is_async = false; - ExpressionT result = - ParseMemberWithNewPrefixesExpression(&is_async, CHECK_OK); + ExpressionT result = ParseMemberWithNewPrefixesExpression(); + if (!Token::IsPropertyOrCall(peek())) return result; + return ParseLeftHandSideContinuation(result); +} - while (true) { +template <typename Impl> +typename ParserBase<Impl>::ExpressionT +ParserBase<Impl>::ParseLeftHandSideContinuation(ExpressionT result) { + DCHECK(Token::IsPropertyOrCall(peek())); + + if (V8_UNLIKELY(peek() == Token::LPAREN && impl()->IsIdentifier(result) && + scanner()->current_token() == Token::ASYNC && + !scanner()->HasLineTerminatorBeforeNext())) { + DCHECK(impl()->IsAsync(impl()->AsIdentifier(result))); + int pos = position(); + + ArrowHeadParsingScope maybe_arrow(impl(), + FunctionKind::kAsyncArrowFunction); + Scope::Snapshot scope_snapshot(scope()); + + ExpressionListT args(pointer_buffer()); + bool has_spread; + ParseArguments(&args, &has_spread, kMaybeArrowHead); + if (V8_LIKELY(peek() == Token::ARROW)) { + fni_.RemoveAsyncKeywordFromEnd(); + next_arrow_function_info_.scope = maybe_arrow.ValidateAndCreateScope(); + scope_snapshot.Reparent(next_arrow_function_info_.scope); + // async () => ... + if (!args.length()) return factory()->NewEmptyParentheses(pos); + // async ( Arguments ) => ... + ExpressionT result = impl()->ExpressionListToExpression(args); + result->mark_parenthesized(); + return result; + } + + if (has_spread) { + result = impl()->SpreadCall(result, args, pos, Call::NOT_EVAL); + } else { + result = factory()->NewCall(result, args, pos, Call::NOT_EVAL); + } + + maybe_arrow.ValidateExpression(); + + fni_.RemoveLastFunction(); + if (!Token::IsPropertyOrCall(peek())) return result; + } + + do { switch (peek()) { + /* Property */ case Token::LBRACK: { - ValidateExpression(CHECK_OK); - BindingPatternUnexpectedToken(); - ArrowFormalParametersUnexpectedToken(); Consume(Token::LBRACK); int pos = position(); - ExpressionT index = ParseExpressionCoverGrammar(true, CHECK_OK); - ValidateExpression(CHECK_OK); + AcceptINScope scope(this, true); + ExpressionT index = ParseExpressionCoverGrammar(); result = factory()->NewProperty(result, index, pos); - Expect(Token::RBRACK, CHECK_OK); + Expect(Token::RBRACK); break; } + /* Property */ + case Token::PERIOD: { + Consume(Token::PERIOD); + int pos = position(); + ExpressionT key = ParsePropertyOrPrivatePropertyName(); + result = factory()->NewProperty(result, key, pos); + break; + } + + /* Call */ case Token::LPAREN: { int pos; - ValidateExpression(CHECK_OK); - BindingPatternUnexpectedToken(); - if (scanner()->current_token() == Token::IDENTIFIER || - scanner()->current_token() == Token::SUPER || - scanner()->current_token() == Token::ASYNC) { + if (Token::IsCallable(scanner()->current_token())) { // For call of an identifier we want to report position of // the identifier as position of the call in the stack trace. pos = position(); @@ -3385,43 +3047,16 @@ ParserBase<Impl>::ParseLeftHandSideExpression(bool* ok) { // function literal eagerly, we can also compile it eagerly. if (result->IsFunctionLiteral()) { result->AsFunctionLiteral()->SetShouldEagerCompile(); - result->AsFunctionLiteral()->mark_as_iife(); - } - } - Scanner::Location spread_pos; - ExpressionListT args; - if (V8_UNLIKELY(is_async && impl()->IsIdentifier(result))) { - ExpressionClassifier async_classifier(this); - bool is_simple_parameter_list = true; - args = ParseArguments(&spread_pos, true, &is_simple_parameter_list, - CHECK_OK); - if (peek() == Token::ARROW) { - fni_.RemoveAsyncKeywordFromEnd(); - ValidateBindingPattern(CHECK_OK); - ValidateFormalParameterInitializer(CHECK_OK); - if (!classifier()->is_valid_async_arrow_formal_parameters()) { - ReportClassifierError( - classifier()->async_arrow_formal_parameters_error()); - *ok = false; - return impl()->NullExpression(); - } - if (args->length()) { - // async ( Arguments ) => ... - if (!is_simple_parameter_list) { - async_classifier.previous()->RecordNonSimpleParameter(); - } - return impl()->ExpressionListToExpression(args); + if (scope()->is_script_scope()) { + // A non-top-level iife is likely to be executed multiple times + // and so shouldn`t be optimized as one-shot. + result->AsFunctionLiteral()->mark_as_oneshot_iife(); } - // async () => ... - return factory()->NewEmptyParentheses(pos); - } else { - AccumulateFormalParameterContainmentErrors(); } - } else { - args = ParseArguments(&spread_pos, CHECK_OK); } - - ArrowFormalParametersUnexpectedToken(); + bool has_spread; + ExpressionListT args(pointer_buffer()); + ParseArguments(&args, &has_spread); // Keep track of eval() calls since they disable all local variable // optimizations. @@ -3433,7 +3068,7 @@ ParserBase<Impl>::ParseLeftHandSideExpression(bool* ok) { Call::PossiblyEval is_possibly_eval = CheckPossibleEvalCall(result, scope()); - if (spread_pos.IsValid()) { + if (has_spread) { result = impl()->SpreadCall(result, args, pos, is_possibly_eval); } else { result = factory()->NewCall(result, args, pos, is_possibly_eval); @@ -3443,36 +3078,19 @@ ParserBase<Impl>::ParseLeftHandSideExpression(bool* ok) { break; } - case Token::PERIOD: { - ValidateExpression(CHECK_OK); - BindingPatternUnexpectedToken(); - ArrowFormalParametersUnexpectedToken(); - Consume(Token::PERIOD); - int pos = position(); - ExpressionT key = ParseIdentifierNameOrPrivateName(CHECK_OK); - result = factory()->NewProperty(result, key, pos); - break; - } - - case Token::TEMPLATE_SPAN: - case Token::TEMPLATE_TAIL: { - ValidateExpression(CHECK_OK); - BindingPatternUnexpectedToken(); - ArrowFormalParametersUnexpectedToken(); - result = ParseTemplateLiteral(result, position(), true, CHECK_OK); - break; - } - + /* Call */ default: - return result; + DCHECK(Token::IsTemplate(peek())); + result = ParseTemplateLiteral(result, position(), true); + break; } - } + } while (Token::IsPropertyOrCall(peek())); + return result; } template <typename Impl> typename ParserBase<Impl>::ExpressionT -ParserBase<Impl>::ParseMemberWithPresentNewPrefixesExpression(bool* is_async, - bool* ok) { +ParserBase<Impl>::ParseMemberWithPresentNewPrefixesExpression() { // NewExpression :: // ('new')+ MemberExpression // @@ -3492,57 +3110,94 @@ ParserBase<Impl>::ParseMemberWithPresentNewPrefixesExpression(bool* is_async, // new new foo means new (new foo) // new new foo() means new (new foo()) // new new foo().bar().baz means (new (new foo()).bar()).baz - BindingPatternUnexpectedToken(); - ArrowFormalParametersUnexpectedToken(); Consume(Token::NEW); int new_pos = position(); ExpressionT result; + + CheckStackOverflow(); + if (peek() == Token::SUPER) { const bool is_new = true; - result = ParseSuperExpression(is_new, CHECK_OK); + result = ParseSuperExpression(is_new); } else if (allow_harmony_dynamic_import() && peek() == Token::IMPORT && (!allow_harmony_import_meta() || PeekAhead() == Token::LPAREN)) { impl()->ReportMessageAt(scanner()->peek_location(), MessageTemplate::kImportCallNotNewExpression); - *ok = false; - return impl()->NullExpression(); + return impl()->FailureExpression(); } else if (peek() == Token::PERIOD) { - *is_async = false; - result = ParseNewTargetExpression(CHECK_OK); - return ParseMemberExpressionContinuation(result, is_async, ok); + result = ParseNewTargetExpression(); + return ParseMemberExpressionContinuation(result); } else { - result = ParseMemberWithNewPrefixesExpression(is_async, CHECK_OK); + result = ParseMemberWithNewPrefixesExpression(); } - ValidateExpression(CHECK_OK); if (peek() == Token::LPAREN) { // NewExpression with arguments. - Scanner::Location spread_pos; - ExpressionListT args = ParseArguments(&spread_pos, CHECK_OK); + { + ExpressionListT args(pointer_buffer()); + bool has_spread; + ParseArguments(&args, &has_spread); - if (spread_pos.IsValid()) { - result = impl()->SpreadCallNew(result, args, new_pos); - } else { - result = factory()->NewCallNew(result, args, new_pos); + if (has_spread) { + result = impl()->SpreadCallNew(result, args, new_pos); + } else { + result = factory()->NewCallNew(result, args, new_pos); + } } // The expression can still continue with . or [ after the arguments. - return ParseMemberExpressionContinuation(result, is_async, ok); + return ParseMemberExpressionContinuation(result); } // NewExpression without arguments. - return factory()->NewCallNew(result, impl()->NewExpressionList(0), new_pos); + ExpressionListT args(pointer_buffer()); + return factory()->NewCallNew(result, args, new_pos); +} + +template <typename Impl> +typename ParserBase<Impl>::ExpressionT +ParserBase<Impl>::ParseMemberWithNewPrefixesExpression() { + return peek() == Token::NEW ? ParseMemberWithPresentNewPrefixesExpression() + : ParseMemberExpression(); } template <typename Impl> typename ParserBase<Impl>::ExpressionT -ParserBase<Impl>::ParseMemberWithNewPrefixesExpression(bool* is_async, - bool* ok) { - return peek() == Token::NEW - ? ParseMemberWithPresentNewPrefixesExpression(is_async, ok) - : ParseMemberExpression(is_async, ok); +ParserBase<Impl>::ParseFunctionExpression() { + Consume(Token::FUNCTION); + int function_token_position = position(); + + FunctionKind function_kind = Check(Token::MUL) + ? FunctionKind::kGeneratorFunction + : FunctionKind::kNormalFunction; + IdentifierT name = impl()->NullIdentifier(); + bool is_strict_reserved_name = Token::IsStrictReservedWord(peek()); + Scanner::Location function_name_location = Scanner::Location::invalid(); + FunctionLiteral::FunctionType function_type = + FunctionLiteral::kAnonymousExpression; + if (impl()->ParsingDynamicFunctionDeclaration()) { + // We don't want dynamic functions to actually declare their name + // "anonymous". We just want that name in the toString(). + Consume(Token::IDENTIFIER); + DCHECK_IMPLIES(!has_error(), + scanner()->CurrentSymbol(ast_value_factory()) == + ast_value_factory()->anonymous_string()); + } else if (peek_any_identifier()) { + name = ParseIdentifier(function_kind); + function_name_location = scanner()->location(); + function_type = FunctionLiteral::kNamedExpression; + } + FunctionLiteralT result = impl()->ParseFunctionLiteral( + name, function_name_location, + is_strict_reserved_name ? kFunctionNameIsStrictReserved + : kFunctionNameValidityUnknown, + function_kind, function_token_position, function_type, language_mode(), + nullptr); + // TODO(verwaest): FailureFunctionLiteral? + if (impl()->IsNull(result)) return impl()->FailureExpression(); + return result; } template <typename Impl> -typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseMemberExpression( - bool* is_async, bool* ok) { +typename ParserBase<Impl>::ExpressionT +ParserBase<Impl>::ParseMemberExpression() { // MemberExpression :: // (PrimaryExpression | FunctionLiteral | ClassLiteral) // ('[' Expression ']' | '.' Identifier | Arguments | TemplateLiteral)* @@ -3558,99 +3213,60 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseMemberExpression( // Parse the initial primary or function expression. ExpressionT result; if (peek() == Token::FUNCTION) { - BindingPatternUnexpectedToken(); - ArrowFormalParametersUnexpectedToken(); - - Consume(Token::FUNCTION); - int function_token_position = position(); - - FunctionKind function_kind = Check(Token::MUL) - ? FunctionKind::kGeneratorFunction - : FunctionKind::kNormalFunction; - IdentifierT name = impl()->NullIdentifier(); - bool is_strict_reserved_name = false; - Scanner::Location function_name_location = Scanner::Location::invalid(); - FunctionLiteral::FunctionType function_type = - FunctionLiteral::kAnonymousExpression; - if (impl()->ParsingDynamicFunctionDeclaration()) { - // We don't want dynamic functions to actually declare their name - // "anonymous". We just want that name in the toString(). - if (stack_overflow()) { - *ok = false; - return impl()->NullExpression(); - } - Consume(Token::IDENTIFIER); - DCHECK(scanner()->CurrentMatchesContextual(Token::ANONYMOUS)); - } else if (peek_any_identifier()) { - bool is_await = false; - name = ParseIdentifierOrStrictReservedWord( - function_kind, &is_strict_reserved_name, &is_await, CHECK_OK); - function_name_location = scanner()->location(); - function_type = FunctionLiteral::kNamedExpression; - } - result = impl()->ParseFunctionLiteral( - name, function_name_location, - is_strict_reserved_name ? kFunctionNameIsStrictReserved - : kFunctionNameValidityUnknown, - function_kind, function_token_position, function_type, language_mode(), - nullptr, CHECK_OK); + result = ParseFunctionExpression(); } else if (peek() == Token::SUPER) { const bool is_new = false; - result = ParseSuperExpression(is_new, CHECK_OK); + result = ParseSuperExpression(is_new); } else if (allow_harmony_dynamic_import() && peek() == Token::IMPORT) { - result = ParseImportExpressions(CHECK_OK); + result = ParseImportExpressions(); } else { - result = ParsePrimaryExpression(is_async, CHECK_OK); + result = ParsePrimaryExpression(); } - return ParseMemberExpressionContinuation(result, is_async, ok); + return ParseMemberExpressionContinuation(result); } template <typename Impl> -typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseImportExpressions( - bool* ok) { +typename ParserBase<Impl>::ExpressionT +ParserBase<Impl>::ParseImportExpressions() { DCHECK(allow_harmony_dynamic_import()); - classifier()->RecordPatternError(scanner()->peek_location(), - MessageTemplate::kUnexpectedToken, - Token::String(Token::IMPORT)); - Consume(Token::IMPORT); int pos = position(); if (allow_harmony_import_meta() && peek() == Token::PERIOD) { - ExpectMetaProperty(Token::META, "import.meta", pos, CHECK_OK); + ExpectMetaProperty(ast_value_factory()->meta_string(), "import.meta", pos); if (!parsing_module_) { impl()->ReportMessageAt(scanner()->location(), MessageTemplate::kImportMetaOutsideModule); - *ok = false; - return impl()->NullExpression(); + return impl()->FailureExpression(); } return impl()->ImportMetaExpression(pos); } - Expect(Token::LPAREN, CHECK_OK); + Expect(Token::LPAREN); if (peek() == Token::RPAREN) { impl()->ReportMessageAt(scanner()->location(), MessageTemplate::kImportMissingSpecifier); - *ok = false; - return impl()->NullExpression(); + return impl()->FailureExpression(); } - ExpressionT arg = ParseAssignmentExpression(true, CHECK_OK); - Expect(Token::RPAREN, CHECK_OK); + AcceptINScope scope(this, true); + ExpressionT arg = ParseAssignmentExpressionCoverGrammar(); + Expect(Token::RPAREN); + return factory()->NewImportCallExpression(arg, pos); } template <typename Impl> typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseSuperExpression( - bool is_new, bool* ok) { - Expect(Token::SUPER, CHECK_OK); + bool is_new) { + Consume(Token::SUPER); int pos = position(); DeclarationScope* scope = GetReceiverScope(); FunctionKind kind = scope->function_kind(); if (IsConciseMethod(kind) || IsAccessorFunction(kind) || IsClassConstructor(kind)) { - if (peek() == Token::PERIOD || peek() == Token::LBRACK) { + if (Token::IsProperty(peek())) { scope->RecordSuperPropertyUsage(); return impl()->NewSuperPropertyReference(pos); } @@ -3665,39 +3281,31 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseSuperExpression( impl()->ReportMessageAt(scanner()->location(), MessageTemplate::kUnexpectedSuper); - *ok = false; - return impl()->NullExpression(); + return impl()->FailureExpression(); } template <typename Impl> -void ParserBase<Impl>::ExpectMetaProperty(Token::Value property_name, - const char* full_name, int pos, - bool* ok) { +void ParserBase<Impl>::ExpectMetaProperty(const AstRawString* property_name, + const char* full_name, int pos) { Consume(Token::PERIOD); - ExpectContextualKeyword(property_name, CHECK_OK_CUSTOM(Void)); - if (scanner()->literal_contains_escapes()) { + ExpectContextualKeyword(property_name); + if (V8_UNLIKELY(scanner()->literal_contains_escapes())) { impl()->ReportMessageAt(Scanner::Location(pos, end_position()), MessageTemplate::kInvalidEscapedMetaProperty, full_name); - *ok = false; } } template <typename Impl> typename ParserBase<Impl>::ExpressionT -ParserBase<Impl>::ParseNewTargetExpression(bool* ok) { +ParserBase<Impl>::ParseNewTargetExpression() { int pos = position(); - ExpectMetaProperty(Token::TARGET, "new.target", pos, CHECK_OK); - - classifier()->RecordAssignmentPatternError( - Scanner::Location(pos, end_position()), - MessageTemplate::kInvalidDestructuringTarget); + ExpectMetaProperty(ast_value_factory()->target_string(), "new.target", pos); if (!GetReceiverScope()->is_function_scope()) { impl()->ReportMessageAt(scanner()->location(), MessageTemplate::kUnexpectedNewTarget); - *ok = false; - return impl()->NullExpression(); + return impl()->FailureExpression(); } return impl()->NewTargetExpression(pos); @@ -3705,45 +3313,31 @@ ParserBase<Impl>::ParseNewTargetExpression(bool* ok) { template <typename Impl> typename ParserBase<Impl>::ExpressionT -ParserBase<Impl>::ParseMemberExpressionContinuation(ExpressionT expression, - bool* is_async, bool* ok) { +ParserBase<Impl>::DoParseMemberExpressionContinuation(ExpressionT expression) { + DCHECK(Token::IsMember(peek())); // Parses this part of MemberExpression: // ('[' Expression ']' | '.' Identifier | TemplateLiteral)* - while (true) { + do { switch (peek()) { case Token::LBRACK: { - *is_async = false; - ValidateExpression(CHECK_OK); - BindingPatternUnexpectedToken(); - ArrowFormalParametersUnexpectedToken(); - Consume(Token::LBRACK); int pos = position(); - ExpressionT index = ParseExpressionCoverGrammar(true, CHECK_OK); - ValidateExpression(CHECK_OK); + AcceptINScope scope(this, true); + ExpressionT index = ParseExpressionCoverGrammar(); expression = factory()->NewProperty(expression, index, pos); impl()->PushPropertyName(index); - Expect(Token::RBRACK, CHECK_OK); + Expect(Token::RBRACK); break; } case Token::PERIOD: { - *is_async = false; - ValidateExpression(CHECK_OK); - BindingPatternUnexpectedToken(); - ArrowFormalParametersUnexpectedToken(); - Consume(Token::PERIOD); int pos = peek_position(); - ExpressionT key = ParseIdentifierNameOrPrivateName(CHECK_OK); + ExpressionT key = ParsePropertyOrPrivatePropertyName(); expression = factory()->NewProperty(expression, key, pos); break; } - case Token::TEMPLATE_SPAN: - case Token::TEMPLATE_TAIL: { - *is_async = false; - ValidateExpression(CHECK_OK); - BindingPatternUnexpectedToken(); - ArrowFormalParametersUnexpectedToken(); + default: { + DCHECK(Token::IsTemplate(peek())); int pos; if (scanner()->current_token() == Token::IDENTIFIER) { pos = position(); @@ -3755,61 +3349,47 @@ ParserBase<Impl>::ParseMemberExpressionContinuation(ExpressionT expression, expression->AsFunctionLiteral()->SetShouldEagerCompile(); } } - expression = ParseTemplateLiteral(expression, pos, true, CHECK_OK); + expression = ParseTemplateLiteral(expression, pos, true); break; } - case Token::ILLEGAL: { - ReportUnexpectedTokenAt(scanner()->peek_location(), Token::ILLEGAL); - *ok = false; - return impl()->NullExpression(); - } - default: - return expression; } - } - DCHECK(false); - return impl()->NullExpression(); + } while (Token::IsMember(peek())); + return expression; } template <typename Impl> -void ParserBase<Impl>::ParseFormalParameter(FormalParametersT* parameters, - bool* ok) { +void ParserBase<Impl>::ParseFormalParameter(FormalParametersT* parameters) { // FormalParameter[Yield,GeneratorParameter] : // BindingElement[?Yield, ?GeneratorParameter] - bool is_rest = parameters->has_rest; - FuncNameInferrerState fni_state(&fni_); - ExpressionT pattern = ParseBindingPattern(CHECK_OK_CUSTOM(Void)); - if (!impl()->IsIdentifier(pattern)) { + int pos = peek_position(); + ExpressionT pattern = ParseBindingPattern(); + if (impl()->IsIdentifier(pattern)) { + ClassifyParameter(impl()->AsIdentifier(pattern), pos, end_position()); + } else { parameters->is_simple = false; - ValidateFormalParameterInitializer(CHECK_OK_CUSTOM(Void)); } ExpressionT initializer = impl()->NullExpression(); if (Check(Token::ASSIGN)) { - if (is_rest) { + parameters->is_simple = false; + + if (parameters->has_rest) { ReportMessage(MessageTemplate::kRestDefaultInitializer); - *ok = false; return; } - ExpressionClassifier init_classifier(this); - initializer = ParseAssignmentExpression(true, CHECK_OK_CUSTOM(Void)); - ValidateExpression(CHECK_OK_CUSTOM(Void)); - ValidateFormalParameterInitializer(CHECK_OK_CUSTOM(Void)); - parameters->is_simple = false; - DiscardExpressionClassifier(); - classifier()->RecordNonSimpleParameter(); + AcceptINScope scope(this, true); + initializer = ParseAssignmentExpression(); impl()->SetFunctionNameFromIdentifierRef(initializer, pattern); } impl()->AddFormalParameter(parameters, pattern, initializer, end_position(), - is_rest); + parameters->has_rest); } template <typename Impl> -void ParserBase<Impl>::ParseFormalParameterList(FormalParametersT* parameters, - bool* ok) { +void ParserBase<Impl>::ParseFormalParameterList(FormalParametersT* parameters) { // FormalParameters[Yield] : // [empty] // FunctionRestParameter[?Yield] @@ -3820,26 +3400,25 @@ void ParserBase<Impl>::ParseFormalParameterList(FormalParametersT* parameters, // FormalParameterList[Yield] : // FormalParameter[?Yield] // FormalParameterList[?Yield] , FormalParameter[?Yield] + ParameterParsingScope scope(impl(), parameters); DCHECK_EQ(0, parameters->arity); if (peek() != Token::RPAREN) { while (true) { - if (parameters->arity > Code::kMaxArguments) { + // Add one since we're going to be adding a parameter. + if (parameters->arity + 1 > Code::kMaxArguments) { ReportMessage(MessageTemplate::kTooManyParameters); - *ok = false; return; } parameters->has_rest = Check(Token::ELLIPSIS); - ParseFormalParameter(parameters, CHECK_OK_CUSTOM(Void)); + ParseFormalParameter(parameters); if (parameters->has_rest) { parameters->is_simple = false; - classifier()->RecordNonSimpleParameter(); if (peek() == Token::COMMA) { impl()->ReportMessageAt(scanner()->peek_location(), MessageTemplate::kParamAfterRest); - *ok = false; return; } break; @@ -3852,15 +3431,14 @@ void ParserBase<Impl>::ParseFormalParameterList(FormalParametersT* parameters, } } - impl()->DeclareFormalParameters(parameters->scope, parameters->params, - parameters->is_simple); + impl()->DeclareFormalParameters(parameters); } template <typename Impl> -typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseVariableDeclarations( +void ParserBase<Impl>::ParseVariableDeclarations( VariableDeclarationContext var_context, DeclarationParsingResult* parsing_result, - ZonePtrList<const AstRawString>* names, bool* ok) { + ZonePtrList<const AstRawString>* names) { // VariableDeclarations :: // ('var' | 'const' | 'let') (Identifier ('=' AssignmentExpression)?)+[','] // @@ -3869,15 +3447,10 @@ typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseVariableDeclarations( // declaration syntax. DCHECK_NOT_NULL(parsing_result); - parsing_result->descriptor.declaration_kind = DeclarationDescriptor::NORMAL; + parsing_result->descriptor.kind = NORMAL_VARIABLE; parsing_result->descriptor.declaration_pos = peek_position(); parsing_result->descriptor.initialization_pos = peek_position(); - BlockT init_block = impl()->NullStatement(); - if (var_context != kForStatement) { - init_block = factory()->NewBlock(1, true); - } - switch (peek()) { case Token::VAR: parsing_result->descriptor.mode = VariableMode::kVar; @@ -3898,40 +3471,29 @@ typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseVariableDeclarations( break; } - parsing_result->descriptor.scope = scope(); + VariableDeclarationParsingScope declaration( + impl(), parsing_result->descriptor.mode, names); int bindings_start = peek_position(); do { // Parse binding pattern. FuncNameInferrerState fni_state(&fni_); - ExpressionT pattern = impl()->NullExpression(); int decl_pos = peek_position(); - { - ExpressionClassifier pattern_classifier(this); - pattern = ParseBindingPattern(CHECK_OK_CUSTOM(NullStatement)); + ExpressionT pattern = ParseBindingPattern(); - if (IsLexicalVariableMode(parsing_result->descriptor.mode)) { - ValidateLetPattern(CHECK_OK_CUSTOM(NullStatement)); - } - } Scanner::Location variable_loc = scanner()->location(); - bool single_name = impl()->IsIdentifier(pattern); - if (single_name) { - impl()->PushVariableName(impl()->AsIdentifier(pattern)); - } - ExpressionT value = impl()->NullExpression(); int initializer_position = kNoSourcePosition; int value_beg_position = kNoSourcePosition; if (Check(Token::ASSIGN)) { value_beg_position = peek_position(); - ExpressionClassifier classifier(this); - value = ParseAssignmentExpression(var_context != kForStatement, - CHECK_OK_CUSTOM(NullStatement)); - ValidateExpression(CHECK_OK_CUSTOM(NullStatement)); + { + AcceptINScope scope(this, var_context != kForStatement); + value = ParseAssignmentExpression(); + } variable_loc.end_pos = end_position(); if (!parsing_result->first_initializer_loc.IsValid()) { @@ -3939,7 +3501,7 @@ typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseVariableDeclarations( } // Don't infer if it is "a = function(){...}();"-like expression. - if (single_name) { + if (impl()->IsIdentifier(pattern)) { if (!value->IsCall() && !value->IsCallNew()) { fni_.Infer(); } else { @@ -3960,8 +3522,7 @@ typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseVariableDeclarations( Scanner::Location(decl_pos, end_position()), MessageTemplate::kDeclarationMissingInitializer, !impl()->IsIdentifier(pattern) ? "destructuring" : "const"); - *ok = false; - return impl()->NullStatement(); + return; } // 'let x' initializes 'x' to undefined. if (parsing_result->descriptor.mode == VariableMode::kLet) { @@ -3976,61 +3537,50 @@ typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseVariableDeclarations( typename DeclarationParsingResult::Declaration decl( pattern, initializer_position, value); decl.value_beg_position = value_beg_position; - if (var_context == kForStatement) { - // Save the declaration for further handling in ParseForStatement. - parsing_result->declarations.push_back(decl); - } else { - // Immediately declare the variable otherwise. This avoids O(N^2) - // behavior (where N is the number of variables in a single - // declaration) in the PatternRewriter having to do with removing - // and adding VariableProxies to the Scope (see bug 4699). - impl()->DeclareAndInitializeVariables( - init_block, &parsing_result->descriptor, &decl, names, - CHECK_OK_CUSTOM(NullStatement)); - } + parsing_result->declarations.push_back(decl); } while (Check(Token::COMMA)); parsing_result->bindings_loc = Scanner::Location(bindings_start, end_position()); - - DCHECK(*ok); - return init_block; } template <typename Impl> typename ParserBase<Impl>::StatementT -ParserBase<Impl>::ParseFunctionDeclaration(bool* ok) { +ParserBase<Impl>::ParseFunctionDeclaration() { Consume(Token::FUNCTION); + int pos = position(); ParseFunctionFlags flags = ParseFunctionFlag::kIsNormal; if (Check(Token::MUL)) { impl()->ReportMessageAt( scanner()->location(), MessageTemplate::kGeneratorInSingleStatementContext); - *ok = false; return impl()->NullStatement(); } - return ParseHoistableDeclaration(pos, flags, nullptr, false, ok); + return ParseHoistableDeclaration(pos, flags, nullptr, false); } template <typename Impl> typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseHoistableDeclaration( - ZonePtrList<const AstRawString>* names, bool default_export, bool* ok) { - Expect(Token::FUNCTION, CHECK_OK_CUSTOM(NullStatement)); + ZonePtrList<const AstRawString>* names, bool default_export) { + Consume(Token::FUNCTION); + int pos = position(); ParseFunctionFlags flags = ParseFunctionFlag::kIsNormal; if (Check(Token::MUL)) { flags |= ParseFunctionFlag::kIsGenerator; } - return ParseHoistableDeclaration(pos, flags, names, default_export, ok); + return ParseHoistableDeclaration(pos, flags, names, default_export); } template <typename Impl> typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseHoistableDeclaration( int pos, ParseFunctionFlags flags, ZonePtrList<const AstRawString>* names, - bool default_export, bool* ok) { + bool default_export) { + CheckStackOverflow(); + // FunctionDeclaration :: // 'function' Identifier '(' FormalParameters ')' '{' FunctionBody '}' // 'function' '(' FormalParameters ')' '{' FunctionBody '}' @@ -4057,10 +3607,8 @@ ParserBase<Impl>::ParseHoistableDeclaration( impl()->GetDefaultStrings(&name, &variable_name); name_validity = kSkipFunctionNameCheck; } else { - bool is_strict_reserved; - bool is_await = false; - name = ParseIdentifierOrStrictReservedWord(&is_strict_reserved, &is_await, - CHECK_OK_CUSTOM(NullStatement)); + bool is_strict_reserved = Token::IsStrictReservedWord(peek()); + name = ParseIdentifier(); name_validity = is_strict_reserved ? kFunctionNameIsStrictReserved : kFunctionNameValidityUnknown; variable_name = name; @@ -4073,8 +3621,7 @@ ParserBase<Impl>::ParseHoistableDeclaration( FunctionLiteralT function = impl()->ParseFunctionLiteral( name, scanner()->location(), name_validity, kind, pos, - FunctionLiteral::kDeclaration, language_mode(), nullptr, - CHECK_OK_CUSTOM(NullStatement)); + FunctionLiteral::kDeclaration, language_mode(), nullptr); // In ES6, a function behaves as a lexical binding, except in // a script scope, or the initial scope of eval or another function. @@ -4092,12 +3639,13 @@ ParserBase<Impl>::ParseHoistableDeclaration( flags == ParseFunctionFlag::kIsNormal; return impl()->DeclareFunction(variable_name, function, mode, pos, - is_sloppy_block_function, names, ok); + end_position(), is_sloppy_block_function, + names); } template <typename Impl> typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseClassDeclaration( - ZonePtrList<const AstRawString>* names, bool default_export, bool* ok) { + ZonePtrList<const AstRawString>* names, bool default_export) { // ClassDeclaration :: // 'class' Identifier ('extends' LeftHandExpression)? '{' ClassBody '}' // 'class' ('extends' LeftHandExpression)? '{' ClassBody '}' @@ -4118,24 +3666,22 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseClassDeclaration( int class_token_pos = position(); IdentifierT name = impl()->NullIdentifier(); - bool is_strict_reserved = false; + bool is_strict_reserved = Token::IsStrictReservedWord(peek()); IdentifierT variable_name = impl()->NullIdentifier(); if (default_export && (peek() == Token::EXTENDS || peek() == Token::LBRACE)) { impl()->GetDefaultStrings(&name, &variable_name); } else { - bool is_await = false; - name = ParseIdentifierOrStrictReservedWord(&is_strict_reserved, &is_await, - CHECK_OK_CUSTOM(NullStatement)); + name = ParseIdentifier(); variable_name = name; } - ExpressionClassifier no_classifier(this); - ExpressionT value = - ParseClassLiteral(name, scanner()->location(), is_strict_reserved, - class_token_pos, CHECK_OK_CUSTOM(NullStatement)); + ExpressionParsingScope no_expression_scope(impl()); + ExpressionT value = ParseClassLiteral(name, scanner()->location(), + is_strict_reserved, class_token_pos); + no_expression_scope.ValidateExpression(); int end_pos = position(); return impl()->DeclareClass(variable_name, value, names, class_token_pos, - end_pos, ok); + end_pos); } // Language extension which is only enabled for source files loaded @@ -4143,86 +3689,84 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseClassDeclaration( // declaration is resolved by looking up the function through a // callback provided by the extension. template <typename Impl> -typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseNativeDeclaration( - bool* ok) { +typename ParserBase<Impl>::StatementT +ParserBase<Impl>::ParseNativeDeclaration() { function_state_->DisableOptimization(BailoutReason::kNativeFunctionLiteral); int pos = peek_position(); - Expect(Token::FUNCTION, CHECK_OK_CUSTOM(NullStatement)); + Consume(Token::FUNCTION); // Allow "eval" or "arguments" for backward compatibility. - IdentifierT name = ParseIdentifier(kAllowRestrictedIdentifiers, - CHECK_OK_CUSTOM(NullStatement)); - Expect(Token::LPAREN, CHECK_OK_CUSTOM(NullStatement)); + IdentifierT name = ParseIdentifier(); + Expect(Token::LPAREN); if (peek() != Token::RPAREN) { do { - ParseIdentifier(kAllowRestrictedIdentifiers, - CHECK_OK_CUSTOM(NullStatement)); + ParseIdentifier(); } while (Check(Token::COMMA)); } - Expect(Token::RPAREN, CHECK_OK_CUSTOM(NullStatement)); - Expect(Token::SEMICOLON, CHECK_OK_CUSTOM(NullStatement)); - return impl()->DeclareNative(name, pos, ok); + Expect(Token::RPAREN); + Expect(Token::SEMICOLON); + return impl()->DeclareNative(name, pos); } template <typename Impl> typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseAsyncFunctionDeclaration( - ZonePtrList<const AstRawString>* names, bool default_export, bool* ok) { + ZonePtrList<const AstRawString>* names, bool default_export) { // AsyncFunctionDeclaration :: // async [no LineTerminator here] function BindingIdentifier[Await] // ( FormalParameters[Await] ) { AsyncFunctionBody } DCHECK_EQ(scanner()->current_token(), Token::ASYNC); int pos = position(); - if (scanner()->HasLineTerminatorBeforeNext()) { - *ok = false; - impl()->ReportUnexpectedToken(scanner()->current_token()); - return impl()->NullStatement(); - } - Expect(Token::FUNCTION, CHECK_OK_CUSTOM(NullStatement)); + DCHECK(!scanner()->HasLineTerminatorBeforeNext()); + Consume(Token::FUNCTION); ParseFunctionFlags flags = ParseFunctionFlag::kIsAsync; - return ParseHoistableDeclaration(pos, flags, names, default_export, ok); + return ParseHoistableDeclaration(pos, flags, names, default_export); } template <typename Impl> void ParserBase<Impl>::ParseFunctionBody( - typename ParserBase<Impl>::StatementListT result, IdentifierT function_name, - int pos, const FormalParametersT& parameters, FunctionKind kind, - FunctionLiteral::FunctionType function_type, FunctionBodyType body_type, - bool accept_IN, bool* ok) { - DeclarationScope* function_scope = scope()->AsDeclarationScope(); + StatementListT* body, IdentifierT function_name, int pos, + const FormalParametersT& parameters, FunctionKind kind, + FunctionLiteral::FunctionType function_type, FunctionBodyType body_type) { + FunctionBodyParsingScope body_parsing_scope(impl()); + + if (IsResumableFunction(kind)) impl()->PrepareGeneratorVariables(); + + DeclarationScope* function_scope = parameters.scope; DeclarationScope* inner_scope = function_scope; - BlockT inner_block = impl()->NullStatement(); - StatementListT body = result; - if (!parameters.is_simple) { + // Building the parameter initialization block declares the parameters. + // TODO(verwaest): Rely on ArrowHeadParsingScope instead. + if (V8_UNLIKELY(!parameters.is_simple)) { + if (has_error()) return; + BlockT init_block = impl()->BuildParameterInitializationBlock(parameters); + if (IsAsyncFunction(kind) && !IsAsyncGeneratorFunction(kind)) { + init_block = impl()->BuildRejectPromiseOnException(init_block); + } + body->Add(init_block); + if (has_error()) return; + inner_scope = NewVarblockScope(); inner_scope->set_start_position(scanner()->location().beg_pos); - inner_block = factory()->NewBlock(8, true); - inner_block->set_scope(inner_scope); - body = inner_block->statements(); } + StatementListT inner_body(pointer_buffer()); + { BlockState block_state(&scope_, inner_scope); - if (IsResumableFunction(kind)) impl()->PrepareGeneratorVariables(); - if (body_type == FunctionBodyType::kExpression) { - ExpressionClassifier classifier(this); - ExpressionT expression = - ParseAssignmentExpression(accept_IN, CHECK_OK_VOID); - ValidateExpression(CHECK_OK_VOID); + ExpressionT expression = ParseAssignmentExpression(); if (IsAsyncFunction(kind)) { BlockT block = factory()->NewBlock(1, true); - impl()->RewriteAsyncFunctionBody(body, block, expression, - CHECK_OK_VOID); + impl()->RewriteAsyncFunctionBody(&inner_body, block, expression); } else { - body->Add(BuildReturnStatement(expression, expression->position()), - zone()); + inner_body.Add( + BuildReturnStatement(expression, expression->position())); } } else { - DCHECK(accept_IN); + DCHECK(accept_IN_); DCHECK_EQ(FunctionBodyType::kBlock, body_type); // If we are parsing the source as if it is wrapped in a function, the // source ends without a closing brace. @@ -4231,63 +3775,64 @@ void ParserBase<Impl>::ParseFunctionBody( : Token::RBRACE; if (IsAsyncGeneratorFunction(kind)) { - impl()->ParseAndRewriteAsyncGeneratorFunctionBody(pos, kind, body, - CHECK_OK_VOID); + impl()->ParseAndRewriteAsyncGeneratorFunctionBody(pos, kind, + &inner_body); } else if (IsGeneratorFunction(kind)) { - impl()->ParseAndRewriteGeneratorFunctionBody(pos, kind, body, - CHECK_OK_VOID); + impl()->ParseAndRewriteGeneratorFunctionBody(pos, kind, &inner_body); } else if (IsAsyncFunction(kind)) { - ParseAsyncFunctionBody(inner_scope, body, CHECK_OK_VOID); + ParseAsyncFunctionBody(inner_scope, &inner_body); } else { - ParseStatementList(body, closing_token, CHECK_OK_VOID); + ParseStatementList(&inner_body, closing_token); } if (IsDerivedConstructor(kind)) { - body->Add(factory()->NewReturnStatement(impl()->ThisExpression(), - kNoSourcePosition), - zone()); + inner_body.Add(factory()->NewReturnStatement(impl()->ThisExpression(), + kNoSourcePosition)); } - Expect(closing_token, CHECK_OK_VOID); + Expect(closing_token); } } scope()->set_end_position(end_position()); - if (!parameters.is_simple) { + bool allow_duplicate_parameters = false; + + if (V8_LIKELY(parameters.is_simple)) { + DCHECK_EQ(inner_scope, function_scope); + if (is_sloppy(function_scope->language_mode())) { + impl()->InsertSloppyBlockFunctionVarBindings(function_scope); + } + allow_duplicate_parameters = + is_sloppy(function_scope->language_mode()) && !IsConciseMethod(kind); + } else { DCHECK_NOT_NULL(inner_scope); DCHECK_EQ(function_scope, scope()); DCHECK_EQ(function_scope, inner_scope->outer_scope()); impl()->SetLanguageMode(function_scope, inner_scope->language_mode()); - BlockT init_block = - impl()->BuildParameterInitializationBlock(parameters, CHECK_OK_VOID); if (is_sloppy(inner_scope->language_mode())) { impl()->InsertSloppyBlockFunctionVarBindings(inner_scope); } - // TODO(littledan): Merge the two rejection blocks into one - if (IsAsyncFunction(kind) && !IsAsyncGeneratorFunction(kind)) { - init_block = impl()->BuildRejectPromiseOnException(init_block); - } - inner_scope->set_end_position(end_position()); if (inner_scope->FinalizeBlockScope() != nullptr) { - impl()->CheckConflictingVarDeclarations(inner_scope, CHECK_OK_VOID); + BlockT inner_block = factory()->NewBlock(true, inner_body); + inner_body.Rewind(); + inner_body.Add(inner_block); + inner_block->set_scope(inner_scope); + const AstRawString* conflict = inner_scope->FindVariableDeclaredIn( + function_scope, VariableMode::kLastLexicalVariableMode); + if (conflict != nullptr) { + impl()->ReportVarRedeclarationIn(conflict, inner_scope); + } + impl()->CheckConflictingVarDeclarations(inner_scope); impl()->InsertShadowingVarBindingInitializers(inner_block); - } else { - inner_block->set_scope(nullptr); - } - inner_scope = nullptr; - - result->Add(init_block, zone()); - result->Add(inner_block, zone()); - } else { - DCHECK_EQ(inner_scope, function_scope); - if (is_sloppy(function_scope->language_mode())) { - impl()->InsertSloppyBlockFunctionVarBindings(function_scope); } } + ValidateFormalParameters(language_mode(), parameters, + allow_duplicate_parameters); + if (!IsArrowFunction(kind)) { // Declare arguments after parsing the function since lexical 'arguments' // masks the arguments object. Declare arguments before declaring the @@ -4296,6 +3841,8 @@ void ParserBase<Impl>::ParseFunctionBody( } impl()->DeclareFunctionNameVar(function_name, function_type, function_scope); + + inner_body.MergeInto(body); } template <typename Impl> @@ -4303,26 +3850,23 @@ void ParserBase<Impl>::CheckArityRestrictions(int param_count, FunctionKind function_kind, bool has_rest, int formals_start_pos, - int formals_end_pos, bool* ok) { + int formals_end_pos) { if (IsGetterFunction(function_kind)) { if (param_count != 0) { impl()->ReportMessageAt( Scanner::Location(formals_start_pos, formals_end_pos), MessageTemplate::kBadGetterArity); - *ok = false; } } else if (IsSetterFunction(function_kind)) { if (param_count != 1) { impl()->ReportMessageAt( Scanner::Location(formals_start_pos, formals_end_pos), MessageTemplate::kBadSetterArity); - *ok = false; } if (has_rest) { impl()->ReportMessageAt( Scanner::Location(formals_start_pos, formals_end_pos), MessageTemplate::kBadSetterRestParameter); - *ok = false; } } } @@ -4353,25 +3897,9 @@ bool ParserBase<Impl>::IsNextLetKeyword() { } template <typename Impl> -bool ParserBase<Impl>::IsTrivialExpression() { - if (Token::IsTrivialExpressionToken(peek())) { - // PeekAhead() may not always be called, so we only call it after checking - // peek(). - Token::Value peek_ahead = PeekAhead(); - if (peek_ahead == Token::COMMA || peek_ahead == Token::RPAREN || - peek_ahead == Token::SEMICOLON || peek_ahead == Token::RBRACK || - Token::IsAssignmentOp(peek_ahead)) { - return true; - } - } - return false; -} - -template <typename Impl> typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseArrowFunctionLiteral( - bool accept_IN, const FormalParametersT& formal_parameters, - int rewritable_length, bool* ok) { + const FormalParametersT& formal_parameters) { const RuntimeCallCounterId counters[2][2] = { {RuntimeCallCounterId::kParseBackgroundArrowFunctionLiteral, RuntimeCallCounterId::kParseArrowFunctionLiteral}, @@ -4383,16 +3911,15 @@ ParserBase<Impl>::ParseArrowFunctionLiteral( base::ElapsedTimer timer; if (V8_UNLIKELY(FLAG_log_function_events)) timer.Start(); - if (peek() == Token::ARROW && scanner_->HasLineTerminatorBeforeNext()) { + DCHECK_IMPLIES(!has_error(), peek() == Token::ARROW); + if (scanner_->HasLineTerminatorBeforeNext()) { // ASI inserts `;` after arrow parameters if a line terminator is found. // `=> ...` is never a valid expression, so report as syntax error. // If next token is not `=>`, it's a syntax error anyways. - ReportUnexpectedTokenAt(scanner_->peek_location(), Token::ARROW); - *ok = false; - return impl()->NullExpression(); + impl()->ReportUnexpectedTokenAt(scanner_->peek_location(), Token::ARROW); + return impl()->FailureExpression(); } - StatementListT body = impl()->NullStatementList(); int expected_property_count = -1; int suspend_count = 0; int function_literal_id = GetNextFunctionLiteralId(); @@ -4407,93 +3934,102 @@ ParserBase<Impl>::ParseArrowFunctionLiteral( bool is_lazy_top_level_function = can_preparse && impl()->AllowsLazyParsingWithoutUnresolvedVariables(); bool has_braces = true; - ProducedPreParsedScopeData* produced_preparsed_scope_data = nullptr; + ProducedPreparseData* produced_preparse_data = nullptr; + StatementListT body(pointer_buffer()); { FunctionState function_state(&function_state_, &scope_, formal_parameters.scope); - // Move any queued destructuring assignments which appeared - // in this function's parameter list into its own function_state. - function_state.AdoptDestructuringAssignmentsFromParentState( - rewritable_length); - - Expect(Token::ARROW, CHECK_OK); + Consume(Token::ARROW); if (peek() == Token::LBRACE) { // Multiple statement body DCHECK_EQ(scope(), formal_parameters.scope); + if (is_lazy_top_level_function) { // FIXME(marja): Arrow function parameters will be parsed even if the // body is preparsed; move relevant parts of parameter handling to // simulate consistent parameter handling. + // Building the parameter initialization block declares the parameters. + // TODO(verwaest): Rely on ArrowHeadParsingScope instead. + if (!formal_parameters.is_simple) { + impl()->BuildParameterInitializationBlock(formal_parameters); + if (has_error()) return impl()->FailureExpression(); + } + // For arrow functions, we don't need to retrieve data about function // parameters. int dummy_num_parameters = -1; DCHECK_NE(kind & FunctionKind::kArrowFunction, 0); - FunctionLiteral::EagerCompileHint hint; bool did_preparse_successfully = impl()->SkipFunction( nullptr, kind, FunctionLiteral::kAnonymousExpression, formal_parameters.scope, &dummy_num_parameters, - &produced_preparsed_scope_data, false, false, &hint, CHECK_OK); + &produced_preparse_data); - DCHECK_NULL(produced_preparsed_scope_data); + DCHECK_NULL(produced_preparse_data); if (did_preparse_successfully) { - // Discard any queued destructuring assignments which appeared - // in this function's parameter list, and which were adopted - // into this function state, above. - function_state.RewindDestructuringAssignments(0); + // Validate parameter names. We can do this only after preparsing the + // function, since the function can declare itself strict. + ValidateFormalParameters(language_mode(), formal_parameters, false); } else { // In case we did not sucessfully preparse the function because of an // unidentified error we do a full reparse to return the error. + // Parse again in the outer scope, since the language mode may change. + BlockState block_state(&scope_, scope()->outer_scope()); + ExpressionT expression = ParseConditionalExpression(); + // Reparsing the head may have caused a stack overflow. + if (has_error()) return impl()->FailureExpression(); + + DeclarationScope* function_scope = next_arrow_function_info_.scope; + FunctionState function_state(&function_state_, &scope_, + function_scope); + Scanner::Location loc(function_scope->start_position(), + end_position()); + FormalParametersT parameters(function_scope); + parameters.is_simple = function_scope->has_simple_parameters(); + impl()->DeclareArrowFunctionFormalParameters(¶meters, expression, + loc); + next_arrow_function_info_.Reset(); + + Consume(Token::ARROW); Consume(Token::LBRACE); - body = impl()->NewStatementList(8); - ParseFunctionBody(body, impl()->NullIdentifier(), kNoSourcePosition, - formal_parameters, kind, + + AcceptINScope scope(this, true); + ParseFunctionBody(&body, impl()->NullIdentifier(), kNoSourcePosition, + parameters, kind, FunctionLiteral::kAnonymousExpression, - FunctionBodyType::kBlock, true, ok); - CHECK(!*ok); - return impl()->NullExpression(); + FunctionBodyType::kBlock); + CHECK(has_error()); + return impl()->FailureExpression(); } } else { Consume(Token::LBRACE); - body = impl()->NewStatementList(8); - ParseFunctionBody(body, impl()->NullIdentifier(), kNoSourcePosition, + AcceptINScope scope(this, true); + ParseFunctionBody(&body, impl()->NullIdentifier(), kNoSourcePosition, formal_parameters, kind, FunctionLiteral::kAnonymousExpression, - FunctionBodyType::kBlock, true, CHECK_OK); + FunctionBodyType::kBlock); expected_property_count = function_state.expected_property_count(); } } else { // Single-expression body has_braces = false; - body = impl()->NewStatementList(1); - ParseFunctionBody(body, impl()->NullIdentifier(), kNoSourcePosition, + ParseFunctionBody(&body, impl()->NullIdentifier(), kNoSourcePosition, formal_parameters, kind, FunctionLiteral::kAnonymousExpression, - FunctionBodyType::kExpression, accept_IN, CHECK_OK); + FunctionBodyType::kExpression); expected_property_count = function_state.expected_property_count(); } formal_parameters.scope->set_end_position(end_position()); - // Arrow function formal parameters are parsed as StrictFormalParameterList, - // which is not the same as "parameters of a strict function"; it only means - // that duplicates are not allowed. Of course, the arrow function may - // itself be strict as well. - const bool allow_duplicate_parameters = false; - ValidateFormalParameters(language_mode(), allow_duplicate_parameters, - CHECK_OK); - // Validate strict mode. if (is_strict(language_mode())) { CheckStrictOctalLiteral(formal_parameters.scope->start_position(), - end_position(), CHECK_OK); + end_position()); } - impl()->CheckConflictingVarDeclarations(formal_parameters.scope, CHECK_OK); - - impl()->RewriteDestructuringAssignments(); suspend_count = function_state.suspend_count(); } @@ -4504,7 +4040,7 @@ ParserBase<Impl>::ParseArrowFunctionLiteral( FunctionLiteral::kNoDuplicateParameters, FunctionLiteral::kAnonymousExpression, eager_compile_hint, formal_parameters.scope->start_position(), has_braces, - function_literal_id, produced_preparsed_scope_data); + function_literal_id, produced_preparse_data); function_literal->set_suspend_count(suspend_count); function_literal->set_function_token_position( @@ -4528,7 +4064,7 @@ ParserBase<Impl>::ParseArrowFunctionLiteral( template <typename Impl> typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseClassLiteral( IdentifierT name, Scanner::Location class_name_location, - bool name_is_strict_reserved, int class_token_pos, bool* ok) { + bool name_is_strict_reserved, int class_token_pos) { bool is_anonymous = impl()->IsNull(name); // All parts of a ClassDeclaration and ClassExpression are strict code. @@ -4536,14 +4072,12 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseClassLiteral( if (name_is_strict_reserved) { impl()->ReportMessageAt(class_name_location, MessageTemplate::kUnexpectedStrictReserved); - *ok = false; - return impl()->NullExpression(); + return impl()->FailureExpression(); } if (impl()->IsEvalOrArguments(name)) { impl()->ReportMessageAt(class_name_location, MessageTemplate::kStrictEvalArguments); - *ok = false; - return impl()->NullExpression(); + return impl()->FailureExpression(); } } @@ -4553,77 +4087,79 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseClassLiteral( ClassInfo class_info(this); class_info.is_anonymous = is_anonymous; - impl()->DeclareClassVariable(name, &class_info, class_token_pos, CHECK_OK); + impl()->DeclareClassVariable(name, &class_info, class_token_pos); scope()->set_start_position(end_position()); if (Check(Token::EXTENDS)) { FuncNameInferrerState fni_state(&fni_); - ExpressionClassifier extends_classifier(this); - class_info.extends = ParseLeftHandSideExpression(CHECK_OK); - ValidateExpression(CHECK_OK); - AccumulateFormalParameterContainmentErrors(); + ExpressionParsingScope scope(impl()); + class_info.extends = ParseLeftHandSideExpression(); + scope.ValidateExpression(); } - ClassLiteralChecker checker(this); - - Expect(Token::LBRACE, CHECK_OK); + Expect(Token::LBRACE); const bool has_extends = !impl()->IsNull(class_info.extends); while (peek() != Token::RBRACE) { if (Check(Token::SEMICOLON)) continue; FuncNameInferrerState fni_state(&fni_); - bool is_computed_name = false; // Classes do not care about computed - // property names here. - bool is_static; - ClassLiteralProperty::Kind property_kind; - ExpressionClassifier property_classifier(this); - IdentifierT property_name; // If we haven't seen the constructor yet, it potentially is the next // property. bool is_constructor = !class_info.has_seen_constructor; - ClassLiteralPropertyT property = ParseClassPropertyDefinition( - &checker, &class_info, &property_name, has_extends, &is_computed_name, - &property_kind, &is_static, CHECK_OK); - if (!class_info.has_static_computed_names && is_static && - is_computed_name) { + ParsePropertyInfo prop_info(this); + prop_info.position = PropertyPosition::kClassLiteral; + ClassLiteralPropertyT property = + ParseClassPropertyDefinition(&class_info, &prop_info, has_extends); + + if (has_error()) return impl()->FailureExpression(); + + ClassLiteralProperty::Kind property_kind = + ClassPropertyKindFor(prop_info.kind); + if (!class_info.has_static_computed_names && prop_info.is_static && + prop_info.is_computed_name) { class_info.has_static_computed_names = true; } - if (is_computed_name && - property_kind == ClassLiteralProperty::PUBLIC_FIELD) { - class_info.computed_field_count++; - } is_constructor &= class_info.has_seen_constructor; - ValidateExpression(CHECK_OK); - AccumulateFormalParameterContainmentErrors(); - impl()->DeclareClassProperty(name, property, property_name, property_kind, - is_static, is_constructor, is_computed_name, - &class_info, CHECK_OK); + if (V8_UNLIKELY(property_kind == ClassLiteralProperty::FIELD)) { + if (prop_info.is_computed_name) { + DCHECK(!prop_info.is_private); + class_info.computed_field_count++; + } + + impl()->DeclareClassField(property, prop_info.name, prop_info.is_static, + prop_info.is_computed_name, + prop_info.is_private, &class_info); + } else { + impl()->DeclareClassProperty(name, property, is_constructor, &class_info); + } impl()->InferFunctionName(); } - Expect(Token::RBRACE, CHECK_OK); + Expect(Token::RBRACE); int end_pos = end_position(); block_scope->set_end_position(end_pos); return impl()->RewriteClassLiteral(block_scope, name, &class_info, - class_token_pos, end_pos, ok); + class_token_pos, end_pos); } template <typename Impl> -void ParserBase<Impl>::ParseAsyncFunctionBody(Scope* scope, StatementListT body, - bool* ok) { - BlockT block = factory()->NewBlock(8, true); - - ParseStatementList(block->statements(), Token::RBRACE, CHECK_OK_VOID); +void ParserBase<Impl>::ParseAsyncFunctionBody(Scope* scope, + StatementListT* body) { + BlockT block = impl()->NullBlock(); + { + StatementListT statements(pointer_buffer()); + ParseStatementList(&statements, Token::RBRACE); + block = factory()->NewBlock(true, statements); + } impl()->RewriteAsyncFunctionBody( - body, block, factory()->NewUndefinedLiteral(kNoSourcePosition), - CHECK_OK_VOID); + body, block, factory()->NewUndefinedLiteral(kNoSourcePosition)); scope->set_end_position(end_position()); } template <typename Impl> typename ParserBase<Impl>::ExpressionT -ParserBase<Impl>::ParseAsyncFunctionLiteral(bool* ok) { +ParserBase<Impl>::ParseAsyncFunctionLiteral() { // AsyncFunctionLiteral :: // async [no LineTerminator here] function ( FormalParameters[Await] ) // { AsyncFunctionBody } @@ -4632,43 +4168,41 @@ ParserBase<Impl>::ParseAsyncFunctionLiteral(bool* ok) { // ( FormalParameters[Await] ) { AsyncFunctionBody } DCHECK_EQ(scanner()->current_token(), Token::ASYNC); int pos = position(); - Expect(Token::FUNCTION, CHECK_OK); - bool is_strict_reserved = false; + Consume(Token::FUNCTION); IdentifierT name = impl()->NullIdentifier(); FunctionLiteral::FunctionType type = FunctionLiteral::kAnonymousExpression; ParseFunctionFlags flags = ParseFunctionFlag::kIsAsync; if (Check(Token::MUL)) flags |= ParseFunctionFlag::kIsGenerator; const FunctionKind kind = FunctionKindFor(flags); + bool is_strict_reserved = Token::IsStrictReservedWord(peek()); if (impl()->ParsingDynamicFunctionDeclaration()) { // We don't want dynamic functions to actually declare their name // "anonymous". We just want that name in the toString(). - if (stack_overflow()) { - *ok = false; - return impl()->NullExpression(); - } + + // Consuming token we did not peek yet, which could lead to a ILLEGAL token + // in the case of a stackoverflow. Consume(Token::IDENTIFIER); - DCHECK(scanner()->CurrentMatchesContextual(Token::ANONYMOUS)); + DCHECK_IMPLIES(!has_error(), + scanner()->CurrentSymbol(ast_value_factory()) == + ast_value_factory()->anonymous_string()); } else if (peek_any_identifier()) { type = FunctionLiteral::kNamedExpression; - bool is_await = false; - name = ParseIdentifierOrStrictReservedWord(kind, &is_strict_reserved, - &is_await, CHECK_OK); - // If the function name is "await", ParseIdentifierOrStrictReservedWord - // recognized the error. - DCHECK(!is_await); - } - return impl()->ParseFunctionLiteral( + name = ParseIdentifier(kind); + } + FunctionLiteralT result = impl()->ParseFunctionLiteral( name, scanner()->location(), is_strict_reserved ? kFunctionNameIsStrictReserved : kFunctionNameValidityUnknown, - kind, pos, type, language_mode(), nullptr, ok); + kind, pos, type, language_mode(), nullptr); + if (impl()->IsNull(result)) return impl()->FailureExpression(); + return result; } template <typename Impl> typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseTemplateLiteral( - ExpressionT tag, int start, bool tagged, bool* ok) { + ExpressionT tag, int start, bool tagged) { // A TemplateLiteral is made up of 0 or more TEMPLATE_SPAN tokens (literal // text followed by a substitution expression), finalized by a single // TEMPLATE_TAIL. @@ -4696,7 +4230,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseTemplateLiteral( Consume(Token::TEMPLATE_TAIL); int pos = position(); typename Impl::TemplateLiteralState ts = impl()->OpenTemplateLiteral(pos); - bool is_valid = CheckTemplateEscapes(forbid_illegal_escapes, CHECK_OK); + bool is_valid = CheckTemplateEscapes(forbid_illegal_escapes); impl()->AddTemplateSpan(&ts, is_valid, true); return impl()->CloseTemplateLiteral(&ts, start, tag); } @@ -4704,7 +4238,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseTemplateLiteral( Consume(Token::TEMPLATE_SPAN); int pos = position(); typename Impl::TemplateLiteralState ts = impl()->OpenTemplateLiteral(pos); - bool is_valid = CheckTemplateEscapes(forbid_illegal_escapes, CHECK_OK); + bool is_valid = CheckTemplateEscapes(forbid_illegal_escapes); impl()->AddTemplateSpan(&ts, is_valid, false); Token::Value next; @@ -4714,29 +4248,16 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseTemplateLiteral( do { next = peek(); - if (next == Token::EOS) { - impl()->ReportMessageAt(Scanner::Location(start, peek_position()), - MessageTemplate::kUnterminatedTemplate); - *ok = false; - return impl()->NullExpression(); - } else if (next == Token::ILLEGAL) { - impl()->ReportMessageAt( - Scanner::Location(position() + 1, peek_position()), - MessageTemplate::kUnexpectedToken, "ILLEGAL", kSyntaxError); - *ok = false; - return impl()->NullExpression(); - } int expr_pos = peek_position(); - ExpressionT expression = ParseExpressionCoverGrammar(true, CHECK_OK); - ValidateExpression(CHECK_OK); + AcceptINScope scope(this, true); + ExpressionT expression = ParseExpressionCoverGrammar(); impl()->AddTemplateExpression(&ts, expression); if (peek() != Token::RBRACE) { impl()->ReportMessageAt(Scanner::Location(expr_pos, peek_position()), MessageTemplate::kUnterminatedTemplateExpr); - *ok = false; - return impl()->NullExpression(); + return impl()->FailureExpression(); } // If we didn't die parsing that expression, our next token should be a @@ -4745,53 +4266,34 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseTemplateLiteral( Next(); pos = position(); - if (next == Token::EOS) { - impl()->ReportMessageAt(Scanner::Location(start, pos), - MessageTemplate::kUnterminatedTemplate); - *ok = false; - return impl()->NullExpression(); - } else if (next == Token::ILLEGAL) { - impl()->ReportMessageAt( - Scanner::Location(position() + 1, peek_position()), - MessageTemplate::kUnexpectedToken, "ILLEGAL", kSyntaxError); - *ok = false; - return impl()->NullExpression(); - } - - bool is_valid = CheckTemplateEscapes(forbid_illegal_escapes, CHECK_OK); + bool is_valid = CheckTemplateEscapes(forbid_illegal_escapes); impl()->AddTemplateSpan(&ts, is_valid, next == Token::TEMPLATE_TAIL); } while (next == Token::TEMPLATE_SPAN); - DCHECK_EQ(next, Token::TEMPLATE_TAIL); + DCHECK_IMPLIES(!has_error(), next == Token::TEMPLATE_TAIL); // Once we've reached a TEMPLATE_TAIL, we can close the TemplateLiteral. return impl()->CloseTemplateLiteral(&ts, start, tag); } template <typename Impl> typename ParserBase<Impl>::ExpressionT -ParserBase<Impl>::CheckAndRewriteReferenceExpression( - ExpressionT expression, int beg_pos, int end_pos, - MessageTemplate::Template message, bool* ok) { - return CheckAndRewriteReferenceExpression(expression, beg_pos, end_pos, - message, kReferenceError, ok); -} +ParserBase<Impl>::RewriteInvalidReferenceExpression(ExpressionT expression, + int beg_pos, int end_pos, + MessageTemplate message, + ParseErrorType type) { + DCHECK(!IsValidReferenceExpression(expression)); + if (impl()->IsIdentifier(expression)) { + DCHECK(is_strict(language_mode())); + DCHECK(impl()->IsEvalOrArguments(impl()->AsIdentifier(expression))); -template <typename Impl> -typename ParserBase<Impl>::ExpressionT -ParserBase<Impl>::CheckAndRewriteReferenceExpression( - ExpressionT expression, int beg_pos, int end_pos, - MessageTemplate::Template message, ParseErrorType type, bool* ok) { - if (impl()->IsIdentifier(expression) && is_strict(language_mode()) && - impl()->IsEvalOrArguments(impl()->AsIdentifier(expression))) { ReportMessageAt(Scanner::Location(beg_pos, end_pos), MessageTemplate::kStrictEvalArguments, kSyntaxError); - *ok = false; - return impl()->NullExpression(); - } - if (expression->IsValidReferenceExpression()) { - return expression; + return impl()->FailureExpression(); } if (expression->IsCall() && !expression->AsCall()->is_tagged_template()) { + expression_scope()->RecordPatternError( + Scanner::Location(beg_pos, end_pos), + MessageTemplate::kInvalidDestructuringTarget); // If it is a call, make it a runtime error for legacy web compatibility. // Bug: https://bugs.chromium.org/p/v8/issues/detail?id=4480 // Rewrite `expr' to `expr[throw ReferenceError]'. @@ -4803,8 +4305,35 @@ ParserBase<Impl>::CheckAndRewriteReferenceExpression( return factory()->NewProperty(expression, error, beg_pos); } ReportMessageAt(Scanner::Location(beg_pos, end_pos), message, type); - *ok = false; - return impl()->NullExpression(); + return impl()->FailureExpression(); +} + +template <typename Impl> +void ParserBase<Impl>::ClassifyParameter(IdentifierT parameter, int begin, + int end) { + if (impl()->IsEvalOrArguments(parameter)) { + expression_scope()->RecordStrictModeParameterError( + Scanner::Location(begin, end), MessageTemplate::kStrictEvalArguments); + } +} + +template <typename Impl> +void ParserBase<Impl>::ClassifyArrowParameter( + AccumulationScope* accumulation_scope, int position, + ExpressionT parameter) { + accumulation_scope->Accumulate(); + if (parameter->is_parenthesized() || + !(impl()->IsIdentifier(parameter) || parameter->IsPattern() || + parameter->IsAssignment())) { + expression_scope()->RecordDeclarationError( + Scanner::Location(position, end_position()), + MessageTemplate::kInvalidDestructuringTarget); + } else if (impl()->IsIdentifier(parameter)) { + ClassifyParameter(impl()->AsIdentifier(parameter), position, + end_position()); + } else { + expression_scope()->RecordNonSimpleParameter(); + } } template <typename Impl> @@ -4813,147 +4342,133 @@ bool ParserBase<Impl>::IsValidReferenceExpression(ExpressionT expression) { } template <typename Impl> -void ParserBase<Impl>::CheckDestructuringElement(ExpressionT expression, - int begin, int end) { - if (!IsValidPattern(expression) && !expression->IsAssignment() && - !IsValidReferenceExpression(expression)) { - classifier()->RecordAssignmentPatternError( - Scanner::Location(begin, end), +typename ParserBase<Impl>::ExpressionT +ParserBase<Impl>::ParsePossibleDestructuringSubPattern( + AccumulationScope* scope) { + if (scope) scope->Accumulate(); + int begin = peek_position(); + ExpressionT result = ParseAssignmentExpressionCoverGrammar(); + + if (IsValidReferenceExpression(result)) { + // Parenthesized identifiers and property references are allowed as part of + // a larger assignment pattern, even though parenthesized patterns + // themselves are not allowed, e.g., "[(x)] = []". Only accumulate + // assignment pattern errors if the parsed expression is more complex. + if (impl()->IsIdentifier(result)) { + if (result->is_parenthesized()) { + expression_scope()->RecordDeclarationError( + Scanner::Location(begin, end_position()), + MessageTemplate::kInvalidDestructuringTarget); + } + IdentifierT identifier = impl()->AsIdentifier(result); + ClassifyParameter(identifier, begin, end_position()); + } else { + DCHECK(result->IsProperty()); + expression_scope()->RecordDeclarationError( + Scanner::Location(begin, end_position()), + MessageTemplate::kInvalidPropertyBindingPattern); + if (scope != nullptr) scope->ValidateExpression(); + } + } else if (result->is_parenthesized() || + (!result->IsPattern() && !result->IsAssignment())) { + expression_scope()->RecordPatternError( + Scanner::Location(begin, end_position()), MessageTemplate::kInvalidDestructuringTarget); } + + return result; } template <typename Impl> -typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseV8Intrinsic( - bool* ok) { +typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseV8Intrinsic() { // CallRuntime :: // '%' Identifier Arguments int pos = peek_position(); - Expect(Token::MOD, CHECK_OK); + Consume(Token::MOD); // Allow "eval" or "arguments" for backward compatibility. - IdentifierT name = ParseIdentifier(kAllowRestrictedIdentifiers, CHECK_OK); - Scanner::Location spread_pos; - ExpressionClassifier classifier(this); - ExpressionListT args = ParseArguments(&spread_pos, CHECK_OK); - - if (spread_pos.IsValid()) { - *ok = false; - ReportMessageAt(spread_pos, MessageTemplate::kIntrinsicWithSpread, - kSyntaxError); - return impl()->NullExpression(); + IdentifierT name = ParseIdentifier(); + if (peek() != Token::LPAREN) { + impl()->ReportUnexpectedToken(peek()); + return impl()->FailureExpression(); } + bool has_spread; + ExpressionListT args(pointer_buffer()); + ParseArguments(&args, &has_spread); - return impl()->NewV8Intrinsic(name, args, pos, ok); -} - -template <typename Impl> -typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseDoExpression( - bool* ok) { - // AssignmentExpression :: - // do '{' StatementList '}' + if (has_spread) { + ReportMessageAt(Scanner::Location(pos, position()), + MessageTemplate::kIntrinsicWithSpread, kSyntaxError); + return impl()->FailureExpression(); + } - int pos = peek_position(); - Expect(Token::DO, CHECK_OK); - BlockT block = ParseBlock(nullptr, CHECK_OK); - return impl()->RewriteDoExpression(block, pos, ok); + return impl()->NewV8Intrinsic(name, args, pos); } -// Redefinition of CHECK_OK for parsing statements. -#undef CHECK_OK -#define CHECK_OK CHECK_OK_CUSTOM(NullStatement) - template <typename Impl> -typename ParserBase<Impl>::LazyParsingResult -ParserBase<Impl>::ParseStatementList(StatementListT body, - Token::Value end_token, bool may_abort, - bool* ok) { +void ParserBase<Impl>::ParseStatementList(StatementListT* body, + Token::Value end_token) { // StatementList :: // (StatementListItem)* <end_token> + DCHECK_NOT_NULL(body); - // Allocate a target stack to use for this set of source - // elements. This way, all scripts and functions get their own - // target stack thus avoiding illegal breaks and continues across - // functions. - typename Types::TargetScope target_scope(this); - int count_statements = 0; + while (peek() == Token::STRING) { + bool use_strict = false; + bool use_asm = false; - DCHECK(!impl()->IsNull(body)); - bool directive_prologue = true; // Parsing directive prologue. + Scanner::Location token_loc = scanner()->peek_location(); - while (peek() != end_token) { - if (directive_prologue && peek() != Token::STRING) { - directive_prologue = false; + if (scanner()->NextLiteralEquals("use strict")) { + use_strict = true; + } else if (scanner()->NextLiteralEquals("use asm")) { + use_asm = true; } - bool starts_with_identifier = peek() == Token::IDENTIFIER; - Scanner::Location token_loc = scanner()->peek_location(); - StatementT stat = - ParseStatementListItem(CHECK_OK_CUSTOM(Return, kLazyParsingComplete)); - - if (impl()->IsNull(stat) || stat->IsEmptyStatement()) { - directive_prologue = false; // End of directive prologue. - continue; - } - - if (directive_prologue) { - // The length of the token is used to distinguish between strings literals - // that evaluate equal to directives but contain either escape sequences - // (e.g., "use \x73trict") or line continuations (e.g., "use \(newline) - // strict"). - if (impl()->IsUseStrictDirective(stat) && - token_loc.end_pos - token_loc.beg_pos == sizeof("use strict") + 1) { - // Directive "use strict" (ES5 14.1). - RaiseLanguageMode(LanguageMode::kStrict); - if (!scope()->HasSimpleParameters()) { - // TC39 deemed "use strict" directives to be an error when occurring - // in the body of a function with non-simple parameter list, on - // 29/7/2015. https://goo.gl/ueA7Ln - impl()->ReportMessageAt( - token_loc, MessageTemplate::kIllegalLanguageModeDirective, - "use strict"); - *ok = false; - return kLazyParsingComplete; - } - } else if (impl()->IsUseAsmDirective(stat) && - token_loc.end_pos - token_loc.beg_pos == - sizeof("use asm") + 1) { - // Directive "use asm". - impl()->SetAsmModule(); - } else if (impl()->IsStringLiteral(stat)) { - // Possibly an unknown directive. - // Should not change mode, but will increment usage counters - // as appropriate. Ditto usages below. - RaiseLanguageMode(LanguageMode::kSloppy); - } else { - // End of the directive prologue. - directive_prologue = false; - RaiseLanguageMode(LanguageMode::kSloppy); + StatementT stat = ParseStatementListItem(); + if (impl()->IsNull(stat)) return; + + body->Add(stat); + + if (!impl()->IsStringLiteral(stat)) break; + + if (use_strict) { + // Directive "use strict" (ES5 14.1). + RaiseLanguageMode(LanguageMode::kStrict); + if (!scope()->HasSimpleParameters()) { + // TC39 deemed "use strict" directives to be an error when occurring + // in the body of a function with non-simple parameter list, on + // 29/7/2015. https://goo.gl/ueA7Ln + impl()->ReportMessageAt(token_loc, + MessageTemplate::kIllegalLanguageModeDirective, + "use strict"); + return; } + } else if (use_asm) { + // Directive "use asm". + impl()->SetAsmModule(); } else { + // Possibly an unknown directive. + // Should not change mode, but will increment usage counters + // as appropriate. Ditto usages below. RaiseLanguageMode(LanguageMode::kSloppy); } + } - // If we're allowed to abort, we will do so when we see a "long and - // trivial" function. Our current definition of "long and trivial" is: - // - over kLazyParseTrialLimit statements - // - all starting with an identifier (i.e., no if, for, while, etc.) - if (may_abort) { - if (!starts_with_identifier) { - may_abort = false; - } else if (++count_statements > kLazyParseTrialLimit) { - return kLazyParsingAborted; - } - } - - body->Add(stat, zone()); + // Allocate a target stack to use for this set of source elements. This way, + // all scripts and functions get their own target stack thus avoiding illegal + // breaks and continues across functions. + TargetScopeT target_scope(this); + while (peek() != end_token) { + StatementT stat = ParseStatementListItem(); + if (impl()->IsNull(stat)) return; + if (stat->IsEmptyStatement()) continue; + body->Add(stat); } - return kLazyParsingComplete; } template <typename Impl> -typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStatementListItem( - bool* ok) { +typename ParserBase<Impl>::StatementT +ParserBase<Impl>::ParseStatementListItem() { // ECMA 262 6th Edition // StatementListItem[Yield, Return] : // Statement[?Yield, ?Return] @@ -4973,36 +4488,36 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStatementListItem( switch (peek()) { case Token::FUNCTION: - return ParseHoistableDeclaration(nullptr, false, ok); + return ParseHoistableDeclaration(nullptr, false); case Token::CLASS: Consume(Token::CLASS); - return ParseClassDeclaration(nullptr, false, ok); + return ParseClassDeclaration(nullptr, false); case Token::VAR: case Token::CONST: - return ParseVariableStatement(kStatementListItem, nullptr, ok); + return ParseVariableStatement(kStatementListItem, nullptr); case Token::LET: if (IsNextLetKeyword()) { - return ParseVariableStatement(kStatementListItem, nullptr, ok); + return ParseVariableStatement(kStatementListItem, nullptr); } break; case Token::ASYNC: if (PeekAhead() == Token::FUNCTION && !scanner()->HasLineTerminatorAfterNext()) { Consume(Token::ASYNC); - return ParseAsyncFunctionDeclaration(nullptr, false, ok); + return ParseAsyncFunctionDeclaration(nullptr, false); } break; default: break; } - return ParseStatement(nullptr, nullptr, kAllowLabelledFunctionStatement, ok); + return ParseStatement(nullptr, nullptr, kAllowLabelledFunctionStatement); } template <typename Impl> typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStatement( ZonePtrList<const AstRawString>* labels, ZonePtrList<const AstRawString>* own_labels, - AllowLabelledFunctionStatement allow_function, bool* ok) { + AllowLabelledFunctionStatement allow_function) { // Statement :: // Block // VariableStatement @@ -5031,46 +4546,48 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStatement( // parsed into an empty statement. switch (peek()) { case Token::LBRACE: - return ParseBlock(labels, ok); + return ParseBlock(labels); case Token::SEMICOLON: Next(); - return factory()->NewEmptyStatement(kNoSourcePosition); + return factory()->EmptyStatement(); case Token::IF: - return ParseIfStatement(labels, ok); + return ParseIfStatement(labels); case Token::DO: - return ParseDoWhileStatement(labels, own_labels, ok); + return ParseDoWhileStatement(labels, own_labels); case Token::WHILE: - return ParseWhileStatement(labels, own_labels, ok); + return ParseWhileStatement(labels, own_labels); case Token::FOR: if (V8_UNLIKELY(is_async_function() && PeekAhead() == Token::AWAIT)) { - return ParseForAwaitStatement(labels, own_labels, ok); + return ParseForAwaitStatement(labels, own_labels); } - return ParseForStatement(labels, own_labels, ok); + return ParseForStatement(labels, own_labels); case Token::CONTINUE: - return ParseContinueStatement(ok); + return ParseContinueStatement(); case Token::BREAK: - return ParseBreakStatement(labels, ok); + return ParseBreakStatement(labels); case Token::RETURN: - return ParseReturnStatement(ok); + return ParseReturnStatement(); case Token::THROW: - return ParseThrowStatement(ok); + return ParseThrowStatement(); case Token::TRY: { // It is somewhat complicated to have labels on try-statements. // When breaking out of a try-finally statement, one must take // great care not to treat it as a fall-through. It is much easier // just to wrap the entire try-statement in a statement block and // put the labels there. - if (labels == nullptr) return ParseTryStatement(ok); - BlockT result = factory()->NewBlock(1, false, labels); - typename Types::Target target(this, result); - StatementT statement = ParseTryStatement(CHECK_OK); - result->statements()->Add(statement, zone()); + if (labels == nullptr) return ParseTryStatement(); + StatementListT statements(pointer_buffer()); + BlockT result = factory()->NewBlock(false, labels); + TargetT target(this, result); + StatementT statement = ParseTryStatement(); + statements.Add(statement); + result->InitializeStatements(statements, zone()); return result; } case Token::WITH: - return ParseWithStatement(labels, ok); + return ParseWithStatement(labels); case Token::SWITCH: - return ParseSwitchStatement(labels, ok); + return ParseSwitchStatement(labels); case Token::FUNCTION: // FunctionDeclaration only allowed as a StatementListItem, not in // an arbitrary Statement position. Exceptions such as @@ -5081,72 +4598,77 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStatement( is_strict(language_mode()) ? MessageTemplate::kStrictFunction : MessageTemplate::kSloppyFunction); - *ok = false; return impl()->NullStatement(); case Token::DEBUGGER: - return ParseDebuggerStatement(ok); + return ParseDebuggerStatement(); case Token::VAR: - return ParseVariableStatement(kStatement, nullptr, ok); + return ParseVariableStatement(kStatement, nullptr); case Token::ASYNC: if (!scanner()->HasLineTerminatorAfterNext() && PeekAhead() == Token::FUNCTION) { impl()->ReportMessageAt( scanner()->peek_location(), MessageTemplate::kAsyncFunctionInSingleStatementContext); - *ok = false; return impl()->NullStatement(); } V8_FALLTHROUGH; default: return ParseExpressionOrLabelledStatement(labels, own_labels, - allow_function, ok); + allow_function); } } template <typename Impl> typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseBlock( - ZonePtrList<const AstRawString>* labels, bool* ok) { + ZonePtrList<const AstRawString>* labels) { // Block :: // '{' StatementList '}' - // Construct block expecting 16 statements. - BlockT body = factory()->NewBlock(16, false, labels); - // Parse the statements and collect escaping labels. - Expect(Token::LBRACE, CHECK_OK_CUSTOM(NullStatement)); + BlockT body = factory()->NewBlock(false, labels); + StatementListT statements(pointer_buffer()); + + CheckStackOverflow(); + { BlockState block_state(zone(), &scope_); - scope()->set_start_position(scanner()->location().beg_pos); - typename Types::Target target(this, body); + scope()->set_start_position(peek_position()); + TargetT target(this, body); + + Expect(Token::LBRACE); while (peek() != Token::RBRACE) { - StatementT stat = ParseStatementListItem(CHECK_OK_CUSTOM(NullStatement)); - if (!impl()->IsNull(stat) && !stat->IsEmptyStatement()) { - body->statements()->Add(stat, zone()); - } + StatementT stat = ParseStatementListItem(); + if (impl()->IsNull(stat)) return body; + if (stat->IsEmptyStatement()) continue; + statements.Add(stat); } - Expect(Token::RBRACE, CHECK_OK_CUSTOM(NullStatement)); + Expect(Token::RBRACE); + int end_pos = end_position(); scope()->set_end_position(end_pos); + impl()->RecordBlockSourceRange(body, end_pos); body->set_scope(scope()->FinalizeBlockScope()); } + + body->InitializeStatements(statements, zone_); return body; } template <typename Impl> typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseScopedStatement( - ZonePtrList<const AstRawString>* labels, bool* ok) { + ZonePtrList<const AstRawString>* labels) { if (is_strict(language_mode()) || peek() != Token::FUNCTION) { - return ParseStatement(labels, nullptr, ok); + return ParseStatement(labels, nullptr); } else { // Make a block around the statement for a lexical binding // is introduced by a FunctionDeclaration. BlockState block_state(zone(), &scope_); scope()->set_start_position(scanner()->location().beg_pos); BlockT block = factory()->NewBlock(1, false); - StatementT body = ParseFunctionDeclaration(CHECK_OK); + StatementT body = ParseFunctionDeclaration(); block->statements()->Add(body, zone()); scope()->set_end_position(end_position()); block->set_scope(scope()->FinalizeBlockScope()); @@ -5157,7 +4679,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseScopedStatement( template <typename Impl> typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseVariableStatement( VariableDeclarationContext var_context, - ZonePtrList<const AstRawString>* names, bool* ok) { + ZonePtrList<const AstRawString>* names) { // VariableStatement :: // VariableDeclarations ';' @@ -5174,15 +4696,14 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseVariableStatement( // is inside an initializer block, it is ignored. DeclarationParsingResult parsing_result; - StatementT result = - ParseVariableDeclarations(var_context, &parsing_result, names, CHECK_OK); - ExpectSemicolon(ok); - return result; + ParseVariableDeclarations(var_context, &parsing_result, names); + ExpectSemicolon(); + return impl()->BuildInitializationBlock(&parsing_result); } template <typename Impl> -typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseDebuggerStatement( - bool* ok) { +typename ParserBase<Impl>::StatementT +ParserBase<Impl>::ParseDebuggerStatement() { // In ECMA-262 'debugger' is defined as a reserved keyword. In some browser // contexts this is used as a statement which invokes the debugger as i a // break point is present. @@ -5190,8 +4711,8 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseDebuggerStatement( // 'debugger' ';' int pos = peek_position(); - Expect(Token::DEBUGGER, CHECK_OK); - ExpectSemicolon(CHECK_OK); + Consume(Token::DEBUGGER); + ExpectSemicolon(); return factory()->NewDebuggerStatement(pos); } @@ -5200,7 +4721,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseExpressionOrLabelledStatement( ZonePtrList<const AstRawString>* labels, ZonePtrList<const AstRawString>* own_labels, - AllowLabelledFunctionStatement allow_function, bool* ok) { + AllowLabelledFunctionStatement allow_function) { // ExpressionStatement | LabelledStatement :: // Expression ';' // Identifier ':' Statement @@ -5216,7 +4737,6 @@ ParserBase<Impl>::ParseExpressionOrLabelledStatement( UNREACHABLE(); // Always handled by the callers. case Token::CLASS: ReportUnexpectedToken(Next()); - *ok = false; return impl()->NullStatement(); case Token::LET: { Token::Value next_next = PeekAhead(); @@ -5230,7 +4750,6 @@ ParserBase<Impl>::ParseExpressionOrLabelledStatement( } impl()->ReportMessageAt(scanner()->peek_location(), MessageTemplate::kUnexpectedLexicalDeclaration); - *ok = false; return impl()->NullStatement(); } default: @@ -5238,20 +4757,20 @@ ParserBase<Impl>::ParseExpressionOrLabelledStatement( } bool starts_with_identifier = peek_any_identifier(); - ExpressionT expr = ParseExpression(CHECK_OK); + ExpressionT expr = ParseExpression(); if (peek() == Token::COLON && starts_with_identifier && impl()->IsIdentifier(expr)) { // The whole expression was a single identifier, and not, e.g., // something starting with an identifier or a parenthesized identifier. impl()->DeclareLabel(&labels, &own_labels, - impl()->AsIdentifierExpression(expr), CHECK_OK); + impl()->AsIdentifierExpression(expr)); Consume(Token::COLON); // ES#sec-labelled-function-declarations Labelled Function Declarations if (peek() == Token::FUNCTION && is_sloppy(language_mode()) && allow_function == kAllowLabelledFunctionStatement) { - return ParseFunctionDeclaration(ok); + return ParseFunctionDeclaration(); } - return ParseStatement(labels, own_labels, allow_function, ok); + return ParseStatement(labels, own_labels, allow_function); } // If we have an extension, we allow a native function declaration. @@ -5260,39 +4779,46 @@ ParserBase<Impl>::ParseExpressionOrLabelledStatement( if (extension_ != nullptr && peek() == Token::FUNCTION && !scanner()->HasLineTerminatorBeforeNext() && impl()->IsNative(expr) && !scanner()->literal_contains_escapes()) { - return ParseNativeDeclaration(ok); + return ParseNativeDeclaration(); } // Parsed expression statement, followed by semicolon. - ExpectSemicolon(CHECK_OK); + ExpectSemicolon(); + if (expr->IsFailureExpression()) return impl()->NullStatement(); return factory()->NewExpressionStatement(expr, pos); } template <typename Impl> typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseIfStatement( - ZonePtrList<const AstRawString>* labels, bool* ok) { + ZonePtrList<const AstRawString>* labels) { // IfStatement :: // 'if' '(' Expression ')' Statement ('else' Statement)? int pos = peek_position(); - Expect(Token::IF, CHECK_OK); - Expect(Token::LPAREN, CHECK_OK); - ExpressionT condition = ParseExpression(CHECK_OK); - Expect(Token::RPAREN, CHECK_OK); + Consume(Token::IF); + Expect(Token::LPAREN); + ExpressionT condition = ParseExpression(); + Expect(Token::RPAREN); SourceRange then_range, else_range; StatementT then_statement = impl()->NullStatement(); { SourceRangeScope range_scope(scanner(), &then_range); - then_statement = ParseScopedStatement(labels, CHECK_OK); + // Make a copy of {labels} to avoid conflicts with any + // labels that may be applied to the else clause below. + auto labels_copy = + labels == nullptr + ? labels + : new (zone()) ZonePtrList<const AstRawString>(*labels, zone()); + then_statement = ParseScopedStatement(labels_copy); } StatementT else_statement = impl()->NullStatement(); if (Check(Token::ELSE)) { - else_statement = ParseScopedStatement(labels, CHECK_OK); + else_statement = ParseScopedStatement(labels); else_range = SourceRange::ContinuationOf(then_range, end_position()); } else { - else_statement = factory()->NewEmptyStatement(kNoSourcePosition); + else_statement = factory()->EmptyStatement(); } StatementT stmt = factory()->NewIfStatement(condition, then_statement, else_statement, pos); @@ -5301,37 +4827,34 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseIfStatement( } template <typename Impl> -typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseContinueStatement( - bool* ok) { +typename ParserBase<Impl>::StatementT +ParserBase<Impl>::ParseContinueStatement() { // ContinueStatement :: // 'continue' Identifier? ';' int pos = peek_position(); - Expect(Token::CONTINUE, CHECK_OK); + Consume(Token::CONTINUE); IdentifierT label = impl()->NullIdentifier(); Token::Value tok = peek(); - if (!scanner()->HasLineTerminatorBeforeNext() && tok != Token::SEMICOLON && - tok != Token::RBRACE && tok != Token::EOS) { + if (!scanner()->HasLineTerminatorBeforeNext() && + !Token::IsAutoSemicolon(tok)) { // ECMA allows "eval" or "arguments" as labels even in strict mode. - label = ParseIdentifier(kAllowRestrictedIdentifiers, CHECK_OK); + label = ParseIdentifier(); } - typename Types::IterationStatement target = - impl()->LookupContinueTarget(label, CHECK_OK); + IterationStatementT target = impl()->LookupContinueTarget(label); if (impl()->IsNull(target)) { // Illegal continue statement. - MessageTemplate::Template message = MessageTemplate::kIllegalContinue; - typename Types::BreakableStatement breakable_target = - impl()->LookupBreakTarget(label, CHECK_OK); + MessageTemplate message = MessageTemplate::kIllegalContinue; + BreakableStatementT breakable_target = impl()->LookupBreakTarget(label); if (impl()->IsNull(label)) { message = MessageTemplate::kNoIterationStatement; } else if (impl()->IsNull(breakable_target)) { message = MessageTemplate::kUnknownLabel; } ReportMessage(message, label); - *ok = false; return impl()->NullStatement(); } - ExpectSemicolon(CHECK_OK); + ExpectSemicolon(); StatementT stmt = factory()->NewContinueStatement(target, pos); impl()->RecordJumpStatementSourceRange(stmt, end_position()); return stmt; @@ -5339,53 +4862,50 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseContinueStatement( template <typename Impl> typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseBreakStatement( - ZonePtrList<const AstRawString>* labels, bool* ok) { + ZonePtrList<const AstRawString>* labels) { // BreakStatement :: // 'break' Identifier? ';' int pos = peek_position(); - Expect(Token::BREAK, CHECK_OK); + Consume(Token::BREAK); IdentifierT label = impl()->NullIdentifier(); Token::Value tok = peek(); - if (!scanner()->HasLineTerminatorBeforeNext() && tok != Token::SEMICOLON && - tok != Token::RBRACE && tok != Token::EOS) { + if (!scanner()->HasLineTerminatorBeforeNext() && + !Token::IsAutoSemicolon(tok)) { // ECMA allows "eval" or "arguments" as labels even in strict mode. - label = ParseIdentifier(kAllowRestrictedIdentifiers, CHECK_OK); + label = ParseIdentifier(); } // Parse labeled break statements that target themselves into // empty statements, e.g. 'l1: l2: l3: break l2;' if (!impl()->IsNull(label) && impl()->ContainsLabel(labels, label)) { - ExpectSemicolon(CHECK_OK); - return factory()->NewEmptyStatement(pos); + ExpectSemicolon(); + return factory()->EmptyStatement(); } - typename Types::BreakableStatement target = - impl()->LookupBreakTarget(label, CHECK_OK); + BreakableStatementT target = impl()->LookupBreakTarget(label); if (impl()->IsNull(target)) { // Illegal break statement. - MessageTemplate::Template message = MessageTemplate::kIllegalBreak; + MessageTemplate message = MessageTemplate::kIllegalBreak; if (!impl()->IsNull(label)) { message = MessageTemplate::kUnknownLabel; } ReportMessage(message, label); - *ok = false; return impl()->NullStatement(); } - ExpectSemicolon(CHECK_OK); + ExpectSemicolon(); StatementT stmt = factory()->NewBreakStatement(target, pos); impl()->RecordJumpStatementSourceRange(stmt, end_position()); return stmt; } template <typename Impl> -typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseReturnStatement( - bool* ok) { +typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseReturnStatement() { // ReturnStatement :: // 'return' [no line terminator] Expression? ';' // Consume the return token. It is necessary to do that before // reporting any errors on it, because of the way errors are // reported (underlining). - Expect(Token::RETURN, CHECK_OK); + Consume(Token::RETURN); Scanner::Location loc = scanner()->location(); switch (GetDeclarationScope()->scope_type()) { @@ -5393,7 +4913,6 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseReturnStatement( case EVAL_SCOPE: case MODULE_SCOPE: impl()->ReportMessageAt(loc, MessageTemplate::kIllegalReturn); - *ok = false; return impl()->NullStatement(); default: break; @@ -5401,15 +4920,15 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseReturnStatement( Token::Value tok = peek(); ExpressionT return_value = impl()->NullExpression(); - if (scanner()->HasLineTerminatorBeforeNext() || tok == Token::SEMICOLON || - tok == Token::RBRACE || tok == Token::EOS) { + if (scanner()->HasLineTerminatorBeforeNext() || Token::IsAutoSemicolon(tok)) { if (IsDerivedConstructor(function_state_->kind())) { return_value = impl()->ThisExpression(loc.beg_pos); } } else { - return_value = ParseExpression(CHECK_OK); + return_value = ParseExpression(); } - ExpectSemicolon(CHECK_OK); + ExpectSemicolon(); + return_value = impl()->RewriteReturn(return_value, loc.beg_pos); int continuation_pos = end_position(); StatementT stmt = @@ -5420,29 +4939,28 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseReturnStatement( template <typename Impl> typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseWithStatement( - ZonePtrList<const AstRawString>* labels, bool* ok) { + ZonePtrList<const AstRawString>* labels) { // WithStatement :: // 'with' '(' Expression ')' Statement - Expect(Token::WITH, CHECK_OK); + Consume(Token::WITH); int pos = position(); if (is_strict(language_mode())) { ReportMessage(MessageTemplate::kStrictWith); - *ok = false; return impl()->NullStatement(); } - Expect(Token::LPAREN, CHECK_OK); - ExpressionT expr = ParseExpression(CHECK_OK); - Expect(Token::RPAREN, CHECK_OK); + Expect(Token::LPAREN); + ExpressionT expr = ParseExpression(); + Expect(Token::RPAREN); Scope* with_scope = NewScope(WITH_SCOPE); StatementT body = impl()->NullStatement(); { BlockState block_state(&scope_, with_scope); with_scope->set_start_position(scanner()->peek_location().beg_pos); - body = ParseStatement(labels, nullptr, CHECK_OK); + body = ParseStatement(labels, nullptr); with_scope->set_end_position(end_position()); } return factory()->NewWithStatement(with_scope, expr, body, pos); @@ -5451,27 +4969,30 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseWithStatement( template <typename Impl> typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseDoWhileStatement( ZonePtrList<const AstRawString>* labels, - ZonePtrList<const AstRawString>* own_labels, bool* ok) { + ZonePtrList<const AstRawString>* own_labels) { // DoStatement :: // 'do' Statement 'while' '(' Expression ')' ';' + typename FunctionState::LoopScope loop_scope(function_state_); auto loop = factory()->NewDoWhileStatement(labels, own_labels, peek_position()); - typename Types::Target target(this, loop); + TargetT target(this, loop); SourceRange body_range; StatementT body = impl()->NullStatement(); - Expect(Token::DO, CHECK_OK); + Consume(Token::DO); + + CheckStackOverflow(); { SourceRangeScope range_scope(scanner(), &body_range); - body = ParseStatement(nullptr, nullptr, CHECK_OK); + body = ParseStatement(nullptr, nullptr); } - Expect(Token::WHILE, CHECK_OK); - Expect(Token::LPAREN, CHECK_OK); + Expect(Token::WHILE); + Expect(Token::LPAREN); - ExpressionT cond = ParseExpression(CHECK_OK); - Expect(Token::RPAREN, CHECK_OK); + ExpressionT cond = ParseExpression(); + Expect(Token::RPAREN); // Allow do-statements to be terminated with and without // semi-colons. This allows code such as 'do;while(0)return' to @@ -5488,23 +5009,24 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseDoWhileStatement( template <typename Impl> typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseWhileStatement( ZonePtrList<const AstRawString>* labels, - ZonePtrList<const AstRawString>* own_labels, bool* ok) { + ZonePtrList<const AstRawString>* own_labels) { // WhileStatement :: // 'while' '(' Expression ')' Statement + typename FunctionState::LoopScope loop_scope(function_state_); auto loop = factory()->NewWhileStatement(labels, own_labels, peek_position()); - typename Types::Target target(this, loop); + TargetT target(this, loop); SourceRange body_range; StatementT body = impl()->NullStatement(); - Expect(Token::WHILE, CHECK_OK); - Expect(Token::LPAREN, CHECK_OK); - ExpressionT cond = ParseExpression(CHECK_OK); - Expect(Token::RPAREN, CHECK_OK); + Consume(Token::WHILE); + Expect(Token::LPAREN); + ExpressionT cond = ParseExpression(); + Expect(Token::RPAREN); { SourceRangeScope range_scope(scanner(), &body_range); - body = ParseStatement(nullptr, nullptr, CHECK_OK); + body = ParseStatement(nullptr, nullptr); } loop->Initialize(cond, body); @@ -5514,20 +5036,18 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseWhileStatement( } template <typename Impl> -typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseThrowStatement( - bool* ok) { +typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseThrowStatement() { // ThrowStatement :: // 'throw' Expression ';' - Expect(Token::THROW, CHECK_OK); + Consume(Token::THROW); int pos = position(); if (scanner()->HasLineTerminatorBeforeNext()) { ReportMessage(MessageTemplate::kNewlineAfterThrow); - *ok = false; return impl()->NullStatement(); } - ExpressionT exception = ParseExpression(CHECK_OK); - ExpectSemicolon(CHECK_OK); + ExpressionT exception = ParseExpression(); + ExpectSemicolon(); StatementT stmt = impl()->NewThrowStatement(exception, pos); impl()->RecordThrowSourceRange(stmt, end_position()); @@ -5537,7 +5057,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseThrowStatement( template <typename Impl> typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseSwitchStatement( - ZonePtrList<const AstRawString>* labels, bool* ok) { + ZonePtrList<const AstRawString>* labels) { // SwitchStatement :: // 'switch' '(' Expression ')' '{' CaseClause* '}' // CaseClause :: @@ -5546,10 +5066,10 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseSwitchStatement( int switch_pos = peek_position(); - Expect(Token::SWITCH, CHECK_OK); - Expect(Token::LPAREN, CHECK_OK); - ExpressionT tag = ParseExpression(CHECK_OK); - Expect(Token::RPAREN, CHECK_OK); + Consume(Token::SWITCH); + Expect(Token::LPAREN); + ExpressionT tag = ParseExpression(); + Expect(Token::RPAREN); auto switch_statement = factory()->NewSwitchStatement(labels, tag, switch_pos); @@ -5558,38 +5078,41 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseSwitchStatement( BlockState cases_block_state(zone(), &scope_); scope()->set_start_position(switch_pos); scope()->SetNonlinear(); - typename Types::Target target(this, switch_statement); + TargetT target(this, switch_statement); bool default_seen = false; - Expect(Token::LBRACE, CHECK_OK); + Expect(Token::LBRACE); while (peek() != Token::RBRACE) { // An empty label indicates the default case. ExpressionT label = impl()->NullExpression(); + StatementListT statements(pointer_buffer()); SourceRange clause_range; - SourceRangeScope range_scope(scanner(), &clause_range); - if (Check(Token::CASE)) { - label = ParseExpression(CHECK_OK); - } else { - Expect(Token::DEFAULT, CHECK_OK); - if (default_seen) { - ReportMessage(MessageTemplate::kMultipleDefaultsInSwitch); - *ok = false; - return impl()->NullStatement(); + { + SourceRangeScope range_scope(scanner(), &clause_range); + if (Check(Token::CASE)) { + label = ParseExpression(); + } else { + Expect(Token::DEFAULT); + if (default_seen) { + ReportMessage(MessageTemplate::kMultipleDefaultsInSwitch); + return impl()->NullStatement(); + } + default_seen = true; + } + Expect(Token::COLON); + while (peek() != Token::CASE && peek() != Token::DEFAULT && + peek() != Token::RBRACE) { + StatementT stat = ParseStatementListItem(); + if (impl()->IsNull(stat)) return stat; + if (stat->IsEmptyStatement()) continue; + statements.Add(stat); } - default_seen = true; - } - Expect(Token::COLON, CHECK_OK); - StatementListT statements = impl()->NewStatementList(5); - while (peek() != Token::CASE && peek() != Token::DEFAULT && - peek() != Token::RBRACE) { - StatementT stat = ParseStatementListItem(CHECK_OK); - statements->Add(stat, zone()); } auto clause = factory()->NewCaseClause(label, statements); - impl()->RecordCaseClauseSourceRange(clause, range_scope.Finalize()); + impl()->RecordCaseClauseSourceRange(clause, clause_range); switch_statement->cases()->Add(clause, zone()); } - Expect(Token::RBRACE, CHECK_OK); + Expect(Token::RBRACE); int end_pos = end_position(); scope()->set_end_position(end_pos); @@ -5603,8 +5126,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseSwitchStatement( } template <typename Impl> -typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseTryStatement( - bool* ok) { +typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseTryStatement() { // TryStatement :: // 'try' Block Catch // 'try' Block Finally @@ -5616,22 +5138,21 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseTryStatement( // Finally :: // 'finally' Block - Expect(Token::TRY, CHECK_OK); + Consume(Token::TRY); int pos = position(); - BlockT try_block = ParseBlock(nullptr, CHECK_OK); + BlockT try_block = ParseBlock(nullptr); CatchInfo catch_info(this); if (peek() != Token::CATCH && peek() != Token::FINALLY) { ReportMessage(MessageTemplate::kNoCatchOrFinally); - *ok = false; return impl()->NullStatement(); } SourceRange catch_range, finally_range; - BlockT catch_block = impl()->NullStatement(); + BlockT catch_block = impl()->NullBlock(); { SourceRangeScope catch_range_scope(scanner(), &catch_range); if (Check(Token::CATCH)) { @@ -5644,57 +5165,74 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseTryStatement( { BlockState catch_block_state(&scope_, catch_info.scope); - - catch_block = factory()->NewBlock(16, false); + StatementListT catch_statements(pointer_buffer()); // Create a block scope to hold any lexical declarations created // as part of destructuring the catch parameter. { BlockState catch_variable_block_state(zone(), &scope_); - scope()->set_start_position(scanner()->location().beg_pos); + scope()->set_start_position(position()); - // This does not simply call ParsePrimaryExpression to avoid - // ExpressionFromIdentifier from being called in the first - // branch, which would introduce an unresolved symbol and mess - // with arrow function names. if (peek_any_identifier()) { - catch_info.name = - ParseIdentifier(kDontAllowRestrictedIdentifiers, CHECK_OK); + IdentifierT identifier = ParseNonRestrictedIdentifier(); + RETURN_IF_PARSE_ERROR; + catch_info.variable = impl()->DeclareCatchVariableName( + catch_info.scope, identifier); } else { - ExpressionClassifier pattern_classifier(this); - catch_info.pattern = ParseBindingPattern(CHECK_OK); + catch_info.variable = catch_info.scope->DeclareCatchVariableName( + ast_value_factory()->dot_catch_string()); + VariableDeclarationParsingScope destructuring( + impl(), VariableMode::kLet, nullptr); + catch_info.pattern = ParseBindingPattern(); + RETURN_IF_PARSE_ERROR; + catch_statements.Add(impl()->RewriteCatchPattern(&catch_info)); } - Expect(Token::RPAREN, CHECK_OK); - impl()->RewriteCatchPattern(&catch_info, CHECK_OK); - if (!impl()->IsNull(catch_info.init_block)) { - catch_block->statements()->Add(catch_info.init_block, zone()); + Expect(Token::RPAREN); + + BlockT inner_block = ParseBlock(nullptr); + catch_statements.Add(inner_block); + + // Check for `catch(e) { let e; }` and similar errors. + Scope* inner_scope = inner_block->scope(); + if (inner_scope != nullptr) { + const AstRawString* conflict = nullptr; + if (impl()->IsNull(catch_info.pattern)) { + const AstRawString* name = catch_info.variable->raw_name(); + if (inner_scope->LookupLocal(name)) conflict = name; + } else { + conflict = inner_scope->FindVariableDeclaredIn( + scope(), VariableMode::kVar); + } + if (conflict != nullptr) { + impl()->ReportVarRedeclarationIn(conflict, inner_scope); + } } - catch_info.inner_block = ParseBlock(nullptr, CHECK_OK); - catch_block->statements()->Add(catch_info.inner_block, zone()); - impl()->ValidateCatchBlock(catch_info, CHECK_OK); scope()->set_end_position(end_position()); + catch_block = factory()->NewBlock(false, catch_statements); catch_block->set_scope(scope()->FinalizeBlockScope()); } } catch_info.scope->set_end_position(end_position()); } else { - catch_block = ParseBlock(nullptr, CHECK_OK); + catch_block = ParseBlock(nullptr); } } } - BlockT finally_block = impl()->NullStatement(); - DCHECK(peek() == Token::FINALLY || !impl()->IsNull(catch_block)); + BlockT finally_block = impl()->NullBlock(); + DCHECK(has_error() || peek() == Token::FINALLY || + !impl()->IsNull(catch_block)); { SourceRangeScope range_scope(scanner(), &finally_range); if (Check(Token::FINALLY)) { - finally_block = ParseBlock(nullptr, CHECK_OK); + finally_block = ParseBlock(nullptr); } } + RETURN_IF_PARSE_ERROR; return impl()->RewriteTryStatement(try_block, catch_block, catch_range, finally_block, finally_range, catch_info, pos); @@ -5703,7 +5241,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseTryStatement( template <typename Impl> typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement( ZonePtrList<const AstRawString>* labels, - ZonePtrList<const AstRawString>* own_labels, bool* ok) { + ZonePtrList<const AstRawString>* own_labels) { // Either a standard for loop // for (<init>; <cond>; <next>) { ... } // or a for-each loop @@ -5711,18 +5249,19 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement( // // We parse a declaration/expression after the 'for (' and then read the first // expression/declaration before we know if this is a for or a for-each. + typename FunctionState::LoopScope loop_scope(function_state_); int stmt_pos = peek_position(); ForInfo for_info(this); - Expect(Token::FOR, CHECK_OK); - Expect(Token::LPAREN, CHECK_OK); + Consume(Token::FOR); + Expect(Token::LPAREN); if (peek() == Token::CONST || (peek() == Token::LET && IsNextLetKeyword())) { // The initializer contains lexical declarations, // so create an in-between scope. BlockState for_state(zone(), &scope_); - scope()->set_start_position(scanner()->location().beg_pos); + scope()->set_start_position(position()); // Also record whether inner functions or evals are found inside // this loop, as this information is used to simplify the desugaring @@ -5736,78 +5275,94 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement( { BlockState inner_state(&scope_, inner_block_scope); ParseVariableDeclarations(kForStatement, &for_info.parsing_result, - nullptr, CHECK_OK); + &for_info.bound_names); } DCHECK(IsLexicalVariableMode(for_info.parsing_result.descriptor.mode)); - for_info.position = scanner()->location().beg_pos; + for_info.position = position(); if (CheckInOrOf(&for_info.mode)) { scope()->set_is_hidden(); return ParseForEachStatementWithDeclarations( - stmt_pos, &for_info, labels, own_labels, inner_block_scope, ok); + stmt_pos, &for_info, labels, own_labels, inner_block_scope); } - Expect(Token::SEMICOLON, CHECK_OK); + Expect(Token::SEMICOLON); - StatementT init = impl()->BuildInitializationBlock( - &for_info.parsing_result, &for_info.bound_names, CHECK_OK); + // Parse the remaining code in the inner block scope since the declaration + // above was parsed there. We'll finalize the unnecessary outer block scope + // after parsing the rest of the loop. + StatementT result = impl()->NullStatement(); + inner_block_scope->set_start_position(scope()->start_position()); + { + BlockState inner_state(&scope_, inner_block_scope); + StatementT init = + impl()->BuildInitializationBlock(&for_info.parsing_result); - Scope* finalized = inner_block_scope->FinalizeBlockScope(); - // No variable declarations will have been created in inner_block_scope. + result = ParseStandardForLoopWithLexicalDeclarations( + stmt_pos, init, &for_info, labels, own_labels); + } + Scope* finalized = scope()->FinalizeBlockScope(); DCHECK_NULL(finalized); USE(finalized); - return ParseStandardForLoopWithLexicalDeclarations( - stmt_pos, init, &for_info, labels, own_labels, ok); + return result; } StatementT init = impl()->NullStatement(); if (peek() == Token::VAR) { - ParseVariableDeclarations(kForStatement, &for_info.parsing_result, nullptr, - CHECK_OK); + ParseVariableDeclarations(kForStatement, &for_info.parsing_result, + &for_info.bound_names); DCHECK_EQ(for_info.parsing_result.descriptor.mode, VariableMode::kVar); for_info.position = scanner()->location().beg_pos; if (CheckInOrOf(&for_info.mode)) { return ParseForEachStatementWithDeclarations(stmt_pos, &for_info, labels, - own_labels, nullptr, ok); + own_labels, scope()); } - init = impl()->BuildInitializationBlock(&for_info.parsing_result, nullptr, - CHECK_OK); + init = impl()->BuildInitializationBlock(&for_info.parsing_result); } 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 = end_position(); - - 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 { - ValidateExpression(CHECK_OK); + int lhs_end_pos; + bool is_for_each; + ExpressionT expression; + { + ExpressionParsingScope parsing_scope(impl()); + AcceptINScope scope(this, false); + expression = ParseExpressionCoverGrammar(); + // Initializer is reference followed by in/of. + lhs_end_pos = end_position(); + is_for_each = CheckInOrOf(&for_info.mode); + if (is_for_each) { + if (expression->IsPattern()) { + parsing_scope.ValidatePattern(expression, lhs_beg_pos, lhs_end_pos); + } else { + expression = parsing_scope.ValidateAndRewriteReference( + expression, lhs_beg_pos, lhs_end_pos); + } + } else { + parsing_scope.ValidateExpression(); + } } if (is_for_each) { return ParseForEachStatementWithoutDeclarations( stmt_pos, expression, lhs_beg_pos, lhs_end_pos, &for_info, labels, - own_labels, ok); + own_labels); } // Initializer is just an expression. init = factory()->NewExpressionStatement(expression, lhs_beg_pos); } - Expect(Token::SEMICOLON, CHECK_OK); + Expect(Token::SEMICOLON); // Standard 'for' loop, we have parsed the initializer at this point. ExpressionT cond = impl()->NullExpression(); StatementT next = impl()->NullStatement(); StatementT body = impl()->NullStatement(); - ForStatementT loop = ParseStandardForLoop(stmt_pos, labels, own_labels, &cond, - &next, &body, CHECK_OK); + ForStatementT loop = + ParseStandardForLoop(stmt_pos, labels, own_labels, &cond, &next, &body); + RETURN_IF_PARSE_ERROR; loop->Initialize(init, cond, next, body); return loop; } @@ -5816,14 +5371,12 @@ template <typename Impl> typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForEachStatementWithDeclarations( int stmt_pos, ForInfo* for_info, ZonePtrList<const AstRawString>* labels, - ZonePtrList<const AstRawString>* own_labels, Scope* inner_block_scope, - bool* ok) { + ZonePtrList<const AstRawString>* own_labels, Scope* inner_block_scope) { // Just one declaration followed by in/of. if (for_info->parsing_result.declarations.size() != 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() && @@ -5835,80 +5388,66 @@ ParserBase<Impl>::ParseForEachStatementWithDeclarations( impl()->ReportMessageAt(for_info->parsing_result.first_initializer_loc, MessageTemplate::kForInOfLoopInitializer, ForEachStatement::VisitModeString(for_info->mode)); - *ok = false; return impl()->NullStatement(); } - // Reset the declaration_kind to ensure proper processing during declaration. - for_info->parsing_result.descriptor.declaration_kind = - DeclarationDescriptor::FOR_EACH; - BlockT init_block = impl()->RewriteForVarInLegacy(*for_info); auto loop = factory()->NewForEachStatement(for_info->mode, labels, own_labels, stmt_pos); - typename Types::Target target(this, loop); + TargetT target(this, loop); ExpressionT enumerable = impl()->NullExpression(); if (for_info->mode == ForEachStatement::ITERATE) { - ExpressionClassifier classifier(this); - enumerable = ParseAssignmentExpression(true, CHECK_OK); - ValidateExpression(CHECK_OK); + AcceptINScope scope(this, true); + enumerable = ParseAssignmentExpression(); } else { - enumerable = ParseExpression(CHECK_OK); + enumerable = ParseExpression(); } - Expect(Token::RPAREN, CHECK_OK); + Expect(Token::RPAREN); - Scope* for_scope = nullptr; - if (inner_block_scope != nullptr) { - for_scope = inner_block_scope->outer_scope(); - DCHECK_EQ(for_scope, scope()); - inner_block_scope->set_start_position(scanner()->location().beg_pos); + if (IsLexicalVariableMode(for_info->parsing_result.descriptor.mode)) { + inner_block_scope->set_start_position(position()); } ExpressionT each_variable = impl()->NullExpression(); - BlockT body_block = impl()->NullStatement(); + BlockT body_block = impl()->NullBlock(); { - BlockState block_state( - &scope_, inner_block_scope != nullptr ? inner_block_scope : scope_); + BlockState block_state(&scope_, inner_block_scope); SourceRange body_range; - SourceRangeScope range_scope(scanner(), &body_range); - - StatementT body = ParseStatement(nullptr, nullptr, CHECK_OK); - impl()->RecordIterationStatementSourceRange(loop, range_scope.Finalize()); + StatementT body = impl()->NullStatement(); + { + SourceRangeScope range_scope(scanner(), &body_range); + body = ParseStatement(nullptr, nullptr); + } + impl()->RecordIterationStatementSourceRange(loop, body_range); - impl()->DesugarBindingInForEachStatement(for_info, &body_block, - &each_variable, CHECK_OK); + DesugarBindingInForEachStatement(for_info, &body_block, &each_variable); body_block->statements()->Add(body, zone()); - if (inner_block_scope != nullptr) { - inner_block_scope->set_end_position(end_position()); - body_block->set_scope(inner_block_scope->FinalizeBlockScope()); + if (IsLexicalVariableMode(for_info->parsing_result.descriptor.mode)) { + scope()->set_end_position(end_position()); + body_block->set_scope(scope()->FinalizeBlockScope()); } } - StatementT final_loop = impl()->InitializeForEachStatement( - loop, each_variable, enumerable, body_block); + loop->Initialize(each_variable, enumerable, body_block); - init_block = - impl()->CreateForEachStatementTDZ(init_block, *for_info, CHECK_OK); - - if (for_scope != nullptr) { - for_scope->set_end_position(end_position()); - for_scope = for_scope->FinalizeBlockScope(); - } + init_block = impl()->CreateForEachStatementTDZ(init_block, *for_info); // Parsed for-in loop w/ variable declarations. if (!impl()->IsNull(init_block)) { - init_block->statements()->Add(final_loop, zone()); - init_block->set_scope(for_scope); + init_block->statements()->Add(loop, zone()); + if (IsLexicalVariableMode(for_info->parsing_result.descriptor.mode)) { + scope()->set_end_position(end_position()); + init_block->set_scope(scope()->FinalizeBlockScope()); + } return init_block; } - DCHECK_NULL(for_scope); - return final_loop; + return loop; } template <typename Impl> @@ -5916,38 +5455,31 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForEachStatementWithoutDeclarations( int stmt_pos, ExpressionT expression, int lhs_beg_pos, int lhs_end_pos, ForInfo* for_info, ZonePtrList<const AstRawString>* labels, - ZonePtrList<const AstRawString>* own_labels, bool* ok) { - // Initializer is reference followed by in/of. - if (!expression->IsArrayLiteral() && !expression->IsObjectLiteral()) { - expression = CheckAndRewriteReferenceExpression( - expression, lhs_beg_pos, lhs_end_pos, MessageTemplate::kInvalidLhsInFor, - kSyntaxError, CHECK_OK); - } - + ZonePtrList<const AstRawString>* own_labels) { auto loop = factory()->NewForEachStatement(for_info->mode, labels, own_labels, stmt_pos); - typename Types::Target target(this, loop); + TargetT target(this, loop); ExpressionT enumerable = impl()->NullExpression(); if (for_info->mode == ForEachStatement::ITERATE) { - ExpressionClassifier classifier(this); - enumerable = ParseAssignmentExpression(true, CHECK_OK); - ValidateExpression(CHECK_OK); + AcceptINScope scope(this, true); + enumerable = ParseAssignmentExpression(); } else { - enumerable = ParseExpression(CHECK_OK); + enumerable = ParseExpression(); } - Expect(Token::RPAREN, CHECK_OK); + Expect(Token::RPAREN); StatementT body = impl()->NullStatement(); + SourceRange body_range; { - SourceRange body_range; SourceRangeScope range_scope(scanner(), &body_range); - - body = ParseStatement(nullptr, nullptr, CHECK_OK); - impl()->RecordIterationStatementSourceRange(loop, range_scope.Finalize()); + body = ParseStatement(nullptr, nullptr); } - return impl()->InitializeForEachStatement(loop, expression, enumerable, body); + impl()->RecordIterationStatementSourceRange(loop, body_range); + RETURN_IF_PARSE_ERROR; + loop->Initialize(expression, enumerable, body); + return loop; } template <typename Impl> @@ -5955,7 +5487,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStandardForLoopWithLexicalDeclarations( int stmt_pos, StatementT init, ForInfo* for_info, ZonePtrList<const AstRawString>* labels, - ZonePtrList<const AstRawString>* own_labels, bool* ok) { + ZonePtrList<const AstRawString>* own_labels) { // The condition and the next statement of the for loop must be parsed // in a new scope. Scope* inner_scope = NewScope(BLOCK_SCOPE); @@ -5966,8 +5498,9 @@ ParserBase<Impl>::ParseStandardForLoopWithLexicalDeclarations( { BlockState block_state(&scope_, inner_scope); scope()->set_start_position(scanner()->location().beg_pos); - loop = ParseStandardForLoop(stmt_pos, labels, own_labels, &cond, &next, - &body, CHECK_OK); + loop = + ParseStandardForLoop(stmt_pos, labels, own_labels, &cond, &next, &body); + RETURN_IF_PARSE_ERROR; scope()->set_end_position(end_position()); } @@ -5976,7 +5509,7 @@ ParserBase<Impl>::ParseStandardForLoopWithLexicalDeclarations( function_state_->contains_function_or_eval()) { scope()->set_is_hidden(); return impl()->DesugarLexicalBindingsInForStatement( - loop, init, cond, next, body, inner_scope, *for_info, ok); + loop, init, cond, next, body, inner_scope, *for_info); } else { inner_scope = inner_scope->FinalizeBlockScope(); DCHECK_NULL(inner_scope); @@ -6012,25 +5545,25 @@ template <typename Impl> typename ParserBase<Impl>::ForStatementT ParserBase<Impl>::ParseStandardForLoop( int stmt_pos, ZonePtrList<const AstRawString>* labels, ZonePtrList<const AstRawString>* own_labels, ExpressionT* cond, - StatementT* next, StatementT* body, bool* ok) { + StatementT* next, StatementT* body) { ForStatementT loop = factory()->NewForStatement(labels, own_labels, stmt_pos); - typename Types::Target target(this, loop); + TargetT target(this, loop); if (peek() != Token::SEMICOLON) { - *cond = ParseExpression(CHECK_OK); + *cond = ParseExpression(); } - Expect(Token::SEMICOLON, CHECK_OK); + Expect(Token::SEMICOLON); if (peek() != Token::RPAREN) { - ExpressionT exp = ParseExpression(CHECK_OK); + ExpressionT exp = ParseExpression(); *next = factory()->NewExpressionStatement(exp, exp->position()); } - Expect(Token::RPAREN, CHECK_OK); + Expect(Token::RPAREN); SourceRange body_range; { SourceRangeScope range_scope(scanner(), &body_range); - *body = ParseStatement(nullptr, nullptr, CHECK_OK); + *body = ParseStatement(nullptr, nullptr); } impl()->RecordIterationStatementSourceRange(loop, body_range); @@ -6038,22 +5571,12 @@ typename ParserBase<Impl>::ForStatementT ParserBase<Impl>::ParseStandardForLoop( } template <typename Impl> -void ParserBase<Impl>::MarkLoopVariableAsAssigned( - Scope* scope, Variable* var, - typename DeclarationDescriptor::Kind declaration_kind) { - if (!IsLexicalVariableMode(var->mode()) && - (!scope->is_function_scope() || - declaration_kind == DeclarationDescriptor::FOR_EACH)) { - var->set_maybe_assigned(); - } -} - -template <typename Impl> typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForAwaitStatement( ZonePtrList<const AstRawString>* labels, - ZonePtrList<const AstRawString>* own_labels, bool* ok) { + ZonePtrList<const AstRawString>* own_labels) { // for await '(' ForDeclaration of AssignmentExpression ')' DCHECK(is_async_function()); + typename FunctionState::LoopScope loop_scope(function_state_); int stmt_pos = peek_position(); @@ -6062,14 +5585,19 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForAwaitStatement( // Create an in-between scope for let-bound iteration variables. BlockState for_state(zone(), &scope_); - Expect(Token::FOR, CHECK_OK); - Expect(Token::AWAIT, CHECK_OK); - Expect(Token::LPAREN, CHECK_OK); + Expect(Token::FOR); + Expect(Token::AWAIT); + Expect(Token::LPAREN); scope()->set_start_position(scanner()->location().beg_pos); scope()->set_is_hidden(); - auto loop = factory()->NewForOfStatement(labels, own_labels, stmt_pos); - typename Types::Target target(this, loop); + auto loop = factory()->NewForOfStatement(labels, own_labels, stmt_pos, + IteratorType::kAsync); + // Two suspends: one for next() and one for return() + function_state_->AddSuspend(); + function_state_->AddSuspend(); + + TargetT target(this, loop); ExpressionT each_variable = impl()->NullExpression(); @@ -6088,7 +5616,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForAwaitStatement( { BlockState inner_state(&scope_, inner_block_scope); ParseVariableDeclarations(kForStatement, &for_info.parsing_result, - nullptr, CHECK_OK); + &for_info.bound_names); } for_info.position = scanner()->location().beg_pos; @@ -6097,7 +5625,6 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForAwaitStatement( impl()->ReportMessageAt(for_info.parsing_result.bindings_loc, MessageTemplate::kForInOfLoopMultiBindings, "for-await-of"); - *ok = false; return impl()->NullStatement(); } @@ -6106,7 +5633,6 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForAwaitStatement( impl()->ReportMessageAt(for_info.parsing_result.first_initializer_loc, MessageTemplate::kForInOfLoopInitializer, "for-await-of"); - *ok = false; return impl()->NullStatement(); } } else { @@ -6115,33 +5641,29 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForAwaitStatement( // Statement int lhs_beg_pos = peek_position(); BlockState inner_state(&scope_, inner_block_scope); - ExpressionClassifier classifier(this); - ExpressionT lhs = each_variable = ParseLeftHandSideExpression(CHECK_OK); + ExpressionParsingScope parsing_scope(impl()); + ExpressionT lhs = each_variable = ParseLeftHandSideExpression(); int lhs_end_pos = end_position(); - if (lhs->IsArrayLiteral() || lhs->IsObjectLiteral()) { - ValidateAssignmentPattern(CHECK_OK); + if (lhs->IsPattern()) { + parsing_scope.ValidatePattern(lhs, lhs_beg_pos, lhs_end_pos); } else { - ValidateExpression(CHECK_OK); - each_variable = CheckAndRewriteReferenceExpression( - lhs, lhs_beg_pos, lhs_end_pos, MessageTemplate::kInvalidLhsInFor, - kSyntaxError, CHECK_OK); + each_variable = parsing_scope.ValidateAndRewriteReference( + lhs, lhs_beg_pos, lhs_end_pos); } } - ExpectContextualKeyword(Token::OF, CHECK_OK); - int each_keyword_pos = scanner()->location().beg_pos; + ExpectContextualKeyword(ast_value_factory()->of_string()); const bool kAllowIn = true; ExpressionT iterable = impl()->NullExpression(); { - ExpressionClassifier classifier(this); - iterable = ParseAssignmentExpression(kAllowIn, CHECK_OK); - ValidateExpression(CHECK_OK); + AcceptINScope scope(this, kAllowIn); + iterable = ParseAssignmentExpression(); } - Expect(Token::RPAREN, CHECK_OK); + Expect(Token::RPAREN); StatementT body = impl()->NullStatement(); { @@ -6149,16 +5671,16 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForAwaitStatement( scope()->set_start_position(scanner()->location().beg_pos); SourceRange body_range; - SourceRangeScope range_scope(scanner(), &body_range); - - body = ParseStatement(nullptr, nullptr, CHECK_OK); - scope()->set_end_position(end_position()); - impl()->RecordIterationStatementSourceRange(loop, range_scope.Finalize()); + { + SourceRangeScope range_scope(scanner(), &body_range); + body = ParseStatement(nullptr, nullptr); + scope()->set_end_position(end_position()); + } + impl()->RecordIterationStatementSourceRange(loop, body_range); if (has_declarations) { - BlockT body_block = impl()->NullStatement(); - impl()->DesugarBindingInForEachStatement(&for_info, &body_block, - &each_variable, CHECK_OK); + BlockT body_block = impl()->NullBlock(); + DesugarBindingInForEachStatement(&for_info, &body_block, &each_variable); body_block->statements()->Add(body, zone()); body_block->set_scope(scope()->FinalizeBlockScope()); body = body_block; @@ -6168,103 +5690,85 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForAwaitStatement( USE(block_scope); } } - const bool finalize = true; - StatementT final_loop = impl()->InitializeForOfStatement( - loop, each_variable, iterable, body, finalize, IteratorType::kAsync, - each_keyword_pos); + + loop->Initialize(each_variable, iterable, body); if (!has_declarations) { Scope* for_scope = scope()->FinalizeBlockScope(); DCHECK_NULL(for_scope); USE(for_scope); - return final_loop; + return loop; } - BlockT init_block = impl()->CreateForEachStatementTDZ(impl()->NullStatement(), - for_info, CHECK_OK); + BlockT init_block = + impl()->CreateForEachStatementTDZ(impl()->NullBlock(), for_info); scope()->set_end_position(end_position()); Scope* for_scope = scope()->FinalizeBlockScope(); // Parsed for-in loop w/ variable declarations. if (!impl()->IsNull(init_block)) { - init_block->statements()->Add(final_loop, zone()); + init_block->statements()->Add(loop, zone()); init_block->set_scope(for_scope); return init_block; } DCHECK_NULL(for_scope); - return final_loop; -} - -template <typename Impl> -void ParserBase<Impl>::ObjectLiteralChecker::CheckDuplicateProto( - Token::Value property) { - if (property == Token::SMI || property == Token::NUMBER) return; - - if (IsProto()) { - if (has_seen_proto_) { - this->parser()->classifier()->RecordExpressionError( - this->scanner()->location(), MessageTemplate::kDuplicateProto); - return; - } - has_seen_proto_ = true; - } + return loop; } template <typename Impl> -void ParserBase<Impl>::ClassLiteralChecker::CheckClassMethodName( - Token::Value property, ParsePropertyKind type, ParseFunctionFlags flags, - bool is_static, bool* ok) { +void ParserBase<Impl>::CheckClassMethodName(IdentifierT name, + ParsePropertyKind type, + ParseFunctionFlags flags, + bool is_static, + bool* has_seen_constructor) { DCHECK(type == ParsePropertyKind::kMethod || IsAccessor(type)); - if (property == Token::SMI || property == Token::NUMBER) return; + AstValueFactory* avf = ast_value_factory(); if (is_static) { - if (IsPrototype()) { - this->parser()->ReportMessage(MessageTemplate::kStaticPrototype); - *ok = false; + if (impl()->IdentifierEquals(name, avf->prototype_string())) { + ReportMessage(MessageTemplate::kStaticPrototype); return; } - } else if (IsConstructor()) { + } else if (impl()->IdentifierEquals(name, + avf->private_constructor_string())) { + ReportMessage(MessageTemplate::kConstructorIsPrivate); + return; + } else if (impl()->IdentifierEquals(name, avf->constructor_string())) { if (flags != ParseFunctionFlag::kIsNormal || IsAccessor(type)) { - MessageTemplate::Template msg = - (flags & ParseFunctionFlag::kIsGenerator) != 0 - ? MessageTemplate::kConstructorIsGenerator - : (flags & ParseFunctionFlag::kIsAsync) != 0 - ? MessageTemplate::kConstructorIsAsync - : MessageTemplate::kConstructorIsAccessor; - this->parser()->ReportMessage(msg); - *ok = false; + MessageTemplate msg = (flags & ParseFunctionFlag::kIsGenerator) != 0 + ? MessageTemplate::kConstructorIsGenerator + : (flags & ParseFunctionFlag::kIsAsync) != 0 + ? MessageTemplate::kConstructorIsAsync + : MessageTemplate::kConstructorIsAccessor; + ReportMessage(msg); return; } - if (has_seen_constructor_) { - this->parser()->ReportMessage(MessageTemplate::kDuplicateConstructor); - *ok = false; + if (*has_seen_constructor) { + ReportMessage(MessageTemplate::kDuplicateConstructor); return; } - has_seen_constructor_ = true; + *has_seen_constructor = true; return; } } template <typename Impl> -void ParserBase<Impl>::ClassLiteralChecker::CheckClassFieldName(bool is_static, - bool* ok) { - if (is_static && IsPrototype()) { - this->parser()->ReportMessage(MessageTemplate::kStaticPrototype); - *ok = false; +void ParserBase<Impl>::CheckClassFieldName(IdentifierT name, bool is_static) { + AstValueFactory* avf = ast_value_factory(); + if (is_static && impl()->IdentifierEquals(name, avf->prototype_string())) { + ReportMessage(MessageTemplate::kStaticPrototype); return; } - if (IsConstructor() || IsPrivateConstructor()) { - this->parser()->ReportMessage(MessageTemplate::kConstructorClassField); - *ok = false; + if (impl()->IdentifierEquals(name, avf->constructor_string()) || + impl()->IdentifierEquals(name, avf->private_constructor_string())) { + ReportMessage(MessageTemplate::kConstructorClassField); return; } } -#undef CHECK_OK -#undef CHECK_OK_CUSTOM -#undef CHECK_OK_VOID +#undef RETURN_IF_PARSE_ERROR } // namespace internal } // namespace v8 |