diff options
author | Michaël Zasso <targos@protonmail.com> | 2016-12-23 16:30:57 +0100 |
---|---|---|
committer | Michaël Zasso <targos@protonmail.com> | 2017-01-26 22:46:17 +0100 |
commit | 2739185b790e040c3b044c577327f5d44bffad4a (patch) | |
tree | 29a466999212f4c85958379d9d400eec8a185ba5 /deps/v8/src/parsing/parser-base.h | |
parent | a67a04d7654faaa04c8da00e42981ebc9fd0911c (diff) | |
download | android-node-v8-2739185b790e040c3b044c577327f5d44bffad4a.tar.gz android-node-v8-2739185b790e040c3b044c577327f5d44bffad4a.tar.bz2 android-node-v8-2739185b790e040c3b044c577327f5d44bffad4a.zip |
deps: update V8 to 5.5.372.40
PR-URL: https://github.com/nodejs/node/pull/9618
Reviewed-By: Ali Ijaz Sheikh <ofrobots@google.com>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Diffstat (limited to 'deps/v8/src/parsing/parser-base.h')
-rw-r--r-- | deps/v8/src/parsing/parser-base.h | 3974 |
1 files changed, 2849 insertions, 1125 deletions
diff --git a/deps/v8/src/parsing/parser-base.h b/deps/v8/src/parsing/parser-base.h index b8703d0691..1ebbee4959 100644 --- a/deps/v8/src/parsing/parser-base.h +++ b/deps/v8/src/parsing/parser-base.h @@ -5,6 +5,7 @@ #ifndef V8_PARSING_PARSER_BASE_H #define V8_PARSING_PARSER_BASE_H +#include "src/ast/ast.h" #include "src/ast/scopes.h" #include "src/bailout-reason.h" #include "src/base/hashmap.h" @@ -56,59 +57,6 @@ static inline bool operator&(ParseFunctionFlags bitfield, return static_cast<T>(bitfield) & static_cast<T>(mask); } -enum class MethodKind { - kNormal = 0, - kStatic = 1 << 0, - kGenerator = 1 << 1, - kStaticGenerator = kStatic | kGenerator, - kAsync = 1 << 2, - kStaticAsync = kStatic | kAsync, - - /* Any non-ordinary method kinds */ - kSpecialMask = kGenerator | kAsync -}; - -inline bool IsValidMethodKind(MethodKind kind) { - return kind == MethodKind::kNormal || kind == MethodKind::kStatic || - kind == MethodKind::kGenerator || - kind == MethodKind::kStaticGenerator || kind == MethodKind::kAsync || - kind == MethodKind::kStaticAsync; -} - -static inline MethodKind operator|(MethodKind lhs, MethodKind rhs) { - typedef unsigned char T; - return static_cast<MethodKind>(static_cast<T>(lhs) | static_cast<T>(rhs)); -} - -static inline MethodKind& operator|=(MethodKind& lhs, const MethodKind& rhs) { - lhs = lhs | rhs; - DCHECK(IsValidMethodKind(lhs)); - return lhs; -} - -static inline bool operator&(MethodKind bitfield, MethodKind mask) { - typedef unsigned char T; - return static_cast<T>(bitfield) & static_cast<T>(mask); -} - -inline bool IsNormalMethod(MethodKind kind) { - return kind == MethodKind::kNormal; -} - -inline bool IsSpecialMethod(MethodKind kind) { - return kind & MethodKind::kSpecialMask; -} - -inline bool IsStaticMethod(MethodKind kind) { - return kind & MethodKind::kStatic; -} - -inline bool IsGeneratorMethod(MethodKind kind) { - return kind & MethodKind::kGenerator; -} - -inline bool IsAsyncMethod(MethodKind kind) { return kind & MethodKind::kAsync; } - struct FormalParametersBase { explicit FormalParametersBase(DeclarationScope* scope) : scope(scope) {} DeclarationScope* scope; @@ -126,8 +74,8 @@ struct FormalParametersBase { // 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 this->x(); \ +#define CHECK_OK_CUSTOM(x, ...) ok); \ + if (!*ok) return impl()->x(__VA_ARGS__); \ ((void)0 #define DUMMY ) // to make indentation work #undef DUMMY @@ -140,93 +88,86 @@ struct FormalParametersBase { // following the Curiously Recurring Template Pattern (CRTP). // The structure of the parser objects is roughly the following: // -// // Common denominator, needed to avoid cyclic dependency. -// // Instances of this template will end up with very minimal -// // definitions, ideally containing just typedefs. +// // A structure template containing type definitions, needed to +// // avoid a cyclic dependency. // template <typename Impl> -// class ParserBaseTraits; - +// struct ParserTypes; +// // // The parser base object, which should just implement pure // // parser behavior. The Impl parameter is the actual derived // // class (according to CRTP), which implements impure parser // // behavior. // template <typename Impl> -// class ParserBase : public ParserBaseTraits<Impl> { ... }; +// class ParserBase { ... }; // // // And then, for each parser variant (e.g., parser, preparser, etc): // class Parser; // // template <> -// class ParserBaseTraits<Parser> { ... }; +// class ParserTypes<Parser> { ... }; // // class Parser : public ParserBase<Parser> { ... }; // -// TODO(nikolaos): Currently the traits objects contain many things -// that will be moved to the implementation objects or to the parser -// base. The following comments will have to change, when this happens. - -// The traits class template encapsulates the differences between -// parser/pre-parser implementations. In particular: - -// - Return types: For example, Parser functions return Expression* and -// PreParser functions return PreParserExpression. - -// - Creating parse tree nodes: Parser generates an AST during the recursive -// descent. PreParser doesn't create a tree. Instead, it passes around minimal -// data objects (PreParserExpression, PreParserIdentifier etc.) which contain -// just enough data for the upper layer functions. PreParserFactory is -// responsible for creating these dummy objects. It provides a similar kind of -// interface as AstNodeFactory, so ParserBase doesn't need to care which one is -// used. - -// - Miscellaneous other tasks interleaved with the recursive descent. For -// example, Parser keeps track of which function literals should be marked as -// pretenured, and PreParser doesn't care. - -// The traits are expected to contain the following typedefs: +// The parser base object implements pure parsing, according to the +// language grammar. Different parser implementations may exhibit +// different parser-driven behavior that is not considered as pure +// parsing, e.g., early error detection and reporting, AST generation, etc. + +// The ParserTypes structure encapsulates the differences in the +// types used in parsing methods. E.g., Parser methods use Expression* +// and PreParser methods use PreParserExpression. For any given parser +// implementation class Impl, it is expected to contain the following typedefs: +// // template <> -// class ParserBaseTraits<Impl> { -// // In particular... -// struct Type { -// typedef GeneratorVariable; -// typedef AstProperties; -// typedef ExpressionClassifier; -// // Return types for traversing functions. -// typedef Identifier; -// typedef Expression; -// typedef YieldExpression; -// typedef FunctionLiteral; -// typedef ClassLiteral; -// typedef Literal; -// typedef ObjectLiteralProperty; -// typedef ExpressionList; -// typedef PropertyList; -// typedef FormalParameter; -// typedef FormalParameters; -// typedef StatementList; -// // For constructing objects returned by the traversing functions. -// typedef Factory; -// }; -// // ... +// struct ParserTypes<Impl> { +// // Synonyms for ParserBase<Impl> and Impl, respectively. +// typedef Base; +// typedef Impl; +// // TODO(nikolaos): this one will probably go away, as it is +// // not related to pure parsing. +// typedef Variable; +// // Return types for traversing functions. +// typedef Identifier; +// typedef Expression; +// typedef FunctionLiteral; +// typedef ObjectLiteralProperty; +// typedef ClassLiteralProperty; +// typedef ExpressionList; +// typedef ObjectPropertyList; +// typedef ClassPropertyList; +// typedef FormalParameters; +// typedef Statement; +// typedef StatementList; +// typedef Block; +// typedef BreakableStatement; +// typedef IterationStatement; +// // For constructing objects returned by the traversing functions. +// typedef Factory; +// // For other implementation-specific tasks. +// typedef Target; +// typedef TargetScope; // }; template <typename Impl> -class ParserBaseTraits; +struct ParserTypes; template <typename Impl> -class ParserBase : public ParserBaseTraits<Impl> { +class ParserBase { public: - // Shorten type names defined by Traits. - typedef ParserBaseTraits<Impl> Traits; - typedef typename Traits::Type::Expression ExpressionT; - typedef typename Traits::Type::Identifier IdentifierT; - typedef typename Traits::Type::FormalParameter FormalParameterT; - typedef typename Traits::Type::FormalParameters FormalParametersT; - typedef typename Traits::Type::FunctionLiteral FunctionLiteralT; - typedef typename Traits::Type::Literal LiteralT; - typedef typename Traits::Type::ObjectLiteralProperty ObjectLiteralPropertyT; - typedef typename Traits::Type::StatementList StatementListT; - typedef typename Traits::Type::ExpressionClassifier ExpressionClassifier; + // 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 Types::ClassLiteralProperty ClassLiteralPropertyT; + typedef typename Types::ExpressionList ExpressionListT; + typedef typename Types::FormalParameters FormalParametersT; + typedef typename Types::Statement StatementT; + typedef typename Types::StatementList StatementListT; + typedef typename Types::Block BlockT; + typedef typename v8::internal::ExpressionClassifier<Types> + ExpressionClassifier; // All implementation-specific methods must be called through this. Impl* impl() { return static_cast<Impl*>(this); } @@ -246,6 +187,7 @@ class ParserBase : public ParserBaseTraits<Impl> { parsing_module_(false), stack_limit_(stack_limit), zone_(zone), + classifier_(nullptr), scanner_(scanner), stack_overflow_(false), allow_lazy_(false), @@ -257,7 +199,8 @@ class ParserBase : public ParserBaseTraits<Impl> { allow_harmony_function_sent_(false), allow_harmony_async_await_(false), allow_harmony_restrictive_generators_(false), - allow_harmony_trailing_commas_(false) {} + allow_harmony_trailing_commas_(false), + allow_harmony_class_fields_(false) {} #define ALLOW_ACCESSORS(name) \ bool allow_##name() const { return allow_##name##_; } \ @@ -273,6 +216,7 @@ class ParserBase : public ParserBaseTraits<Impl> { ALLOW_ACCESSORS(harmony_async_await); ALLOW_ACCESSORS(harmony_restrictive_generators); ALLOW_ACCESSORS(harmony_trailing_commas); + ALLOW_ACCESSORS(harmony_class_fields); #undef ALLOW_ACCESSORS @@ -280,7 +224,12 @@ class ParserBase : public ParserBaseTraits<Impl> { void set_stack_limit(uintptr_t stack_limit) { stack_limit_ = stack_limit; } + Zone* zone() const { return zone_; } + protected: + friend class v8::internal::ExpressionClassifier<ParserTypes<Impl>>; + + // clang-format off enum AllowRestrictedIdentifiers { kAllowRestrictedIdentifiers, kDontAllowRestrictedIdentifiers @@ -291,14 +240,26 @@ class ParserBase : public ParserBaseTraits<Impl> { PARSE_EAGERLY }; + enum LazyParsingResult { + kLazyParsingComplete, + kLazyParsingAborted + }; + enum VariableDeclarationContext { kStatementListItem, kStatement, kForStatement }; + enum class FunctionBodyType { + kNormal, + kSingleExpression + }; + // clang-format on + class Checkpoint; - class ObjectLiteralCheckerBase; + class ClassLiteralChecker; + class ObjectLiteralChecker; // --------------------------------------------------------------------------- // ScopeState and its subclasses implement the parser's scope stack. @@ -333,8 +294,8 @@ class ParserBase : public ParserBaseTraits<Impl> { // allocation. // TODO(verwaest): Move to LazyBlockState class that only allocates the // scope when needed. - explicit BlockState(ScopeState** scope_stack) - : ScopeState(scope_stack, NewScope(*scope_stack)) {} + explicit BlockState(Zone* zone, ScopeState** scope_stack) + : ScopeState(scope_stack, NewScope(zone, *scope_stack)) {} void SetNonlinear() { this->scope()->SetNonlinear(); } void set_start_position(int pos) { this->scope()->set_start_position(pos); } @@ -348,9 +309,8 @@ class ParserBase : public ParserBaseTraits<Impl> { } private: - Scope* NewScope(ScopeState* outer_state) { + Scope* NewScope(Zone* zone, ScopeState* outer_state) { Scope* parent = outer_state->scope(); - Zone* zone = outer_state->zone(); return new (zone) Scope(zone, parent, BLOCK_SCOPE); } }; @@ -384,14 +344,6 @@ class ParserBase : public ParserBaseTraits<Impl> { expressions_.Add(expr, zone_); } - void AddExplicitTailCall(ExpressionT expr, const Scanner::Location& loc) { - if (!has_explicit_tail_calls()) { - loc_ = loc; - has_explicit_tail_calls_ = true; - } - expressions_.Add(expr, zone_); - } - void Append(const TailCallExpressionList& other) { if (!has_explicit_tail_calls()) { loc_ = other.loc_; @@ -425,9 +377,13 @@ class ParserBase : public ParserBaseTraits<Impl> { class FunctionState final : public ScopeState { public: FunctionState(FunctionState** function_state_stack, - ScopeState** scope_stack, Scope* scope, FunctionKind kind); + ScopeState** scope_stack, DeclarationScope* scope); ~FunctionState(); + DeclarationScope* scope() const { + return ScopeState::scope()->AsDeclarationScope(); + } + int NextMaterializedLiteralIndex() { return next_materialized_literal_index_++; } @@ -442,24 +398,27 @@ class ParserBase : public ParserBaseTraits<Impl> { void AddProperty() { expected_property_count_++; } int expected_property_count() { return expected_property_count_; } - bool is_generator() const { return IsGeneratorFunction(kind_); } - bool is_async_function() const { return IsAsyncFunction(kind_); } - bool is_resumable() const { return is_generator() || is_async_function(); } - - FunctionKind kind() const { return kind_; } + FunctionKind kind() const { return scope()->function_kind(); } FunctionState* outer() const { return outer_function_state_; } - void set_generator_object_variable( - typename Traits::Type::GeneratorVariable* variable) { + void set_generator_object_variable(typename Types::Variable* variable) { DCHECK(variable != NULL); - DCHECK(is_resumable()); + DCHECK(IsResumableFunction(kind())); generator_object_variable_ = variable; } - typename Traits::Type::GeneratorVariable* generator_object_variable() - const { + typename Types::Variable* generator_object_variable() const { return generator_object_variable_; } + void set_promise_variable(typename Types::Variable* variable) { + DCHECK(variable != NULL); + DCHECK(IsAsyncFunction(kind())); + promise_variable_ = variable; + } + typename Types::Variable* promise_variable() const { + return promise_variable_; + } + const ZoneList<DestructuringAssignment>& destructuring_assignments_to_rewrite() const { return destructuring_assignments_to_rewrite_; @@ -474,14 +433,6 @@ class ParserBase : public ParserBaseTraits<Impl> { tail_call_expressions_.AddImplicitTailCall(expression); } } - void AddExplicitTailCallExpression(ExpressionT expression, - const Scanner::Location& loc) { - DCHECK(expression->IsCall()); - if (return_expr_context() == - ReturnExprContext::kInsideValidReturnStatement) { - tail_call_expressions_.AddExplicitTailCall(expression, loc); - } - } ZoneList<typename ExpressionClassifier::Error>* GetReportedErrorList() { return &reported_errors_; @@ -530,11 +481,13 @@ class ParserBase : public ParserBaseTraits<Impl> { // Properties count estimation. int expected_property_count_; - FunctionKind kind_; // For generators, this variable may hold the generator object. It variable // is used by yield expressions and return statements. It is not necessary // for generator functions to have this variable set. Variable* generator_object_variable_; + // For async functions, this variable holds a temporary for the Promise + // being created as output of the async function. + Variable* promise_variable_; FunctionState** function_state_stack_; FunctionState* outer_function_state_; @@ -644,8 +597,97 @@ class ParserBase : public ParserBaseTraits<Impl> { Mode old_mode_; }; + struct DeclarationDescriptor { + enum Kind { NORMAL, PARAMETER }; + Scope* scope; + Scope* hoist_scope; + VariableMode mode; + int declaration_pos; + int initialization_pos; + Kind declaration_kind; + }; + + struct DeclarationParsingResult { + struct Declaration { + Declaration(ExpressionT pattern, int initializer_position, + ExpressionT initializer) + : pattern(pattern), + initializer_position(initializer_position), + initializer(initializer) {} + + ExpressionT pattern; + int initializer_position; + ExpressionT initializer; + }; + + DeclarationParsingResult() + : declarations(4), + first_initializer_loc(Scanner::Location::invalid()), + bindings_loc(Scanner::Location::invalid()) {} + + DeclarationDescriptor descriptor; + List<Declaration> declarations; + Scanner::Location first_initializer_loc; + Scanner::Location bindings_loc; + }; + + struct CatchInfo { + public: + explicit CatchInfo(ParserBase* parser) + : name(parser->impl()->EmptyIdentifier()), + variable(nullptr), + pattern(parser->impl()->EmptyExpression()), + scope(nullptr), + init_block(parser->impl()->NullBlock()), + inner_block(parser->impl()->NullBlock()), + for_promise_reject(false), + bound_names(1, parser->zone()), + tail_call_expressions(parser->zone()) {} + IdentifierT name; + Variable* variable; + ExpressionT pattern; + Scope* scope; + BlockT init_block; + BlockT inner_block; + bool for_promise_reject; + ZoneList<const AstRawString*> bound_names; + TailCallExpressionList tail_call_expressions; + }; + + struct ForInfo { + public: + explicit ForInfo(ParserBase* parser) + : bound_names(1, parser->zone()), + mode(ForEachStatement::ENUMERATE), + each_loc(), + parsing_result() {} + ZoneList<const AstRawString*> bound_names; + ForEachStatement::VisitMode mode; + Scanner::Location each_loc; + DeclarationParsingResult parsing_result; + }; + + struct ClassInfo { + public: + explicit ClassInfo(ParserBase* parser) + : proxy(nullptr), + extends(parser->impl()->EmptyExpression()), + properties(parser->impl()->NewClassPropertyList(4)), + instance_field_initializers(parser->impl()->NewExpressionList(0)), + constructor(parser->impl()->EmptyFunctionLiteral()), + has_seen_constructor(false), + static_initializer_var(nullptr) {} + VariableProxy* proxy; + ExpressionT extends; + typename Types::ClassPropertyList properties; + ExpressionListT instance_field_initializers; + FunctionLiteralT constructor; + bool has_seen_constructor; + Variable* static_initializer_var; + }; + DeclarationScope* NewScriptScope() const { - return new (zone()) DeclarationScope(zone()); + return new (zone()) DeclarationScope(zone(), ast_value_factory()); } DeclarationScope* NewVarblockScope() const { @@ -653,7 +695,7 @@ class ParserBase : public ParserBaseTraits<Impl> { } ModuleScope* NewModuleScope(DeclarationScope* parent) const { - return new (zone()) ModuleScope(zone(), parent, ast_value_factory()); + return new (zone()) ModuleScope(parent, ast_value_factory()); } DeclarationScope* NewEvalScope(Scope* parent) const { @@ -683,12 +725,18 @@ class ParserBase : public ParserBaseTraits<Impl> { new (zone()) DeclarationScope(zone(), scope(), FUNCTION_SCOPE, kind); // TODO(verwaest): Move into the DeclarationScope constructor. if (!IsArrowFunction(kind)) { - result->DeclareThis(ast_value_factory()); result->DeclareDefaultFunctionVariables(ast_value_factory()); } return result; } + V8_INLINE DeclarationScope* GetDeclarationScope() const { + return scope()->GetDeclarationScope(); + } + V8_INLINE DeclarationScope* GetClosureScope() const { + return scope()->GetClosureScope(); + } + Scanner* scanner() const { return scanner_; } AstValueFactory* ast_value_factory() const { return ast_value_factory_; } int position() const { return scanner_->location().beg_pos; } @@ -696,7 +744,6 @@ class ParserBase : public ParserBaseTraits<Impl> { bool stack_overflow() const { return stack_overflow_; } void set_stack_overflow() { stack_overflow_ = true; } Mode mode() const { return mode_; } - Zone* zone() const { return zone_; } INLINE(Token::Value peek()) { if (stack_overflow_) return Token::ILLEGAL; @@ -761,8 +808,12 @@ class ParserBase : public ParserBaseTraits<Impl> { Expect(Token::SEMICOLON, ok); } - // A dummy function, just useful as an argument to CHECK_OK_CUSTOM. + // Dummy functions, just useful as arguments to CHECK_OK_CUSTOM. static void Void() {} + template <typename T> + static T Return(T result) { + return result; + } bool is_any_identifier(Token::Value token) { return token == Token::IDENTIFIER || token == Token::ENUM || @@ -796,7 +847,7 @@ class ParserBase : public ParserBaseTraits<Impl> { } } - bool CheckInOrOf(ForEachStatement::VisitMode* visit_mode, bool* ok) { + bool CheckInOrOf(ForEachStatement::VisitMode* visit_mode) { if (Check(Token::IN)) { *visit_mode = ForEachStatement::ENUMERATE; return true; @@ -818,21 +869,19 @@ class ParserBase : public ParserBaseTraits<Impl> { Scanner::Location octal = scanner()->octal_position(); if (octal.IsValid() && beg_pos <= octal.beg_pos && octal.end_pos <= end_pos) { - ReportMessageAt(octal, message); + impl()->ReportMessageAt(octal, message); scanner()->clear_octal_position(); *ok = false; } } // for now, this check just collects statistics. - void CheckDecimalLiteralWithLeadingZero(int* use_counts, int beg_pos, - int end_pos) { + void CheckDecimalLiteralWithLeadingZero(int beg_pos, int end_pos) { Scanner::Location token_location = scanner()->decimal_with_leading_zero_position(); if (token_location.IsValid() && beg_pos <= token_location.beg_pos && token_location.end_pos <= end_pos) { scanner()->clear_decimal_with_leading_zero_position(); - if (use_counts != nullptr) - ++use_counts[v8::Isolate::kDecimalWithLeadingZeroInStrictMode]; + impl()->CountUsage(v8::Isolate::kDecimalWithLeadingZeroInStrictMode); } } @@ -846,9 +895,7 @@ class ParserBase : public ParserBaseTraits<Impl> { ok); } - void CheckDestructuringElement(ExpressionT element, - ExpressionClassifier* classifier, int beg_pos, - int end_pos); + void CheckDestructuringElement(ExpressionT element, int beg_pos, int end_pos); // Checking the name of a function literal. This has to be done after parsing // the function, since the function can declare itself strict. @@ -859,14 +906,14 @@ class ParserBase : public ParserBaseTraits<Impl> { // The function name needs to be checked in strict mode. if (is_sloppy(language_mode)) return; - if (this->IsEvalOrArguments(function_name)) { - Traits::ReportMessageAt(function_name_loc, + if (impl()->IsEvalOrArguments(function_name)) { + impl()->ReportMessageAt(function_name_loc, MessageTemplate::kStrictEvalArguments); *ok = false; return; } if (function_name_validity == kFunctionNameIsStrictReserved) { - Traits::ReportMessageAt(function_name_loc, + impl()->ReportMessageAt(function_name_loc, MessageTemplate::kUnexpectedStrictReserved); *ok = false; return; @@ -880,50 +927,45 @@ class ParserBase : public ParserBaseTraits<Impl> { return Token::Precedence(token); } - typename Traits::Type::Factory* factory() { return &ast_node_factory_; } + typename Types::Factory* factory() { return &ast_node_factory_; } DeclarationScope* GetReceiverScope() const { return scope()->GetReceiverScope(); } LanguageMode language_mode() { return scope()->language_mode(); } - bool is_generator() const { return function_state_->is_generator(); } + void RaiseLanguageMode(LanguageMode mode) { + LanguageMode old = scope()->language_mode(); + impl()->SetLanguageMode(scope(), old > mode ? old : mode); + } + bool is_generator() const { + return IsGeneratorFunction(function_state_->kind()); + } bool is_async_function() const { - return function_state_->is_async_function(); + return IsAsyncFunction(function_state_->kind()); + } + bool is_resumable() const { + return IsResumableFunction(function_state_->kind()); } - bool is_resumable() const { return function_state_->is_resumable(); } // Report syntax errors. - void ReportMessage(MessageTemplate::Template message, const char* arg = NULL, - ParseErrorType error_type = kSyntaxError) { + void ReportMessage(MessageTemplate::Template message) { Scanner::Location source_location = scanner()->location(); - Traits::ReportMessageAt(source_location, message, arg, error_type); + impl()->ReportMessageAt(source_location, message, + static_cast<const char*>(nullptr), kSyntaxError); } - void ReportMessage(MessageTemplate::Template message, const AstRawString* arg, + template <typename T> + void ReportMessage(MessageTemplate::Template message, T arg, ParseErrorType error_type = kSyntaxError) { Scanner::Location source_location = scanner()->location(); - Traits::ReportMessageAt(source_location, message, arg, error_type); - } - - void ReportMessageAt(Scanner::Location location, - MessageTemplate::Template message, - const char* arg = NULL, - ParseErrorType error_type = kSyntaxError) { - Traits::ReportMessageAt(location, message, arg, error_type); - } - - void ReportMessageAt(Scanner::Location location, - MessageTemplate::Template message, - const AstRawString* arg, - ParseErrorType error_type = kSyntaxError) { - Traits::ReportMessageAt(location, message, arg, error_type); + impl()->ReportMessageAt(source_location, message, arg, error_type); } void ReportMessageAt(Scanner::Location location, MessageTemplate::Template message, ParseErrorType error_type) { - ReportMessageAt(location, message, static_cast<const char*>(nullptr), - error_type); + impl()->ReportMessageAt(location, message, + static_cast<const char*>(nullptr), error_type); } void GetUnexpectedTokenMessage( @@ -938,59 +980,47 @@ class ParserBase : public ParserBaseTraits<Impl> { void ReportClassifierError( const typename ExpressionClassifier::Error& error) { - Traits::ReportMessageAt(error.location, error.message, error.arg, + impl()->ReportMessageAt(error.location, error.message, error.arg, error.type); } - void ValidateExpression(const ExpressionClassifier* classifier, bool* ok) { - if (!classifier->is_valid_expression() || - classifier->has_object_literal_error()) { - const Scanner::Location& a = classifier->expression_error().location; - const Scanner::Location& b = - classifier->object_literal_error().location; - if (a.beg_pos < 0 || (b.beg_pos >= 0 && a.beg_pos > b.beg_pos)) { - ReportClassifierError(classifier->object_literal_error()); - } else { - ReportClassifierError(classifier->expression_error()); - } + void ValidateExpression(bool* ok) { + if (!classifier()->is_valid_expression()) { + ReportClassifierError(classifier()->expression_error()); *ok = false; } } - void ValidateFormalParameterInitializer( - const ExpressionClassifier* classifier, bool* ok) { - if (!classifier->is_valid_formal_parameter_initializer()) { - ReportClassifierError(classifier->formal_parameter_initializer_error()); + void ValidateFormalParameterInitializer(bool* ok) { + if (!classifier()->is_valid_formal_parameter_initializer()) { + ReportClassifierError(classifier()->formal_parameter_initializer_error()); *ok = false; } } - void ValidateBindingPattern(const ExpressionClassifier* classifier, - bool* ok) { - if (!classifier->is_valid_binding_pattern()) { - ReportClassifierError(classifier->binding_pattern_error()); + void ValidateBindingPattern(bool* ok) { + if (!classifier()->is_valid_binding_pattern()) { + ReportClassifierError(classifier()->binding_pattern_error()); *ok = false; } } - void ValidateAssignmentPattern(const ExpressionClassifier* classifier, - bool* ok) { - if (!classifier->is_valid_assignment_pattern()) { - ReportClassifierError(classifier->assignment_pattern_error()); + void ValidateAssignmentPattern(bool* ok) { + if (!classifier()->is_valid_assignment_pattern()) { + ReportClassifierError(classifier()->assignment_pattern_error()); *ok = false; } } - void ValidateFormalParameters(const ExpressionClassifier* classifier, - LanguageMode language_mode, + 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()); + !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()); + !classifier()->is_valid_strict_mode_formal_parameters()) { + ReportClassifierError(classifier()->strict_mode_formal_parameter_error()); *ok = false; } } @@ -999,78 +1029,73 @@ class ParserBase : public ParserBaseTraits<Impl> { return is_any_identifier(token) || token == Token::LPAREN; } - void ValidateArrowFormalParameters(const ExpressionClassifier* classifier, - ExpressionT expr, + void ValidateArrowFormalParameters(ExpressionT expr, bool parenthesized_formals, bool is_async, bool* ok) { - if (classifier->is_valid_binding_pattern()) { + if (classifier()->is_valid_binding_pattern()) { // A simple arrow formal parameter: IDENTIFIER => BODY. - if (!this->IsIdentifier(expr)) { - Traits::ReportMessageAt(scanner()->location(), + 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()) { + } 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(); + 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()) { + if (is_async && !classifier()->is_valid_async_arrow_formal_parameters()) { const typename ExpressionClassifier::Error& error = - classifier->async_arrow_formal_parameters_error(); + classifier()->async_arrow_formal_parameters_error(); ReportClassifierError(error); *ok = false; } } - void ValidateLetPattern(const ExpressionClassifier* classifier, bool* ok) { - if (!classifier->is_valid_let_pattern()) { - ReportClassifierError(classifier->let_pattern_error()); - *ok = false; - } - } - - void CheckNoTailCallExpressions(const ExpressionClassifier* classifier, - bool* ok) { - if (FLAG_harmony_explicit_tailcalls && - classifier->has_tail_call_expression()) { - ReportClassifierError(classifier->tail_call_expression_error()); + void ValidateLetPattern(bool* ok) { + if (!classifier()->is_valid_let_pattern()) { + ReportClassifierError(classifier()->let_pattern_error()); *ok = false; } } - void ExpressionUnexpectedToken(ExpressionClassifier* classifier) { + void ExpressionUnexpectedToken() { MessageTemplate::Template message = MessageTemplate::kUnexpectedToken; const char* arg; Scanner::Location location = scanner()->peek_location(); GetUnexpectedTokenMessage(peek(), &message, &location, &arg); - classifier->RecordExpressionError(location, message, arg); + classifier()->RecordExpressionError(location, message, arg); } - void BindingPatternUnexpectedToken(ExpressionClassifier* classifier) { + 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); + classifier()->RecordBindingPatternError(location, message, arg); } - void ArrowFormalParametersUnexpectedToken(ExpressionClassifier* classifier) { + 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); + classifier()->RecordArrowFormalParametersError(location, message, arg); } - // Recursive descent functions: + // 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 @@ -1078,8 +1103,7 @@ class ParserBase : public ParserBaseTraits<Impl> { // "arguments" as identifier even in strict mode (this is needed in cases like // "var foo = eval;"). IdentifierT ParseIdentifier(AllowRestrictedIdentifiers, bool* ok); - IdentifierT ParseAndClassifyIdentifier(ExpressionClassifier* classifier, - 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 @@ -1098,76 +1122,173 @@ class ParserBase : public ParserBaseTraits<Impl> { ExpressionT ParseRegExpLiteral(bool* ok); - ExpressionT ParsePrimaryExpression(ExpressionClassifier* classifier, - bool* is_async, bool* ok); - ExpressionT ParsePrimaryExpression(ExpressionClassifier* classifier, - bool* ok) { + ExpressionT ParsePrimaryExpression(bool* is_async, bool* ok); + ExpressionT ParsePrimaryExpression(bool* ok) { bool is_async; - return ParsePrimaryExpression(classifier, &is_async, ok); + return ParsePrimaryExpression(&is_async, ok); } - ExpressionT ParseExpression(bool accept_IN, bool* ok); - ExpressionT ParseExpression(bool accept_IN, ExpressionClassifier* classifier, - bool* ok); - ExpressionT ParseArrayLiteral(ExpressionClassifier* classifier, bool* ok); - ExpressionT ParsePropertyName(IdentifierT* name, bool* is_get, bool* is_set, - bool* is_computed_name, - ExpressionClassifier* classifier, bool* ok); - ExpressionT ParseObjectLiteral(ExpressionClassifier* classifier, bool* ok); - ObjectLiteralPropertyT ParsePropertyDefinition( - ObjectLiteralCheckerBase* checker, bool in_class, bool has_extends, - MethodKind kind, bool* is_computed_name, bool* has_seen_constructor, - ExpressionClassifier* classifier, IdentifierT* name, bool* ok); - typename Traits::Type::ExpressionList ParseArguments( - Scanner::Location* first_spread_pos, bool maybe_arrow, - ExpressionClassifier* classifier, bool* ok); - typename Traits::Type::ExpressionList ParseArguments( - Scanner::Location* first_spread_pos, ExpressionClassifier* classifier, - bool* ok) { - return ParseArguments(first_spread_pos, false, classifier, ok); - } - - ExpressionT ParseAssignmentExpression(bool accept_IN, - ExpressionClassifier* classifier, - bool* ok); - ExpressionT ParseYieldExpression(bool accept_IN, - ExpressionClassifier* classifier, bool* ok); - ExpressionT ParseTailCallExpression(ExpressionClassifier* classifier, - bool* ok); - ExpressionT ParseConditionalExpression(bool accept_IN, - ExpressionClassifier* classifier, - bool* ok); - ExpressionT ParseBinaryExpression(int prec, bool accept_IN, - ExpressionClassifier* classifier, bool* ok); - ExpressionT ParseUnaryExpression(ExpressionClassifier* classifier, bool* ok); - ExpressionT ParsePostfixExpression(ExpressionClassifier* classifier, - bool* ok); - ExpressionT ParseLeftHandSideExpression(ExpressionClassifier* classifier, - bool* ok); - ExpressionT ParseMemberWithNewPrefixesExpression( - ExpressionClassifier* classifier, bool* is_async, bool* ok); - ExpressionT ParseMemberExpression(ExpressionClassifier* classifier, - bool* is_async, bool* ok); - ExpressionT ParseMemberExpressionContinuation( - ExpressionT expression, bool* is_async, ExpressionClassifier* classifier, - bool* ok); + + // This method wraps the parsing of the expression inside a new expression + // classifier and calls RewriteNonPattern if parsing is successful. + // It should be used whenever we're parsing an expression that will be + // used as a non-pattern (i.e., in most cases). + V8_INLINE ExpressionT ParseExpression(bool accept_IN, 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 + // "CoverParenthesizedExpressionAndArrowParameterList" in the ES 2017 + // specification). + ExpressionT ParseExpressionCoverGrammar(bool accept_IN, bool* ok); + + ExpressionT ParseArrayLiteral(bool* ok); + + enum class PropertyKind { + kAccessorProperty, + kValueProperty, + kShorthandProperty, + kMethodProperty, + kClassField, + kNotSet + }; + + bool SetPropertyKindFromToken(Token::Value token, PropertyKind* kind); + ExpressionT ParsePropertyName(IdentifierT* name, PropertyKind* kind, + bool* is_generator, bool* is_get, bool* is_set, + bool* is_async, bool* is_computed_name, + bool* ok); + ExpressionT ParseObjectLiteral(bool* ok); + ClassLiteralPropertyT ParseClassPropertyDefinition( + ClassLiteralChecker* checker, bool has_extends, bool* is_computed_name, + bool* has_seen_constructor, bool* ok); + FunctionLiteralT ParseClassFieldForInitializer(bool has_initializer, + bool* ok); + ObjectLiteralPropertyT ParseObjectPropertyDefinition( + ObjectLiteralChecker* checker, bool* is_computed_name, bool* ok); + ExpressionListT ParseArguments(Scanner::Location* first_spread_pos, + bool maybe_arrow, bool* ok); + ExpressionListT ParseArguments(Scanner::Location* first_spread_pos, + bool* ok) { + return ParseArguments(first_spread_pos, false, ok); + } + + ExpressionT ParseAssignmentExpression(bool accept_IN, bool* ok); + ExpressionT ParseYieldExpression(bool accept_IN, bool* ok); + ExpressionT ParseConditionalExpression(bool accept_IN, bool* ok); + ExpressionT ParseBinaryExpression(int prec, bool accept_IN, bool* ok); + ExpressionT ParseUnaryExpression(bool* ok); + ExpressionT ParsePostfixExpression(bool* ok); + ExpressionT ParseLeftHandSideExpression(bool* ok); + ExpressionT ParseMemberWithNewPrefixesExpression(bool* is_async, bool* ok); + ExpressionT ParseMemberExpression(bool* is_async, bool* ok); + ExpressionT ParseMemberExpressionContinuation(ExpressionT expression, + bool* is_async, bool* ok); ExpressionT ParseArrowFunctionLiteral(bool accept_IN, const FormalParametersT& parameters, - bool is_async, - const ExpressionClassifier& classifier, bool* ok); - ExpressionT ParseTemplateLiteral(ExpressionT tag, int start, - ExpressionClassifier* classifier, bool* ok); + void ParseAsyncFunctionBody(Scope* scope, StatementListT body, + FunctionKind kind, FunctionBodyType type, + bool accept_IN, int pos, bool* ok); + ExpressionT ParseAsyncFunctionLiteral(bool* ok); + 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* ok); ExpressionT ParseSuperExpression(bool is_new, bool* ok); ExpressionT ParseNewTargetExpression(bool* ok); - void ParseFormalParameter(FormalParametersT* parameters, - ExpressionClassifier* classifier, bool* ok); - void ParseFormalParameterList(FormalParametersT* parameters, - ExpressionClassifier* classifier, bool* ok); + void ParseFormalParameter(FormalParametersT* parameters, bool* ok); + void ParseFormalParameterList(FormalParametersT* parameters, bool* ok); void CheckArityRestrictions(int param_count, FunctionKind function_type, bool has_rest, int formals_start_pos, int formals_end_pos, bool* ok); + BlockT ParseVariableDeclarations(VariableDeclarationContext var_context, + DeclarationParsingResult* parsing_result, + ZoneList<const AstRawString*>* names, + bool* ok); + StatementT ParseAsyncFunctionDeclaration(ZoneList<const AstRawString*>* names, + bool default_export, bool* ok); + StatementT ParseFunctionDeclaration(bool* ok); + StatementT ParseHoistableDeclaration(ZoneList<const AstRawString*>* names, + bool default_export, bool* ok); + StatementT ParseHoistableDeclaration(int pos, ParseFunctionFlags flags, + ZoneList<const AstRawString*>* names, + bool default_export, bool* ok); + StatementT ParseClassDeclaration(ZoneList<const AstRawString*>* names, + bool default_export, bool* ok); + StatementT ParseNativeDeclaration(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; + + // 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, int end_token, + bool* ok) { + LazyParsingResult result = ParseStatementList(body, end_token, false, ok); + USE(result); + DCHECK_EQ(result, kLazyParsingComplete); + } + LazyParsingResult ParseStatementList(StatementListT body, int end_token, + bool may_abort, bool* ok); + StatementT ParseStatementListItem(bool* ok); + StatementT ParseStatement(ZoneList<const AstRawString*>* labels, + AllowLabelledFunctionStatement allow_function, + bool* ok); + StatementT ParseStatementAsUnlabelled(ZoneList<const AstRawString*>* labels, + bool* ok); + BlockT ParseBlock(ZoneList<const AstRawString*>* labels, bool* ok); + + // Parse a SubStatement in strict mode, or with an extra block scope in + // sloppy mode to handle + // ES#sec-functiondeclarations-in-ifstatement-statement-clauses + // The legacy parameter indicates whether function declarations are + // banned by the ES2015 specification in this location, and they are being + // permitted here to match previous V8 behavior. + StatementT ParseScopedStatement(ZoneList<const AstRawString*>* labels, + bool legacy, bool* ok); + + StatementT ParseVariableStatement(VariableDeclarationContext var_context, + ZoneList<const AstRawString*>* names, + bool* ok); + + // Magical syntax support. + ExpressionT ParseV8Intrinsic(bool* ok); + + ExpressionT ParseDoExpression(bool* ok); + + StatementT ParseDebuggerStatement(bool* ok); + + StatementT ParseExpressionOrLabelledStatement( + ZoneList<const AstRawString*>* labels, + AllowLabelledFunctionStatement allow_function, bool* ok); + StatementT ParseIfStatement(ZoneList<const AstRawString*>* labels, bool* ok); + StatementT ParseContinueStatement(bool* ok); + StatementT ParseBreakStatement(ZoneList<const AstRawString*>* labels, + bool* ok); + StatementT ParseReturnStatement(bool* ok); + StatementT ParseWithStatement(ZoneList<const AstRawString*>* labels, + bool* ok); + StatementT ParseDoWhileStatement(ZoneList<const AstRawString*>* labels, + bool* ok); + StatementT ParseWhileStatement(ZoneList<const AstRawString*>* labels, + bool* ok); + StatementT ParseThrowStatement(bool* ok); + StatementT ParseSwitchStatement(ZoneList<const AstRawString*>* labels, + bool* ok); + StatementT ParseTryStatement(bool* ok); + StatementT ParseForStatement(ZoneList<const AstRawString*>* labels, bool* ok); + bool IsNextLetKeyword(); bool IsTrivialExpression(); @@ -1184,9 +1305,9 @@ class ParserBase : public ParserBaseTraits<Impl> { bool IsValidReferenceExpression(ExpressionT expression); bool IsAssignableIdentifier(ExpressionT expression) { - if (!Traits::IsIdentifier(expression)) return false; + if (!impl()->IsIdentifier(expression)) return false; if (is_strict(language_mode()) && - Traits::IsEvalOrArguments(Traits::AsIdentifier(expression))) { + impl()->IsEvalOrArguments(impl()->AsIdentifier(expression))) { return false; } return true; @@ -1201,8 +1322,8 @@ class ParserBase : public ParserBaseTraits<Impl> { // forwards the information to scope. Call::PossiblyEval CheckPossibleEvalCall(ExpressionT expression, Scope* scope) { - if (Traits::IsIdentifier(expression) && - Traits::IsEval(Traits::AsIdentifier(expression))) { + if (impl()->IsIdentifier(expression) && + impl()->IsEval(impl()->AsIdentifier(expression))) { scope->RecordEvalCall(); if (is_sloppy(scope->language_mode())) { // For sloppy scopes we also have to record the call at function level, @@ -1214,56 +1335,33 @@ class ParserBase : public ParserBaseTraits<Impl> { return Call::NOT_EVAL; } - // Used to validate property names in object literals and class literals - enum PropertyKind { - kAccessorProperty, - kValueProperty, - kMethodProperty - }; - - class ObjectLiteralCheckerBase { - public: - explicit ObjectLiteralCheckerBase(ParserBase* parser) : parser_(parser) {} - - virtual void CheckProperty(Token::Value property, PropertyKind type, - MethodKind method_type, - ExpressionClassifier* classifier, bool* ok) = 0; - - virtual ~ObjectLiteralCheckerBase() {} - - protected: - ParserBase* parser() const { return parser_; } - Scanner* scanner() const { return parser_->scanner(); } - - private: - ParserBase* parser_; - }; - // Validation per ES6 object literals. - class ObjectLiteralChecker : public ObjectLiteralCheckerBase { + class ObjectLiteralChecker { public: explicit ObjectLiteralChecker(ParserBase* parser) - : ObjectLiteralCheckerBase(parser), has_seen_proto_(false) {} + : parser_(parser), has_seen_proto_(false) {} - void CheckProperty(Token::Value property, PropertyKind type, - MethodKind method_type, ExpressionClassifier* classifier, - bool* ok) override; + void CheckDuplicateProto(Token::Value property); private: bool IsProto() { return this->scanner()->LiteralMatches("__proto__", 9); } + ParserBase* parser() const { return parser_; } + Scanner* scanner() const { return parser_->scanner(); } + + ParserBase* parser_; bool has_seen_proto_; }; // Validation per ES6 class literals. - class ClassLiteralChecker : public ObjectLiteralCheckerBase { + class ClassLiteralChecker { public: explicit ClassLiteralChecker(ParserBase* parser) - : ObjectLiteralCheckerBase(parser), has_seen_constructor_(false) {} + : parser_(parser), has_seen_constructor_(false) {} - void CheckProperty(Token::Value property, PropertyKind type, - MethodKind method_type, ExpressionClassifier* classifier, - bool* ok) override; + void CheckClassMethodName(Token::Value property, PropertyKind type, + bool is_generator, bool is_async, bool is_static, + bool* ok); private: bool IsConstructor() { @@ -1273,6 +1371,10 @@ class ParserBase : public ParserBaseTraits<Impl> { return this->scanner()->LiteralMatches("prototype", 9); } + ParserBase* parser() const { return parser_; } + Scanner* scanner() const { return parser_->scanner(); } + + ParserBase* parser_; bool has_seen_constructor_; }; @@ -1281,19 +1383,63 @@ class ParserBase : public ParserBaseTraits<Impl> { } Scope* scope() const { return scope_state_->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, + bool merge_non_patterns = true) { + DCHECK_NOT_NULL(classifier_); + ExpressionClassifier* previous = classifier_->previous(); + DCHECK_NOT_NULL(previous); + previous->Accumulate(classifier_, productions, merge_non_patterns); + classifier_ = previous; + } + + // Pops and discards the classifier that is on top of the stack + // without accumulating. + V8_INLINE void Discard() { + DCHECK_NOT_NULL(classifier_); + classifier_->Discard(); + classifier_ = classifier_->previous(); + } + + // 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); + } + + // Parser base's protected field members. + ScopeState* scope_state_; // Scope stack. FunctionState* function_state_; // Function state stack. v8::Extension* extension_; FuncNameInferrer* fni_; AstValueFactory* ast_value_factory_; // Not owned. - typename Traits::Type::Factory ast_node_factory_; + typename Types::Factory ast_node_factory_; ParserRecorder* log_; Mode mode_; bool parsing_module_; uintptr_t stack_limit_; + // Parser base's private field members. + private: Zone* zone_; + ExpressionClassifier* classifier_; Scanner* scanner_; bool stack_overflow_; @@ -1308,6 +1454,7 @@ class ParserBase : public ParserBaseTraits<Impl> { bool allow_harmony_async_await_; bool allow_harmony_restrictive_generators_; bool allow_harmony_trailing_commas_; + bool allow_harmony_class_fields_; friend class DiscardableZoneScope; }; @@ -1315,12 +1462,12 @@ class ParserBase : public ParserBaseTraits<Impl> { template <typename Impl> ParserBase<Impl>::FunctionState::FunctionState( FunctionState** function_state_stack, ScopeState** scope_stack, - Scope* scope, FunctionKind kind) + DeclarationScope* scope) : ScopeState(scope_stack, scope), next_materialized_literal_index_(0), expected_property_count_(0), - kind_(kind), - generator_object_variable_(NULL), + generator_object_variable_(nullptr), + promise_variable_(nullptr), function_state_stack_(function_state_stack), outer_function_state_(*function_state_stack), destructuring_assignments_to_rewrite_(16, scope->zone()), @@ -1413,19 +1560,18 @@ void ParserBase<Impl>::ReportUnexpectedTokenAt( MessageTemplate::Template message) { const char* arg; GetUnexpectedTokenMessage(token, &message, &source_location, &arg); - Traits::ReportMessageAt(source_location, message, 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(&classifier, CHECK_OK_CUSTOM(EmptyIdentifier)); + auto result = ParseAndClassifyIdentifier(CHECK_OK_CUSTOM(EmptyIdentifier)); if (allow_restricted_identifiers == kDontAllowRestrictedIdentifiers) { - ValidateAssignmentPattern(&classifier, CHECK_OK_CUSTOM(EmptyIdentifier)); - ValidateBindingPattern(&classifier, CHECK_OK_CUSTOM(EmptyIdentifier)); + ValidateAssignmentPattern(CHECK_OK_CUSTOM(EmptyIdentifier)); + ValidateBindingPattern(CHECK_OK_CUSTOM(EmptyIdentifier)); } return result; @@ -1433,33 +1579,32 @@ typename ParserBase<Impl>::IdentifierT ParserBase<Impl>::ParseIdentifier( template <typename Impl> typename ParserBase<Impl>::IdentifierT -ParserBase<Impl>::ParseAndClassifyIdentifier(ExpressionClassifier* classifier, - bool* ok) { +ParserBase<Impl>::ParseAndClassifyIdentifier(bool* ok) { Token::Value next = Next(); if (next == Token::IDENTIFIER || next == Token::ASYNC || (next == Token::AWAIT && !parsing_module_ && !is_async_function())) { - IdentifierT name = this->GetSymbol(scanner()); + 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 (this->IsEvalOrArguments(name)) { - classifier->RecordStrictModeFormalParameterError( + if (impl()->IsEvalOrArguments(name)) { + classifier()->RecordStrictModeFormalParameterError( scanner()->location(), MessageTemplate::kStrictEvalArguments); if (is_strict(language_mode())) { - classifier->RecordBindingPatternError( + classifier()->RecordBindingPatternError( scanner()->location(), MessageTemplate::kStrictEvalArguments); } } else if (next == Token::AWAIT) { - classifier->RecordAsyncArrowFormalParametersError( + classifier()->RecordAsyncArrowFormalParametersError( scanner()->location(), MessageTemplate::kAwaitBindingIdentifier); } - if (classifier->duplicate_finder() != nullptr && - scanner()->FindSymbol(classifier->duplicate_finder(), 1) != 0) { - classifier->RecordDuplicateFormalParameterError(scanner()->location()); + if (classifier()->duplicate_finder() != nullptr && + scanner()->FindSymbol(classifier()->duplicate_finder(), 1) != 0) { + classifier()->RecordDuplicateFormalParameterError(scanner()->location()); } return name; } else if (is_sloppy(language_mode()) && @@ -1467,25 +1612,25 @@ ParserBase<Impl>::ParseAndClassifyIdentifier(ExpressionClassifier* classifier, next == Token::ESCAPED_STRICT_RESERVED_WORD || next == Token::LET || next == Token::STATIC || (next == Token::YIELD && !is_generator()))) { - classifier->RecordStrictModeFormalParameterError( + classifier()->RecordStrictModeFormalParameterError( scanner()->location(), MessageTemplate::kUnexpectedStrictReserved); if (next == Token::ESCAPED_STRICT_RESERVED_WORD && is_strict(language_mode())) { ReportUnexpectedToken(next); *ok = false; - return Traits::EmptyIdentifier(); + return impl()->EmptyIdentifier(); } if (next == Token::LET || (next == Token::ESCAPED_STRICT_RESERVED_WORD && scanner()->is_literal_contextual_keyword(CStrVector("let")))) { - classifier->RecordLetPatternError(scanner()->location(), - MessageTemplate::kLetInLexicalBinding); + classifier()->RecordLetPatternError( + scanner()->location(), MessageTemplate::kLetInLexicalBinding); } - return this->GetSymbol(scanner()); + return impl()->GetSymbol(); } else { - this->ReportUnexpectedToken(next); + ReportUnexpectedToken(next); *ok = false; - return Traits::EmptyIdentifier(); + return impl()->EmptyIdentifier(); } } @@ -1505,10 +1650,10 @@ ParserBase<Impl>::ParseIdentifierOrStrictReservedWord( } else { ReportUnexpectedToken(next); *ok = false; - return Traits::EmptyIdentifier(); + return impl()->EmptyIdentifier(); } - return this->GetSymbol(scanner()); + return impl()->GetSymbol(); } template <typename Impl> @@ -1521,12 +1666,12 @@ typename ParserBase<Impl>::IdentifierT ParserBase<Impl>::ParseIdentifierName( next != Token::FUTURE_STRICT_RESERVED_WORD && next != Token::ESCAPED_KEYWORD && next != Token::ESCAPED_STRICT_RESERVED_WORD && !Token::IsKeyword(next)) { - this->ReportUnexpectedToken(next); + ReportUnexpectedToken(next); *ok = false; - return Traits::EmptyIdentifier(); + return impl()->EmptyIdentifier(); } - return this->GetSymbol(scanner()); + return impl()->GetSymbol(); } template <typename Impl> @@ -1537,18 +1682,18 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseRegExpLiteral( Next(); ReportMessage(MessageTemplate::kUnterminatedRegExp); *ok = false; - return Traits::EmptyExpression(); + return impl()->EmptyExpression(); } int literal_index = function_state_->NextMaterializedLiteralIndex(); - IdentifierT js_pattern = this->GetNextSymbol(scanner()); + IdentifierT js_pattern = impl()->GetNextSymbol(); Maybe<RegExp::Flags> flags = scanner()->ScanRegExpFlags(); if (flags.IsNothing()) { Next(); ReportMessage(MessageTemplate::kMalformedRegExpFlags); *ok = false; - return Traits::EmptyExpression(); + return impl()->EmptyExpression(); } int js_flags = flags.FromJust(); Next(); @@ -1557,7 +1702,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseRegExpLiteral( template <typename Impl> typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePrimaryExpression( - ExpressionClassifier* classifier, bool* is_async, bool* ok) { + bool* is_async, bool* ok) { // PrimaryExpression :: // 'this' // 'null' @@ -1573,14 +1718,14 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePrimaryExpression( // '(' Expression ')' // TemplateLiteral // do Block - // AsyncFunctionExpression + // AsyncFunctionLiteral int beg_pos = peek_position(); switch (peek()) { case Token::THIS: { - BindingPatternUnexpectedToken(classifier); + BindingPatternUnexpectedToken(); Consume(Token::THIS); - return this->ThisExpression(beg_pos); + return impl()->ThisExpression(beg_pos); } case Token::NULL_LITERAL: @@ -1588,15 +1733,15 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePrimaryExpression( case Token::FALSE_LITERAL: case Token::SMI: case Token::NUMBER: - BindingPatternUnexpectedToken(classifier); - return this->ExpressionFromLiteral(Next(), beg_pos, scanner(), factory()); + BindingPatternUnexpectedToken(); + return impl()->ExpressionFromLiteral(Next(), beg_pos); case Token::ASYNC: if (allow_harmony_async_await() && !scanner()->HasAnyLineTerminatorAfterNext() && PeekAhead() == Token::FUNCTION) { Consume(Token::ASYNC); - return impl()->ParseAsyncFunctionExpression(CHECK_OK); + return ParseAsyncFunctionLiteral(CHECK_OK); } // CoverCallExpressionAndAsyncArrowHead *is_async = true; @@ -1609,28 +1754,28 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePrimaryExpression( case Token::ESCAPED_STRICT_RESERVED_WORD: case Token::FUTURE_STRICT_RESERVED_WORD: { // Using eval or arguments in this context is OK even in strict mode. - IdentifierT name = ParseAndClassifyIdentifier(classifier, CHECK_OK); - return this->ExpressionFromIdentifier(name, beg_pos, - scanner()->location().end_pos); + IdentifierT name = ParseAndClassifyIdentifier(CHECK_OK); + return impl()->ExpressionFromIdentifier(name, beg_pos, + scanner()->location().end_pos); } case Token::STRING: { - BindingPatternUnexpectedToken(classifier); + BindingPatternUnexpectedToken(); Consume(Token::STRING); - return this->ExpressionFromString(beg_pos, scanner(), factory()); + return impl()->ExpressionFromString(beg_pos); } case Token::ASSIGN_DIV: case Token::DIV: - classifier->RecordBindingPatternError( + classifier()->RecordBindingPatternError( scanner()->peek_location(), MessageTemplate::kUnexpectedTokenRegExp); - return this->ParseRegExpLiteral(ok); + return ParseRegExpLiteral(ok); case Token::LBRACK: - return this->ParseArrayLiteral(classifier, ok); + return ParseArrayLiteral(ok); case Token::LBRACE: - return this->ParseObjectLiteral(classifier, ok); + return ParseObjectLiteral(ok); case Token::LPAREN: { // Arrow function formal parameters are either a single identifier or a @@ -1638,61 +1783,34 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePrimaryExpression( // 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(classifier); + 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)); + classifier()->RecordExpressionError(scanner()->location(), + MessageTemplate::kUnexpectedToken, + Token::String(Token::RPAREN)); return factory()->NewEmptyParentheses(beg_pos); - } else if (Check(Token::ELLIPSIS)) { - // (...x)=>x. The continuation that looks for the => is in - // ParseAssignmentExpression. - int ellipsis_pos = position(); - int expr_pos = peek_position(); - classifier->RecordExpressionError(scanner()->location(), - MessageTemplate::kUnexpectedToken, - Token::String(Token::ELLIPSIS)); - classifier->RecordNonSimpleParameter(); - ExpressionClassifier binding_classifier(this); - ExpressionT expr = this->ParseAssignmentExpression( - true, &binding_classifier, CHECK_OK); - classifier->Accumulate(&binding_classifier, - ExpressionClassifier::AllProductions); - if (!this->IsIdentifier(expr) && !IsValidPattern(expr)) { - classifier->RecordArrowFormalParametersError( - Scanner::Location(ellipsis_pos, scanner()->location().end_pos), - MessageTemplate::kInvalidRestParameter); - } - if (peek() == Token::COMMA) { - ReportMessageAt(scanner()->peek_location(), - MessageTemplate::kParamAfterRest); - *ok = false; - return this->EmptyExpression(); - } - Expect(Token::RPAREN, CHECK_OK); - return factory()->NewSpread(expr, ellipsis_pos, expr_pos); } // Heuristically try to detect immediately called functions before // seeing the call parentheses. function_state_->set_next_function_is_parenthesized(peek() == Token::FUNCTION); - ExpressionT expr = this->ParseExpression(true, classifier, CHECK_OK); + ExpressionT expr = ParseExpressionCoverGrammar(true, CHECK_OK); Expect(Token::RPAREN, CHECK_OK); return expr; } case Token::CLASS: { - BindingPatternUnexpectedToken(classifier); + BindingPatternUnexpectedToken(); Consume(Token::CLASS); - int class_token_position = position(); - IdentifierT name = this->EmptyIdentifier(); + int class_token_pos = position(); + IdentifierT name = impl()->EmptyIdentifier(); bool is_strict_reserved_name = false; Scanner::Location class_name_location = Scanner::Location::invalid(); if (peek_any_identifier()) { @@ -1700,28 +1818,26 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePrimaryExpression( CHECK_OK); class_name_location = scanner()->location(); } - return impl()->ParseClassLiteral(classifier, name, class_name_location, - is_strict_reserved_name, - class_token_position, ok); + return ParseClassLiteral(name, class_name_location, + is_strict_reserved_name, class_token_pos, ok); } case Token::TEMPLATE_SPAN: case Token::TEMPLATE_TAIL: - BindingPatternUnexpectedToken(classifier); - return this->ParseTemplateLiteral(Traits::NoTemplateTag(), beg_pos, - classifier, ok); + BindingPatternUnexpectedToken(); + return ParseTemplateLiteral(impl()->NoTemplateTag(), beg_pos, ok); case Token::MOD: if (allow_natives() || extension_ != NULL) { - BindingPatternUnexpectedToken(classifier); - return impl()->ParseV8Intrinsic(ok); + BindingPatternUnexpectedToken(); + return ParseV8Intrinsic(ok); } break; case Token::DO: if (allow_harmony_do_expressions()) { - BindingPatternUnexpectedToken(classifier); - return impl()->ParseDoExpression(ok); + BindingPatternUnexpectedToken(); + return ParseDoExpression(ok); } break; @@ -1731,78 +1847,71 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePrimaryExpression( ReportUnexpectedToken(Next()); *ok = false; - return this->EmptyExpression(); + return impl()->EmptyExpression(); } template <typename Impl> typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseExpression( bool accept_IN, bool* ok) { ExpressionClassifier classifier(this); - ExpressionT result = ParseExpression(accept_IN, &classifier, CHECK_OK); - impl()->RewriteNonPattern(&classifier, CHECK_OK); + ExpressionT result = ParseExpressionCoverGrammar(accept_IN, CHECK_OK); + impl()->RewriteNonPattern(CHECK_OK); return result; } template <typename Impl> -typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseExpression( - bool accept_IN, ExpressionClassifier* classifier, bool* ok) { +typename ParserBase<Impl>::ExpressionT +ParserBase<Impl>::ParseExpressionCoverGrammar(bool accept_IN, bool* ok) { // Expression :: // AssignmentExpression // Expression ',' AssignmentExpression - ExpressionT result; - { + ExpressionT result = impl()->EmptyExpression(); + while (true) { + int comma_pos = position(); ExpressionClassifier binding_classifier(this); - result = this->ParseAssignmentExpression(accept_IN, &binding_classifier, - CHECK_OK); - classifier->Accumulate(&binding_classifier, - ExpressionClassifier::AllProductions); - } - bool is_simple_parameter_list = this->IsIdentifier(result); - bool seen_rest = false; - while (peek() == Token::COMMA) { - CheckNoTailCallExpressions(classifier, CHECK_OK); - if (seen_rest) { - // At this point the production can't possibly be valid, but we don't know - // which error to signal. - classifier->RecordArrowFormalParametersError( - scanner()->peek_location(), MessageTemplate::kParamAfterRest); - } - Consume(Token::COMMA); - bool is_rest = false; + 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 = ParsePrimaryExpression(CHECK_OK); + ValidateBindingPattern(CHECK_OK); + 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. + impl()->Accumulate(ExpressionClassifier::AllProductions & + ~(ExpressionClassifier::BindingPatternProduction | + ExpressionClassifier::LetPatternProduction)); + if (!impl()->IsIdentifier(right)) classifier()->RecordNonSimpleParameter(); + if (impl()->IsEmptyExpression(result)) { + // First time through the loop. + result = right; + } else { + result = + factory()->NewBinaryOperation(Token::COMMA, result, right, comma_pos); + } + + if (!Check(Token::COMMA)) break; + + if (right->IsSpread()) { + classifier()->RecordArrowFormalParametersError( + scanner()->location(), MessageTemplate::kParamAfterRest); + } + if (allow_harmony_trailing_commas() && peek() == Token::RPAREN && PeekAhead() == Token::ARROW) { // a trailing comma is allowed at the end of an arrow parameter list break; - } else if (peek() == Token::ELLIPSIS) { - // 'x, y, ...z' in CoverParenthesizedExpressionAndArrowParameterList only - // as the formal parameters of'(x, y, ...z) => foo', and is not itself a - // valid expression or binding pattern. - ExpressionUnexpectedToken(classifier); - BindingPatternUnexpectedToken(classifier); - Consume(Token::ELLIPSIS); - seen_rest = is_rest = true; - } - int pos = position(), expr_pos = peek_position(); - ExpressionClassifier binding_classifier(this); - ExpressionT right = this->ParseAssignmentExpression( - accept_IN, &binding_classifier, CHECK_OK); - classifier->Accumulate(&binding_classifier, - ExpressionClassifier::AllProductions); - if (is_rest) { - if (!this->IsIdentifier(right) && !IsValidPattern(right)) { - classifier->RecordArrowFormalParametersError( - Scanner::Location(pos, scanner()->location().end_pos), - MessageTemplate::kInvalidRestParameter); - } - right = factory()->NewSpread(right, pos, expr_pos); } - is_simple_parameter_list = - is_simple_parameter_list && this->IsIdentifier(right); - result = factory()->NewBinaryOperation(Token::COMMA, result, right, pos); - } - if (!is_simple_parameter_list || seen_rest) { - classifier->RecordNonSimpleParameter(); } return result; @@ -1810,26 +1919,23 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseExpression( template <typename Impl> typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseArrayLiteral( - ExpressionClassifier* classifier, bool* ok) { + bool* ok) { // ArrayLiteral :: // '[' Expression? (',' Expression?)* ']' int pos = peek_position(); - typename Traits::Type::ExpressionList values = - this->NewExpressionList(4, zone_); + ExpressionListT values = impl()->NewExpressionList(4); int first_spread_index = -1; Expect(Token::LBRACK, CHECK_OK); while (peek() != Token::RBRACK) { ExpressionT elem; if (peek() == Token::COMMA) { - elem = this->GetLiteralTheHole(peek_position(), factory()); + elem = impl()->GetLiteralTheHole(peek_position()); } else if (peek() == Token::ELLIPSIS) { int start_pos = peek_position(); Consume(Token::ELLIPSIS); int expr_pos = peek_position(); - ExpressionT argument = - this->ParseAssignmentExpression(true, classifier, CHECK_OK); - CheckNoTailCallExpressions(classifier, CHECK_OK); + ExpressionT argument = ParseAssignmentExpression(true, CHECK_OK); elem = factory()->NewSpread(argument, start_pos, expr_pos); if (first_spread_index < 0) { @@ -1837,25 +1943,23 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseArrayLiteral( } if (argument->IsAssignment()) { - classifier->RecordPatternError( + classifier()->RecordPatternError( Scanner::Location(start_pos, scanner()->location().end_pos), MessageTemplate::kInvalidDestructuringTarget); } else { - CheckDestructuringElement(argument, classifier, start_pos, + CheckDestructuringElement(argument, start_pos, scanner()->location().end_pos); } if (peek() == Token::COMMA) { - classifier->RecordPatternError( + classifier()->RecordPatternError( Scanner::Location(start_pos, scanner()->location().end_pos), MessageTemplate::kElementAfterRest); } } else { int beg_pos = peek_position(); - elem = this->ParseAssignmentExpression(true, classifier, CHECK_OK); - CheckNoTailCallExpressions(classifier, CHECK_OK); - CheckDestructuringElement(elem, classifier, beg_pos, - scanner()->location().end_pos); + elem = ParseAssignmentExpression(true, CHECK_OK); + CheckDestructuringElement(elem, beg_pos, scanner()->location().end_pos); } values->Add(elem, zone_); if (peek() != Token::RBRACK) { @@ -1878,19 +1982,87 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseArrayLiteral( // to change. Also, this error message will never appear while pre- // parsing (this is OK, as it is an implementation limitation). ReportMessage(MessageTemplate::kTooManySpreads); - return this->EmptyExpression(); + return impl()->EmptyExpression(); } } return result; } template <class Impl> +bool ParserBase<Impl>::SetPropertyKindFromToken(Token::Value token, + PropertyKind* 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 = PropertyKind::kValueProperty; + return true; + case Token::COMMA: + case Token::RBRACE: + case Token::ASSIGN: + *kind = PropertyKind::kShorthandProperty; + return true; + case Token::LPAREN: + *kind = PropertyKind::kMethodProperty; + return true; + case Token::MUL: + case Token::SEMICOLON: + *kind = PropertyKind::kClassField; + return true; + default: + break; + } + return false; +} + +template <class Impl> typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePropertyName( - IdentifierT* name, bool* is_get, bool* is_set, bool* is_computed_name, - ExpressionClassifier* classifier, bool* ok) { + IdentifierT* name, PropertyKind* kind, bool* is_generator, bool* is_get, + bool* is_set, bool* is_async, bool* is_computed_name, bool* ok) { + DCHECK(*kind == PropertyKind::kNotSet); + DCHECK(!*is_generator); + DCHECK(!*is_get); + DCHECK(!*is_set); + DCHECK(!*is_async); + DCHECK(!*is_computed_name); + + *is_generator = Check(Token::MUL); + if (*is_generator) { + *kind = PropertyKind::kMethodProperty; + } + Token::Value token = peek(); int pos = peek_position(); + if (allow_harmony_async_await() && !*is_generator && token == Token::ASYNC && + !scanner()->HasAnyLineTerminatorAfterNext()) { + Consume(Token::ASYNC); + token = peek(); + if (SetPropertyKindFromToken(token, kind)) { + *name = impl()->GetSymbol(); // TODO(bakkot) specialize on 'async' + impl()->PushLiteralName(*name); + return factory()->NewStringLiteral(*name, pos); + } + *kind = PropertyKind::kMethodProperty; + *is_async = true; + pos = peek_position(); + } + + if (token == Token::IDENTIFIER && !*is_generator && !*is_async) { + // This is checking for 'get' and 'set' in particular. + Consume(Token::IDENTIFIER); + token = peek(); + if (SetPropertyKindFromToken(token, kind) || + !scanner()->IsGetOrSet(is_get, is_set)) { + *name = impl()->GetSymbol(); + impl()->PushLiteralName(*name); + return factory()->NewStringLiteral(*name, pos); + } + *kind = PropertyKind::kAccessorProperty; + pos = peek_position(); + } + // For non computed property names we normalize the name a bit: // // "12" -> 12 @@ -1900,274 +2072,417 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePropertyName( // // This is important because we use the property name as a key in a hash // table when we compute constant properties. + ExpressionT expression = impl()->EmptyExpression(); switch (token) { case Token::STRING: Consume(Token::STRING); - *name = this->GetSymbol(scanner()); + *name = impl()->GetSymbol(); break; case Token::SMI: Consume(Token::SMI); - *name = this->GetNumberAsSymbol(scanner()); + *name = impl()->GetNumberAsSymbol(); break; case Token::NUMBER: Consume(Token::NUMBER); - *name = this->GetNumberAsSymbol(scanner()); + *name = impl()->GetNumberAsSymbol(); break; case Token::LBRACK: { + *name = impl()->EmptyIdentifier(); *is_computed_name = true; Consume(Token::LBRACK); ExpressionClassifier computed_name_classifier(this); - ExpressionT expression = - ParseAssignmentExpression(true, &computed_name_classifier, CHECK_OK); - impl()->RewriteNonPattern(&computed_name_classifier, CHECK_OK); - classifier->Accumulate(&computed_name_classifier, - ExpressionClassifier::ExpressionProductions); + expression = ParseAssignmentExpression(true, CHECK_OK); + impl()->RewriteNonPattern(CHECK_OK); + impl()->AccumulateFormalParameterContainmentErrors(); Expect(Token::RBRACK, CHECK_OK); - return expression; + break; } default: *name = ParseIdentifierName(CHECK_OK); - scanner()->IsGetOrSet(is_get, is_set); break; } + if (*kind == PropertyKind::kNotSet) { + SetPropertyKindFromToken(peek(), kind); + } + + if (*is_computed_name) { + return expression; + } + + impl()->PushLiteralName(*name); + uint32_t index; - return this->IsArrayIndex(*name, &index) + return impl()->IsArrayIndex(*name, &index) ? factory()->NewNumberLiteral(index, pos) : factory()->NewStringLiteral(*name, pos); } template <typename Impl> -typename ParserBase<Impl>::ObjectLiteralPropertyT -ParserBase<Impl>::ParsePropertyDefinition( - ObjectLiteralCheckerBase* checker, bool in_class, bool has_extends, - MethodKind method_kind, bool* is_computed_name, bool* has_seen_constructor, - ExpressionClassifier* classifier, IdentifierT* name, bool* ok) { - DCHECK(!in_class || IsStaticMethod(method_kind) || - has_seen_constructor != nullptr); +typename ParserBase<Impl>::ClassLiteralPropertyT +ParserBase<Impl>::ParseClassPropertyDefinition(ClassLiteralChecker* checker, + bool has_extends, + bool* is_computed_name, + bool* has_seen_constructor, + bool* ok) { + DCHECK(has_seen_constructor != nullptr); bool is_get = false; bool is_set = false; - bool is_generator = Check(Token::MUL); + bool is_generator = false; bool is_async = false; - const bool is_static = IsStaticMethod(method_kind); + bool is_static = false; + PropertyKind kind = PropertyKind::kNotSet; Token::Value name_token = peek(); - if (is_generator) { - method_kind |= MethodKind::kGenerator; - } else if (allow_harmony_async_await() && name_token == Token::ASYNC && - !scanner()->HasAnyLineTerminatorAfterNext() && - PeekAhead() != Token::LPAREN && PeekAhead()) { - is_async = true; + IdentifierT name = impl()->EmptyIdentifier(); + ExpressionT name_expression; + if (name_token == Token::STATIC) { + Consume(Token::STATIC); + if (peek() == Token::LPAREN) { + kind = PropertyKind::kMethodProperty; + name = impl()->GetSymbol(); // TODO(bakkot) specialize on 'static' + name_expression = factory()->NewStringLiteral(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 { + is_static = true; + name_expression = ParsePropertyName( + &name, &kind, &is_generator, &is_get, &is_set, &is_async, + is_computed_name, CHECK_OK_CUSTOM(EmptyClassLiteralProperty)); + } + } else { + name_expression = ParsePropertyName( + &name, &kind, &is_generator, &is_get, &is_set, &is_async, + is_computed_name, CHECK_OK_CUSTOM(EmptyClassLiteralProperty)); + } + + switch (kind) { + case PropertyKind::kClassField: + case PropertyKind::kNotSet: // This case is a name followed by a name or + // other property. Here we have to assume + // that's an uninitialized field followed by a + // linebreak followed by a property, with ASI + // adding the semicolon. If not, there will be + // a syntax error after parsing the first name + // as an uninitialized field. + case PropertyKind::kShorthandProperty: + case PropertyKind::kValueProperty: + if (allow_harmony_class_fields()) { + bool has_initializer = Check(Token::ASSIGN); + ExpressionT function_literal = ParseClassFieldForInitializer( + has_initializer, CHECK_OK_CUSTOM(EmptyClassLiteralProperty)); + ExpectSemicolon(CHECK_OK_CUSTOM(EmptyClassLiteralProperty)); + return factory()->NewClassLiteralProperty( + name_expression, function_literal, ClassLiteralProperty::FIELD, + is_static, *is_computed_name); + } else { + ReportUnexpectedToken(Next()); + *ok = false; + return impl()->EmptyClassLiteralProperty(); + } + + case PropertyKind::kMethodProperty: { + DCHECK(!is_get && !is_set); + + // MethodDefinition + // PropertyName '(' StrictFormalParameters ')' '{' FunctionBody '}' + // '*' PropertyName '(' StrictFormalParameters ')' '{' FunctionBody '}' + + if (!*is_computed_name) { + checker->CheckClassMethodName( + name_token, PropertyKind::kMethodProperty, is_generator, is_async, + is_static, CHECK_OK_CUSTOM(EmptyClassLiteralProperty)); + } + + FunctionKind kind = is_generator + ? FunctionKind::kConciseGeneratorMethod + : is_async ? FunctionKind::kAsyncConciseMethod + : FunctionKind::kConciseMethod; + + if (!is_static && impl()->IsConstructor(name)) { + *has_seen_constructor = true; + kind = has_extends ? FunctionKind::kSubclassConstructor + : FunctionKind::kBaseConstructor; + } + + ExpressionT value = impl()->ParseFunctionLiteral( + name, scanner()->location(), kSkipFunctionNameCheck, kind, + kNoSourcePosition, FunctionLiteral::kAccessorOrMethod, + language_mode(), CHECK_OK_CUSTOM(EmptyClassLiteralProperty)); + + return factory()->NewClassLiteralProperty(name_expression, value, + ClassLiteralProperty::METHOD, + is_static, *is_computed_name); + } + + case PropertyKind::kAccessorProperty: { + DCHECK((is_get || is_set) && !is_generator && !is_async); + + if (!*is_computed_name) { + checker->CheckClassMethodName( + name_token, PropertyKind::kAccessorProperty, false, false, + is_static, CHECK_OK_CUSTOM(EmptyClassLiteralProperty)); + // 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()); + } + + FunctionKind kind = is_get ? FunctionKind::kGetterFunction + : FunctionKind::kSetterFunction; + + FunctionLiteralT value = impl()->ParseFunctionLiteral( + name, scanner()->location(), kSkipFunctionNameCheck, kind, + kNoSourcePosition, FunctionLiteral::kAccessorOrMethod, + language_mode(), CHECK_OK_CUSTOM(EmptyClassLiteralProperty)); + + if (!*is_computed_name) { + impl()->AddAccessorPrefixToFunctionName(is_get, value, name); + } + + return factory()->NewClassLiteralProperty( + name_expression, value, + is_get ? ClassLiteralProperty::GETTER : ClassLiteralProperty::SETTER, + is_static, *is_computed_name); + } } + UNREACHABLE(); + return impl()->EmptyClassLiteralProperty(); +} +template <typename Impl> +typename ParserBase<Impl>::FunctionLiteralT +ParserBase<Impl>::ParseClassFieldForInitializer(bool has_initializer, + bool* ok) { + // Makes a concise method which evaluates and returns the initialized value + // (or undefined if absent). + FunctionKind kind = FunctionKind::kConciseMethod; + DeclarationScope* initializer_scope = NewFunctionScope(kind); + initializer_scope->set_start_position(scanner()->location().end_pos); + FunctionState initializer_state(&function_state_, &scope_state_, + initializer_scope); + DCHECK(scope() == initializer_scope); + scope()->SetLanguageMode(STRICT); + ExpressionClassifier expression_classifier(this); + ExpressionT value; + if (has_initializer) { + value = this->ParseAssignmentExpression( + true, CHECK_OK_CUSTOM(EmptyFunctionLiteral)); + impl()->RewriteNonPattern(CHECK_OK_CUSTOM(EmptyFunctionLiteral)); + } else { + value = factory()->NewUndefinedLiteral(kNoSourcePosition); + } + initializer_scope->set_end_position(scanner()->location().end_pos); + typename Types::StatementList body = impl()->NewStatementList(1); + body->Add(factory()->NewReturnStatement(value, kNoSourcePosition), zone()); + FunctionLiteralT function_literal = factory()->NewFunctionLiteral( + impl()->EmptyIdentifierString(), initializer_scope, body, + initializer_state.materialized_literal_count(), + initializer_state.expected_property_count(), 0, + FunctionLiteral::kNoDuplicateParameters, + FunctionLiteral::kAnonymousExpression, + FunctionLiteral::kShouldLazyCompile, initializer_scope->start_position()); + function_literal->set_is_class_field_initializer(true); + return function_literal; +} + +template <typename Impl> +typename ParserBase<Impl>::ObjectLiteralPropertyT +ParserBase<Impl>::ParseObjectPropertyDefinition(ObjectLiteralChecker* checker, + bool* is_computed_name, + bool* ok) { + bool is_get = false; + bool is_set = false; + bool is_generator = false; + bool is_async = false; + PropertyKind kind = PropertyKind::kNotSet; + + IdentifierT name = impl()->EmptyIdentifier(); + Token::Value name_token = peek(); int next_beg_pos = scanner()->peek_location().beg_pos; int next_end_pos = scanner()->peek_location().end_pos; - ExpressionT name_expression = - ParsePropertyName(name, &is_get, &is_set, is_computed_name, classifier, - CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); - if (fni_ != nullptr && !*is_computed_name) { - this->PushLiteralName(fni_, *name); - } + ExpressionT name_expression = ParsePropertyName( + &name, &kind, &is_generator, &is_get, &is_set, &is_async, + is_computed_name, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); + + switch (kind) { + case PropertyKind::kValueProperty: { + DCHECK(!is_get && !is_set && !is_generator && !is_async); - if (!in_class && !is_generator) { - DCHECK(!IsStaticMethod(method_kind)); - if (peek() == Token::COLON) { - // PropertyDefinition - // PropertyName ':' AssignmentExpression if (!*is_computed_name) { - checker->CheckProperty(name_token, kValueProperty, MethodKind::kNormal, - classifier, - CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); + checker->CheckDuplicateProto(name_token); } Consume(Token::COLON); int beg_pos = peek_position(); - ExpressionT value = this->ParseAssignmentExpression( - true, classifier, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); - CheckDestructuringElement(value, classifier, beg_pos, - scanner()->location().end_pos); + ExpressionT value = ParseAssignmentExpression( + true, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); + CheckDestructuringElement(value, beg_pos, scanner()->location().end_pos); + + ObjectLiteralPropertyT result = factory()->NewObjectLiteralProperty( + name_expression, value, *is_computed_name); + + if (!*is_computed_name) { + impl()->SetFunctionNameFromPropertyName(result, name); + } - return factory()->NewObjectLiteralProperty(name_expression, value, - is_static, *is_computed_name); + return result; } - if (Token::IsIdentifier(name_token, language_mode(), this->is_generator(), - parsing_module_ || is_async_function()) && - (peek() == Token::COMMA || peek() == Token::RBRACE || - peek() == Token::ASSIGN)) { + case PropertyKind::kShorthandProperty: { // PropertyDefinition // IdentifierReference // CoverInitializedName // // CoverInitializedName // IdentifierReference Initializer? - if (classifier->duplicate_finder() != nullptr && - scanner()->FindSymbol(classifier->duplicate_finder(), 1) != 0) { - classifier->RecordDuplicateFormalParameterError(scanner()->location()); + DCHECK(!is_get && !is_set && !is_generator && !is_async); + + if (!Token::IsIdentifier(name_token, language_mode(), + this->is_generator(), + parsing_module_ || is_async_function())) { + ReportUnexpectedToken(Next()); + *ok = false; + return impl()->EmptyObjectLiteralProperty(); } - if (this->IsEvalOrArguments(*name) && is_strict(language_mode())) { - classifier->RecordBindingPatternError( + DCHECK(!*is_computed_name); + + if (classifier()->duplicate_finder() != nullptr && + scanner()->FindSymbol(classifier()->duplicate_finder(), 1) != 0) { + classifier()->RecordDuplicateFormalParameterError( + scanner()->location()); + } + + if (impl()->IsEvalOrArguments(name) && is_strict(language_mode())) { + classifier()->RecordBindingPatternError( scanner()->location(), MessageTemplate::kStrictEvalArguments); } if (name_token == Token::LET) { - classifier->RecordLetPatternError( + classifier()->RecordLetPatternError( scanner()->location(), MessageTemplate::kLetInLexicalBinding); } if (name_token == Token::AWAIT) { DCHECK(!is_async_function()); - classifier->RecordAsyncArrowFormalParametersError( + classifier()->RecordAsyncArrowFormalParametersError( Scanner::Location(next_beg_pos, next_end_pos), MessageTemplate::kAwaitBindingIdentifier); } ExpressionT lhs = - this->ExpressionFromIdentifier(*name, next_beg_pos, next_end_pos); - CheckDestructuringElement(lhs, classifier, next_beg_pos, next_end_pos); + impl()->ExpressionFromIdentifier(name, next_beg_pos, next_end_pos); + CheckDestructuringElement(lhs, next_beg_pos, next_end_pos); ExpressionT value; if (peek() == Token::ASSIGN) { Consume(Token::ASSIGN); ExpressionClassifier rhs_classifier(this); - ExpressionT rhs = this->ParseAssignmentExpression( - true, &rhs_classifier, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); - impl()->RewriteNonPattern(&rhs_classifier, - CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); - classifier->Accumulate(&rhs_classifier, - ExpressionClassifier::ExpressionProductions); + ExpressionT rhs = ParseAssignmentExpression( + true, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); + impl()->RewriteNonPattern(CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); + impl()->AccumulateFormalParameterContainmentErrors(); value = factory()->NewAssignment(Token::ASSIGN, lhs, rhs, kNoSourcePosition); - classifier->RecordObjectLiteralError( + classifier()->RecordExpressionError( Scanner::Location(next_beg_pos, scanner()->location().end_pos), MessageTemplate::kInvalidCoverInitializedName); - Traits::SetFunctionNameFromIdentifierRef(rhs, lhs); + impl()->SetFunctionNameFromIdentifierRef(rhs, lhs); } else { value = lhs; } return factory()->NewObjectLiteralProperty( - name_expression, value, ObjectLiteralProperty::COMPUTED, is_static, - false); + name_expression, value, ObjectLiteralProperty::COMPUTED, false); } - } - // Method definitions are never valid in patterns. - classifier->RecordPatternError( - Scanner::Location(next_beg_pos, scanner()->location().end_pos), - MessageTemplate::kInvalidDestructuringTarget); + case PropertyKind::kMethodProperty: { + DCHECK(!is_get && !is_set); - if (is_async && !IsSpecialMethod(method_kind)) { - DCHECK(!is_get); - DCHECK(!is_set); - bool dont_care; - name_expression = ParsePropertyName( - name, &dont_care, &dont_care, is_computed_name, classifier, - CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); - method_kind |= MethodKind::kAsync; - } - - if (is_generator || peek() == Token::LPAREN) { - // MethodDefinition - // PropertyName '(' StrictFormalParameters ')' '{' FunctionBody '}' - // '*' PropertyName '(' StrictFormalParameters ')' '{' FunctionBody '}' - if (!*is_computed_name) { - checker->CheckProperty(name_token, kMethodProperty, method_kind, - classifier, - CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); - } - - FunctionKind kind = is_generator - ? FunctionKind::kConciseGeneratorMethod - : is_async ? FunctionKind::kAsyncConciseMethod - : FunctionKind::kConciseMethod; - - if (in_class && !IsStaticMethod(method_kind) && - this->IsConstructor(*name)) { - *has_seen_constructor = true; - kind = has_extends ? FunctionKind::kSubclassConstructor - : FunctionKind::kBaseConstructor; - } - - ExpressionT value = impl()->ParseFunctionLiteral( - *name, scanner()->location(), kSkipFunctionNameCheck, kind, - kNoSourcePosition, FunctionLiteral::kAccessorOrMethod, language_mode(), - CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); - - return factory()->NewObjectLiteralProperty(name_expression, value, - ObjectLiteralProperty::COMPUTED, - is_static, *is_computed_name); - } - - if (in_class && name_token == Token::STATIC && IsNormalMethod(method_kind)) { - // ClassElement (static) - // 'static' MethodDefinition - *name = this->EmptyIdentifier(); - ObjectLiteralPropertyT property = ParsePropertyDefinition( - checker, true, has_extends, MethodKind::kStatic, is_computed_name, - nullptr, classifier, name, ok); - impl()->RewriteNonPattern(classifier, ok); - return property; - } - - if (is_get || is_set) { - // MethodDefinition (Accessors) - // get PropertyName '(' ')' '{' FunctionBody '}' - // set PropertyName '(' PropertySetParameterList ')' '{' FunctionBody '}' - *name = this->EmptyIdentifier(); - bool dont_care = false; - name_token = peek(); + // MethodDefinition + // PropertyName '(' StrictFormalParameters ')' '{' FunctionBody '}' + // '*' PropertyName '(' StrictFormalParameters ')' '{' FunctionBody '}' - name_expression = ParsePropertyName( - name, &dont_care, &dont_care, is_computed_name, classifier, - CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); + classifier()->RecordPatternError( + Scanner::Location(next_beg_pos, scanner()->location().end_pos), + MessageTemplate::kInvalidDestructuringTarget); + + FunctionKind kind = is_generator + ? FunctionKind::kConciseGeneratorMethod + : is_async ? FunctionKind::kAsyncConciseMethod + : FunctionKind::kConciseMethod; + + ExpressionT value = impl()->ParseFunctionLiteral( + name, scanner()->location(), kSkipFunctionNameCheck, kind, + kNoSourcePosition, FunctionLiteral::kAccessorOrMethod, + language_mode(), CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); - if (!*is_computed_name) { - checker->CheckProperty(name_token, kAccessorProperty, method_kind, - classifier, - CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); + return factory()->NewObjectLiteralProperty( + name_expression, value, ObjectLiteralProperty::COMPUTED, + *is_computed_name); } - typename Traits::Type::FunctionLiteral value = impl()->ParseFunctionLiteral( - *name, scanner()->location(), kSkipFunctionNameCheck, - is_get ? FunctionKind::kGetterFunction : FunctionKind::kSetterFunction, - kNoSourcePosition, FunctionLiteral::kAccessorOrMethod, language_mode(), - CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); + case PropertyKind::kAccessorProperty: { + DCHECK((is_get || is_set) && !(is_set && is_get) && !is_generator && + !is_async); + + classifier()->RecordPatternError( + Scanner::Location(next_beg_pos, scanner()->location().end_pos), + MessageTemplate::kInvalidDestructuringTarget); + + if (!*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. + name_expression = + factory()->NewStringLiteral(name, name_expression->position()); + } + + FunctionKind kind = is_get ? FunctionKind::kGetterFunction + : FunctionKind::kSetterFunction; - // 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. - if (!*is_computed_name) { - name_expression = - factory()->NewStringLiteral(*name, name_expression->position()); + FunctionLiteralT value = impl()->ParseFunctionLiteral( + name, scanner()->location(), kSkipFunctionNameCheck, kind, + kNoSourcePosition, FunctionLiteral::kAccessorOrMethod, + language_mode(), CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); + + if (!*is_computed_name) { + impl()->AddAccessorPrefixToFunctionName(is_get, value, name); + } + + return factory()->NewObjectLiteralProperty( + name_expression, value, is_get ? ObjectLiteralProperty::GETTER + : ObjectLiteralProperty::SETTER, + *is_computed_name); } - return factory()->NewObjectLiteralProperty( - name_expression, value, - is_get ? ObjectLiteralProperty::GETTER : ObjectLiteralProperty::SETTER, - is_static, *is_computed_name); + case PropertyKind::kClassField: + case PropertyKind::kNotSet: + ReportUnexpectedToken(Next()); + *ok = false; + return impl()->EmptyObjectLiteralProperty(); } - - Token::Value next = Next(); - ReportUnexpectedToken(next); - *ok = false; - return this->EmptyObjectLiteralProperty(); + UNREACHABLE(); + return impl()->EmptyObjectLiteralProperty(); } template <typename Impl> typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseObjectLiteral( - ExpressionClassifier* classifier, bool* ok) { + bool* ok) { // ObjectLiteral :: // '{' (PropertyDefinition (',' PropertyDefinition)* ','? )? '}' int pos = peek_position(); - typename Traits::Type::PropertyList properties = - this->NewPropertyList(4, zone_); + typename Types::ObjectPropertyList properties = + impl()->NewObjectPropertyList(4); int number_of_boilerplate_properties = 0; bool has_computed_names = false; ObjectLiteralChecker checker(this); @@ -2177,20 +2492,16 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseObjectLiteral( while (peek() != Token::RBRACE) { FuncNameInferrer::State fni_state(fni_); - const bool in_class = false; - const bool has_extends = false; bool is_computed_name = false; - IdentifierT name = this->EmptyIdentifier(); - ObjectLiteralPropertyT property = this->ParsePropertyDefinition( - &checker, in_class, has_extends, MethodKind::kNormal, &is_computed_name, - NULL, classifier, &name, CHECK_OK); + ObjectLiteralPropertyT property = + ParseObjectPropertyDefinition(&checker, &is_computed_name, CHECK_OK); if (is_computed_name) { has_computed_names = true; } // Count CONSTANT or COMPUTED properties to maintain the enumeration order. - if (!has_computed_names && this->IsBoilerplateProperty(property)) { + if (!has_computed_names && impl()->IsBoilerplateProperty(property)) { number_of_boilerplate_properties++; } properties->Add(property, zone()); @@ -2201,8 +2512,6 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseObjectLiteral( } if (fni_ != nullptr) fni_->Infer(); - - Traits::SetFunctionNameFromPropertyName(property, name); } Expect(Token::RBRACE, CHECK_OK); @@ -2216,16 +2525,13 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseObjectLiteral( } template <typename Impl> -typename ParserBase<Impl>::Traits::Type::ExpressionList -ParserBase<Impl>::ParseArguments(Scanner::Location* first_spread_arg_loc, - bool maybe_arrow, - ExpressionClassifier* classifier, bool* ok) { +typename ParserBase<Impl>::ExpressionListT ParserBase<Impl>::ParseArguments( + Scanner::Location* first_spread_arg_loc, bool maybe_arrow, bool* ok) { // Arguments :: // '(' (AssignmentExpression)*[','] ')' Scanner::Location spread_arg = Scanner::Location::invalid(); - typename Traits::Type::ExpressionList result = - this->NewExpressionList(4, zone_); + ExpressionListT result = impl()->NewExpressionList(4); Expect(Token::LPAREN, CHECK_OK_CUSTOM(NullExpressionList)); bool done = (peek() == Token::RPAREN); bool was_unspread = false; @@ -2235,12 +2541,10 @@ ParserBase<Impl>::ParseArguments(Scanner::Location* first_spread_arg_loc, bool is_spread = Check(Token::ELLIPSIS); int expr_pos = peek_position(); - ExpressionT argument = this->ParseAssignmentExpression( - true, classifier, CHECK_OK_CUSTOM(NullExpressionList)); - CheckNoTailCallExpressions(classifier, CHECK_OK_CUSTOM(NullExpressionList)); + ExpressionT argument = + ParseAssignmentExpression(true, CHECK_OK_CUSTOM(NullExpressionList)); if (!maybe_arrow) { - impl()->RewriteNonPattern(classifier, - CHECK_OK_CUSTOM(NullExpressionList)); + impl()->RewriteNonPattern(CHECK_OK_CUSTOM(NullExpressionList)); } if (is_spread) { if (!spread_arg.IsValid()) { @@ -2263,7 +2567,7 @@ ParserBase<Impl>::ParseArguments(Scanner::Location* first_spread_arg_loc, if (result->length() > Code::kMaxArguments) { ReportMessage(MessageTemplate::kTooManyArguments); *ok = false; - return this->NullExpressionList(); + return impl()->NullExpressionList(); } done = (peek() != Token::COMMA); if (!done) { @@ -2276,22 +2580,21 @@ ParserBase<Impl>::ParseArguments(Scanner::Location* first_spread_arg_loc, } Scanner::Location location = scanner_->location(); if (Token::RPAREN != Next()) { - ReportMessageAt(location, MessageTemplate::kUnterminatedArgList); + impl()->ReportMessageAt(location, MessageTemplate::kUnterminatedArgList); *ok = false; - return this->NullExpressionList(); + return impl()->NullExpressionList(); } *first_spread_arg_loc = spread_arg; if (!maybe_arrow || peek() != Token::ARROW) { if (maybe_arrow) { - impl()->RewriteNonPattern(classifier, - CHECK_OK_CUSTOM(NullExpressionList)); + impl()->RewriteNonPattern(CHECK_OK_CUSTOM(NullExpressionList)); } if (spread_arg.IsValid()) { // Unspread parameter sequences are translated into array literals in the // parser. Ensure that the number of materialized literals matches between // the parser and preparser - Traits::MaterializeUnspreadArgumentsLiterals(unspread_sequences_count); + impl()->MaterializeUnspreadArgumentsLiterals(unspread_sequences_count); } } @@ -2301,9 +2604,7 @@ ParserBase<Impl>::ParseArguments(Scanner::Location* first_spread_arg_loc, // Precedence = 2 template <typename Impl> typename ParserBase<Impl>::ExpressionT -ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN, - ExpressionClassifier* classifier, - bool* ok) { +ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN, bool* ok) { // AssignmentExpression :: // ConditionalExpression // ArrowFunction @@ -2312,13 +2613,13 @@ ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN, int lhs_beg_pos = peek_position(); if (peek() == Token::YIELD && is_generator()) { - return this->ParseYieldExpression(accept_IN, classifier, ok); + return ParseYieldExpression(accept_IN, ok); } FuncNameInferrer::State fni_state(fni_); Checkpoint checkpoint(this); - ExpressionClassifier arrow_formals_classifier(this, - classifier->duplicate_finder()); + ExpressionClassifier arrow_formals_classifier( + this, classifier()->duplicate_finder()); Scope::Snapshot scope_snapshot(scope()); @@ -2328,26 +2629,23 @@ ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN, bool parenthesized_formals = peek() == Token::LPAREN; if (!is_async && !parenthesized_formals) { - ArrowFormalParametersUnexpectedToken(&arrow_formals_classifier); + 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 = this->ParsePrimaryExpression(&arrow_formals_classifier, - &is_async, CHECK_OK); + expression = ParsePrimaryExpression(&is_async, CHECK_OK); } else { - expression = this->ParseConditionalExpression( - accept_IN, &arrow_formals_classifier, CHECK_OK); + expression = ParseConditionalExpression(accept_IN, CHECK_OK); } - if (is_async && this->IsIdentifier(expression) && peek_any_identifier() && + if (is_async && impl()->IsIdentifier(expression) && peek_any_identifier() && PeekAhead() == Token::ARROW) { // async Identifier => AsyncConciseBody - IdentifierT name = - ParseAndClassifyIdentifier(&arrow_formals_classifier, CHECK_OK); - expression = this->ExpressionFromIdentifier( + IdentifierT name = ParseAndClassifyIdentifier(CHECK_OK); + expression = impl()->ExpressionFromIdentifier( name, position(), scanner()->location().end_pos, InferName::kNo); if (fni_) { // Remove `async` keyword from inferred name stack. @@ -2357,26 +2655,29 @@ ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN, if (peek() == Token::ARROW) { Scanner::Location arrow_loc = scanner()->peek_location(); - ValidateArrowFormalParameters(&arrow_formals_classifier, expression, - parenthesized_formals, is_async, CHECK_OK); + 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(&arrow_formals_classifier, ok); + ValidateFormalParameterInitializer(ok); Scanner::Location loc(lhs_beg_pos, scanner()->location().end_pos); DeclarationScope* scope = - this->NewFunctionScope(is_async ? FunctionKind::kAsyncArrowFunction - : FunctionKind::kArrowFunction); + NewFunctionScope(is_async ? FunctionKind::kAsyncArrowFunction + : FunctionKind::kArrowFunction); // Because the arrow's parameters were parsed in the outer scope, any // usage flags that might have been triggered there need to be copied // to the arrow scope. this->scope()->PropagateUsageFlagsToScope(scope); + + scope_snapshot.Reparent(scope); + FormalParametersT parameters(scope); - if (!arrow_formals_classifier.is_simple_parameter_list()) { + if (!classifier()->is_simple_parameter_list()) { scope->SetHasNonSimpleParameters(); parameters.is_simple = false; } @@ -2385,18 +2686,16 @@ ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN, scope->set_start_position(lhs_beg_pos); Scanner::Location duplicate_loc = Scanner::Location::invalid(); - this->ParseArrowFunctionFormalParameterList( - ¶meters, expression, loc, &duplicate_loc, scope_snapshot, CHECK_OK); + impl()->DeclareArrowFunctionFormalParameters(¶meters, expression, loc, + &duplicate_loc, CHECK_OK); if (duplicate_loc.IsValid()) { - arrow_formals_classifier.RecordDuplicateFormalParameterError( - duplicate_loc); + classifier()->RecordDuplicateFormalParameterError(duplicate_loc); } - expression = this->ParseArrowFunctionLiteral( - accept_IN, parameters, is_async, arrow_formals_classifier, CHECK_OK); - arrow_formals_classifier.Discard(); - classifier->RecordPatternError(arrow_loc, - MessageTemplate::kUnexpectedToken, - Token::String(Token::ARROW)); + expression = ParseArrowFunctionLiteral(accept_IN, parameters, CHECK_OK); + impl()->Discard(); + classifier()->RecordPatternError(arrow_loc, + MessageTemplate::kUnexpectedToken, + Token::String(Token::ARROW)); if (fni_ != nullptr) fni_->Infer(); @@ -2407,87 +2706,70 @@ ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN, // form part of one. Propagate speculative formal parameter error locations // (including those for binding patterns, since formal parameters can // themselves contain binding patterns). - // Do not merge pending non-pattern expressions yet! - unsigned productions = - ExpressionClassifier::FormalParametersProductions | - ExpressionClassifier::AsyncArrowFormalParametersProduction | - ExpressionClassifier::FormalParameterInitializerProduction; + unsigned productions = ExpressionClassifier::AllProductions & + ~ExpressionClassifier::ArrowFormalParametersProduction; // Parenthesized identifiers and property references are allowed as part - // of a larger binding pattern, even though parenthesized patterns + // 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 (this->IsValidReferenceExpression(expression)) { - productions |= ExpressionClassifier::PatternProductions & - ~ExpressionClassifier::AssignmentPatternProduction; - } else { - productions |= ExpressionClassifier::PatternProductions; + if (IsValidReferenceExpression(expression)) { + productions &= ~ExpressionClassifier::AssignmentPatternProduction; } const bool is_destructuring_assignment = IsValidPattern(expression) && peek() == Token::ASSIGN; - if (!is_destructuring_assignment) { - // This may be an expression or a pattern, so we must continue to - // accumulate expression-related errors. - productions |= ExpressionClassifier::ExpressionProduction | - ExpressionClassifier::TailCallExpressionProduction | - ExpressionClassifier::ObjectLiteralProduction; + if (is_destructuring_assignment) { + // This is definitely not an expression so don't accumulate + // expression-related errors. + productions &= ~(ExpressionClassifier::ExpressionProduction | + ExpressionClassifier::TailCallExpressionProduction); } - classifier->Accumulate(&arrow_formals_classifier, productions, false); - if (!Token::IsAssignmentOp(peek())) { // Parsed conditional expression only (no assignment). - // Now pending non-pattern expressions must be merged. - classifier->MergeNonPatterns(&arrow_formals_classifier); + // Pending non-pattern expressions must be merged. + impl()->Accumulate(productions); return expression; + } else { + // Pending non-pattern expressions must be discarded. + impl()->Accumulate(productions, false); } - // Now pending non-pattern expressions must be discarded. - arrow_formals_classifier.Discard(); - - CheckNoTailCallExpressions(classifier, CHECK_OK); - if (is_destructuring_assignment) { - ValidateAssignmentPattern(classifier, CHECK_OK); + ValidateAssignmentPattern(CHECK_OK); } else { - expression = this->CheckAndRewriteReferenceExpression( + expression = CheckAndRewriteReferenceExpression( expression, lhs_beg_pos, scanner()->location().end_pos, MessageTemplate::kInvalidLhsInAssignment, CHECK_OK); } - expression = this->MarkExpressionAsAssigned(expression); + expression = impl()->MarkExpressionAsAssigned(expression); Token::Value op = Next(); // Get assignment operator. if (op != Token::ASSIGN) { - classifier->RecordPatternError(scanner()->location(), - MessageTemplate::kUnexpectedToken, - Token::String(op)); + classifier()->RecordPatternError(scanner()->location(), + MessageTemplate::kUnexpectedToken, + Token::String(op)); } int pos = position(); ExpressionClassifier rhs_classifier(this); - ExpressionT right = - this->ParseAssignmentExpression(accept_IN, &rhs_classifier, CHECK_OK); - CheckNoTailCallExpressions(&rhs_classifier, CHECK_OK); - impl()->RewriteNonPattern(&rhs_classifier, CHECK_OK); - classifier->Accumulate( - &rhs_classifier, - ExpressionClassifier::ExpressionProductions | - ExpressionClassifier::ObjectLiteralProduction | - ExpressionClassifier::AsyncArrowFormalParametersProduction); + ExpressionT right = ParseAssignmentExpression(accept_IN, CHECK_OK); + impl()->RewriteNonPattern(CHECK_OK); + impl()->AccumulateFormalParameterContainmentErrors(); // TODO(1231235): 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 && this->IsThisProperty(expression)) { + if (op == Token::ASSIGN && impl()->IsThisProperty(expression)) { function_state_->AddProperty(); } - this->CheckAssigningFunctionLiteralToProperty(expression, right); + impl()->CheckAssigningFunctionLiteralToProperty(expression, right); if (fni_ != NULL) { // Check if the right hand side is a call to avoid inferring a @@ -2502,7 +2784,7 @@ ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN, } if (op == Token::ASSIGN) { - Traits::SetFunctionNameFromIdentifierRef(right, expression); + impl()->SetFunctionNameFromIdentifierRef(right, expression); } if (op == Token::ASSIGN_EXP) { @@ -2522,19 +2804,19 @@ ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN, template <typename Impl> typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseYieldExpression( - bool accept_IN, ExpressionClassifier* classifier, bool* ok) { + bool accept_IN, bool* ok) { // YieldExpression :: // 'yield' ([no line terminator] '*'? AssignmentExpression)? int pos = peek_position(); - classifier->RecordPatternError(scanner()->peek_location(), - MessageTemplate::kInvalidDestructuringTarget); - classifier->RecordFormalParameterInitializerError( + classifier()->RecordPatternError( + scanner()->peek_location(), MessageTemplate::kInvalidDestructuringTarget); + classifier()->RecordFormalParameterInitializerError( scanner()->peek_location(), MessageTemplate::kYieldInParameter); Expect(Token::YIELD, CHECK_OK); ExpressionT generator_object = factory()->NewVariableProxy(function_state_->generator_object_variable()); // The following initialization is necessary. - ExpressionT expression = Traits::EmptyExpression(); + ExpressionT expression = impl()->EmptyExpression(); bool delegating = false; // yield* if (!scanner()->HasAnyLineTerminatorBeforeNext()) { if (Check(Token::MUL)) delegating = true; @@ -2553,8 +2835,8 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseYieldExpression( if (!delegating) break; // Delegating yields require an RHS; fall through. default: - expression = ParseAssignmentExpression(accept_IN, classifier, CHECK_OK); - impl()->RewriteNonPattern(classifier, CHECK_OK); + expression = ParseAssignmentExpression(accept_IN, CHECK_OK); + impl()->RewriteNonPattern(CHECK_OK); break; } } @@ -2563,87 +2845,18 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseYieldExpression( return impl()->RewriteYieldStar(generator_object, expression, pos); } - expression = Traits::BuildIteratorResult(expression, false); + expression = impl()->BuildIteratorResult(expression, false); // Hackily disambiguate o from o.next and o [Symbol.iterator](). // TODO(verwaest): Come up with a better solution. - typename Traits::Type::YieldExpression yield = factory()->NewYield( - generator_object, expression, pos, Yield::kOnExceptionThrow); + ExpressionT yield = factory()->NewYield(generator_object, expression, pos, + Yield::kOnExceptionThrow); return yield; } -template <typename Impl> -typename ParserBase<Impl>::ExpressionT -ParserBase<Impl>::ParseTailCallExpression(ExpressionClassifier* classifier, - bool* ok) { - // TailCallExpression:: - // 'continue' MemberExpression Arguments - // 'continue' CallExpression Arguments - // 'continue' MemberExpression TemplateLiteral - // 'continue' CallExpression TemplateLiteral - Expect(Token::CONTINUE, CHECK_OK); - int pos = position(); - int sub_expression_pos = peek_position(); - ExpressionT expression = - this->ParseLeftHandSideExpression(classifier, CHECK_OK); - CheckNoTailCallExpressions(classifier, CHECK_OK); - - Scanner::Location loc(pos, scanner()->location().end_pos); - if (!expression->IsCall()) { - Scanner::Location sub_loc(sub_expression_pos, loc.end_pos); - ReportMessageAt(sub_loc, MessageTemplate::kUnexpectedInsideTailCall); - *ok = false; - return Traits::EmptyExpression(); - } - if (Traits::IsDirectEvalCall(expression)) { - Scanner::Location sub_loc(sub_expression_pos, loc.end_pos); - ReportMessageAt(sub_loc, MessageTemplate::kUnexpectedTailCallOfEval); - *ok = false; - return Traits::EmptyExpression(); - } - if (!is_strict(language_mode())) { - ReportMessageAt(loc, MessageTemplate::kUnexpectedSloppyTailCall); - *ok = false; - return Traits::EmptyExpression(); - } - if (is_resumable()) { - Scanner::Location sub_loc(sub_expression_pos, loc.end_pos); - ReportMessageAt(sub_loc, MessageTemplate::kUnexpectedTailCall); - *ok = false; - return Traits::EmptyExpression(); - } - ReturnExprContext return_expr_context = - function_state_->return_expr_context(); - if (return_expr_context != ReturnExprContext::kInsideValidReturnStatement) { - MessageTemplate::Template msg = MessageTemplate::kNone; - switch (return_expr_context) { - case ReturnExprContext::kInsideValidReturnStatement: - UNREACHABLE(); - return Traits::EmptyExpression(); - case ReturnExprContext::kInsideValidBlock: - msg = MessageTemplate::kUnexpectedTailCall; - break; - case ReturnExprContext::kInsideTryBlock: - msg = MessageTemplate::kUnexpectedTailCallInTryBlock; - break; - case ReturnExprContext::kInsideForInOfBody: - msg = MessageTemplate::kUnexpectedTailCallInForInOf; - break; - } - ReportMessageAt(loc, msg); - *ok = false; - return Traits::EmptyExpression(); - } - classifier->RecordTailCallExpressionError( - loc, MessageTemplate::kUnexpectedTailCall); - function_state_->AddExplicitTailCallExpression(expression, loc); - return expression; -} - // Precedence = 3 template <typename Impl> typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseConditionalExpression(bool accept_IN, - ExpressionClassifier* classifier, bool* ok) { // ConditionalExpression :: // LogicalOrExpression @@ -2651,23 +2864,20 @@ ParserBase<Impl>::ParseConditionalExpression(bool accept_IN, int pos = peek_position(); // We start using the binary expression parser for prec >= 4 only! - ExpressionT expression = - this->ParseBinaryExpression(4, accept_IN, classifier, CHECK_OK); + ExpressionT expression = ParseBinaryExpression(4, accept_IN, CHECK_OK); if (peek() != Token::CONDITIONAL) return expression; - CheckNoTailCallExpressions(classifier, CHECK_OK); - impl()->RewriteNonPattern(classifier, CHECK_OK); - BindingPatternUnexpectedToken(classifier); - ArrowFormalParametersUnexpectedToken(classifier); + impl()->RewriteNonPattern(CHECK_OK); + BindingPatternUnexpectedToken(); + ArrowFormalParametersUnexpectedToken(); Consume(Token::CONDITIONAL); // In parsing the first assignment expression in conditional // expressions we always accept the 'in' keyword; see ECMA-262, // section 11.12, page 58. - ExpressionT left = ParseAssignmentExpression(true, classifier, CHECK_OK); - impl()->RewriteNonPattern(classifier, CHECK_OK); + ExpressionT left = ParseAssignmentExpression(true, CHECK_OK); + impl()->RewriteNonPattern(CHECK_OK); Expect(Token::COLON, CHECK_OK); - ExpressionT right = - ParseAssignmentExpression(accept_IN, classifier, CHECK_OK); - impl()->RewriteNonPattern(classifier, CHECK_OK); + ExpressionT right = ParseAssignmentExpression(accept_IN, CHECK_OK); + impl()->RewriteNonPattern(CHECK_OK); return factory()->NewConditional(expression, left, right, pos); } @@ -2675,30 +2885,24 @@ ParserBase<Impl>::ParseConditionalExpression(bool accept_IN, // Precedence >= 4 template <typename Impl> typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseBinaryExpression( - int prec, bool accept_IN, ExpressionClassifier* classifier, bool* ok) { + int prec, bool accept_IN, bool* ok) { DCHECK(prec >= 4); - ExpressionT x = this->ParseUnaryExpression(classifier, CHECK_OK); + ExpressionT x = ParseUnaryExpression(CHECK_OK); for (int prec1 = Precedence(peek(), accept_IN); prec1 >= prec; prec1--) { // prec1 >= 4 while (Precedence(peek(), accept_IN) == prec1) { - CheckNoTailCallExpressions(classifier, CHECK_OK); - impl()->RewriteNonPattern(classifier, CHECK_OK); - BindingPatternUnexpectedToken(classifier); - ArrowFormalParametersUnexpectedToken(classifier); + impl()->RewriteNonPattern(CHECK_OK); + BindingPatternUnexpectedToken(); + ArrowFormalParametersUnexpectedToken(); 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, classifier, CHECK_OK); - if (op != Token::OR && op != Token::AND) { - CheckNoTailCallExpressions(classifier, CHECK_OK); - } - impl()->RewriteNonPattern(classifier, CHECK_OK); + ExpressionT y = ParseBinaryExpression(next_prec, accept_IN, CHECK_OK); + impl()->RewriteNonPattern(CHECK_OK); - if (this->ShortcutNumericLiteralBinaryExpression(&x, y, op, pos, - factory())) { + if (impl()->ShortcutNumericLiteralBinaryExpression(&x, y, op, pos)) { continue; } @@ -2731,7 +2935,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseBinaryExpression( template <typename Impl> typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseUnaryExpression( - ExpressionClassifier* classifier, bool* ok) { + bool* ok) { // UnaryExpression :: // PostfixExpression // 'delete' UnaryExpression @@ -2747,44 +2951,42 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseUnaryExpression( Token::Value op = peek(); if (Token::IsUnaryOp(op)) { - BindingPatternUnexpectedToken(classifier); - ArrowFormalParametersUnexpectedToken(classifier); + BindingPatternUnexpectedToken(); + ArrowFormalParametersUnexpectedToken(); op = Next(); int pos = position(); - ExpressionT expression = ParseUnaryExpression(classifier, CHECK_OK); - CheckNoTailCallExpressions(classifier, CHECK_OK); - impl()->RewriteNonPattern(classifier, CHECK_OK); + ExpressionT expression = ParseUnaryExpression(CHECK_OK); + impl()->RewriteNonPattern(CHECK_OK); if (op == Token::DELETE && is_strict(language_mode())) { - if (this->IsIdentifier(expression)) { + if (impl()->IsIdentifier(expression)) { // "delete identifier" is a syntax error in strict mode. ReportMessage(MessageTemplate::kStrictDelete); *ok = false; - return this->EmptyExpression(); + return impl()->EmptyExpression(); } } if (peek() == Token::EXP) { ReportUnexpectedToken(Next()); *ok = false; - return this->EmptyExpression(); + return impl()->EmptyExpression(); } - // Allow Traits do rewrite the expression. - return this->BuildUnaryExpression(expression, op, pos, factory()); + // Allow the parser's implementation to rewrite the expression. + return impl()->BuildUnaryExpression(expression, op, pos); } else if (Token::IsCountOp(op)) { - BindingPatternUnexpectedToken(classifier); - ArrowFormalParametersUnexpectedToken(classifier); + BindingPatternUnexpectedToken(); + ArrowFormalParametersUnexpectedToken(); op = Next(); int beg_pos = peek_position(); - ExpressionT expression = this->ParseUnaryExpression(classifier, CHECK_OK); - CheckNoTailCallExpressions(classifier, CHECK_OK); - expression = this->CheckAndRewriteReferenceExpression( + ExpressionT expression = ParseUnaryExpression(CHECK_OK); + expression = CheckAndRewriteReferenceExpression( expression, beg_pos, scanner()->location().end_pos, MessageTemplate::kInvalidLhsInPrefixOp, CHECK_OK); - this->MarkExpressionAsAssigned(expression); - impl()->RewriteNonPattern(classifier, CHECK_OK); + expression = impl()->MarkExpressionAsAssigned(expression); + impl()->RewriteNonPattern(CHECK_OK); return factory()->NewCountOperation(op, true /* prefix */, @@ -2792,41 +2994,39 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseUnaryExpression( position()); } else if (is_async_function() && peek() == Token::AWAIT) { - classifier->RecordFormalParameterInitializerError( + classifier()->RecordFormalParameterInitializerError( scanner()->peek_location(), MessageTemplate::kAwaitExpressionFormalParameter); int await_pos = peek_position(); Consume(Token::AWAIT); - ExpressionT value = ParseUnaryExpression(classifier, CHECK_OK); + ExpressionT value = ParseUnaryExpression(CHECK_OK); return impl()->RewriteAwaitExpression(value, await_pos); } else { - return this->ParsePostfixExpression(classifier, ok); + return ParsePostfixExpression(ok); } } template <typename Impl> typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePostfixExpression( - ExpressionClassifier* classifier, bool* ok) { + bool* ok) { // PostfixExpression :: // LeftHandSideExpression ('++' | '--')? int lhs_beg_pos = peek_position(); - ExpressionT expression = - this->ParseLeftHandSideExpression(classifier, CHECK_OK); + ExpressionT expression = ParseLeftHandSideExpression(CHECK_OK); if (!scanner()->HasAnyLineTerminatorBeforeNext() && Token::IsCountOp(peek())) { - CheckNoTailCallExpressions(classifier, CHECK_OK); - BindingPatternUnexpectedToken(classifier); - ArrowFormalParametersUnexpectedToken(classifier); + BindingPatternUnexpectedToken(); + ArrowFormalParametersUnexpectedToken(); - expression = this->CheckAndRewriteReferenceExpression( + expression = CheckAndRewriteReferenceExpression( expression, lhs_beg_pos, scanner()->location().end_pos, MessageTemplate::kInvalidLhsInPostfixOp, CHECK_OK); - expression = this->MarkExpressionAsAssigned(expression); - impl()->RewriteNonPattern(classifier, CHECK_OK); + expression = impl()->MarkExpressionAsAssigned(expression); + impl()->RewriteNonPattern(CHECK_OK); Token::Value next = Next(); expression = @@ -2840,40 +3040,33 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePostfixExpression( template <typename Impl> typename ParserBase<Impl>::ExpressionT -ParserBase<Impl>::ParseLeftHandSideExpression(ExpressionClassifier* classifier, - bool* ok) { +ParserBase<Impl>::ParseLeftHandSideExpression(bool* ok) { // LeftHandSideExpression :: // (NewExpression | MemberExpression) ... - if (FLAG_harmony_explicit_tailcalls && peek() == Token::CONTINUE) { - return this->ParseTailCallExpression(classifier, ok); - } - bool is_async = false; - ExpressionT result = this->ParseMemberWithNewPrefixesExpression( - classifier, &is_async, CHECK_OK); + ExpressionT result = + ParseMemberWithNewPrefixesExpression(&is_async, CHECK_OK); while (true) { switch (peek()) { case Token::LBRACK: { - CheckNoTailCallExpressions(classifier, CHECK_OK); - impl()->RewriteNonPattern(classifier, CHECK_OK); - BindingPatternUnexpectedToken(classifier); - ArrowFormalParametersUnexpectedToken(classifier); + impl()->RewriteNonPattern(CHECK_OK); + BindingPatternUnexpectedToken(); + ArrowFormalParametersUnexpectedToken(); Consume(Token::LBRACK); int pos = position(); - ExpressionT index = ParseExpression(true, classifier, CHECK_OK); - impl()->RewriteNonPattern(classifier, CHECK_OK); + ExpressionT index = ParseExpressionCoverGrammar(true, CHECK_OK); + impl()->RewriteNonPattern(CHECK_OK); result = factory()->NewProperty(result, index, pos); Expect(Token::RBRACK, CHECK_OK); break; } case Token::LPAREN: { - CheckNoTailCallExpressions(classifier, CHECK_OK); int pos; - impl()->RewriteNonPattern(classifier, CHECK_OK); - BindingPatternUnexpectedToken(classifier); + impl()->RewriteNonPattern(CHECK_OK); + BindingPatternUnexpectedToken(); if (scanner()->current_token() == Token::IDENTIFIER || scanner()->current_token() == Token::SUPER || scanner()->current_token() == Token::ASYNC) { @@ -2895,36 +3088,36 @@ ParserBase<Impl>::ParseLeftHandSideExpression(ExpressionClassifier* classifier, } } Scanner::Location spread_pos; - typename Traits::Type::ExpressionList args; - if (V8_UNLIKELY(is_async && this->IsIdentifier(result))) { + ExpressionListT args; + if (V8_UNLIKELY(is_async && impl()->IsIdentifier(result))) { ExpressionClassifier async_classifier(this); - args = ParseArguments(&spread_pos, true, &async_classifier, CHECK_OK); + args = ParseArguments(&spread_pos, true, CHECK_OK); if (peek() == Token::ARROW) { if (fni_) { fni_->RemoveAsyncKeywordFromEnd(); } - ValidateBindingPattern(&async_classifier, CHECK_OK); - if (!async_classifier.is_valid_async_arrow_formal_parameters()) { + ValidateBindingPattern(CHECK_OK); + ValidateFormalParameterInitializer(CHECK_OK); + if (!classifier()->is_valid_async_arrow_formal_parameters()) { ReportClassifierError( - async_classifier.async_arrow_formal_parameters_error()); + classifier()->async_arrow_formal_parameters_error()); *ok = false; - return this->EmptyExpression(); + return impl()->EmptyExpression(); } if (args->length()) { // async ( Arguments ) => ... - return Traits::ExpressionListToExpression(args); + return impl()->ExpressionListToExpression(args); } // async () => ... return factory()->NewEmptyParentheses(pos); } else { - classifier->Accumulate(&async_classifier, - ExpressionClassifier::AllProductions); + impl()->AccumulateFormalParameterContainmentErrors(); } } else { - args = ParseArguments(&spread_pos, false, classifier, CHECK_OK); + args = ParseArguments(&spread_pos, false, CHECK_OK); } - ArrowFormalParametersUnexpectedToken(classifier); + ArrowFormalParametersUnexpectedToken(); // Keep track of eval() calls since they disable all local variable // optimizations. @@ -2947,7 +3140,8 @@ ParserBase<Impl>::ParseLeftHandSideExpression(ExpressionClassifier* classifier, // Explicit calls to the super constructor using super() perform an // implicit binding assignment to the 'this' variable. if (is_super_call) { - ExpressionT this_expr = this->ThisExpression(pos); + result = impl()->RewriteSuperCall(result); + ExpressionT this_expr = impl()->ThisExpression(pos); result = factory()->NewAssignment(Token::INIT, this_expr, result, pos); } @@ -2957,26 +3151,24 @@ ParserBase<Impl>::ParseLeftHandSideExpression(ExpressionClassifier* classifier, } case Token::PERIOD: { - CheckNoTailCallExpressions(classifier, CHECK_OK); - impl()->RewriteNonPattern(classifier, CHECK_OK); - BindingPatternUnexpectedToken(classifier); - ArrowFormalParametersUnexpectedToken(classifier); + impl()->RewriteNonPattern(CHECK_OK); + BindingPatternUnexpectedToken(); + ArrowFormalParametersUnexpectedToken(); Consume(Token::PERIOD); int pos = position(); IdentifierT name = ParseIdentifierName(CHECK_OK); result = factory()->NewProperty( result, factory()->NewStringLiteral(name, pos), pos); - if (fni_ != NULL) this->PushLiteralName(fni_, name); + impl()->PushLiteralName(name); break; } case Token::TEMPLATE_SPAN: case Token::TEMPLATE_TAIL: { - CheckNoTailCallExpressions(classifier, CHECK_OK); - impl()->RewriteNonPattern(classifier, CHECK_OK); - BindingPatternUnexpectedToken(classifier); - ArrowFormalParametersUnexpectedToken(classifier); - result = ParseTemplateLiteral(result, position(), classifier, CHECK_OK); + impl()->RewriteNonPattern(CHECK_OK); + BindingPatternUnexpectedToken(); + ArrowFormalParametersUnexpectedToken(); + result = ParseTemplateLiteral(result, position(), CHECK_OK); break; } @@ -2988,8 +3180,8 @@ ParserBase<Impl>::ParseLeftHandSideExpression(ExpressionClassifier* classifier, template <typename Impl> typename ParserBase<Impl>::ExpressionT -ParserBase<Impl>::ParseMemberWithNewPrefixesExpression( - ExpressionClassifier* classifier, bool* is_async, bool* ok) { +ParserBase<Impl>::ParseMemberWithNewPrefixesExpression(bool* is_async, + bool* ok) { // NewExpression :: // ('new')+ MemberExpression // @@ -3011,8 +3203,8 @@ ParserBase<Impl>::ParseMemberWithNewPrefixesExpression( // new new foo().bar().baz means (new (new foo()).bar()).baz if (peek() == Token::NEW) { - BindingPatternUnexpectedToken(classifier); - ArrowFormalParametersUnexpectedToken(classifier); + BindingPatternUnexpectedToken(); + ArrowFormalParametersUnexpectedToken(); Consume(Token::NEW); int new_pos = position(); ExpressionT result; @@ -3022,15 +3214,13 @@ ParserBase<Impl>::ParseMemberWithNewPrefixesExpression( } else if (peek() == Token::PERIOD) { return ParseNewTargetExpression(CHECK_OK); } else { - result = this->ParseMemberWithNewPrefixesExpression(classifier, is_async, - CHECK_OK); + result = ParseMemberWithNewPrefixesExpression(is_async, CHECK_OK); } - impl()->RewriteNonPattern(classifier, CHECK_OK); + impl()->RewriteNonPattern(CHECK_OK); if (peek() == Token::LPAREN) { // NewExpression with arguments. Scanner::Location spread_pos; - typename Traits::Type::ExpressionList args = - this->ParseArguments(&spread_pos, classifier, CHECK_OK); + ExpressionListT args = ParseArguments(&spread_pos, CHECK_OK); if (spread_pos.IsValid()) { args = impl()->PrepareSpreadArguments(args); @@ -3039,21 +3229,19 @@ ParserBase<Impl>::ParseMemberWithNewPrefixesExpression( result = factory()->NewCallNew(result, args, new_pos); } // The expression can still continue with . or [ after the arguments. - result = this->ParseMemberExpressionContinuation(result, is_async, - classifier, CHECK_OK); + result = ParseMemberExpressionContinuation(result, is_async, CHECK_OK); return result; } // NewExpression without arguments. - return factory()->NewCallNew(result, this->NewExpressionList(0, zone_), - new_pos); + return factory()->NewCallNew(result, impl()->NewExpressionList(0), new_pos); } // No 'new' or 'super' keyword. - return this->ParseMemberExpression(classifier, is_async, ok); + return ParseMemberExpression(is_async, ok); } template <typename Impl> typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseMemberExpression( - ExpressionClassifier* classifier, bool* is_async, bool* ok) { + bool* is_async, bool* ok) { // MemberExpression :: // (PrimaryExpression | FunctionLiteral | ClassLiteral) // ('[' Expression ']' | '.' Identifier | Arguments | TemplateLiteral)* @@ -3065,8 +3253,8 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseMemberExpression( // Parse the initial primary or function expression. ExpressionT result; if (peek() == Token::FUNCTION) { - BindingPatternUnexpectedToken(classifier); - ArrowFormalParametersUnexpectedToken(classifier); + BindingPatternUnexpectedToken(); + ArrowFormalParametersUnexpectedToken(); Consume(Token::FUNCTION); int function_token_position = position(); @@ -3078,19 +3266,19 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseMemberExpression( if (!is_generator()) { // TODO(neis): allow escaping into closures? - ReportMessageAt(scanner()->location(), - MessageTemplate::kUnexpectedFunctionSent); + impl()->ReportMessageAt(scanner()->location(), + MessageTemplate::kUnexpectedFunctionSent); *ok = false; - return this->EmptyExpression(); + return impl()->EmptyExpression(); } - return this->FunctionSentExpression(factory(), pos); + return impl()->FunctionSentExpression(pos); } FunctionKind function_kind = Check(Token::MUL) ? FunctionKind::kGeneratorFunction : FunctionKind::kNormalFunction; - IdentifierT name = this->EmptyIdentifier(); + IdentifierT name = impl()->EmptyIdentifier(); bool is_strict_reserved_name = false; Scanner::Location function_name_location = Scanner::Location::invalid(); FunctionLiteral::FunctionType function_type = @@ -3111,11 +3299,10 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseMemberExpression( const bool is_new = false; result = ParseSuperExpression(is_new, CHECK_OK); } else { - result = ParsePrimaryExpression(classifier, is_async, CHECK_OK); + result = ParsePrimaryExpression(is_async, CHECK_OK); } - result = - ParseMemberExpressionContinuation(result, is_async, classifier, CHECK_OK); + result = ParseMemberExpressionContinuation(result, is_async, CHECK_OK); return result; } @@ -3131,20 +3318,21 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseSuperExpression( IsClassConstructor(kind)) { if (peek() == Token::PERIOD || peek() == Token::LBRACK) { scope->RecordSuperPropertyUsage(); - return this->NewSuperPropertyReference(factory(), pos); + return impl()->NewSuperPropertyReference(pos); } // new super() is never allowed. // super() is only allowed in derived constructor if (!is_new && peek() == Token::LPAREN && IsSubclassConstructor(kind)) { // TODO(rossberg): This might not be the correct FunctionState for the // method here. - return this->NewSuperCallReference(factory(), pos); + return impl()->NewSuperCallReference(pos); } } - ReportMessageAt(scanner()->location(), MessageTemplate::kUnexpectedSuper); + impl()->ReportMessageAt(scanner()->location(), + MessageTemplate::kUnexpectedSuper); *ok = false; - return this->EmptyExpression(); + return impl()->EmptyExpression(); } template <typename Impl> @@ -3154,7 +3342,7 @@ void ParserBase<Impl>::ExpectMetaProperty(Vector<const char> property_name, Consume(Token::PERIOD); ExpectContextualKeyword(property_name, CHECK_OK_CUSTOM(Void)); if (scanner()->literal_contains_escapes()) { - Traits::ReportMessageAt( + impl()->ReportMessageAt( Scanner::Location(pos, scanner()->location().end_pos), MessageTemplate::kInvalidEscapedMetaProperty, full_name); *ok = false; @@ -3168,63 +3356,58 @@ ParserBase<Impl>::ParseNewTargetExpression(bool* ok) { ExpectMetaProperty(CStrVector("target"), "new.target", pos, CHECK_OK); if (!GetReceiverScope()->is_function_scope()) { - ReportMessageAt(scanner()->location(), - MessageTemplate::kUnexpectedNewTarget); + impl()->ReportMessageAt(scanner()->location(), + MessageTemplate::kUnexpectedNewTarget); *ok = false; - return this->EmptyExpression(); + return impl()->EmptyExpression(); } - return this->NewTargetExpression(pos); + return impl()->NewTargetExpression(pos); } template <typename Impl> typename ParserBase<Impl>::ExpressionT -ParserBase<Impl>::ParseMemberExpressionContinuation( - ExpressionT expression, bool* is_async, ExpressionClassifier* classifier, - bool* ok) { +ParserBase<Impl>::ParseMemberExpressionContinuation(ExpressionT expression, + bool* is_async, bool* ok) { // Parses this part of MemberExpression: // ('[' Expression ']' | '.' Identifier | TemplateLiteral)* while (true) { switch (peek()) { case Token::LBRACK: { *is_async = false; - impl()->RewriteNonPattern(classifier, CHECK_OK); - BindingPatternUnexpectedToken(classifier); - ArrowFormalParametersUnexpectedToken(classifier); + impl()->RewriteNonPattern(CHECK_OK); + BindingPatternUnexpectedToken(); + ArrowFormalParametersUnexpectedToken(); Consume(Token::LBRACK); int pos = position(); - ExpressionT index = this->ParseExpression(true, classifier, CHECK_OK); - impl()->RewriteNonPattern(classifier, CHECK_OK); + ExpressionT index = ParseExpressionCoverGrammar(true, CHECK_OK); + impl()->RewriteNonPattern(CHECK_OK); expression = factory()->NewProperty(expression, index, pos); - if (fni_ != NULL) { - this->PushPropertyName(fni_, index); - } + impl()->PushPropertyName(index); Expect(Token::RBRACK, CHECK_OK); break; } case Token::PERIOD: { *is_async = false; - impl()->RewriteNonPattern(classifier, CHECK_OK); - BindingPatternUnexpectedToken(classifier); - ArrowFormalParametersUnexpectedToken(classifier); + impl()->RewriteNonPattern(CHECK_OK); + BindingPatternUnexpectedToken(); + ArrowFormalParametersUnexpectedToken(); Consume(Token::PERIOD); int pos = position(); IdentifierT name = ParseIdentifierName(CHECK_OK); expression = factory()->NewProperty( expression, factory()->NewStringLiteral(name, pos), pos); - if (fni_ != NULL) { - this->PushLiteralName(fni_, name); - } + impl()->PushLiteralName(name); break; } case Token::TEMPLATE_SPAN: case Token::TEMPLATE_TAIL: { *is_async = false; - impl()->RewriteNonPattern(classifier, CHECK_OK); - BindingPatternUnexpectedToken(classifier); - ArrowFormalParametersUnexpectedToken(classifier); + impl()->RewriteNonPattern(CHECK_OK); + BindingPatternUnexpectedToken(); + ArrowFormalParametersUnexpectedToken(); int pos; if (scanner()->current_token() == Token::IDENTIFIER) { pos = position(); @@ -3236,62 +3419,58 @@ ParserBase<Impl>::ParseMemberExpressionContinuation( expression->AsFunctionLiteral()->set_should_eager_compile(); } } - expression = - ParseTemplateLiteral(expression, pos, classifier, CHECK_OK); + expression = ParseTemplateLiteral(expression, pos, CHECK_OK); break; } case Token::ILLEGAL: { ReportUnexpectedTokenAt(scanner()->peek_location(), Token::ILLEGAL); *ok = false; - return this->EmptyExpression(); + return impl()->EmptyExpression(); } default: return expression; } } DCHECK(false); - return this->EmptyExpression(); + return impl()->EmptyExpression(); } template <typename Impl> void ParserBase<Impl>::ParseFormalParameter(FormalParametersT* parameters, - ExpressionClassifier* classifier, bool* ok) { // FormalParameter[Yield,GeneratorParameter] : // BindingElement[?Yield, ?GeneratorParameter] bool is_rest = parameters->has_rest; - ExpressionT pattern = - ParsePrimaryExpression(classifier, CHECK_OK_CUSTOM(Void)); - ValidateBindingPattern(classifier, CHECK_OK_CUSTOM(Void)); + ExpressionT pattern = ParsePrimaryExpression(CHECK_OK_CUSTOM(Void)); + ValidateBindingPattern(CHECK_OK_CUSTOM(Void)); - if (!Traits::IsIdentifier(pattern)) { + if (!impl()->IsIdentifier(pattern)) { parameters->is_simple = false; - ValidateFormalParameterInitializer(classifier, CHECK_OK_CUSTOM(Void)); - classifier->RecordNonSimpleParameter(); + ValidateFormalParameterInitializer(CHECK_OK_CUSTOM(Void)); + classifier()->RecordNonSimpleParameter(); } - ExpressionT initializer = Traits::EmptyExpression(); + ExpressionT initializer = impl()->EmptyExpression(); if (!is_rest && Check(Token::ASSIGN)) { ExpressionClassifier init_classifier(this); - initializer = ParseAssignmentExpression(true, &init_classifier, - CHECK_OK_CUSTOM(Void)); - impl()->RewriteNonPattern(&init_classifier, CHECK_OK_CUSTOM(Void)); - ValidateFormalParameterInitializer(&init_classifier, CHECK_OK_CUSTOM(Void)); + initializer = ParseAssignmentExpression(true, CHECK_OK_CUSTOM(Void)); + impl()->RewriteNonPattern(CHECK_OK_CUSTOM(Void)); + ValidateFormalParameterInitializer(CHECK_OK_CUSTOM(Void)); parameters->is_simple = false; - init_classifier.Discard(); - classifier->RecordNonSimpleParameter(); + impl()->Discard(); + classifier()->RecordNonSimpleParameter(); - Traits::SetFunctionNameFromIdentifierRef(initializer, pattern); + impl()->SetFunctionNameFromIdentifierRef(initializer, pattern); } - Traits::AddFormalParameter(parameters, pattern, initializer, + impl()->AddFormalParameter(parameters, pattern, initializer, scanner()->location().end_pos, is_rest); } template <typename Impl> -void ParserBase<Impl>::ParseFormalParameterList( - FormalParametersT* parameters, ExpressionClassifier* classifier, bool* ok) { +void ParserBase<Impl>::ParseFormalParameterList(FormalParametersT* parameters, + bool* ok) { // FormalParameters[Yield] : // [empty] // FunctionRestParameter[?Yield] @@ -3313,14 +3492,14 @@ void ParserBase<Impl>::ParseFormalParameterList( return; } parameters->has_rest = Check(Token::ELLIPSIS); - ParseFormalParameter(parameters, classifier, CHECK_OK_CUSTOM(Void)); + ParseFormalParameter(parameters, CHECK_OK_CUSTOM(Void)); if (parameters->has_rest) { parameters->is_simple = false; - classifier->RecordNonSimpleParameter(); + classifier()->RecordNonSimpleParameter(); if (peek() == Token::COMMA) { - ReportMessageAt(scanner()->peek_location(), - MessageTemplate::kParamAfterRest); + impl()->ReportMessageAt(scanner()->peek_location(), + MessageTemplate::kParamAfterRest); *ok = false; return; } @@ -3336,8 +3515,318 @@ void ParserBase<Impl>::ParseFormalParameterList( for (int i = 0; i < parameters->Arity(); ++i) { auto parameter = parameters->at(i); - Traits::DeclareFormalParameter(parameters->scope, parameter, classifier); + impl()->DeclareFormalParameter(parameters->scope, parameter); + } +} + +template <typename Impl> +typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseVariableDeclarations( + VariableDeclarationContext var_context, + DeclarationParsingResult* parsing_result, + ZoneList<const AstRawString*>* names, bool* ok) { + // VariableDeclarations :: + // ('var' | 'const' | 'let') (Identifier ('=' AssignmentExpression)?)+[','] + // + // ES6: + // FIXME(marja, nikolaos): Add an up-to-date comment about ES6 variable + // declaration syntax. + + DCHECK_NOT_NULL(parsing_result); + parsing_result->descriptor.declaration_kind = DeclarationDescriptor::NORMAL; + parsing_result->descriptor.declaration_pos = peek_position(); + parsing_result->descriptor.initialization_pos = peek_position(); + + BlockT init_block = impl()->NullBlock(); + if (var_context != kForStatement) { + init_block = factory()->NewBlock( + nullptr, 1, true, parsing_result->descriptor.declaration_pos); + } + + switch (peek()) { + case Token::VAR: + parsing_result->descriptor.mode = VAR; + Consume(Token::VAR); + break; + case Token::CONST: + Consume(Token::CONST); + DCHECK(var_context != kStatement); + parsing_result->descriptor.mode = CONST; + break; + case Token::LET: + Consume(Token::LET); + DCHECK(var_context != kStatement); + parsing_result->descriptor.mode = LET; + break; + default: + UNREACHABLE(); // by current callers + break; + } + + parsing_result->descriptor.scope = scope(); + parsing_result->descriptor.hoist_scope = nullptr; + + // The scope of a var/const declared variable anywhere inside a function + // is the entire function (ECMA-262, 3rd, 10.1.3, and 12.2). The scope + // of a let declared variable is the scope of the immediately enclosing + // block. + int bindings_start = peek_position(); + do { + // Parse binding pattern. + FuncNameInferrer::State fni_state(fni_); + + ExpressionT pattern = impl()->EmptyExpression(); + int decl_pos = peek_position(); + { + ExpressionClassifier pattern_classifier(this); + pattern = ParsePrimaryExpression(CHECK_OK_CUSTOM(NullBlock)); + + ValidateBindingPattern(CHECK_OK_CUSTOM(NullBlock)); + if (IsLexicalVariableMode(parsing_result->descriptor.mode)) { + ValidateLetPattern(CHECK_OK_CUSTOM(NullBlock)); + } + } + + Scanner::Location variable_loc = scanner()->location(); + bool single_name = impl()->IsIdentifier(pattern); + + if (single_name) { + impl()->PushVariableName(impl()->AsIdentifier(pattern)); + } + + ExpressionT value = impl()->EmptyExpression(); + int initializer_position = kNoSourcePosition; + if (Check(Token::ASSIGN)) { + ExpressionClassifier classifier(this); + value = ParseAssignmentExpression(var_context != kForStatement, + CHECK_OK_CUSTOM(NullBlock)); + impl()->RewriteNonPattern(CHECK_OK_CUSTOM(NullBlock)); + variable_loc.end_pos = scanner()->location().end_pos; + + if (!parsing_result->first_initializer_loc.IsValid()) { + parsing_result->first_initializer_loc = variable_loc; + } + + // Don't infer if it is "a = function(){...}();"-like expression. + if (single_name && fni_ != nullptr) { + if (!value->IsCall() && !value->IsCallNew()) { + fni_->Infer(); + } else { + fni_->RemoveLastFunction(); + } + } + + impl()->SetFunctionNameFromIdentifierRef(value, pattern); + + // End position of the initializer is after the assignment expression. + initializer_position = scanner()->location().end_pos; + } else { + if (var_context != kForStatement || !PeekInOrOf()) { + // ES6 'const' and binding patterns require initializers. + if (parsing_result->descriptor.mode == CONST || + !impl()->IsIdentifier(pattern)) { + impl()->ReportMessageAt( + Scanner::Location(decl_pos, scanner()->location().end_pos), + MessageTemplate::kDeclarationMissingInitializer, + !impl()->IsIdentifier(pattern) ? "destructuring" : "const"); + *ok = false; + return impl()->NullBlock(); + } + // 'let x' initializes 'x' to undefined. + if (parsing_result->descriptor.mode == LET) { + value = impl()->GetLiteralUndefined(position()); + } + } + + // End position of the initializer is after the variable. + initializer_position = position(); + } + + typename DeclarationParsingResult::Declaration decl( + pattern, initializer_position, value); + if (var_context == kForStatement) { + // Save the declaration for further handling in ParseForStatement. + parsing_result->declarations.Add(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(NullBlock)); + } + } while (Check(Token::COMMA)); + + parsing_result->bindings_loc = + Scanner::Location(bindings_start, scanner()->location().end_pos); + + DCHECK(*ok); + return init_block; +} + +template <typename Impl> +typename ParserBase<Impl>::StatementT +ParserBase<Impl>::ParseFunctionDeclaration(bool* ok) { + Consume(Token::FUNCTION); + int pos = position(); + ParseFunctionFlags flags = ParseFunctionFlags::kIsNormal; + if (Check(Token::MUL)) { + flags |= ParseFunctionFlags::kIsGenerator; + if (allow_harmony_restrictive_declarations()) { + impl()->ReportMessageAt(scanner()->location(), + MessageTemplate::kGeneratorInLegacyContext); + *ok = false; + return impl()->NullStatement(); + } + } + return ParseHoistableDeclaration(pos, flags, nullptr, false, ok); +} + +template <typename Impl> +typename ParserBase<Impl>::StatementT +ParserBase<Impl>::ParseHoistableDeclaration( + ZoneList<const AstRawString*>* names, bool default_export, bool* ok) { + Expect(Token::FUNCTION, CHECK_OK_CUSTOM(NullStatement)); + int pos = position(); + ParseFunctionFlags flags = ParseFunctionFlags::kIsNormal; + if (Check(Token::MUL)) { + flags |= ParseFunctionFlags::kIsGenerator; + } + return ParseHoistableDeclaration(pos, flags, names, default_export, ok); +} + +template <typename Impl> +typename ParserBase<Impl>::StatementT +ParserBase<Impl>::ParseHoistableDeclaration( + int pos, ParseFunctionFlags flags, ZoneList<const AstRawString*>* names, + bool default_export, bool* ok) { + // FunctionDeclaration :: + // 'function' Identifier '(' FormalParameters ')' '{' FunctionBody '}' + // 'function' '(' FormalParameters ')' '{' FunctionBody '}' + // GeneratorDeclaration :: + // 'function' '*' Identifier '(' FormalParameters ')' '{' FunctionBody '}' + // 'function' '*' '(' FormalParameters ')' '{' FunctionBody '}' + // + // The anonymous forms are allowed iff [default_export] is true. + // + // 'function' and '*' (if present) have been consumed by the caller. + + const bool is_generator = flags & ParseFunctionFlags::kIsGenerator; + const bool is_async = flags & ParseFunctionFlags::kIsAsync; + DCHECK(!is_generator || !is_async); + + IdentifierT name; + FunctionNameValidity name_validity; + IdentifierT variable_name; + if (default_export && peek() == Token::LPAREN) { + impl()->GetDefaultStrings(&name, &variable_name); + name_validity = kSkipFunctionNameCheck; + } else { + bool is_strict_reserved; + name = ParseIdentifierOrStrictReservedWord(&is_strict_reserved, + CHECK_OK_CUSTOM(NullStatement)); + name_validity = is_strict_reserved ? kFunctionNameIsStrictReserved + : kFunctionNameValidityUnknown; + variable_name = name; + } + + FuncNameInferrer::State fni_state(fni_); + impl()->PushEnclosingName(name); + FunctionLiteralT function = impl()->ParseFunctionLiteral( + name, scanner()->location(), name_validity, + is_generator ? FunctionKind::kGeneratorFunction + : is_async ? FunctionKind::kAsyncFunction + : FunctionKind::kNormalFunction, + pos, FunctionLiteral::kDeclaration, language_mode(), + CHECK_OK_CUSTOM(NullStatement)); + + return impl()->DeclareFunction(variable_name, function, pos, is_generator, + is_async, names, ok); +} + +template <typename Impl> +typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseClassDeclaration( + ZoneList<const AstRawString*>* names, bool default_export, bool* ok) { + // ClassDeclaration :: + // 'class' Identifier ('extends' LeftHandExpression)? '{' ClassBody '}' + // 'class' ('extends' LeftHandExpression)? '{' ClassBody '}' + // + // The anonymous form is allowed iff [default_export] is true. + // + // 'class' is expected to be consumed by the caller. + // + // A ClassDeclaration + // + // class C { ... } + // + // has the same semantics as: + // + // let C = class C { ... }; + // + // so rewrite it as such. + + int class_token_pos = position(); + IdentifierT name = impl()->EmptyIdentifier(); + bool is_strict_reserved = false; + IdentifierT variable_name = impl()->EmptyIdentifier(); + if (default_export && (peek() == Token::EXTENDS || peek() == Token::LBRACE)) { + impl()->GetDefaultStrings(&name, &variable_name); + } else { + name = ParseIdentifierOrStrictReservedWord(&is_strict_reserved, + CHECK_OK_CUSTOM(NullStatement)); + variable_name = name; + } + + ExpressionClassifier no_classifier(this); + ExpressionT value = + ParseClassLiteral(name, scanner()->location(), is_strict_reserved, + class_token_pos, CHECK_OK_CUSTOM(NullStatement)); + int end_pos = position(); + return impl()->DeclareClass(variable_name, value, names, class_token_pos, + end_pos, ok); +} + +// Language extension which is only enabled for source files loaded +// through the API's extension mechanism. A native function +// 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) { + int pos = peek_position(); + Expect(Token::FUNCTION, CHECK_OK_CUSTOM(NullStatement)); + // Allow "eval" or "arguments" for backward compatibility. + IdentifierT name = ParseIdentifier(kAllowRestrictedIdentifiers, + CHECK_OK_CUSTOM(NullStatement)); + Expect(Token::LPAREN, CHECK_OK_CUSTOM(NullStatement)); + if (peek() != Token::RPAREN) { + do { + ParseIdentifier(kAllowRestrictedIdentifiers, + CHECK_OK_CUSTOM(NullStatement)); + } while (Check(Token::COMMA)); + } + Expect(Token::RPAREN, CHECK_OK_CUSTOM(NullStatement)); + Expect(Token::SEMICOLON, CHECK_OK_CUSTOM(NullStatement)); + return impl()->DeclareNative(name, pos, ok); +} + +template <typename Impl> +typename ParserBase<Impl>::StatementT +ParserBase<Impl>::ParseAsyncFunctionDeclaration( + ZoneList<const AstRawString*>* names, bool default_export, bool* ok) { + // AsyncFunctionDeclaration :: + // async [no LineTerminator here] function BindingIdentifier[Await] + // ( FormalParameters[Await] ) { AsyncFunctionBody } + DCHECK_EQ(scanner()->current_token(), Token::ASYNC); + int pos = position(); + if (scanner()->HasAnyLineTerminatorBeforeNext()) { + *ok = false; + impl()->ReportUnexpectedToken(scanner()->current_token()); + return impl()->NullStatement(); } + Expect(Token::FUNCTION, CHECK_OK_CUSTOM(NullStatement)); + ParseFunctionFlags flags = ParseFunctionFlags::kIsAsync; + return ParseHoistableDeclaration(pos, flags, names, default_export, ok); } template <typename Impl> @@ -3348,19 +3837,22 @@ void ParserBase<Impl>::CheckArityRestrictions(int param_count, int formals_end_pos, bool* ok) { if (IsGetterFunction(function_kind)) { if (param_count != 0) { - ReportMessageAt(Scanner::Location(formals_start_pos, formals_end_pos), - MessageTemplate::kBadGetterArity); + impl()->ReportMessageAt( + Scanner::Location(formals_start_pos, formals_end_pos), + MessageTemplate::kBadGetterArity); *ok = false; } } else if (IsSetterFunction(function_kind)) { if (param_count != 1) { - ReportMessageAt(Scanner::Location(formals_start_pos, formals_end_pos), - MessageTemplate::kBadSetterArity); + impl()->ReportMessageAt( + Scanner::Location(formals_start_pos, formals_end_pos), + MessageTemplate::kBadSetterArity); *ok = false; } if (has_rest) { - ReportMessageAt(Scanner::Location(formals_start_pos, formals_end_pos), - MessageTemplate::kBadSetterRestParameter); + impl()->ReportMessageAt( + Scanner::Location(formals_start_pos, formals_end_pos), + MessageTemplate::kBadSetterRestParameter); *ok = false; } } @@ -3412,31 +3904,33 @@ bool ParserBase<Impl>::IsTrivialExpression() { template <typename Impl> typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseArrowFunctionLiteral( - bool accept_IN, const FormalParametersT& formal_parameters, bool is_async, - const ExpressionClassifier& formals_classifier, bool* ok) { + bool accept_IN, const FormalParametersT& formal_parameters, bool* ok) { if (peek() == Token::ARROW && scanner_->HasAnyLineTerminatorBeforeNext()) { // 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 this->EmptyExpression(); + return impl()->EmptyExpression(); } - typename Traits::Type::StatementList body; + StatementListT body = impl()->NullStatementList(); int num_parameters = formal_parameters.scope->num_parameters(); int materialized_literal_count = -1; int expected_property_count = -1; - FunctionKind arrow_kind = is_async ? kAsyncArrowFunction : kArrowFunction; + FunctionKind kind = formal_parameters.scope->function_kind(); + FunctionLiteral::EagerCompileHint eager_compile_hint = + FunctionLiteral::kShouldLazyCompile; + bool should_be_used_once_hint = false; { FunctionState function_state(&function_state_, &scope_state_, - formal_parameters.scope, arrow_kind); + formal_parameters.scope); function_state.SkipMaterializedLiterals( formal_parameters.materialized_literals_count); - this->ReindexLiterals(formal_parameters); + impl()->ReindexLiterals(formal_parameters); Expect(Token::ARROW, CHECK_OK); @@ -3444,20 +3938,42 @@ ParserBase<Impl>::ParseArrowFunctionLiteral( // Multiple statement body Consume(Token::LBRACE); DCHECK_EQ(scope(), formal_parameters.scope); - bool is_lazily_parsed = (mode() == PARSE_LAZILY && - formal_parameters.scope->AllowsLazyParsing()); + bool is_lazily_parsed = + (mode() == PARSE_LAZILY && + formal_parameters.scope + ->AllowsLazyParsingWithoutUnresolvedVariables()); + // TODO(marja): consider lazy-parsing inner arrow functions too. is_this + // handling in Scope::ResolveVariable needs to change. if (is_lazily_parsed) { - body = this->NewStatementList(0, zone()); - impl()->SkipLazyFunctionBody(&materialized_literal_count, - &expected_property_count, CHECK_OK); + Scanner::BookmarkScope bookmark(scanner()); + bookmark.Set(); + LazyParsingResult result = impl()->SkipLazyFunctionBody( + &materialized_literal_count, &expected_property_count, false, true, + CHECK_OK); + formal_parameters.scope->ResetAfterPreparsing( + ast_value_factory_, result == kLazyParsingAborted); + if (formal_parameters.materialized_literals_count > 0) { materialized_literal_count += formal_parameters.materialized_literals_count; } - } else { + + if (result == kLazyParsingAborted) { + bookmark.Apply(); + // Trigger eager (re-)parsing, just below this block. + is_lazily_parsed = false; + + // This is probably an initialization function. Inform the compiler it + // should also eager-compile this function, and that we expect it to + // be used once. + eager_compile_hint = FunctionLiteral::kShouldEagerCompile; + should_be_used_once_hint = true; + } + } + if (!is_lazily_parsed) { body = impl()->ParseEagerFunctionBody( - this->EmptyIdentifier(), kNoSourcePosition, formal_parameters, - arrow_kind, FunctionLiteral::kAnonymousExpression, CHECK_OK); + impl()->EmptyIdentifier(), kNoSourcePosition, formal_parameters, + kind, FunctionLiteral::kAnonymousExpression, CHECK_OK); materialized_literal_count = function_state.materialized_literal_count(); expected_property_count = function_state.expected_property_count(); @@ -3469,18 +3985,18 @@ ParserBase<Impl>::ParseArrowFunctionLiteral( function_state_->return_expr_context()); ReturnExprScope allow_tail_calls( function_state_, ReturnExprContext::kInsideValidReturnStatement); - body = this->NewStatementList(1, zone()); - this->AddParameterInitializationBlock(formal_parameters, body, is_async, - CHECK_OK); + body = impl()->NewStatementList(1); + impl()->AddParameterInitializationBlock( + formal_parameters, body, kind == kAsyncArrowFunction, CHECK_OK); ExpressionClassifier classifier(this); - if (is_async) { - impl()->ParseAsyncArrowSingleExpressionBody(body, accept_IN, - &classifier, pos, CHECK_OK); - impl()->RewriteNonPattern(&classifier, CHECK_OK); + if (kind == kAsyncArrowFunction) { + ParseAsyncFunctionBody(scope(), body, kAsyncArrowFunction, + FunctionBodyType::kSingleExpression, accept_IN, + pos, CHECK_OK); + impl()->RewriteNonPattern(CHECK_OK); } else { - ExpressionT expression = - ParseAssignmentExpression(accept_IN, &classifier, CHECK_OK); - impl()->RewriteNonPattern(&classifier, CHECK_OK); + ExpressionT expression = ParseAssignmentExpression(accept_IN, CHECK_OK); + impl()->RewriteNonPattern(CHECK_OK); body->Add(factory()->NewReturnStatement(expression, pos), zone()); if (allow_tailcalls() && !is_sloppy(language_mode())) { // ES6 14.6.1 Static Semantics: IsInTailPosition @@ -3499,8 +4015,8 @@ ParserBase<Impl>::ParseArrowFunctionLiteral( // that duplicates are not allowed. Of course, the arrow function may // itself be strict as well. const bool allow_duplicate_parameters = false; - this->ValidateFormalParameters(&formals_classifier, language_mode(), - allow_duplicate_parameters, CHECK_OK); + ValidateFormalParameters(language_mode(), allow_duplicate_parameters, + CHECK_OK); // Validate strict mode. if (is_strict(language_mode())) { @@ -3513,24 +4029,141 @@ ParserBase<Impl>::ParseArrowFunctionLiteral( } FunctionLiteralT function_literal = factory()->NewFunctionLiteral( - this->EmptyIdentifierString(), formal_parameters.scope, body, + impl()->EmptyIdentifierString(), formal_parameters.scope, body, materialized_literal_count, expected_property_count, num_parameters, FunctionLiteral::kNoDuplicateParameters, - FunctionLiteral::kAnonymousExpression, - FunctionLiteral::kShouldLazyCompile, arrow_kind, + FunctionLiteral::kAnonymousExpression, eager_compile_hint, formal_parameters.scope->start_position()); function_literal->set_function_token_position( formal_parameters.scope->start_position()); + if (should_be_used_once_hint) { + function_literal->set_should_be_used_once_hint(); + } - if (fni_ != NULL) this->InferFunctionName(fni_, function_literal); + impl()->AddFunctionForNameInference(function_literal); return function_literal; } 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) { + // All parts of a ClassDeclaration and ClassExpression are strict code. + if (name_is_strict_reserved) { + impl()->ReportMessageAt(class_name_location, + MessageTemplate::kUnexpectedStrictReserved); + *ok = false; + return impl()->EmptyExpression(); + } + if (impl()->IsEvalOrArguments(name)) { + impl()->ReportMessageAt(class_name_location, + MessageTemplate::kStrictEvalArguments); + *ok = false; + return impl()->EmptyExpression(); + } + + BlockState block_state(zone(), &scope_state_); + RaiseLanguageMode(STRICT); + + ClassInfo class_info(this); + impl()->DeclareClassVariable(name, block_state.scope(), &class_info, + class_token_pos, CHECK_OK); + + if (Check(Token::EXTENDS)) { + block_state.set_start_position(scanner()->location().end_pos); + ExpressionClassifier extends_classifier(this); + class_info.extends = ParseLeftHandSideExpression(CHECK_OK); + impl()->RewriteNonPattern(CHECK_OK); + impl()->AccumulateFormalParameterContainmentErrors(); + } else { + block_state.set_start_position(scanner()->location().end_pos); + } + + ClassLiteralChecker checker(this); + + Expect(Token::LBRACE, CHECK_OK); + + const bool has_extends = !impl()->IsEmptyExpression(class_info.extends); + while (peek() != Token::RBRACE) { + if (Check(Token::SEMICOLON)) continue; + FuncNameInferrer::State fni_state(fni_); + bool is_computed_name = false; // Classes do not care about computed + // property names here. + ExpressionClassifier property_classifier(this); + ClassLiteralPropertyT property = ParseClassPropertyDefinition( + &checker, has_extends, &is_computed_name, + &class_info.has_seen_constructor, CHECK_OK); + impl()->RewriteNonPattern(CHECK_OK); + impl()->AccumulateFormalParameterContainmentErrors(); + + impl()->DeclareClassProperty(name, property, &class_info, CHECK_OK); + impl()->InferFunctionName(); + } + + Expect(Token::RBRACE, CHECK_OK); + return impl()->RewriteClassLiteral(name, &class_info, class_token_pos, ok); +} + +template <typename Impl> +void ParserBase<Impl>::ParseAsyncFunctionBody(Scope* scope, StatementListT body, + FunctionKind kind, + FunctionBodyType body_type, + bool accept_IN, int pos, + bool* ok) { + scope->ForceContextAllocation(); + + impl()->PrepareAsyncFunctionBody(body, kind, pos); + + BlockT block = factory()->NewBlock(nullptr, 8, true, kNoSourcePosition); + + ExpressionT return_value = impl()->EmptyExpression(); + if (body_type == FunctionBodyType::kNormal) { + ParseStatementList(block->statements(), Token::RBRACE, + CHECK_OK_CUSTOM(Void)); + return_value = factory()->NewUndefinedLiteral(kNoSourcePosition); + } else { + return_value = ParseAssignmentExpression(accept_IN, CHECK_OK_CUSTOM(Void)); + impl()->RewriteNonPattern(CHECK_OK_CUSTOM(Void)); + } + + impl()->RewriteAsyncFunctionBody(body, block, return_value, + CHECK_OK_CUSTOM(Void)); + scope->set_end_position(scanner()->location().end_pos); +} + +template <typename Impl> +typename ParserBase<Impl>::ExpressionT +ParserBase<Impl>::ParseAsyncFunctionLiteral(bool* ok) { + // AsyncFunctionLiteral :: + // async [no LineTerminator here] function ( FormalParameters[Await] ) + // { AsyncFunctionBody } + // + // async [no LineTerminator here] function BindingIdentifier[Await] + // ( FormalParameters[Await] ) { AsyncFunctionBody } + DCHECK_EQ(scanner()->current_token(), Token::ASYNC); + int pos = position(); + Expect(Token::FUNCTION, CHECK_OK); + bool is_strict_reserved = false; + IdentifierT name = impl()->EmptyIdentifier(); + FunctionLiteral::FunctionType type = FunctionLiteral::kAnonymousExpression; + + if (peek_any_identifier()) { + type = FunctionLiteral::kNamedExpression; + name = ParseIdentifierOrStrictReservedWord(FunctionKind::kAsyncFunction, + &is_strict_reserved, CHECK_OK); + } + return impl()->ParseFunctionLiteral( + name, scanner()->location(), + is_strict_reserved ? kFunctionNameIsStrictReserved + : kFunctionNameValidityUnknown, + FunctionKind::kAsyncFunction, pos, type, language_mode(), CHECK_OK); +} + +template <typename Impl> typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseTemplateLiteral( - ExpressionT tag, int start, ExpressionClassifier* classifier, bool* ok) { + ExpressionT tag, int start, bool* ok) { // 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. @@ -3569,29 +4202,28 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseTemplateLiteral( CheckTemplateOctalLiteral(pos, peek_position(), CHECK_OK); next = peek(); if (next == Token::EOS) { - ReportMessageAt(Scanner::Location(start, peek_position()), - MessageTemplate::kUnterminatedTemplate); + impl()->ReportMessageAt(Scanner::Location(start, peek_position()), + MessageTemplate::kUnterminatedTemplate); *ok = false; - return Traits::EmptyExpression(); + return impl()->EmptyExpression(); } else if (next == Token::ILLEGAL) { - Traits::ReportMessageAt( + impl()->ReportMessageAt( Scanner::Location(position() + 1, peek_position()), MessageTemplate::kUnexpectedToken, "ILLEGAL", kSyntaxError); *ok = false; - return Traits::EmptyExpression(); + return impl()->EmptyExpression(); } int expr_pos = peek_position(); - ExpressionT expression = this->ParseExpression(true, classifier, CHECK_OK); - CheckNoTailCallExpressions(classifier, CHECK_OK); - impl()->RewriteNonPattern(classifier, CHECK_OK); + ExpressionT expression = ParseExpressionCoverGrammar(true, CHECK_OK); + impl()->RewriteNonPattern(CHECK_OK); impl()->AddTemplateExpression(&ts, expression); if (peek() != Token::RBRACE) { - ReportMessageAt(Scanner::Location(expr_pos, peek_position()), - MessageTemplate::kUnterminatedTemplateExpr); + impl()->ReportMessageAt(Scanner::Location(expr_pos, peek_position()), + MessageTemplate::kUnterminatedTemplateExpr); *ok = false; - return Traits::EmptyExpression(); + return impl()->EmptyExpression(); } // If we didn't die parsing that expression, our next token should be a @@ -3601,16 +4233,16 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseTemplateLiteral( pos = position(); if (next == Token::EOS) { - ReportMessageAt(Scanner::Location(start, pos), - MessageTemplate::kUnterminatedTemplate); + impl()->ReportMessageAt(Scanner::Location(start, pos), + MessageTemplate::kUnterminatedTemplate); *ok = false; - return Traits::EmptyExpression(); + return impl()->EmptyExpression(); } else if (next == Token::ILLEGAL) { - Traits::ReportMessageAt( + impl()->ReportMessageAt( Scanner::Location(position() + 1, peek_position()), MessageTemplate::kUnexpectedToken, "ILLEGAL", kSyntaxError); *ok = false; - return Traits::EmptyExpression(); + return impl()->EmptyExpression(); } impl()->AddTemplateSpan(&ts, next == Token::TEMPLATE_TAIL); @@ -3627,8 +4259,8 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::CheckAndRewriteReferenceExpression( ExpressionT expression, int beg_pos, int end_pos, MessageTemplate::Template message, bool* ok) { - return this->CheckAndRewriteReferenceExpression(expression, beg_pos, end_pos, - message, kReferenceError, ok); + return CheckAndRewriteReferenceExpression(expression, beg_pos, end_pos, + message, kReferenceError, ok); } template <typename Impl> @@ -3636,12 +4268,12 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::CheckAndRewriteReferenceExpression( ExpressionT expression, int beg_pos, int end_pos, MessageTemplate::Template message, ParseErrorType type, bool* ok) { - if (this->IsIdentifier(expression) && is_strict(language_mode()) && - this->IsEvalOrArguments(this->AsIdentifier(expression))) { + 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 this->EmptyExpression(); + return impl()->EmptyExpression(); } if (expression->IsValidReferenceExpression()) { return expression; @@ -3649,47 +4281,1140 @@ ParserBase<Impl>::CheckAndRewriteReferenceExpression( if (expression->IsCall()) { // If it is a call, make it a runtime error for legacy web compatibility. // Rewrite `expr' to `expr[throw ReferenceError]'. - ExpressionT error = this->NewThrowReferenceError(message, beg_pos); + ExpressionT error = impl()->NewThrowReferenceError(message, beg_pos); return factory()->NewProperty(expression, error, beg_pos); } ReportMessageAt(Scanner::Location(beg_pos, end_pos), message, type); *ok = false; - return this->EmptyExpression(); + return impl()->EmptyExpression(); } template <typename Impl> bool ParserBase<Impl>::IsValidReferenceExpression(ExpressionT expression) { - return this->IsAssignableIdentifier(expression) || expression->IsProperty(); + return IsAssignableIdentifier(expression) || expression->IsProperty(); } template <typename Impl> -void ParserBase<Impl>::CheckDestructuringElement( - ExpressionT expression, ExpressionClassifier* classifier, int begin, - int end) { +void ParserBase<Impl>::CheckDestructuringElement(ExpressionT expression, + int begin, int end) { if (!IsValidPattern(expression) && !expression->IsAssignment() && !IsValidReferenceExpression(expression)) { - classifier->RecordAssignmentPatternError( + classifier()->RecordAssignmentPatternError( Scanner::Location(begin, end), MessageTemplate::kInvalidDestructuringTarget); } } +template <typename Impl> +typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseV8Intrinsic( + bool* ok) { + // CallRuntime :: + // '%' Identifier Arguments + + int pos = peek_position(); + Expect(Token::MOD, CHECK_OK); + // 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); + + DCHECK(!spread_pos.IsValid()); + + return impl()->NewV8Intrinsic(name, args, pos, ok); +} + +template <typename Impl> +typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseDoExpression( + bool* ok) { + // AssignmentExpression :: + // do '{' StatementList '}' + + int pos = peek_position(); + Expect(Token::DO, CHECK_OK); + BlockT block = ParseBlock(nullptr, CHECK_OK); + return impl()->RewriteDoExpression(block, pos, ok); +} +// Redefinition of CHECK_OK for parsing statements. #undef CHECK_OK -#undef CHECK_OK_CUSTOM +#define CHECK_OK CHECK_OK_CUSTOM(NullStatement) + +template <typename Impl> +typename ParserBase<Impl>::LazyParsingResult +ParserBase<Impl>::ParseStatementList(StatementListT body, int end_token, + bool may_abort, bool* ok) { + // StatementList :: + // (StatementListItem)* <end_token> + + // 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; + + DCHECK(!impl()->IsNullStatementList(body)); + bool directive_prologue = true; // Parsing directive prologue. + + while (peek() != end_token) { + if (directive_prologue && peek() != Token::STRING) { + directive_prologue = false; + } + + bool starts_with_identifier = peek() == Token::IDENTIFIER; + Scanner::Location token_loc = scanner()->peek_location(); + StatementT stat = + ParseStatementListItem(CHECK_OK_CUSTOM(Return, kLazyParsingComplete)); + + if (impl()->IsNullStatement(stat) || impl()->IsEmptyStatement(stat)) { + 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(STRICT); + 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; + } + // Because declarations in strict eval code don't leak into the scope + // of the eval call, it is likely that functions declared in strict + // eval code will be used within the eval code, so lazy parsing is + // probably not a win. + if (scope()->is_eval_scope()) mode_ = PARSE_EAGERLY; + } 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(SLOPPY); + } else { + // End of the directive prologue. + directive_prologue = false; + RaiseLanguageMode(SLOPPY); + } + } else { + RaiseLanguageMode(SLOPPY); + } + + // 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()); + } + return kLazyParsingComplete; +} + +template <typename Impl> +typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStatementListItem( + bool* ok) { + // ECMA 262 6th Edition + // StatementListItem[Yield, Return] : + // Statement[?Yield, ?Return] + // Declaration[?Yield] + // + // Declaration[Yield] : + // HoistableDeclaration[?Yield] + // ClassDeclaration[?Yield] + // LexicalDeclaration[In, ?Yield] + // + // HoistableDeclaration[Yield, Default] : + // FunctionDeclaration[?Yield, ?Default] + // GeneratorDeclaration[?Yield, ?Default] + // + // LexicalDeclaration[In, Yield] : + // LetOrConst BindingList[?In, ?Yield] ; + + switch (peek()) { + case Token::FUNCTION: + return ParseHoistableDeclaration(nullptr, false, ok); + case Token::CLASS: + Consume(Token::CLASS); + return ParseClassDeclaration(nullptr, false, ok); + case Token::VAR: + case Token::CONST: + return ParseVariableStatement(kStatementListItem, nullptr, ok); + case Token::LET: + if (IsNextLetKeyword()) { + return ParseVariableStatement(kStatementListItem, nullptr, ok); + } + break; + case Token::ASYNC: + if (allow_harmony_async_await() && PeekAhead() == Token::FUNCTION && + !scanner()->HasAnyLineTerminatorAfterNext()) { + Consume(Token::ASYNC); + return ParseAsyncFunctionDeclaration(nullptr, false, ok); + } + /* falls through */ + default: + break; + } + return ParseStatement(nullptr, kAllowLabelledFunctionStatement, ok); +} + +template <typename Impl> +typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStatement( + ZoneList<const AstRawString*>* labels, + AllowLabelledFunctionStatement allow_function, bool* ok) { + // Statement :: + // Block + // VariableStatement + // EmptyStatement + // ExpressionStatement + // IfStatement + // IterationStatement + // ContinueStatement + // BreakStatement + // ReturnStatement + // WithStatement + // LabelledStatement + // SwitchStatement + // ThrowStatement + // TryStatement + // DebuggerStatement + + // Note: Since labels can only be used by 'break' and 'continue' + // statements, which themselves are only valid within blocks, + // iterations or 'switch' statements (i.e., BreakableStatements), + // labels can be simply ignored in all other cases; except for + // trivial labeled break statements 'label: break label' which is + // parsed into an empty statement. + switch (peek()) { + case Token::LBRACE: + return ParseBlock(labels, ok); + case Token::SEMICOLON: + Next(); + return factory()->NewEmptyStatement(kNoSourcePosition); + case Token::IF: + return ParseIfStatement(labels, ok); + case Token::DO: + return ParseDoWhileStatement(labels, ok); + case Token::WHILE: + return ParseWhileStatement(labels, ok); + case Token::FOR: + return ParseForStatement(labels, ok); + case Token::CONTINUE: + case Token::BREAK: + case Token::RETURN: + case Token::THROW: + case Token::TRY: { + // These statements must have their labels preserved in an enclosing + // block, as the corresponding AST nodes do not currently store their + // labels. + // TODO(nikolaos, marja): Consider adding the labels to the AST nodes. + if (labels == nullptr) { + return ParseStatementAsUnlabelled(labels, ok); + } else { + BlockT result = + factory()->NewBlock(labels, 1, false, kNoSourcePosition); + typename Types::Target target(this, result); + StatementT statement = ParseStatementAsUnlabelled(labels, CHECK_OK); + result->statements()->Add(statement, zone()); + return result; + } + } + case Token::WITH: + return ParseWithStatement(labels, ok); + case Token::SWITCH: + return ParseSwitchStatement(labels, ok); + case Token::FUNCTION: + // FunctionDeclaration only allowed as a StatementListItem, not in + // an arbitrary Statement position. Exceptions such as + // ES#sec-functiondeclarations-in-ifstatement-statement-clauses + // are handled by calling ParseScopedStatement rather than + // ParseStatement directly. + impl()->ReportMessageAt(scanner()->peek_location(), + is_strict(language_mode()) + ? MessageTemplate::kStrictFunction + : MessageTemplate::kSloppyFunction); + *ok = false; + return impl()->NullStatement(); + case Token::DEBUGGER: + return ParseDebuggerStatement(ok); + case Token::VAR: + return ParseVariableStatement(kStatement, nullptr, ok); + default: + return ParseExpressionOrLabelledStatement(labels, allow_function, ok); + } +} + +// This method parses a subset of statements (break, continue, return, throw, +// try) which are to be grouped because they all require their labeles to be +// preserved in an enclosing block. +template <typename Impl> +typename ParserBase<Impl>::StatementT +ParserBase<Impl>::ParseStatementAsUnlabelled( + ZoneList<const AstRawString*>* labels, bool* ok) { + switch (peek()) { + case Token::CONTINUE: + return ParseContinueStatement(ok); + case Token::BREAK: + return ParseBreakStatement(labels, ok); + case Token::RETURN: + return ParseReturnStatement(ok); + case Token::THROW: + return ParseThrowStatement(ok); + case Token::TRY: + return ParseTryStatement(ok); + default: + UNREACHABLE(); + return impl()->NullStatement(); + } +} + +template <typename Impl> +typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseBlock( + ZoneList<const AstRawString*>* labels, bool* ok) { + // Block :: + // '{' StatementList '}' + + // Construct block expecting 16 statements. + BlockT body = factory()->NewBlock(labels, 16, false, kNoSourcePosition); + + // Parse the statements and collect escaping labels. + Expect(Token::LBRACE, CHECK_OK_CUSTOM(NullBlock)); + { + BlockState block_state(zone(), &scope_state_); + block_state.set_start_position(scanner()->location().beg_pos); + typename Types::Target target(this, body); + + while (peek() != Token::RBRACE) { + StatementT stat = ParseStatementListItem(CHECK_OK_CUSTOM(NullBlock)); + if (!impl()->IsNullStatement(stat) && !impl()->IsEmptyStatement(stat)) { + body->statements()->Add(stat, zone()); + } + } + + Expect(Token::RBRACE, CHECK_OK_CUSTOM(NullBlock)); + block_state.set_end_position(scanner()->location().end_pos); + body->set_scope(block_state.FinalizedBlockScope()); + } + return body; +} + +template <typename Impl> +typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseScopedStatement( + ZoneList<const AstRawString*>* labels, bool legacy, bool* ok) { + if (is_strict(language_mode()) || peek() != Token::FUNCTION || + (legacy && allow_harmony_restrictive_declarations())) { + return ParseStatement(labels, kDisallowLabelledFunctionStatement, ok); + } else { + if (legacy) { + impl()->CountUsage(v8::Isolate::kLegacyFunctionDeclaration); + } + // Make a block around the statement for a lexical binding + // is introduced by a FunctionDeclaration. + BlockState block_state(zone(), &scope_state_); + block_state.set_start_position(scanner()->location().beg_pos); + BlockT block = factory()->NewBlock(NULL, 1, false, kNoSourcePosition); + StatementT body = ParseFunctionDeclaration(CHECK_OK); + block->statements()->Add(body, zone()); + block_state.set_end_position(scanner()->location().end_pos); + block->set_scope(block_state.FinalizedBlockScope()); + return block; + } +} + +template <typename Impl> +typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseVariableStatement( + VariableDeclarationContext var_context, + ZoneList<const AstRawString*>* names, bool* ok) { + // VariableStatement :: + // VariableDeclarations ';' + + // The scope of a var declared variable anywhere inside a function + // is the entire function (ECMA-262, 3rd, 10.1.3, and 12.2). Thus we can + // transform a source-level var declaration into a (Function) Scope + // declaration, and rewrite the source-level initialization into an assignment + // statement. We use a block to collect multiple assignments. + // + // We mark the block as initializer block because we don't want the + // rewriter to add a '.result' assignment to such a block (to get compliant + // behavior for code such as print(eval('var x = 7')), and for cosmetic + // reasons when pretty-printing. Also, unless an assignment (initialization) + // is inside an initializer block, it is ignored. + + DeclarationParsingResult parsing_result; + StatementT result = + ParseVariableDeclarations(var_context, &parsing_result, names, CHECK_OK); + ExpectSemicolon(CHECK_OK); + return result; +} + +template <typename Impl> +typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseDebuggerStatement( + bool* ok) { + // 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. + // DebuggerStatement :: + // 'debugger' ';' + + int pos = peek_position(); + Expect(Token::DEBUGGER, CHECK_OK); + ExpectSemicolon(CHECK_OK); + return factory()->NewDebuggerStatement(pos); +} + +template <typename Impl> +typename ParserBase<Impl>::StatementT +ParserBase<Impl>::ParseExpressionOrLabelledStatement( + ZoneList<const AstRawString*>* labels, + AllowLabelledFunctionStatement allow_function, bool* ok) { + // ExpressionStatement | LabelledStatement :: + // Expression ';' + // Identifier ':' Statement + // + // ExpressionStatement[Yield] : + // [lookahead ∉ {{, function, class, let [}] Expression[In, ?Yield] ; + + int pos = peek_position(); + + switch (peek()) { + case Token::FUNCTION: + case Token::LBRACE: + UNREACHABLE(); // Always handled by the callers. + case Token::CLASS: + ReportUnexpectedToken(Next()); + *ok = false; + return impl()->NullStatement(); + default: + break; + } + + bool starts_with_identifier = peek_any_identifier(); + ExpressionT expr = ParseExpression(true, CHECK_OK); + 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. + labels = impl()->DeclareLabel(labels, impl()->AsIdentifierExpression(expr), + CHECK_OK); + Consume(Token::COLON); + // ES#sec-labelled-function-declarations Labelled Function Declarations + if (peek() == Token::FUNCTION && is_sloppy(language_mode())) { + if (allow_function == kAllowLabelledFunctionStatement) { + return ParseFunctionDeclaration(ok); + } else { + return ParseScopedStatement(labels, true, ok); + } + } + return ParseStatement(labels, kDisallowLabelledFunctionStatement, ok); + } + + // If we have an extension, we allow a native function declaration. + // A native function declaration starts with "native function" with + // no line-terminator between the two words. + if (extension_ != nullptr && peek() == Token::FUNCTION && + !scanner()->HasAnyLineTerminatorBeforeNext() && impl()->IsNative(expr) && + !scanner()->literal_contains_escapes()) { + return ParseNativeDeclaration(ok); + } + + // Parsed expression statement, followed by semicolon. + ExpectSemicolon(CHECK_OK); + return factory()->NewExpressionStatement(expr, pos); +} + +template <typename Impl> +typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseIfStatement( + ZoneList<const AstRawString*>* labels, bool* ok) { + // IfStatement :: + // 'if' '(' Expression ')' Statement ('else' Statement)? + + int pos = peek_position(); + Expect(Token::IF, CHECK_OK); + Expect(Token::LPAREN, CHECK_OK); + ExpressionT condition = ParseExpression(true, CHECK_OK); + Expect(Token::RPAREN, CHECK_OK); + StatementT then_statement = ParseScopedStatement(labels, false, CHECK_OK); + StatementT else_statement = impl()->NullStatement(); + if (Check(Token::ELSE)) { + else_statement = ParseScopedStatement(labels, false, CHECK_OK); + } else { + else_statement = factory()->NewEmptyStatement(kNoSourcePosition); + } + return factory()->NewIfStatement(condition, then_statement, else_statement, + pos); +} + +template <typename Impl> +typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseContinueStatement( + bool* ok) { + // ContinueStatement :: + // 'continue' Identifier? ';' + + int pos = peek_position(); + Expect(Token::CONTINUE, CHECK_OK); + IdentifierT label = impl()->EmptyIdentifier(); + Token::Value tok = peek(); + if (!scanner()->HasAnyLineTerminatorBeforeNext() && tok != Token::SEMICOLON && + tok != Token::RBRACE && tok != Token::EOS) { + // ECMA allows "eval" or "arguments" as labels even in strict mode. + label = ParseIdentifier(kAllowRestrictedIdentifiers, CHECK_OK); + } + typename Types::IterationStatement target = + impl()->LookupContinueTarget(label, CHECK_OK); + if (impl()->IsNullStatement(target)) { + // Illegal continue statement. + MessageTemplate::Template message = MessageTemplate::kIllegalContinue; + if (!impl()->IsEmptyIdentifier(label)) { + message = MessageTemplate::kUnknownLabel; + } + ReportMessage(message, label); + *ok = false; + return impl()->NullStatement(); + } + ExpectSemicolon(CHECK_OK); + return factory()->NewContinueStatement(target, pos); +} template <typename Impl> -void ParserBase<Impl>::ObjectLiteralChecker::CheckProperty( - Token::Value property, PropertyKind type, MethodKind method_type, - ExpressionClassifier* classifier, bool* ok) { - DCHECK(!IsStaticMethod(method_type)); - DCHECK(!IsSpecialMethod(method_type) || type == kMethodProperty); +typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseBreakStatement( + ZoneList<const AstRawString*>* labels, bool* ok) { + // BreakStatement :: + // 'break' Identifier? ';' + int pos = peek_position(); + Expect(Token::BREAK, CHECK_OK); + IdentifierT label = impl()->EmptyIdentifier(); + Token::Value tok = peek(); + if (!scanner()->HasAnyLineTerminatorBeforeNext() && tok != Token::SEMICOLON && + tok != Token::RBRACE && tok != Token::EOS) { + // ECMA allows "eval" or "arguments" as labels even in strict mode. + label = ParseIdentifier(kAllowRestrictedIdentifiers, CHECK_OK); + } + // Parse labeled break statements that target themselves into + // empty statements, e.g. 'l1: l2: l3: break l2;' + if (!impl()->IsEmptyIdentifier(label) && + impl()->ContainsLabel(labels, label)) { + ExpectSemicolon(CHECK_OK); + return factory()->NewEmptyStatement(pos); + } + typename Types::BreakableStatement target = + impl()->LookupBreakTarget(label, CHECK_OK); + if (impl()->IsNullStatement(target)) { + // Illegal break statement. + MessageTemplate::Template message = MessageTemplate::kIllegalBreak; + if (!impl()->IsEmptyIdentifier(label)) { + message = MessageTemplate::kUnknownLabel; + } + ReportMessage(message, label); + *ok = false; + return impl()->NullStatement(); + } + ExpectSemicolon(CHECK_OK); + return factory()->NewBreakStatement(target, pos); +} + +template <typename Impl> +typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseReturnStatement( + bool* ok) { + // 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); + Scanner::Location loc = scanner()->location(); + + switch (GetDeclarationScope()->scope_type()) { + case SCRIPT_SCOPE: + case EVAL_SCOPE: + case MODULE_SCOPE: + impl()->ReportMessageAt(loc, MessageTemplate::kIllegalReturn); + *ok = false; + return impl()->NullStatement(); + default: + break; + } + + Token::Value tok = peek(); + ExpressionT return_value = impl()->EmptyExpression(); + if (scanner()->HasAnyLineTerminatorBeforeNext() || tok == Token::SEMICOLON || + tok == Token::RBRACE || tok == Token::EOS) { + if (IsSubclassConstructor(function_state_->kind())) { + return_value = impl()->ThisExpression(loc.beg_pos); + } else { + return_value = impl()->GetLiteralUndefined(position()); + } + } else { + if (IsSubclassConstructor(function_state_->kind())) { + // Because of the return code rewriting that happens in case of a subclass + // constructor we don't want to accept tail calls, therefore we don't set + // ReturnExprScope to kInsideValidReturnStatement here. + return_value = ParseExpression(true, CHECK_OK); + } else { + ReturnExprScope maybe_allow_tail_calls( + function_state_, ReturnExprContext::kInsideValidReturnStatement); + return_value = ParseExpression(true, CHECK_OK); + + if (allow_tailcalls() && !is_sloppy(language_mode()) && !is_resumable()) { + // ES6 14.6.1 Static Semantics: IsInTailPosition + function_state_->AddImplicitTailCallExpression(return_value); + } + } + } + ExpectSemicolon(CHECK_OK); + return_value = impl()->RewriteReturn(return_value, loc.beg_pos); + return factory()->NewReturnStatement(return_value, loc.beg_pos); +} + +template <typename Impl> +typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseWithStatement( + ZoneList<const AstRawString*>* labels, bool* ok) { + // WithStatement :: + // 'with' '(' Expression ')' Statement + + Expect(Token::WITH, CHECK_OK); + int pos = position(); + + if (is_strict(language_mode())) { + ReportMessage(MessageTemplate::kStrictWith); + *ok = false; + return impl()->NullStatement(); + } + + Expect(Token::LPAREN, CHECK_OK); + ExpressionT expr = ParseExpression(true, CHECK_OK); + Expect(Token::RPAREN, CHECK_OK); + + Scope* with_scope = NewScope(WITH_SCOPE); + StatementT body = impl()->NullStatement(); + { + BlockState block_state(&scope_state_, with_scope); + with_scope->set_start_position(scanner()->peek_location().beg_pos); + body = ParseScopedStatement(labels, true, CHECK_OK); + with_scope->set_end_position(scanner()->location().end_pos); + } + return factory()->NewWithStatement(with_scope, expr, body, pos); +} + +template <typename Impl> +typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseDoWhileStatement( + ZoneList<const AstRawString*>* labels, bool* ok) { + // DoStatement :: + // 'do' Statement 'while' '(' Expression ')' ';' + + auto loop = factory()->NewDoWhileStatement(labels, peek_position()); + typename Types::Target target(this, loop); + + Expect(Token::DO, CHECK_OK); + StatementT body = ParseScopedStatement(nullptr, true, CHECK_OK); + Expect(Token::WHILE, CHECK_OK); + Expect(Token::LPAREN, CHECK_OK); + + ExpressionT cond = ParseExpression(true, CHECK_OK); + Expect(Token::RPAREN, CHECK_OK); + + // Allow do-statements to be terminated with and without + // semi-colons. This allows code such as 'do;while(0)return' to + // parse, which would not be the case if we had used the + // ExpectSemicolon() functionality here. + Check(Token::SEMICOLON); + + loop->Initialize(cond, body); + return loop; +} + +template <typename Impl> +typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseWhileStatement( + ZoneList<const AstRawString*>* labels, bool* ok) { + // WhileStatement :: + // 'while' '(' Expression ')' Statement + + auto loop = factory()->NewWhileStatement(labels, peek_position()); + typename Types::Target target(this, loop); + + Expect(Token::WHILE, CHECK_OK); + Expect(Token::LPAREN, CHECK_OK); + ExpressionT cond = ParseExpression(true, CHECK_OK); + Expect(Token::RPAREN, CHECK_OK); + StatementT body = ParseScopedStatement(nullptr, true, CHECK_OK); + + loop->Initialize(cond, body); + return loop; +} + +template <typename Impl> +typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseThrowStatement( + bool* ok) { + // ThrowStatement :: + // 'throw' Expression ';' + + Expect(Token::THROW, CHECK_OK); + int pos = position(); + if (scanner()->HasAnyLineTerminatorBeforeNext()) { + ReportMessage(MessageTemplate::kNewlineAfterThrow); + *ok = false; + return impl()->NullStatement(); + } + ExpressionT exception = ParseExpression(true, CHECK_OK); + ExpectSemicolon(CHECK_OK); + + return impl()->NewThrowStatement(exception, pos); +} + +template <typename Impl> +typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseSwitchStatement( + ZoneList<const AstRawString*>* labels, bool* ok) { + // SwitchStatement :: + // 'switch' '(' Expression ')' '{' CaseClause* '}' + // CaseClause :: + // 'case' Expression ':' StatementList + // 'default' ':' StatementList + + int switch_pos = peek_position(); + + Expect(Token::SWITCH, CHECK_OK); + Expect(Token::LPAREN, CHECK_OK); + ExpressionT tag = ParseExpression(true, CHECK_OK); + Expect(Token::RPAREN, CHECK_OK); + + auto switch_statement = factory()->NewSwitchStatement(labels, switch_pos); + + { + BlockState cases_block_state(zone(), &scope_state_); + cases_block_state.set_start_position(scanner()->location().beg_pos); + cases_block_state.SetNonlinear(); + typename Types::Target target(this, switch_statement); + + bool default_seen = false; + auto cases = impl()->NewCaseClauseList(4); + Expect(Token::LBRACE, CHECK_OK); + while (peek() != Token::RBRACE) { + // An empty label indicates the default case. + ExpressionT label = impl()->EmptyExpression(); + if (Check(Token::CASE)) { + label = ParseExpression(true, CHECK_OK); + } else { + Expect(Token::DEFAULT, CHECK_OK); + if (default_seen) { + ReportMessage(MessageTemplate::kMultipleDefaultsInSwitch); + *ok = false; + return impl()->NullStatement(); + } + default_seen = true; + } + Expect(Token::COLON, CHECK_OK); + int clause_pos = position(); + 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, clause_pos); + cases->Add(clause, zone()); + } + Expect(Token::RBRACE, CHECK_OK); + + cases_block_state.set_end_position(scanner()->location().end_pos); + return impl()->RewriteSwitchStatement( + tag, switch_statement, cases, cases_block_state.FinalizedBlockScope()); + } +} + +template <typename Impl> +typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseTryStatement( + bool* ok) { + // TryStatement :: + // 'try' Block Catch + // 'try' Block Finally + // 'try' Block Catch Finally + // + // Catch :: + // 'catch' '(' Identifier ')' Block + // + // Finally :: + // 'finally' Block + + Expect(Token::TRY, CHECK_OK); + int pos = position(); + + BlockT try_block = impl()->NullBlock(); + { + ReturnExprScope no_tail_calls(function_state_, + ReturnExprContext::kInsideTryBlock); + try_block = ParseBlock(nullptr, CHECK_OK); + } + + CatchInfo catch_info(this); + catch_info.for_promise_reject = allow_natives() && Check(Token::MOD); + + if (peek() != Token::CATCH && peek() != Token::FINALLY) { + ReportMessage(MessageTemplate::kNoCatchOrFinally); + *ok = false; + return impl()->NullStatement(); + } + + BlockT catch_block = impl()->NullBlock(); + if (Check(Token::CATCH)) { + Expect(Token::LPAREN, CHECK_OK); + catch_info.scope = NewScope(CATCH_SCOPE); + catch_info.scope->set_start_position(scanner()->location().beg_pos); + + { + CollectExpressionsInTailPositionToListScope + collect_tail_call_expressions_scope( + function_state_, &catch_info.tail_call_expressions); + BlockState catch_block_state(&scope_state_, catch_info.scope); + + catch_block = factory()->NewBlock(nullptr, 16, false, kNoSourcePosition); + + // Create a block scope to hold any lexical declarations created + // as part of destructuring the catch parameter. + { + BlockState catch_variable_block_state(zone(), &scope_state_); + catch_variable_block_state.set_start_position( + scanner()->location().beg_pos); + typename Types::Target target(this, catch_block); + + // 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); + } else { + ExpressionClassifier pattern_classifier(this); + catch_info.pattern = ParsePrimaryExpression(CHECK_OK); + ValidateBindingPattern(CHECK_OK); + } + + Expect(Token::RPAREN, CHECK_OK); + impl()->RewriteCatchPattern(&catch_info, CHECK_OK); + if (!impl()->IsNullStatement(catch_info.init_block)) { + catch_block->statements()->Add(catch_info.init_block, zone()); + } + + catch_info.inner_block = ParseBlock(nullptr, CHECK_OK); + catch_block->statements()->Add(catch_info.inner_block, zone()); + impl()->ValidateCatchBlock(catch_info, CHECK_OK); + catch_variable_block_state.set_end_position( + scanner()->location().end_pos); + catch_block->set_scope( + catch_variable_block_state.FinalizedBlockScope()); + } + } + + catch_info.scope->set_end_position(scanner()->location().end_pos); + } + + BlockT finally_block = impl()->NullBlock(); + DCHECK(peek() == Token::FINALLY || !impl()->IsNullStatement(catch_block)); + if (Check(Token::FINALLY)) { + finally_block = ParseBlock(nullptr, CHECK_OK); + } + + return impl()->RewriteTryStatement(try_block, catch_block, finally_block, + catch_info, pos); +} + +template <typename Impl> +typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement( + ZoneList<const AstRawString*>* labels, bool* ok) { + int stmt_pos = peek_position(); + ForInfo for_info(this); + bool bound_names_are_lexical = false; + + // Create an in-between scope for let-bound iteration variables. + BlockState for_state(zone(), &scope_state_); + Expect(Token::FOR, CHECK_OK); + Expect(Token::LPAREN, CHECK_OK); + for_state.set_start_position(scanner()->location().beg_pos); + for_state.set_is_hidden(); + + StatementT init = impl()->NullStatement(); + if (peek() != Token::SEMICOLON) { + // An initializer is present. + if (peek() == Token::VAR || peek() == Token::CONST || + (peek() == Token::LET && IsNextLetKeyword())) { + // The initializer contains declarations. + ParseVariableDeclarations(kForStatement, &for_info.parsing_result, + nullptr, CHECK_OK); + bound_names_are_lexical = + IsLexicalVariableMode(for_info.parsing_result.descriptor.mode); + for_info.each_loc = scanner()->location(); + + if (CheckInOrOf(&for_info.mode)) { + // Just one declaration followed by in/of. + if (for_info.parsing_result.declarations.length() != 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() && + (is_strict(language_mode()) || + for_info.mode == ForEachStatement::ITERATE || + bound_names_are_lexical || + !impl()->IsIdentifier( + for_info.parsing_result.declarations[0].pattern) || + allow_harmony_for_in())) { + // Only increment the use count if we would have let this through + // without the flag. + if (allow_harmony_for_in()) { + impl()->CountUsage(v8::Isolate::kForInInitializer); + } + impl()->ReportMessageAt( + for_info.parsing_result.first_initializer_loc, + MessageTemplate::kForInOfLoopInitializer, + ForEachStatement::VisitModeString(for_info.mode)); + *ok = false; + return impl()->NullStatement(); + } + + BlockT init_block = impl()->RewriteForVarInLegacy(for_info); + + auto loop = + factory()->NewForEachStatement(for_info.mode, labels, stmt_pos); + typename Types::Target target(this, loop); + + int each_keyword_pos = scanner()->location().beg_pos; + + ExpressionT enumerable = impl()->EmptyExpression(); + if (for_info.mode == ForEachStatement::ITERATE) { + ExpressionClassifier classifier(this); + enumerable = ParseAssignmentExpression(true, CHECK_OK); + impl()->RewriteNonPattern(CHECK_OK); + } else { + enumerable = ParseExpression(true, CHECK_OK); + } + + Expect(Token::RPAREN, CHECK_OK); + + StatementT final_loop = impl()->NullStatement(); + { + ReturnExprScope no_tail_calls(function_state_, + ReturnExprContext::kInsideForInOfBody); + BlockState block_state(zone(), &scope_state_); + block_state.set_start_position(scanner()->location().beg_pos); + + StatementT body = ParseScopedStatement(nullptr, true, CHECK_OK); + + BlockT body_block = impl()->NullBlock(); + ExpressionT each_variable = impl()->EmptyExpression(); + impl()->DesugarBindingInForEachStatement(&for_info, &body_block, + &each_variable, CHECK_OK); + body_block->statements()->Add(body, zone()); + final_loop = impl()->InitializeForEachStatement( + loop, each_variable, enumerable, body_block, each_keyword_pos); + + block_state.set_end_position(scanner()->location().end_pos); + body_block->set_scope(block_state.FinalizedBlockScope()); + } + + init_block = + impl()->CreateForEachStatementTDZ(init_block, for_info, ok); + + for_state.set_end_position(scanner()->location().end_pos); + Scope* for_scope = for_state.FinalizedBlockScope(); + // Parsed for-in loop w/ variable declarations. + if (!impl()->IsNullStatement(init_block)) { + init_block->statements()->Add(final_loop, zone()); + init_block->set_scope(for_scope); + return init_block; + } else { + DCHECK_NULL(for_scope); + return final_loop; + } + } else { + // One or more declaration not followed by in/of. + init = impl()->BuildInitializationBlock( + &for_info.parsing_result, + bound_names_are_lexical ? &for_info.bound_names : nullptr, + CHECK_OK); + } + } else { + // 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 = scanner()->location().end_pos; + + 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 { + impl()->RewriteNonPattern(CHECK_OK); + } + + if (is_for_each) { + // Initializer is reference followed by in/of. + if (!is_destructuring) { + expression = impl()->CheckAndRewriteReferenceExpression( + expression, lhs_beg_pos, lhs_end_pos, + MessageTemplate::kInvalidLhsInFor, kSyntaxError, CHECK_OK); + } + + auto loop = + factory()->NewForEachStatement(for_info.mode, labels, stmt_pos); + typename Types::Target target(this, loop); + + int each_keyword_pos = scanner()->location().beg_pos; + + ExpressionT enumerable = impl()->EmptyExpression(); + if (for_info.mode == ForEachStatement::ITERATE) { + ExpressionClassifier classifier(this); + enumerable = ParseAssignmentExpression(true, CHECK_OK); + impl()->RewriteNonPattern(CHECK_OK); + } else { + enumerable = ParseExpression(true, CHECK_OK); + } + + Expect(Token::RPAREN, CHECK_OK); + + { + ReturnExprScope no_tail_calls(function_state_, + ReturnExprContext::kInsideForInOfBody); + BlockState block_state(zone(), &scope_state_); + block_state.set_start_position(scanner()->location().beg_pos); + + // For legacy compat reasons, give for loops similar treatment to + // if statements in allowing a function declaration for a body + StatementT body = ParseScopedStatement(nullptr, true, CHECK_OK); + block_state.set_end_position(scanner()->location().end_pos); + StatementT final_loop = impl()->InitializeForEachStatement( + loop, expression, enumerable, body, each_keyword_pos); + + Scope* for_scope = for_state.FinalizedBlockScope(); + DCHECK_NULL(for_scope); + USE(for_scope); + Scope* block_scope = block_state.FinalizedBlockScope(); + DCHECK_NULL(block_scope); + USE(block_scope); + return final_loop; + } + } else { + // Initializer is just an expression. + init = factory()->NewExpressionStatement(expression, lhs_beg_pos); + } + } + } + + // Standard 'for' loop, we have parsed the initializer at this point. + auto loop = factory()->NewForStatement(labels, stmt_pos); + typename Types::Target target(this, loop); + + Expect(Token::SEMICOLON, CHECK_OK); + + ExpressionT cond = impl()->EmptyExpression(); + StatementT next = impl()->NullStatement(); + StatementT body = impl()->NullStatement(); + + // If there are let bindings, then condition and the next statement of the + // for loop must be parsed in a new scope. + Scope* inner_scope = scope(); + // TODO(verwaest): Allocate this through a ScopeState as well. + if (bound_names_are_lexical && for_info.bound_names.length() > 0) { + inner_scope = NewScopeWithParent(inner_scope, BLOCK_SCOPE); + inner_scope->set_start_position(scanner()->location().beg_pos); + } + { + BlockState block_state(&scope_state_, inner_scope); + + if (peek() != Token::SEMICOLON) { + cond = ParseExpression(true, CHECK_OK); + } + Expect(Token::SEMICOLON, CHECK_OK); + + if (peek() != Token::RPAREN) { + ExpressionT exp = ParseExpression(true, CHECK_OK); + next = factory()->NewExpressionStatement(exp, exp->position()); + } + Expect(Token::RPAREN, CHECK_OK); + + body = ParseScopedStatement(nullptr, true, CHECK_OK); + } + + if (bound_names_are_lexical && for_info.bound_names.length() > 0) { + auto result = impl()->DesugarLexicalBindingsInForStatement( + loop, init, cond, next, body, inner_scope, for_info, CHECK_OK); + for_state.set_end_position(scanner()->location().end_pos); + return result; + } else { + for_state.set_end_position(scanner()->location().end_pos); + Scope* for_scope = for_state.FinalizedBlockScope(); + if (for_scope != nullptr) { + // Rewrite a for statement of the form + // for (const x = i; c; n) b + // + // into + // + // { + // const x = i; + // for (; c; n) b + // } + // + // or, desugar + // for (; c; n) b + // into + // { + // for (; c; n) b + // } + // just in case b introduces a lexical binding some other way, e.g., if b + // is a FunctionDeclaration. + BlockT block = factory()->NewBlock(nullptr, 2, false, kNoSourcePosition); + if (!impl()->IsNullStatement(init)) { + block->statements()->Add(init, zone()); + } + block->statements()->Add(loop, zone()); + block->set_scope(for_scope); + loop->Initialize(init, cond, next, body); + return block; + } else { + loop->Initialize(init, cond, next, body); + return loop; + } + } +} + +#undef CHECK_OK +#undef CHECK_OK_CUSTOM + +template <typename Impl> +void ParserBase<Impl>::ObjectLiteralChecker::CheckDuplicateProto( + Token::Value property) { if (property == Token::SMI || property == Token::NUMBER) return; - if (type == kValueProperty && IsProto()) { + if (IsProto()) { if (has_seen_proto_) { - classifier->RecordObjectLiteralError( + this->parser()->classifier()->RecordExpressionError( this->scanner()->location(), MessageTemplate::kDuplicateProto); return; } @@ -3698,23 +5423,22 @@ void ParserBase<Impl>::ObjectLiteralChecker::CheckProperty( } template <typename Impl> -void ParserBase<Impl>::ClassLiteralChecker::CheckProperty( - Token::Value property, PropertyKind type, MethodKind method_type, - ExpressionClassifier* classifier, bool* ok) { - DCHECK(type == kMethodProperty || type == kAccessorProperty); +void ParserBase<Impl>::ClassLiteralChecker::CheckClassMethodName( + Token::Value property, PropertyKind type, bool is_generator, bool is_async, + bool is_static, bool* ok) { + DCHECK(type == PropertyKind::kMethodProperty || + type == PropertyKind::kAccessorProperty); if (property == Token::SMI || property == Token::NUMBER) return; - if (IsStaticMethod(method_type)) { + if (is_static) { if (IsPrototype()) { this->parser()->ReportMessage(MessageTemplate::kStaticPrototype); *ok = false; return; } } else if (IsConstructor()) { - const bool is_generator = IsGeneratorMethod(method_type); - const bool is_async = IsAsyncMethod(method_type); - if (is_generator || is_async || type == kAccessorProperty) { + if (is_generator || is_async || type == PropertyKind::kAccessorProperty) { MessageTemplate::Template msg = is_generator ? MessageTemplate::kConstructorIsGenerator : is_async ? MessageTemplate::kConstructorIsAsync |