// Copyright 2012 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef V8_PARSING_PARSER_BASE_H_ #define V8_PARSING_PARSER_BASE_H_ #include <vector> #include "src/ast/ast-source-ranges.h" #include "src/ast/ast.h" #include "src/ast/scopes.h" #include "src/bailout-reason.h" #include "src/base/hashmap.h" #include "src/base/v8-fallthrough.h" #include "src/counters.h" #include "src/globals.h" #include "src/log.h" #include "src/messages.h" #include "src/parsing/expression-classifier.h" #include "src/parsing/func-name-inferrer.h" #include "src/parsing/scanner.h" #include "src/parsing/token.h" #include "src/zone/zone-chunk-list.h" namespace v8 { namespace internal { enum FunctionNameValidity { kFunctionNameIsStrictReserved, kSkipFunctionNameCheck, kFunctionNameValidityUnknown }; enum AllowLabelledFunctionStatement { kAllowLabelledFunctionStatement, kDisallowLabelledFunctionStatement, }; enum class ParseFunctionFlags { kIsNormal = 0, kIsGenerator = 1, kIsAsync = 2, kIsDefault = 4 }; static inline ParseFunctionFlags operator|(ParseFunctionFlags lhs, ParseFunctionFlags rhs) { typedef unsigned char T; return static_cast<ParseFunctionFlags>(static_cast<T>(lhs) | static_cast<T>(rhs)); } static inline ParseFunctionFlags& operator|=(ParseFunctionFlags& lhs, const ParseFunctionFlags& rhs) { lhs = lhs | rhs; return lhs; } static inline bool operator&(ParseFunctionFlags bitfield, ParseFunctionFlags mask) { typedef unsigned char T; return static_cast<T>(bitfield) & static_cast<T>(mask); } struct FormalParametersBase { explicit FormalParametersBase(DeclarationScope* scope) : scope(scope) {} int num_parameters() const { // Don't include the rest parameter into the function's formal parameter // count (esp. the SharedFunctionInfo::internal_formal_parameter_count, // which says whether we need to create an arguments adaptor frame). return arity - has_rest; } void UpdateArityAndFunctionLength(bool is_optional, bool is_rest) { if (!is_optional && !is_rest && function_length == arity) { ++function_length; } ++arity; } DeclarationScope* scope; bool has_rest = false; bool is_simple = true; int function_length = 0; int arity = 0; }; // Stack-allocated scope to collect source ranges from the parser. class SourceRangeScope final { public: enum PositionKind { POSITION_BEG, POSITION_END, PEEK_POSITION_BEG, PEEK_POSITION_END, }; SourceRangeScope(Scanner* scanner, SourceRange* range, PositionKind pre_kind = PEEK_POSITION_BEG, PositionKind post_kind = POSITION_END) : scanner_(scanner), range_(range), post_kind_(post_kind) { range_->start = GetPosition(pre_kind); DCHECK_NE(range_->start, kNoSourcePosition); } ~SourceRangeScope() { Finalize(); } const SourceRange& Finalize() { if (is_finalized_) return *range_; is_finalized_ = true; range_->end = GetPosition(post_kind_); DCHECK_NE(range_->end, kNoSourcePosition); return *range_; } private: int32_t GetPosition(PositionKind kind) { switch (kind) { case POSITION_BEG: return scanner_->location().beg_pos; case POSITION_END: return scanner_->location().end_pos; case PEEK_POSITION_BEG: return scanner_->peek_location().beg_pos; case PEEK_POSITION_END: return scanner_->peek_location().end_pos; default: UNREACHABLE(); } } Scanner* scanner_; SourceRange* range_; PositionKind post_kind_; bool is_finalized_ = false; DISALLOW_IMPLICIT_CONSTRUCTORS(SourceRangeScope); }; // ---------------------------------------------------------------------------- // The CHECK_OK macro is a convenient macro to enforce error // handling for functions that may fail (by returning !*ok). // // CAUTION: This macro appends extra statements after a call, // thus it must never be used where only a single statement // is correct (e.g. an if statement branch w/o braces)! #define CHECK_OK_CUSTOM(x, ...) ok); \ if (!*ok) return impl()->x(__VA_ARGS__); \ ((void)0 #define DUMMY ) // to make indentation work #undef DUMMY // Used in functions where the return type is ExpressionT. #define CHECK_OK CHECK_OK_CUSTOM(NullExpression) #define CHECK_OK_VOID ok); \ if (!*ok) return; \ ((void)0 #define DUMMY ) // to make indentation work #undef DUMMY // Common base class template shared between parser and pre-parser. // The Impl parameter is the actual class of the parser/pre-parser, // following the Curiously Recurring Template Pattern (CRTP). // The structure of the parser objects is roughly the following: // // // A structure template containing type definitions, needed to // // avoid a cyclic dependency. // template <typename Impl> // 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 { ... }; // // // And then, for each parser variant (e.g., parser, preparser, etc): // class Parser; // // template <> // class ParserTypes<Parser> { ... }; // // class Parser : public ParserBase<Parser> { ... }; // // 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 <> // struct ParserTypes<Impl> { // // Synonyms for ParserBase<Impl> and Impl, respectively. // typedef Base; // typedef Impl; // // 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 ForStatement; // typedef IterationStatement; // // For constructing objects returned by the traversing functions. // typedef Factory; // // For other implementation-specific tasks. // typedef Target; // typedef TargetScope; // }; template <typename Impl> struct ParserTypes; template <typename Impl> class ParserBase { public: // Shorten type names defined by ParserTypes<Impl>. typedef ParserTypes<Impl> Types; typedef typename Types::Identifier IdentifierT; typedef typename Types::Expression ExpressionT; typedef typename Types::FunctionLiteral FunctionLiteralT; typedef typename Types::ObjectLiteralProperty ObjectLiteralPropertyT; typedef typename Types::ClassLiteralProperty ClassLiteralPropertyT; typedef typename Types::Suspend SuspendExpressionT; typedef typename Types::RewritableExpression RewritableExpressionT; 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 Types::ForStatement ForStatementT; typedef typename v8::internal::ExpressionClassifier<Types> ExpressionClassifier; // All implementation-specific methods must be called through this. Impl* impl() { return static_cast<Impl*>(this); } const Impl* impl() const { return static_cast<const Impl*>(this); } ParserBase(Zone* zone, Scanner* scanner, uintptr_t stack_limit, v8::Extension* extension, AstValueFactory* ast_value_factory, PendingCompilationErrorHandler* pending_error_handler, RuntimeCallStats* runtime_call_stats, Logger* logger, int script_id, bool parsing_module, bool parsing_on_main_thread) : scope_(nullptr), original_scope_(nullptr), function_state_(nullptr), extension_(extension), fni_(nullptr), ast_value_factory_(ast_value_factory), ast_node_factory_(ast_value_factory, zone), runtime_call_stats_(runtime_call_stats), logger_(logger), parsing_on_main_thread_(parsing_on_main_thread), parsing_module_(parsing_module), stack_limit_(stack_limit), pending_error_handler_(pending_error_handler), zone_(zone), classifier_(nullptr), scanner_(scanner), default_eager_compile_hint_(FunctionLiteral::kShouldLazyCompile), function_literal_id_(0), script_id_(script_id), allow_natives_(false), allow_harmony_do_expressions_(false), allow_harmony_public_fields_(false), allow_harmony_static_fields_(false), allow_harmony_dynamic_import_(false), allow_harmony_import_meta_(false), allow_harmony_private_fields_(false), allow_eval_cache_(true) {} #define ALLOW_ACCESSORS(name) \ bool allow_##name() const { return allow_##name##_; } \ void set_allow_##name(bool allow) { allow_##name##_ = allow; } ALLOW_ACCESSORS(natives); ALLOW_ACCESSORS(harmony_do_expressions); ALLOW_ACCESSORS(harmony_public_fields); ALLOW_ACCESSORS(harmony_static_fields); ALLOW_ACCESSORS(harmony_dynamic_import); ALLOW_ACCESSORS(harmony_import_meta); ALLOW_ACCESSORS(eval_cache); #undef ALLOW_ACCESSORS bool allow_harmony_bigint() const { return scanner()->allow_harmony_bigint(); } void set_allow_harmony_bigint(bool allow) { scanner()->set_allow_harmony_bigint(allow); } bool allow_harmony_numeric_separator() const { return scanner()->allow_harmony_numeric_separator(); } void set_allow_harmony_numeric_separator(bool allow) { scanner()->set_allow_harmony_numeric_separator(allow); } bool allow_harmony_private_fields() const { return scanner()->allow_harmony_private_fields(); } void set_allow_harmony_private_fields(bool allow) { scanner()->set_allow_harmony_private_fields(allow); } uintptr_t stack_limit() const { return stack_limit_; } void set_stack_limit(uintptr_t stack_limit) { stack_limit_ = stack_limit; } void set_default_eager_compile_hint( FunctionLiteral::EagerCompileHint eager_compile_hint) { default_eager_compile_hint_ = eager_compile_hint; } FunctionLiteral::EagerCompileHint default_eager_compile_hint() const { return default_eager_compile_hint_; } int GetNextFunctionLiteralId() { return ++function_literal_id_; } int GetLastFunctionLiteralId() const { return function_literal_id_; } void SkipFunctionLiterals(int delta) { function_literal_id_ += delta; } void ResetFunctionLiteralId() { function_literal_id_ = 0; } // The Zone where the parsing outputs are stored. Zone* main_zone() const { return ast_value_factory()->zone(); } // The current Zone, which might be the main zone or a temporary Zone. Zone* zone() const { return zone_; } protected: friend class v8::internal::ExpressionClassifier<ParserTypes<Impl>>; enum AllowRestrictedIdentifiers { kAllowRestrictedIdentifiers, kDontAllowRestrictedIdentifiers }; enum LazyParsingResult { kLazyParsingComplete, kLazyParsingAborted }; enum VariableDeclarationContext { kStatementListItem, kStatement, kForStatement }; class ClassLiteralChecker; class ObjectLiteralChecker; // --------------------------------------------------------------------------- // BlockState and FunctionState implement the parser's scope stack. // The parser's current scope is in scope_. BlockState and FunctionState // constructors push on the scope stack and the destructors pop. They are also // used to hold the parser's per-funcion state. class BlockState BASE_EMBEDDED { public: BlockState(Scope** scope_stack, Scope* scope) : scope_stack_(scope_stack), outer_scope_(*scope_stack) { *scope_stack_ = scope; } BlockState(Zone* zone, Scope** scope_stack) : BlockState(scope_stack, new (zone) Scope(zone, *scope_stack, BLOCK_SCOPE)) {} ~BlockState() { *scope_stack_ = outer_scope_; } private: Scope** const scope_stack_; Scope* const outer_scope_; }; class FunctionState final : public BlockState { public: FunctionState(FunctionState** function_state_stack, Scope** scope_stack, DeclarationScope* scope); ~FunctionState(); DeclarationScope* scope() const { return scope_->AsDeclarationScope(); } void AddProperty() { expected_property_count_++; } int expected_property_count() { return expected_property_count_; } void DisableOptimization(BailoutReason reason) { dont_optimize_reason_ = reason; } BailoutReason dont_optimize_reason() { return dont_optimize_reason_; } void AddSuspend() { suspend_count_++; } int suspend_count() const { return suspend_count_; } bool CanSuspend() const { return suspend_count_ > 0; } FunctionKind kind() const { return scope()->function_kind(); } void RewindDestructuringAssignments(int pos) { destructuring_assignments_to_rewrite_.Rewind(pos); } void AdoptDestructuringAssignmentsFromParentState(int pos) { const auto& outer_assignments = outer_function_state_->destructuring_assignments_to_rewrite_; DCHECK_GE(outer_assignments.size(), pos); auto it = outer_assignments.begin(); it.Advance(pos); for (; it != outer_assignments.end(); ++it) { auto expr = *it; expr->set_scope(scope_); destructuring_assignments_to_rewrite_.push_back(expr); } outer_function_state_->RewindDestructuringAssignments(pos); } const ZoneChunkList<RewritableExpressionT>& destructuring_assignments_to_rewrite() const { return destructuring_assignments_to_rewrite_; } ZoneVector<typename ExpressionClassifier::Error>* GetReportedErrorList() { return &reported_errors_; } bool next_function_is_likely_called() const { return next_function_is_likely_called_; } bool previous_function_was_likely_called() const { return previous_function_was_likely_called_; } void set_next_function_is_likely_called() { next_function_is_likely_called_ = true; } void RecordFunctionOrEvalCall() { contains_function_or_eval_ = true; } bool contains_function_or_eval() const { return contains_function_or_eval_; } class FunctionOrEvalRecordingScope { public: explicit FunctionOrEvalRecordingScope(FunctionState* state) : state_(state) { prev_value_ = state->contains_function_or_eval_; state->contains_function_or_eval_ = false; } ~FunctionOrEvalRecordingScope() { bool found = state_->contains_function_or_eval_; if (!found) { state_->contains_function_or_eval_ = prev_value_; } } private: FunctionState* state_; bool prev_value_; }; private: void AddDestructuringAssignment(RewritableExpressionT expr) { destructuring_assignments_to_rewrite_.push_back(expr); } // Properties count estimation. int expected_property_count_; // How many suspends are needed for this function. int suspend_count_; FunctionState** function_state_stack_; FunctionState* outer_function_state_; DeclarationScope* scope_; ZoneChunkList<RewritableExpressionT> destructuring_assignments_to_rewrite_; // We use a ZoneVector here because we need to do a lot of random access. ZoneVector<typename ExpressionClassifier::Error> reported_errors_; // A reason, if any, why this function should not be optimized. BailoutReason dont_optimize_reason_; // Record whether the next (=== immediately following) function literal is // preceded by a parenthesis / exclamation mark. Also record the previous // state. // These are managed by the FunctionState constructor; the caller may only // call set_next_function_is_likely_called. bool next_function_is_likely_called_; bool previous_function_was_likely_called_; // Track if a function or eval occurs within this FunctionState bool contains_function_or_eval_; friend Impl; }; struct DeclarationDescriptor { enum Kind { NORMAL, PARAMETER, FOR_EACH }; Scope* 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; int value_beg_position = kNoSourcePosition; ExpressionT initializer; }; DeclarationParsingResult() : first_initializer_loc(Scanner::Location::invalid()), bindings_loc(Scanner::Location::invalid()) {} DeclarationDescriptor descriptor; std::vector<Declaration> declarations; Scanner::Location first_initializer_loc; Scanner::Location bindings_loc; }; struct CatchInfo { public: explicit CatchInfo(ParserBase* parser) : name(parser->impl()->NullIdentifier()), pattern(parser->impl()->NullExpression()), scope(nullptr), init_block(parser->impl()->NullStatement()), inner_block(parser->impl()->NullStatement()), bound_names(1, parser->zone()) {} IdentifierT name; ExpressionT pattern; Scope* scope; BlockT init_block; BlockT inner_block; ZonePtrList<const AstRawString> bound_names; }; struct ForInfo { public: explicit ForInfo(ParserBase* parser) : bound_names(1, parser->zone()), mode(ForEachStatement::ENUMERATE), position(kNoSourcePosition), parsing_result() {} ZonePtrList<const AstRawString> bound_names; ForEachStatement::VisitMode mode; int position; DeclarationParsingResult parsing_result; }; struct ClassInfo { public: explicit ClassInfo(ParserBase* parser) : variable(nullptr), extends(parser->impl()->NullExpression()), properties(parser->impl()->NewClassPropertyList(4)), static_fields(parser->impl()->NewClassPropertyList(4)), instance_fields(parser->impl()->NewClassPropertyList(4)), constructor(parser->impl()->NullExpression()), has_seen_constructor(false), has_name_static_property(false), has_static_computed_names(false), has_static_class_fields(false), has_instance_class_fields(false), is_anonymous(false), static_fields_scope(nullptr), instance_fields_scope(nullptr), computed_field_count(0) {} Variable* variable; ExpressionT extends; typename Types::ClassPropertyList properties; typename Types::ClassPropertyList static_fields; typename Types::ClassPropertyList instance_fields; FunctionLiteralT constructor; bool has_seen_constructor; bool has_name_static_property; bool has_static_computed_names; bool has_static_class_fields; bool has_instance_class_fields; bool is_anonymous; DeclarationScope* static_fields_scope; DeclarationScope* instance_fields_scope; int computed_field_count; }; const AstRawString* ClassFieldVariableName(AstValueFactory* ast_value_factory, int index) { std::string name = ".class-field-" + std::to_string(index); return ast_value_factory->GetOneByteString(name.c_str()); } DeclarationScope* NewScriptScope() const { return new (zone()) DeclarationScope(zone(), ast_value_factory()); } DeclarationScope* NewVarblockScope() const { return new (zone()) DeclarationScope(zone(), scope(), BLOCK_SCOPE); } ModuleScope* NewModuleScope(DeclarationScope* parent) const { return new (zone()) ModuleScope(parent, ast_value_factory()); } DeclarationScope* NewEvalScope(Scope* parent) const { return new (zone()) DeclarationScope(zone(), parent, EVAL_SCOPE); } Scope* NewScope(ScopeType scope_type) const { return NewScopeWithParent(scope(), scope_type); } // This constructor should only be used when absolutely necessary. Most scopes // should automatically use scope() as parent, and be fine with // NewScope(ScopeType) above. Scope* NewScopeWithParent(Scope* parent, ScopeType scope_type) const { // Must always use the specific constructors for the blacklisted scope // types. DCHECK_NE(FUNCTION_SCOPE, scope_type); DCHECK_NE(SCRIPT_SCOPE, scope_type); DCHECK_NE(MODULE_SCOPE, scope_type); DCHECK_NOT_NULL(parent); return new (zone()) Scope(zone(), parent, scope_type); } // Creates a function scope that always allocates in zone(). The function // scope itself is either allocated in zone() or in target_zone if one is // passed in. DeclarationScope* NewFunctionScope(FunctionKind kind, Zone* target_zone = nullptr) const { DCHECK(ast_value_factory()); if (target_zone == nullptr) target_zone = zone(); DeclarationScope* result = new (target_zone) DeclarationScope(zone(), scope(), FUNCTION_SCOPE, kind); // Record presence of an inner function scope function_state_->RecordFunctionOrEvalCall(); // TODO(verwaest): Move into the DeclarationScope constructor. if (!IsArrowFunction(kind)) { 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; } int peek_position() const { return scanner_->peek_location().beg_pos; } bool stack_overflow() const { return pending_error_handler()->stack_overflow(); } void set_stack_overflow() { pending_error_handler()->set_stack_overflow(); } int script_id() { return script_id_; } void set_script_id(int id) { script_id_ = id; } V8_INLINE Token::Value peek() { if (stack_overflow()) return Token::ILLEGAL; return scanner()->peek(); } // Returns the position past the following semicolon (if it exists), and the // position past the end of the current token otherwise. int PositionAfterSemicolon() { return (peek() == Token::SEMICOLON) ? scanner_->peek_location().end_pos : scanner_->location().end_pos; } V8_INLINE Token::Value PeekAhead() { if (stack_overflow()) return Token::ILLEGAL; return scanner()->PeekAhead(); } V8_INLINE Token::Value Next() { if (stack_overflow()) return Token::ILLEGAL; { if (GetCurrentStackPosition() < stack_limit_) { // Any further calls to Next or peek will return the illegal token. // The current call must return the next token, which might already // have been peek'ed. set_stack_overflow(); } } return scanner()->Next(); } void Consume(Token::Value token) { Token::Value next = Next(); USE(next); USE(token); DCHECK(next == token); } bool Check(Token::Value token) { Token::Value next = peek(); if (next == token) { Consume(next); return true; } return false; } void Expect(Token::Value token, bool* ok) { Token::Value next = Next(); if (next != token) { ReportUnexpectedToken(next); *ok = false; } } void ExpectSemicolon(bool* ok) { // Check for automatic semicolon insertion according to // the rules given in ECMA-262, section 7.9, page 21. Token::Value tok = peek(); if (tok == Token::SEMICOLON) { Next(); return; } if (scanner()->HasLineTerminatorBeforeNext() || tok == Token::RBRACE || tok == Token::EOS) { return; } Token::Value current = scanner()->current_token(); Scanner::Location current_location = scanner()->location(); Token::Value next = Next(); if (next == Token::SEMICOLON) { return; } *ok = false; if (current == Token::AWAIT && !is_async_function()) { ReportMessageAt(current_location, MessageTemplate::kAwaitNotInAsyncFunction, kSyntaxError); return; } ReportUnexpectedToken(next); } // Dummy functions, just useful as arguments to CHECK_OK_CUSTOM. static void Void() {} template <typename T> static T Return(T result) { return result; } bool is_any_identifier(Token::Value token) { return token == Token::IDENTIFIER || token == Token::ENUM || token == Token::AWAIT || token == Token::ASYNC || token == Token::ESCAPED_STRICT_RESERVED_WORD || token == Token::FUTURE_STRICT_RESERVED_WORD || token == Token::LET || token == Token::STATIC || token == Token::YIELD; } bool peek_any_identifier() { return is_any_identifier(peek()); } bool CheckContextualKeyword(Token::Value token) { if (PeekContextualKeyword(token)) { Consume(Token::IDENTIFIER); return true; } return false; } bool PeekContextualKeyword(Token::Value token) { DCHECK(Token::IsContextualKeyword(token)); return peek() == Token::IDENTIFIER && scanner()->next_contextual_token() == token; } void ExpectMetaProperty(Token::Value property_name, const char* full_name, int pos, bool* ok); void ExpectContextualKeyword(Token::Value token, bool* ok) { DCHECK(Token::IsContextualKeyword(token)); Expect(Token::IDENTIFIER, CHECK_OK_CUSTOM(Void)); if (scanner()->current_contextual_token() != token) { ReportUnexpectedToken(scanner()->current_token()); *ok = false; } } bool CheckInOrOf(ForEachStatement::VisitMode* visit_mode) { if (Check(Token::IN)) { *visit_mode = ForEachStatement::ENUMERATE; return true; } else if (CheckContextualKeyword(Token::OF)) { *visit_mode = ForEachStatement::ITERATE; return true; } return false; } bool PeekInOrOf() { return peek() == Token::IN || PeekContextualKeyword(Token::OF); } // Checks whether an octal literal was last seen between beg_pos and end_pos. // Only called for strict mode strings. void CheckStrictOctalLiteral(int beg_pos, int end_pos, bool* ok) { Scanner::Location octal = scanner()->octal_position(); if (octal.IsValid() && beg_pos <= octal.beg_pos && octal.end_pos <= end_pos) { MessageTemplate::Template message = scanner()->octal_message(); DCHECK_NE(message, MessageTemplate::kNone); impl()->ReportMessageAt(octal, message); scanner()->clear_octal_position(); if (message == MessageTemplate::kStrictDecimalWithLeadingZero) { impl()->CountUsage(v8::Isolate::kDecimalWithLeadingZeroInStrictMode); } *ok = false; } } // Checks if an octal literal or an invalid hex or unicode escape sequence // appears in the current template literal token. In the presence of such, // either returns false or reports an error, depending on should_throw. // Otherwise returns true. inline bool CheckTemplateEscapes(bool should_throw, bool* ok) { DCHECK(scanner()->current_token() == Token::TEMPLATE_SPAN || scanner()->current_token() == Token::TEMPLATE_TAIL); if (!scanner()->has_invalid_template_escape()) { return true; } // Handle error case(s) if (should_throw) { impl()->ReportMessageAt(scanner()->invalid_template_escape_location(), scanner()->invalid_template_escape_message()); *ok = false; } return false; } 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. void CheckFunctionName(LanguageMode language_mode, IdentifierT function_name, FunctionNameValidity function_name_validity, const Scanner::Location& function_name_loc, bool* ok) { if (impl()->IsNull(function_name)) return; if (function_name_validity == kSkipFunctionNameCheck) return; // The function name needs to be checked in strict mode. if (is_sloppy(language_mode)) return; if (impl()->IsEvalOrArguments(function_name)) { impl()->ReportMessageAt(function_name_loc, MessageTemplate::kStrictEvalArguments); *ok = false; return; } if (function_name_validity == kFunctionNameIsStrictReserved) { impl()->ReportMessageAt(function_name_loc, MessageTemplate::kUnexpectedStrictReserved); *ok = false; return; } } // Determine precedence of given token. static int Precedence(Token::Value token, bool accept_IN) { if (token == Token::IN && !accept_IN) return 0; // 0 precedence will terminate binary expression parsing return Token::Precedence(token); } typename Types::Factory* factory() { return &ast_node_factory_; } DeclarationScope* GetReceiverScope() const { return scope()->GetReceiverScope(); } LanguageMode language_mode() { return scope()->language_mode(); } 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 IsAsyncFunction(function_state_->kind()); } bool is_async_generator() const { return IsAsyncGeneratorFunction(function_state_->kind()); } bool is_resumable() const { return IsResumableFunction(function_state_->kind()); } const PendingCompilationErrorHandler* pending_error_handler() const { return pending_error_handler_; } PendingCompilationErrorHandler* pending_error_handler() { return pending_error_handler_; } // Report syntax errors. void ReportMessage(MessageTemplate::Template message) { Scanner::Location source_location = scanner()->location(); impl()->ReportMessageAt(source_location, message, static_cast<const char*>(nullptr), kSyntaxError); } template <typename T> void ReportMessage(MessageTemplate::Template message, T arg, ParseErrorType error_type = kSyntaxError) { Scanner::Location source_location = scanner()->location(); impl()->ReportMessageAt(source_location, message, arg, error_type); } void ReportMessageAt(Scanner::Location location, MessageTemplate::Template message, ParseErrorType error_type) { impl()->ReportMessageAt(location, message, static_cast<const char*>(nullptr), error_type); } void GetUnexpectedTokenMessage( Token::Value token, MessageTemplate::Template* message, Scanner::Location* location, const char** arg, MessageTemplate::Template default_ = MessageTemplate::kUnexpectedToken); void ReportUnexpectedToken(Token::Value token); void ReportUnexpectedTokenAt( Scanner::Location location, Token::Value token, MessageTemplate::Template message = MessageTemplate::kUnexpectedToken); void ReportClassifierError( const typename ExpressionClassifier::Error& error) { impl()->ReportMessageAt(error.location, error.message, error.arg); } void ValidateExpression(bool* ok) { if (!classifier()->is_valid_expression()) { ReportClassifierError(classifier()->expression_error()); *ok = false; } } void ValidateFormalParameterInitializer(bool* ok) { if (!classifier()->is_valid_formal_parameter_initializer()) { ReportClassifierError(classifier()->formal_parameter_initializer_error()); *ok = false; } } void ValidateBindingPattern(bool* ok) { if (!classifier()->is_valid_binding_pattern()) { ReportClassifierError(classifier()->binding_pattern_error()); *ok = false; } } void ValidateAssignmentPattern(bool* ok) { if (!classifier()->is_valid_assignment_pattern()) { ReportClassifierError(classifier()->assignment_pattern_error()); *ok = false; } } void ValidateFormalParameters(LanguageMode language_mode, bool allow_duplicates, bool* ok) { if (!allow_duplicates && !classifier()->is_valid_formal_parameter_list_without_duplicates()) { ReportClassifierError(classifier()->duplicate_formal_parameter_error()); *ok = false; } else if (is_strict(language_mode) && !classifier()->is_valid_strict_mode_formal_parameters()) { ReportClassifierError(classifier()->strict_mode_formal_parameter_error()); *ok = false; } } bool IsValidArrowFormalParametersStart(Token::Value token) { return is_any_identifier(token) || token == Token::LPAREN; } void ValidateArrowFormalParameters(ExpressionT expr, bool parenthesized_formals, bool is_async, bool* ok) { if (classifier()->is_valid_binding_pattern()) { // A simple arrow formal parameter: IDENTIFIER => BODY. if (!impl()->IsIdentifier(expr)) { impl()->ReportMessageAt(scanner()->location(), MessageTemplate::kUnexpectedToken, Token::String(scanner()->current_token())); *ok = false; } } else if (!classifier()->is_valid_arrow_formal_parameters()) { // If after parsing the expr, we see an error but the expression is // neither a valid binding pattern nor a valid parenthesized formal // parameter list, show the "arrow formal parameters" error if the formals // started with a parenthesis, and the binding pattern error otherwise. const typename ExpressionClassifier::Error& error = parenthesized_formals ? classifier()->arrow_formal_parameters_error() : classifier()->binding_pattern_error(); ReportClassifierError(error); *ok = false; } if (is_async && !classifier()->is_valid_async_arrow_formal_parameters()) { const typename ExpressionClassifier::Error& error = classifier()->async_arrow_formal_parameters_error(); ReportClassifierError(error); *ok = false; } } void ValidateLetPattern(bool* ok) { if (!classifier()->is_valid_let_pattern()) { ReportClassifierError(classifier()->let_pattern_error()); *ok = false; } } void BindingPatternUnexpectedToken() { MessageTemplate::Template message = MessageTemplate::kUnexpectedToken; const char* arg; Scanner::Location location = scanner()->peek_location(); GetUnexpectedTokenMessage(peek(), &message, &location, &arg); classifier()->RecordBindingPatternError(location, message, arg); } void ArrowFormalParametersUnexpectedToken() { MessageTemplate::Template message = MessageTemplate::kUnexpectedToken; const char* arg; Scanner::Location location = scanner()->peek_location(); GetUnexpectedTokenMessage(peek(), &message, &location, &arg); classifier()->RecordArrowFormalParametersError(location, message, arg); } // Recursive descent functions. // All ParseXXX functions take as the last argument an *ok parameter // which is set to false if parsing failed; it is unchanged otherwise. // By making the 'exception handling' explicit, we are forced to check // for failure at the call sites. The family of CHECK_OK* macros can // be useful for this. // Parses an identifier that is valid for the current scope, in particular it // fails on strict mode future reserved keywords in a strict scope. If // allow_eval_or_arguments is kAllowEvalOrArguments, we allow "eval" or // "arguments" as identifier even in strict mode (this is needed in cases like // "var foo = eval;"). IdentifierT ParseIdentifier(AllowRestrictedIdentifiers, bool* ok); IdentifierT ParseAndClassifyIdentifier(bool* ok); // Parses an identifier or a strict mode future reserved word, and indicate // whether it is strict mode future reserved. Allows passing in function_kind // for the case of parsing the identifier in a function expression, where the // relevant "function_kind" bit is of the function being parsed, not the // containing function. IdentifierT ParseIdentifierOrStrictReservedWord(FunctionKind function_kind, bool* is_strict_reserved, bool* is_await, bool* ok); IdentifierT ParseIdentifierOrStrictReservedWord(bool* is_strict_reserved, bool* is_await, bool* ok) { return ParseIdentifierOrStrictReservedWord( function_state_->kind(), is_strict_reserved, is_await, ok); } V8_INLINE IdentifierT ParseIdentifierName(bool* ok); ExpressionT ParseIdentifierNameOrPrivateName(bool* ok); ExpressionT ParseRegExpLiteral(bool* ok); ExpressionT ParsePrimaryExpression(bool* is_async, bool* ok); ExpressionT ParsePrimaryExpression(bool* ok) { bool is_async; return ParsePrimaryExpression(&is_async, ok); } // Use when parsing an expression that is known to not be a pattern or part // of a pattern. 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, kSpreadProperty, 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, ClassInfo* class_info, IdentifierT* property_name, bool has_extends, bool* is_computed_name, ClassLiteralProperty::Kind* property_kind, bool* is_static, bool* ok); ExpressionT ParseClassFieldInitializer(ClassInfo* class_info, bool is_static, bool* ok); ObjectLiteralPropertyT ParseObjectPropertyDefinition( ObjectLiteralChecker* checker, bool* is_computed_name, bool* is_rest_property, bool* ok); ExpressionListT ParseArguments(Scanner::Location* first_spread_pos, bool maybe_arrow, bool* is_simple_parameter_list, bool* ok); ExpressionListT ParseArguments(Scanner::Location* first_spread_pos, bool* ok) { return ParseArguments(first_spread_pos, false, nullptr, ok); } ExpressionT ParseAssignmentExpression(bool accept_IN, bool* ok); ExpressionT ParseYieldExpression(bool accept_IN, bool* ok); V8_INLINE ExpressionT ParseConditionalExpression(bool accept_IN, bool* ok); ExpressionT ParseBinaryExpression(int prec, bool accept_IN, bool* ok); ExpressionT ParseUnaryExpression(bool* ok); V8_INLINE ExpressionT ParsePostfixExpression(bool* ok); V8_INLINE ExpressionT ParseLeftHandSideExpression(bool* ok); ExpressionT ParseMemberWithNewPrefixesExpression(bool* is_async, bool* ok); V8_INLINE ExpressionT ParseMemberExpression(bool* is_async, bool* ok); V8_INLINE ExpressionT ParseMemberExpressionContinuation( ExpressionT expression, bool* is_async, bool* ok); // `rewritable_length`: length of the destructuring_assignments_to_rewrite() // queue in the parent function state, prior to parsing of formal parameters. // If the arrow function is lazy, any items added during formal parameter // parsing are removed from the queue. ExpressionT ParseArrowFunctionLiteral(bool accept_IN, const FormalParametersT& parameters, int rewritable_length, bool* ok); void ParseSingleExpressionFunctionBody(StatementListT body, bool is_async, bool accept_IN, bool* ok); void ParseAsyncFunctionBody(Scope* scope, StatementListT body, 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 tagged, bool* ok); ExpressionT ParseSuperExpression(bool is_new, bool* ok); ExpressionT ParseImportExpressions(bool* ok); ExpressionT ParseNewTargetExpression(bool* ok); V8_INLINE void ParseFormalParameter(FormalParametersT* parameters, bool* ok); void ParseFormalParameterList(FormalParametersT* parameters, bool* ok); 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, ZonePtrList<const AstRawString>* names, bool* ok); StatementT ParseAsyncFunctionDeclaration( ZonePtrList<const AstRawString>* names, bool default_export, bool* ok); StatementT ParseFunctionDeclaration(bool* ok); StatementT ParseHoistableDeclaration(ZonePtrList<const AstRawString>* names, bool default_export, bool* ok); StatementT ParseHoistableDeclaration(int pos, ParseFunctionFlags flags, ZonePtrList<const AstRawString>* names, bool default_export, bool* ok); StatementT ParseClassDeclaration(ZonePtrList<const AstRawString>* names, bool default_export, bool* ok); StatementT ParseNativeDeclaration(bool* ok); // Consumes the ending }. void ParseFunctionBody(StatementListT result, IdentifierT function_name, int pos, const FormalParametersT& parameters, FunctionKind kind, FunctionLiteral::FunctionType function_type, 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, Token::Value end_token, bool* ok) { LazyParsingResult result = ParseStatementList(body, end_token, false, ok); USE(result); DCHECK_EQ(result, kLazyParsingComplete); } V8_INLINE LazyParsingResult ParseStatementList(StatementListT body, Token::Value end_token, bool may_abort, bool* ok); StatementT ParseStatementListItem(bool* ok); StatementT ParseStatement(ZonePtrList<const AstRawString>* labels, ZonePtrList<const AstRawString>* own_labels, bool* ok) { return ParseStatement(labels, own_labels, kDisallowLabelledFunctionStatement, ok); } StatementT ParseStatement(ZonePtrList<const AstRawString>* labels, ZonePtrList<const AstRawString>* own_labels, AllowLabelledFunctionStatement allow_function, bool* ok); BlockT ParseBlock(ZonePtrList<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 StatementT ParseScopedStatement(ZonePtrList<const AstRawString>* labels, bool* ok); StatementT ParseVariableStatement(VariableDeclarationContext var_context, ZonePtrList<const AstRawString>* names, bool* ok); // Magical syntax support. ExpressionT ParseV8Intrinsic(bool* ok); ExpressionT ParseDoExpression(bool* ok); StatementT ParseDebuggerStatement(bool* ok); StatementT ParseExpressionOrLabelledStatement( ZonePtrList<const AstRawString>* labels, ZonePtrList<const AstRawString>* own_labels, AllowLabelledFunctionStatement allow_function, bool* ok); StatementT ParseIfStatement(ZonePtrList<const AstRawString>* labels, bool* ok); StatementT ParseContinueStatement(bool* ok); StatementT ParseBreakStatement(ZonePtrList<const AstRawString>* labels, bool* ok); StatementT ParseReturnStatement(bool* ok); StatementT ParseWithStatement(ZonePtrList<const AstRawString>* labels, bool* ok); StatementT ParseDoWhileStatement(ZonePtrList<const AstRawString>* labels, ZonePtrList<const AstRawString>* own_labels, bool* ok); StatementT ParseWhileStatement(ZonePtrList<const AstRawString>* labels, ZonePtrList<const AstRawString>* own_labels, bool* ok); StatementT ParseThrowStatement(bool* ok); StatementT ParseSwitchStatement(ZonePtrList<const AstRawString>* labels, bool* ok); V8_INLINE StatementT ParseTryStatement(bool* ok); StatementT ParseForStatement(ZonePtrList<const AstRawString>* labels, ZonePtrList<const AstRawString>* own_labels, bool* ok); StatementT ParseForEachStatementWithDeclarations( int stmt_pos, ForInfo* for_info, ZonePtrList<const AstRawString>* labels, ZonePtrList<const AstRawString>* own_labels, Scope* inner_block_scope, bool* ok); StatementT ParseForEachStatementWithoutDeclarations( int stmt_pos, ExpressionT expression, int lhs_beg_pos, int lhs_end_pos, ForInfo* for_info, ZonePtrList<const AstRawString>* labels, ZonePtrList<const AstRawString>* own_labels, bool* ok); // Parse a C-style for loop: 'for (<init>; <cond>; <next>) { ... }' // "for (<init>;" is assumed to have been parser already. ForStatementT ParseStandardForLoop( int stmt_pos, ZonePtrList<const AstRawString>* labels, ZonePtrList<const AstRawString>* own_labels, ExpressionT* cond, StatementT* next, StatementT* body, bool* ok); // Same as the above, but handles those cases where <init> is a // lexical variable declaration. StatementT ParseStandardForLoopWithLexicalDeclarations( int stmt_pos, StatementT init, ForInfo* for_info, ZonePtrList<const AstRawString>* labels, ZonePtrList<const AstRawString>* own_labels, bool* ok); StatementT ParseForAwaitStatement(ZonePtrList<const AstRawString>* labels, ZonePtrList<const AstRawString>* own_labels, bool* ok); bool IsNextLetKeyword(); bool IsTrivialExpression(); // Checks if the expression is a valid reference expression (e.g., on the // left-hand side of assignments). Although ruled out by ECMA as early errors, // we allow calls for web compatibility and rewrite them to a runtime throw. ExpressionT CheckAndRewriteReferenceExpression( ExpressionT expression, int beg_pos, int end_pos, MessageTemplate::Template message, bool* ok); ExpressionT CheckAndRewriteReferenceExpression( ExpressionT expression, int beg_pos, int end_pos, MessageTemplate::Template message, ParseErrorType type, bool* ok); bool IsValidReferenceExpression(ExpressionT expression); bool IsAssignableIdentifier(ExpressionT expression) { if (!impl()->IsIdentifier(expression)) return false; if (is_strict(language_mode()) && impl()->IsEvalOrArguments(impl()->AsIdentifier(expression))) { return false; } return true; } bool IsValidPattern(ExpressionT expression) { return expression->IsObjectLiteral() || expression->IsArrayLiteral(); } // Due to hoisting, the value of a 'var'-declared variable may actually change // even if the code contains only the "initial" assignment, namely when that // assignment occurs inside a loop. For example: // // let i = 10; // do { var x = i } while (i--): // // As a simple and very conservative approximation of this, we explicitly mark // as maybe-assigned any non-lexical variable whose initializing "declaration" // does not syntactically occur in the function scope. (In the example above, // it occurs in a block scope.) // // Note that non-lexical variables include temporaries, which may also get // assigned inside a loop due to the various rewritings that the parser // performs. // // This also handles marking of loop variables in for-in and for-of loops, // as determined by declaration_kind. // static void MarkLoopVariableAsAssigned( Scope* scope, Variable* var, typename DeclarationDescriptor::Kind declaration_kind); FunctionKind FunctionKindForImpl(bool is_method, bool is_generator, bool is_async) { static const FunctionKind kFunctionKinds[][2][2] = { { // is_method=false {// is_generator=false FunctionKind::kNormalFunction, FunctionKind::kAsyncFunction}, {// is_generator=true FunctionKind::kGeneratorFunction, FunctionKind::kAsyncGeneratorFunction}, }, { // is_method=true {// is_generator=false FunctionKind::kConciseMethod, FunctionKind::kAsyncConciseMethod}, {// is_generator=true FunctionKind::kConciseGeneratorMethod, FunctionKind::kAsyncConciseGeneratorMethod}, }}; return kFunctionKinds[is_method][is_generator][is_async]; } inline FunctionKind FunctionKindFor(bool is_generator, bool is_async) { const bool kIsMethod = false; return FunctionKindForImpl(kIsMethod, is_generator, is_async); } inline FunctionKind MethodKindFor(bool is_generator, bool is_async) { const bool kIsMethod = true; return FunctionKindForImpl(kIsMethod, is_generator, is_async); } // Keep track of eval() calls since they disable all local variable // optimizations. This checks if expression is an eval call, and if yes, // forwards the information to scope. Call::PossiblyEval CheckPossibleEvalCall(ExpressionT expression, Scope* scope) { if (impl()->IsIdentifier(expression) && impl()->IsEval(impl()->AsIdentifier(expression))) { scope->RecordInnerScopeEvalCall(); function_state_->RecordFunctionOrEvalCall(); if (is_sloppy(scope->language_mode())) { // For sloppy scopes we also have to record the call at function level, // in case it includes declarations that will be hoisted. scope->GetDeclarationScope()->RecordEvalCall(); } // This call is only necessary to track evals that may be // inside arrow function parameter lists. In that case, // Scope::Snapshot::Reparent will move this bit down into // the arrow function's scope. scope->RecordEvalCall(); return Call::IS_POSSIBLY_EVAL; } return Call::NOT_EVAL; } // Convenience method which determines the type of return statement to emit // depending on the current function type. inline StatementT BuildReturnStatement(ExpressionT expr, int pos, int end_pos = kNoSourcePosition) { if (impl()->IsNull(expr)) { expr = factory()->NewUndefinedLiteral(kNoSourcePosition); } else if (is_async_generator()) { // In async generators, if there is an explicit operand to the return // statement, await the operand. expr = factory()->NewAwait(expr, kNoSourcePosition); function_state_->AddSuspend(); } if (is_async_function()) { return factory()->NewAsyncReturnStatement(expr, pos, end_pos); } return factory()->NewReturnStatement(expr, pos, end_pos); } // Validation per ES6 object literals. class ObjectLiteralChecker { public: explicit ObjectLiteralChecker(ParserBase* parser) : parser_(parser), has_seen_proto_(false) {} void CheckDuplicateProto(Token::Value property); private: bool IsProto() const { return this->scanner()->CurrentMatchesContextualEscaped( Token::PROTO_UNDERSCORED); } 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: explicit ClassLiteralChecker(ParserBase* parser) : parser_(parser), has_seen_constructor_(false) {} void CheckClassMethodName(Token::Value property, PropertyKind type, bool is_generator, bool is_async, bool is_static, bool* ok); void CheckClassFieldName(bool is_static, bool* ok); private: bool IsConstructor() { return this->scanner()->CurrentMatchesContextualEscaped( Token::CONSTRUCTOR); } bool IsPrivateConstructor() { return this->scanner()->CurrentMatchesContextualEscaped( Token::PRIVATE_CONSTRUCTOR); } bool IsPrototype() { return this->scanner()->CurrentMatchesContextualEscaped(Token::PROTOTYPE); } ParserBase* parser() const { return parser_; } Scanner* scanner() const { return parser_->scanner(); } ParserBase* parser_; bool has_seen_constructor_; }; ModuleDescriptor* module() const { return scope()->AsModuleScope()->module(); } Scope* scope() const { return scope_; } // Stack of expression classifiers. // The top of the stack is always pointed to by classifier(). V8_INLINE ExpressionClassifier* classifier() const { DCHECK_NOT_NULL(classifier_); return classifier_; } // Accumulates the classifier that is on top of the stack (inner) to // the one that is right below (outer) and pops the inner. V8_INLINE void Accumulate(unsigned productions) { DCHECK_NOT_NULL(classifier_); ExpressionClassifier* previous = classifier_->previous(); DCHECK_NOT_NULL(previous); previous->Accumulate(classifier_, productions); classifier_ = previous; } V8_INLINE void AccumulateNonBindingPatternErrors() { this->Accumulate(ExpressionClassifier::AllProductions & ~(ExpressionClassifier::BindingPatternProduction | ExpressionClassifier::LetPatternProduction)); } // Pops and discards the classifier that is on top of the stack // without accumulating. V8_INLINE void DiscardExpressionClassifier() { DCHECK_NOT_NULL(classifier_); classifier_->Discard(); classifier_ = classifier_->previous(); } // 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. Scope* scope_; // Scope stack. Scope* original_scope_; // The top scope for the current parsing item. FunctionState* function_state_; // Function state stack. v8::Extension* extension_; FuncNameInferrer* fni_; AstValueFactory* ast_value_factory_; // Not owned. typename Types::Factory ast_node_factory_; RuntimeCallStats* runtime_call_stats_; internal::Logger* logger_; bool parsing_on_main_thread_; const bool parsing_module_; uintptr_t stack_limit_; PendingCompilationErrorHandler* pending_error_handler_; // Parser base's private field members. private: Zone* zone_; ExpressionClassifier* classifier_; Scanner* scanner_; FunctionLiteral::EagerCompileHint default_eager_compile_hint_; int function_literal_id_; int script_id_; bool allow_natives_; bool allow_harmony_do_expressions_; bool allow_harmony_public_fields_; bool allow_harmony_static_fields_; bool allow_harmony_dynamic_import_; bool allow_harmony_import_meta_; bool allow_harmony_private_fields_; bool allow_eval_cache_; friend class DiscardableZoneScope; }; template <typename Impl> ParserBase<Impl>::FunctionState::FunctionState( FunctionState** function_state_stack, Scope** scope_stack, DeclarationScope* scope) : BlockState(scope_stack, scope), expected_property_count_(0), suspend_count_(0), function_state_stack_(function_state_stack), outer_function_state_(*function_state_stack), scope_(scope), destructuring_assignments_to_rewrite_(scope->zone()), reported_errors_(scope_->zone()), dont_optimize_reason_(BailoutReason::kNoReason), next_function_is_likely_called_(false), previous_function_was_likely_called_(false), contains_function_or_eval_(false) { *function_state_stack = this; reported_errors_.reserve(16); if (outer_function_state_) { outer_function_state_->previous_function_was_likely_called_ = outer_function_state_->next_function_is_likely_called_; outer_function_state_->next_function_is_likely_called_ = false; } } template <typename Impl> ParserBase<Impl>::FunctionState::~FunctionState() { *function_state_stack_ = outer_function_state_; } template <typename Impl> void ParserBase<Impl>::GetUnexpectedTokenMessage( Token::Value token, MessageTemplate::Template* message, Scanner::Location* location, const char** arg, MessageTemplate::Template default_) { *arg = nullptr; switch (token) { case Token::EOS: *message = MessageTemplate::kUnexpectedEOS; break; case Token::SMI: case Token::NUMBER: case Token::BIGINT: *message = MessageTemplate::kUnexpectedTokenNumber; break; case Token::STRING: *message = MessageTemplate::kUnexpectedTokenString; break; case Token::PRIVATE_NAME: case Token::IDENTIFIER: *message = MessageTemplate::kUnexpectedTokenIdentifier; break; case Token::AWAIT: case Token::ENUM: *message = MessageTemplate::kUnexpectedReserved; break; case Token::LET: case Token::STATIC: case Token::YIELD: case Token::FUTURE_STRICT_RESERVED_WORD: *message = is_strict(language_mode()) ? MessageTemplate::kUnexpectedStrictReserved : MessageTemplate::kUnexpectedTokenIdentifier; break; case Token::TEMPLATE_SPAN: case Token::TEMPLATE_TAIL: *message = MessageTemplate::kUnexpectedTemplateString; break; case Token::ESCAPED_STRICT_RESERVED_WORD: case Token::ESCAPED_KEYWORD: *message = MessageTemplate::kInvalidEscapedReservedWord; break; case Token::ILLEGAL: if (scanner()->has_error()) { *message = scanner()->error(); *location = scanner()->error_location(); } else { *message = MessageTemplate::kInvalidOrUnexpectedToken; } break; case Token::REGEXP_LITERAL: *message = MessageTemplate::kUnexpectedTokenRegExp; break; default: const char* name = Token::String(token); DCHECK_NOT_NULL(name); *arg = name; break; } } template <typename Impl> void ParserBase<Impl>::ReportUnexpectedToken(Token::Value token) { return ReportUnexpectedTokenAt(scanner_->location(), token); } template <typename Impl> void ParserBase<Impl>::ReportUnexpectedTokenAt( Scanner::Location source_location, Token::Value token, MessageTemplate::Template message) { const char* arg; GetUnexpectedTokenMessage(token, &message, &source_location, &arg); impl()->ReportMessageAt(source_location, message, arg); } template <typename Impl> typename ParserBase<Impl>::IdentifierT ParserBase<Impl>::ParseIdentifier( AllowRestrictedIdentifiers allow_restricted_identifiers, bool* ok) { ExpressionClassifier classifier(this); auto result = ParseAndClassifyIdentifier(CHECK_OK_CUSTOM(NullIdentifier)); if (allow_restricted_identifiers == kDontAllowRestrictedIdentifiers) { ValidateAssignmentPattern(CHECK_OK_CUSTOM(NullIdentifier)); ValidateBindingPattern(CHECK_OK_CUSTOM(NullIdentifier)); } return result; } template <typename Impl> typename ParserBase<Impl>::IdentifierT 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 = impl()->GetSymbol(); if (impl()->IsArguments(name) && scope()->ShouldBanArguments()) { ReportMessage(MessageTemplate::kArgumentsDisallowedInInitializer); *ok = false; return impl()->NullIdentifier(); } // When this function is used to read a formal parameter, we don't always // know whether the function is going to be strict or sloppy. Indeed for // arrow functions we don't always know that the identifier we are reading // is actually a formal parameter. Therefore besides the errors that we // must detect because we know we're in strict mode, we also record any // error that we might make in the future once we know the language mode. if (impl()->IsEvalOrArguments(name)) { classifier()->RecordStrictModeFormalParameterError( scanner()->location(), MessageTemplate::kStrictEvalArguments); if (is_strict(language_mode())) { classifier()->RecordBindingPatternError( scanner()->location(), MessageTemplate::kStrictEvalArguments); } } else if (next == Token::AWAIT) { classifier()->RecordAsyncArrowFormalParametersError( scanner()->location(), MessageTemplate::kAwaitBindingIdentifier); } if (classifier()->duplicate_finder() != nullptr && scanner()->IsDuplicateSymbol(classifier()->duplicate_finder(), ast_value_factory())) { classifier()->RecordDuplicateFormalParameterError(scanner()->location()); } return name; } else if (is_sloppy(language_mode()) && (next == Token::FUTURE_STRICT_RESERVED_WORD || next == Token::ESCAPED_STRICT_RESERVED_WORD || next == Token::LET || next == Token::STATIC || (next == Token::YIELD && !is_generator()))) { classifier()->RecordStrictModeFormalParameterError( scanner()->location(), MessageTemplate::kUnexpectedStrictReserved); if (next == Token::ESCAPED_STRICT_RESERVED_WORD && is_strict(language_mode())) { ReportUnexpectedToken(next); *ok = false; return impl()->NullIdentifier(); } if (scanner()->IsLet()) { classifier()->RecordLetPatternError( scanner()->location(), MessageTemplate::kLetInLexicalBinding); } return impl()->GetSymbol(); } else { ReportUnexpectedToken(next); *ok = false; return impl()->NullIdentifier(); } } template <class Impl> typename ParserBase<Impl>::IdentifierT ParserBase<Impl>::ParseIdentifierOrStrictReservedWord( FunctionKind function_kind, bool* is_strict_reserved, bool* is_await, bool* ok) { Token::Value next = Next(); if (next == Token::IDENTIFIER || (next == Token::AWAIT && !parsing_module_ && !IsAsyncFunction(function_kind)) || next == Token::ASYNC) { *is_strict_reserved = false; *is_await = next == Token::AWAIT; } else if (next == Token::ESCAPED_STRICT_RESERVED_WORD || next == Token::FUTURE_STRICT_RESERVED_WORD || next == Token::LET || next == Token::STATIC || (next == Token::YIELD && !IsGeneratorFunction(function_kind))) { *is_strict_reserved = true; } else { ReportUnexpectedToken(next); *ok = false; return impl()->NullIdentifier(); } return impl()->GetSymbol(); } template <typename Impl> typename ParserBase<Impl>::IdentifierT ParserBase<Impl>::ParseIdentifierName( bool* ok) { Token::Value next = Next(); if (next != Token::IDENTIFIER && next != Token::ASYNC && next != Token::ENUM && next != Token::AWAIT && next != Token::LET && next != Token::STATIC && next != Token::YIELD && next != Token::FUTURE_STRICT_RESERVED_WORD && next != Token::ESCAPED_KEYWORD && next != Token::ESCAPED_STRICT_RESERVED_WORD && !Token::IsKeyword(next)) { ReportUnexpectedToken(next); *ok = false; return impl()->NullIdentifier(); } return impl()->GetSymbol(); } template <typename Impl> typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseIdentifierNameOrPrivateName(bool* ok) { int pos = position(); IdentifierT name; ExpressionT key; if (allow_harmony_private_fields() && peek() == Token::PRIVATE_NAME) { Consume(Token::PRIVATE_NAME); name = impl()->GetSymbol(); auto key_proxy = impl()->ExpressionFromIdentifier(name, pos, InferName::kNo); key_proxy->set_is_private_field(); key = key_proxy; } else { name = ParseIdentifierName(CHECK_OK); key = factory()->NewStringLiteral(name, pos); } impl()->PushLiteralName(name); return key; } template <typename Impl> typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseRegExpLiteral( bool* ok) { int pos = peek_position(); if (!scanner()->ScanRegExpPattern()) { Next(); ReportMessage(MessageTemplate::kUnterminatedRegExp); *ok = false; return impl()->NullExpression(); } IdentifierT js_pattern = impl()->GetNextSymbol(); Maybe<RegExp::Flags> flags = scanner()->ScanRegExpFlags(); if (flags.IsNothing()) { Next(); ReportMessage(MessageTemplate::kMalformedRegExpFlags); *ok = false; return impl()->NullExpression(); } int js_flags = flags.FromJust(); Next(); return factory()->NewRegExpLiteral(js_pattern, js_flags, pos); } template <typename Impl> typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePrimaryExpression( bool* is_async, bool* ok) { // PrimaryExpression :: // 'this' // 'null' // 'true' // 'false' // Identifier // Number // String // ArrayLiteral // ObjectLiteral // RegExpLiteral // ClassLiteral // '(' Expression ')' // TemplateLiteral // do Block // AsyncFunctionLiteral int beg_pos = peek_position(); switch (peek()) { case Token::THIS: { BindingPatternUnexpectedToken(); Consume(Token::THIS); return impl()->ThisExpression(beg_pos); } case Token::NULL_LITERAL: case Token::TRUE_LITERAL: case Token::FALSE_LITERAL: case Token::SMI: case Token::NUMBER: case Token::BIGINT: BindingPatternUnexpectedToken(); return impl()->ExpressionFromLiteral(Next(), beg_pos); case Token::ASYNC: if (!scanner()->HasLineTerminatorAfterNext() && PeekAhead() == Token::FUNCTION) { BindingPatternUnexpectedToken(); Consume(Token::ASYNC); return ParseAsyncFunctionLiteral(CHECK_OK); } // CoverCallExpressionAndAsyncArrowHead *is_async = true; V8_FALLTHROUGH; case Token::IDENTIFIER: case Token::LET: case Token::STATIC: case Token::YIELD: case Token::AWAIT: 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(CHECK_OK); return impl()->ExpressionFromIdentifier(name, beg_pos); } case Token::STRING: { BindingPatternUnexpectedToken(); Consume(Token::STRING); return impl()->ExpressionFromString(beg_pos); } case Token::ASSIGN_DIV: case Token::DIV: classifier()->RecordBindingPatternError( scanner()->peek_location(), MessageTemplate::kUnexpectedTokenRegExp); return ParseRegExpLiteral(ok); case Token::LBRACK: return ParseArrayLiteral(ok); case Token::LBRACE: return ParseObjectLiteral(ok); case Token::LPAREN: { // Arrow function formal parameters are either a single identifier or a // list of BindingPattern productions enclosed in parentheses. // Parentheses are not valid on the LHS of a BindingPattern, so we use the // is_valid_binding_pattern() check to detect multiple levels of // parenthesization. bool pattern_error = !classifier()->is_valid_binding_pattern(); classifier()->RecordPatternError(scanner()->peek_location(), MessageTemplate::kUnexpectedToken, Token::String(Token::LPAREN)); if (pattern_error) ArrowFormalParametersUnexpectedToken(); Consume(Token::LPAREN); if (Check(Token::RPAREN)) { // ()=>x. The continuation that looks for the => is in // ParseAssignmentExpression. classifier()->RecordExpressionError(scanner()->location(), MessageTemplate::kUnexpectedToken, Token::String(Token::RPAREN)); return factory()->NewEmptyParentheses(beg_pos); } // Heuristically try to detect immediately called functions before // seeing the call parentheses. if (peek() == Token::FUNCTION || (peek() == Token::ASYNC && PeekAhead() == Token::FUNCTION)) { function_state_->set_next_function_is_likely_called(); } ExpressionT expr = ParseExpressionCoverGrammar(true, CHECK_OK); Expect(Token::RPAREN, CHECK_OK); return expr; } case Token::CLASS: { BindingPatternUnexpectedToken(); Consume(Token::CLASS); int class_token_pos = position(); IdentifierT name = impl()->NullIdentifier(); bool is_strict_reserved_name = false; Scanner::Location class_name_location = Scanner::Location::invalid(); if (peek_any_identifier()) { bool is_await = false; name = ParseIdentifierOrStrictReservedWord(&is_strict_reserved_name, &is_await, CHECK_OK); class_name_location = scanner()->location(); if (is_await) { classifier()->RecordAsyncArrowFormalParametersError( scanner()->location(), MessageTemplate::kAwaitBindingIdentifier); } } return ParseClassLiteral(name, class_name_location, is_strict_reserved_name, class_token_pos, ok); } case Token::TEMPLATE_SPAN: case Token::TEMPLATE_TAIL: BindingPatternUnexpectedToken(); return ParseTemplateLiteral(impl()->NullExpression(), beg_pos, false, ok); case Token::MOD: if (allow_natives() || extension_ != nullptr) { BindingPatternUnexpectedToken(); return ParseV8Intrinsic(ok); } break; case Token::DO: if (allow_harmony_do_expressions()) { BindingPatternUnexpectedToken(); return ParseDoExpression(ok); } break; default: break; } ReportUnexpectedToken(Next()); *ok = false; return impl()->NullExpression(); } template <typename Impl> typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseExpression( bool accept_IN, bool* ok) { ExpressionClassifier classifier(this); ExpressionT result = ParseExpressionCoverGrammar(accept_IN, CHECK_OK); ValidateExpression(CHECK_OK); return result; } template <typename Impl> typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseExpressionCoverGrammar(bool accept_IN, bool* ok) { // Expression :: // AssignmentExpression // Expression ',' AssignmentExpression ExpressionT result = impl()->NullExpression(); while (true) { int comma_pos = position(); ExpressionClassifier binding_classifier(this); ExpressionT right; if (Check(Token::ELLIPSIS)) { // 'x, y, ...z' in CoverParenthesizedExpressionAndArrowParameterList only // as the formal parameters of'(x, y, ...z) => foo', and is not itself a // valid expression. classifier()->RecordExpressionError(scanner()->location(), MessageTemplate::kUnexpectedToken, Token::String(Token::ELLIPSIS)); int ellipsis_pos = position(); int pattern_pos = peek_position(); ExpressionT pattern = ParsePrimaryExpression(CHECK_OK); if (peek() == Token::ASSIGN) { ReportMessage(MessageTemplate::kRestDefaultInitializer); *ok = false; return result; } 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. AccumulateNonBindingPatternErrors(); if (!impl()->IsIdentifier(right)) classifier()->RecordNonSimpleParameter(); if (impl()->IsNull(result)) { // First time through the loop. result = right; } else if (impl()->CollapseNaryExpression(&result, right, Token::COMMA, comma_pos, SourceRange::Empty())) { // Do nothing, "result" is already updated. } else { result = factory()->NewBinaryOperation(Token::COMMA, result, right, comma_pos); } if (!Check(Token::COMMA)) break; if (right->IsSpread()) { classifier()->RecordArrowFormalParametersError( scanner()->location(), MessageTemplate::kParamAfterRest); } if (peek() == Token::RPAREN && PeekAhead() == Token::ARROW) { // a trailing comma is allowed at the end of an arrow parameter list break; } // Pass on the 'set_next_function_is_likely_called' flag if we have // several function literals separated by comma. if (peek() == Token::FUNCTION && function_state_->previous_function_was_likely_called()) { function_state_->set_next_function_is_likely_called(); } } return result; } template <typename Impl> typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseArrayLiteral( bool* ok) { // ArrayLiteral :: // '[' Expression? (',' Expression?)* ']' int pos = peek_position(); 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 = factory()->NewTheHoleLiteral(); } else if (peek() == Token::ELLIPSIS) { int start_pos = peek_position(); Consume(Token::ELLIPSIS); int expr_pos = peek_position(); ExpressionT argument = ParseAssignmentExpression(true, CHECK_OK); elem = factory()->NewSpread(argument, start_pos, expr_pos); if (first_spread_index < 0) { first_spread_index = values->length(); } if (argument->IsAssignment()) { classifier()->RecordPatternError( Scanner::Location(start_pos, scanner()->location().end_pos), MessageTemplate::kInvalidDestructuringTarget); } else { CheckDestructuringElement(argument, start_pos, scanner()->location().end_pos); } if (peek() == Token::COMMA) { classifier()->RecordPatternError( Scanner::Location(start_pos, scanner()->location().end_pos), MessageTemplate::kElementAfterRest); } } else { int beg_pos = peek_position(); elem = ParseAssignmentExpression(true, CHECK_OK); CheckDestructuringElement(elem, beg_pos, scanner()->location().end_pos); } values->Add(elem, zone_); if (peek() != Token::RBRACK) { Expect(Token::COMMA, CHECK_OK); } } Expect(Token::RBRACK, CHECK_OK); return factory()->NewArrayLiteral(values, first_spread_index, pos); } 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; case Token::PRIVATE_NAME: *kind = PropertyKind::kClassField; return true; default: break; } return false; } template <class Impl> typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePropertyName( IdentifierT* name, PropertyKind* kind, bool* is_generator, bool* is_get, bool* is_set, bool* is_async, bool* is_computed_name, bool* ok) { DCHECK_EQ(*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 (!*is_generator && token == Token::ASYNC && !scanner()->HasLineTerminatorAfterNext()) { Consume(Token::ASYNC); token = peek(); if (token == Token::MUL && !scanner()->HasLineTerminatorBeforeNext()) { Consume(Token::MUL); token = peek(); *is_generator = true; } else 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 // 12.3 -> "12.3" // 12.30 -> "12.3" // identifier -> "identifier" // // This is important because we use the property name as a key in a hash // table when we compute constant properties. ExpressionT expression = impl()->NullExpression(); switch (token) { case Token::STRING: Consume(Token::STRING); *name = impl()->GetSymbol(); break; case Token::SMI: Consume(Token::SMI); *name = impl()->GetNumberAsSymbol(); break; case Token::NUMBER: Consume(Token::NUMBER); *name = impl()->GetNumberAsSymbol(); break; case Token::LBRACK: { *name = impl()->NullIdentifier(); *is_computed_name = true; Consume(Token::LBRACK); ExpressionClassifier computed_name_classifier(this); expression = ParseAssignmentExpression(true, CHECK_OK); ValidateExpression(CHECK_OK); AccumulateFormalParameterContainmentErrors(); Expect(Token::RBRACK, CHECK_OK); break; } case Token::ELLIPSIS: if (!*is_generator && !*is_async && !*is_get && !*is_set) { *name = impl()->NullIdentifier(); Consume(Token::ELLIPSIS); expression = ParseAssignmentExpression(true, CHECK_OK); *kind = PropertyKind::kSpreadProperty; if (!impl()->IsIdentifier(expression)) { classifier()->RecordBindingPatternError( scanner()->location(), MessageTemplate::kInvalidRestBindingPattern); } if (!expression->IsValidReferenceExpression()) { classifier()->RecordAssignmentPatternError( scanner()->location(), MessageTemplate::kInvalidRestAssignmentPattern); } if (peek() != Token::RBRACE) { classifier()->RecordPatternError(scanner()->location(), MessageTemplate::kElementAfterRest); } return expression; } V8_FALLTHROUGH; default: *name = ParseIdentifierName(CHECK_OK); break; } if (*kind == PropertyKind::kNotSet) { SetPropertyKindFromToken(peek(), kind); } if (*is_computed_name) { return expression; } impl()->PushLiteralName(*name); uint32_t index; return impl()->IsArrayIndex(*name, &index) ? factory()->NewNumberLiteral(index, pos) : factory()->NewStringLiteral(*name, pos); } template <typename Impl> typename ParserBase<Impl>::ClassLiteralPropertyT ParserBase<Impl>::ParseClassPropertyDefinition( ClassLiteralChecker* checker, ClassInfo* class_info, IdentifierT* name, bool has_extends, bool* is_computed_name, ClassLiteralProperty::Kind* property_kind, bool* is_static, bool* ok) { DCHECK_NOT_NULL(class_info); bool is_get = false; bool is_set = false; bool is_generator = false; bool is_async = false; *is_static = false; *property_kind = ClassLiteralProperty::METHOD; PropertyKind kind = PropertyKind::kNotSet; Token::Value name_token = peek(); DCHECK_IMPLIES(name_token == Token::PRIVATE_NAME, allow_harmony_private_fields()); int name_token_position = scanner()->peek_location().beg_pos; *name = impl()->NullIdentifier(); ExpressionT name_expression; if (name_token == Token::STATIC) { Consume(Token::STATIC); name_token_position = scanner()->peek_location().beg_pos; if (peek() == Token::LPAREN) { kind = 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 if (peek() == Token::PRIVATE_NAME) { DCHECK(allow_harmony_private_fields()); // TODO(gsathya): Make a better error message for this. ReportUnexpectedToken(Next()); *ok = false; return impl()->NullLiteralProperty(); } else { *is_static = true; name_expression = ParsePropertyName(name, &kind, &is_generator, &is_get, &is_set, &is_async, is_computed_name, CHECK_OK_CUSTOM(NullLiteralProperty)); } } else if (name_token == Token::PRIVATE_NAME) { Consume(Token::PRIVATE_NAME); *name = impl()->GetSymbol(); name_expression = factory()->NewStringLiteral(*name, position()); } else { name_expression = ParsePropertyName(name, &kind, &is_generator, &is_get, &is_set, &is_async, is_computed_name, CHECK_OK_CUSTOM(NullLiteralProperty)); } if (!class_info->has_name_static_property && *is_static && impl()->IsName(*name)) { class_info->has_name_static_property = true; } 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_public_fields() || allow_harmony_private_fields()) { *property_kind = name_token == Token::PRIVATE_NAME ? ClassLiteralProperty::PRIVATE_FIELD : ClassLiteralProperty::PUBLIC_FIELD; if (*is_static && !allow_harmony_static_fields()) { ReportUnexpectedToken(Next()); *ok = false; return impl()->NullLiteralProperty(); } if (!*is_computed_name) { checker->CheckClassFieldName(*is_static, CHECK_OK_CUSTOM(NullLiteralProperty)); } ExpressionT initializer = ParseClassFieldInitializer( class_info, *is_static, CHECK_OK_CUSTOM(NullLiteralProperty)); ExpectSemicolon(CHECK_OK_CUSTOM(NullLiteralProperty)); ClassLiteralPropertyT result = factory()->NewClassLiteralProperty( name_expression, initializer, *property_kind, *is_static, *is_computed_name); impl()->SetFunctionNameFromPropertyName(result, *name); return result; } else { ReportUnexpectedToken(Next()); *ok = false; return impl()->NullLiteralProperty(); } case PropertyKind::kMethodProperty: { DCHECK(!is_get && !is_set); // MethodDefinition // PropertyName '(' StrictFormalParameters ')' '{' FunctionBody '}' // '*' PropertyName '(' StrictFormalParameters ')' '{' FunctionBody '}' // async PropertyName '(' StrictFormalParameters ')' // '{' FunctionBody '}' // async '*' PropertyName '(' StrictFormalParameters ')' // '{' FunctionBody '}' if (!*is_computed_name) { checker->CheckClassMethodName(name_token, PropertyKind::kMethodProperty, is_generator, is_async, *is_static, CHECK_OK_CUSTOM(NullLiteralProperty)); } FunctionKind kind = MethodKindFor(is_generator, is_async); if (!*is_static && impl()->IsConstructor(*name)) { class_info->has_seen_constructor = true; kind = has_extends ? FunctionKind::kDerivedConstructor : FunctionKind::kBaseConstructor; } ExpressionT value = impl()->ParseFunctionLiteral( *name, scanner()->location(), kSkipFunctionNameCheck, kind, FLAG_harmony_function_tostring ? name_token_position : kNoSourcePosition, FunctionLiteral::kAccessorOrMethod, language_mode(), nullptr, CHECK_OK_CUSTOM(NullLiteralProperty)); *property_kind = ClassLiteralProperty::METHOD; ClassLiteralPropertyT result = factory()->NewClassLiteralProperty( name_expression, value, *property_kind, *is_static, *is_computed_name); impl()->SetFunctionNameFromPropertyName(result, *name); return result; } 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(NullLiteralProperty)); // 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, FLAG_harmony_function_tostring ? name_token_position : kNoSourcePosition, FunctionLiteral::kAccessorOrMethod, language_mode(), nullptr, CHECK_OK_CUSTOM(NullLiteralProperty)); *property_kind = is_get ? ClassLiteralProperty::GETTER : ClassLiteralProperty::SETTER; ClassLiteralPropertyT result = factory()->NewClassLiteralProperty( name_expression, value, *property_kind, *is_static, *is_computed_name); const AstRawString* prefix = is_get ? ast_value_factory()->get_space_string() : ast_value_factory()->set_space_string(); impl()->SetFunctionNameFromPropertyName(result, *name, prefix); return result; } case PropertyKind::kSpreadProperty: ReportUnexpectedTokenAt( Scanner::Location(name_token_position, name_expression->position()), name_token); *ok = false; return impl()->NullLiteralProperty(); } UNREACHABLE(); } template <typename Impl> typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseClassFieldInitializer(ClassInfo* class_info, bool is_static, bool* ok) { DeclarationScope* initializer_scope = is_static ? class_info->static_fields_scope : class_info->instance_fields_scope; if (initializer_scope == nullptr) { initializer_scope = NewFunctionScope(FunctionKind::kClassFieldsInitializerFunction); // TODO(gsathya): Make scopes be non contiguous. initializer_scope->set_start_position(scanner()->location().end_pos); initializer_scope->SetLanguageMode(LanguageMode::kStrict); } ExpressionT initializer; if (Check(Token::ASSIGN)) { FunctionState initializer_state(&function_state_, &scope_, initializer_scope); ExpressionClassifier expression_classifier(this); initializer = ParseAssignmentExpression(true, CHECK_OK_CUSTOM(NullExpression)); ValidateExpression(CHECK_OK_CUSTOM(NullExpression)); } else { initializer = factory()->NewUndefinedLiteral(kNoSourcePosition); } initializer_scope->set_end_position(scanner()->location().end_pos); if (is_static) { class_info->static_fields_scope = initializer_scope; class_info->has_static_class_fields = true; } else { class_info->instance_fields_scope = initializer_scope; class_info->has_instance_class_fields = true; } return initializer; } template <typename Impl> typename ParserBase<Impl>::ObjectLiteralPropertyT ParserBase<Impl>::ParseObjectPropertyDefinition(ObjectLiteralChecker* checker, bool* is_computed_name, bool* is_rest_property, 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()->NullIdentifier(); 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, &kind, &is_generator, &is_get, &is_set, &is_async, is_computed_name, CHECK_OK_CUSTOM(NullLiteralProperty)); switch (kind) { case PropertyKind::kSpreadProperty: DCHECK(!is_get && !is_set && !is_generator && !is_async && !*is_computed_name); DCHECK(name_token == Token::ELLIPSIS); *is_computed_name = true; *is_rest_property = true; return factory()->NewObjectLiteralProperty( factory()->NewTheHoleLiteral(), name_expression, ObjectLiteralProperty::SPREAD, true); case PropertyKind::kValueProperty: { DCHECK(!is_get && !is_set && !is_generator && !is_async); if (!*is_computed_name) { checker->CheckDuplicateProto(name_token); } Consume(Token::COLON); int beg_pos = peek_position(); ExpressionT value = ParseAssignmentExpression(true, CHECK_OK_CUSTOM(NullLiteralProperty)); CheckDestructuringElement(value, beg_pos, scanner()->location().end_pos); ObjectLiteralPropertyT result = factory()->NewObjectLiteralProperty( name_expression, value, *is_computed_name); impl()->SetFunctionNameFromPropertyName(result, name); return result; } case PropertyKind::kShorthandProperty: { // PropertyDefinition // IdentifierReference // CoverInitializedName // // CoverInitializedName // IdentifierReference Initializer? 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()->NullLiteralProperty(); } DCHECK(!*is_computed_name); if (classifier()->duplicate_finder() != nullptr && scanner()->IsDuplicateSymbol(classifier()->duplicate_finder(), ast_value_factory())) { classifier()->RecordDuplicateFormalParameterError( scanner()->location()); } if (impl()->IsEvalOrArguments(name) && is_strict(language_mode())) { classifier()->RecordBindingPatternError( scanner()->location(), MessageTemplate::kStrictEvalArguments); } if (name_token == Token::LET) { classifier()->RecordLetPatternError( scanner()->location(), MessageTemplate::kLetInLexicalBinding); } if (name_token == Token::AWAIT) { DCHECK(!is_async_function()); classifier()->RecordAsyncArrowFormalParametersError( Scanner::Location(next_beg_pos, next_end_pos), MessageTemplate::kAwaitBindingIdentifier); } ExpressionT lhs = impl()->ExpressionFromIdentifier(name, next_beg_pos); CheckDestructuringElement(lhs, next_beg_pos, next_end_pos); ExpressionT value; if (peek() == Token::ASSIGN) { Consume(Token::ASSIGN); ExpressionClassifier rhs_classifier(this); ExpressionT rhs = ParseAssignmentExpression( true, CHECK_OK_CUSTOM(NullLiteralProperty)); ValidateExpression(CHECK_OK_CUSTOM(NullLiteralProperty)); AccumulateFormalParameterContainmentErrors(); value = factory()->NewAssignment(Token::ASSIGN, lhs, rhs, kNoSourcePosition); classifier()->RecordExpressionError( Scanner::Location(next_beg_pos, scanner()->location().end_pos), MessageTemplate::kInvalidCoverInitializedName); impl()->SetFunctionNameFromIdentifierRef(rhs, lhs); } else { value = lhs; } ObjectLiteralPropertyT result = factory()->NewObjectLiteralProperty( name_expression, value, ObjectLiteralProperty::COMPUTED, false); impl()->SetFunctionNameFromPropertyName(result, name); return result; } case PropertyKind::kMethodProperty: { DCHECK(!is_get && !is_set); // MethodDefinition // PropertyName '(' StrictFormalParameters ')' '{' FunctionBody '}' // '*' PropertyName '(' StrictFormalParameters ')' '{' FunctionBody '}' classifier()->RecordPatternError( Scanner::Location(next_beg_pos, scanner()->location().end_pos), MessageTemplate::kInvalidDestructuringTarget); FunctionKind kind = MethodKindFor(is_generator, is_async); ExpressionT value = impl()->ParseFunctionLiteral( name, scanner()->location(), kSkipFunctionNameCheck, kind, FLAG_harmony_function_tostring ? next_beg_pos : kNoSourcePosition, FunctionLiteral::kAccessorOrMethod, language_mode(), nullptr, CHECK_OK_CUSTOM(NullLiteralProperty)); ObjectLiteralPropertyT result = factory()->NewObjectLiteralProperty( name_expression, value, ObjectLiteralProperty::COMPUTED, *is_computed_name); impl()->SetFunctionNameFromPropertyName(result, name); return result; } 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; FunctionLiteralT value = impl()->ParseFunctionLiteral( name, scanner()->location(), kSkipFunctionNameCheck, kind, FLAG_harmony_function_tostring ? next_beg_pos : kNoSourcePosition, FunctionLiteral::kAccessorOrMethod, language_mode(), nullptr, CHECK_OK_CUSTOM(NullLiteralProperty)); ObjectLiteralPropertyT result = factory()->NewObjectLiteralProperty( name_expression, value, is_get ? ObjectLiteralProperty::GETTER : ObjectLiteralProperty::SETTER, *is_computed_name); const AstRawString* prefix = is_get ? ast_value_factory()->get_space_string() : ast_value_factory()->set_space_string(); impl()->SetFunctionNameFromPropertyName(result, name, prefix); return result; } case PropertyKind::kClassField: case PropertyKind::kNotSet: ReportUnexpectedToken(Next()); *ok = false; return impl()->NullLiteralProperty(); } UNREACHABLE(); } template <typename Impl> typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseObjectLiteral( bool* ok) { // ObjectLiteral :: // '{' (PropertyDefinition (',' PropertyDefinition)* ','? )? '}' int pos = peek_position(); typename Types::ObjectPropertyList properties = impl()->NewObjectPropertyList(4); int number_of_boilerplate_properties = 0; bool has_computed_names = false; bool has_rest_property = false; ObjectLiteralChecker checker(this); Expect(Token::LBRACE, CHECK_OK); while (peek() != Token::RBRACE) { FuncNameInferrer::State fni_state(fni_); bool is_computed_name = false; bool is_rest_property = false; ObjectLiteralPropertyT property = ParseObjectPropertyDefinition( &checker, &is_computed_name, &is_rest_property, CHECK_OK); if (is_computed_name) { has_computed_names = true; } if (is_rest_property) { has_rest_property = true; } if (impl()->IsBoilerplateProperty(property) && !has_computed_names) { // Count CONSTANT or COMPUTED properties to maintain the enumeration // order. number_of_boilerplate_properties++; } properties->Add(property, zone()); if (peek() != Token::RBRACE) { // Need {} because of the CHECK_OK macro. Expect(Token::COMMA, CHECK_OK); } if (fni_ != nullptr) fni_->Infer(); } Expect(Token::RBRACE, CHECK_OK); // In pattern rewriter, we rewrite rest property to call out to a // runtime function passing all the other properties as arguments to // this runtime function. Here, we make sure that the number of // properties is less than number of arguments allowed for a runtime // call. if (has_rest_property && properties->length() > Code::kMaxArguments) { this->classifier()->RecordPatternError(Scanner::Location(pos, position()), MessageTemplate::kTooManyArguments); } return impl()->InitializeObjectLiteral(factory()->NewObjectLiteral( properties, number_of_boilerplate_properties, pos, has_rest_property)); } template <typename Impl> typename ParserBase<Impl>::ExpressionListT ParserBase<Impl>::ParseArguments( Scanner::Location* first_spread_arg_loc, bool maybe_arrow, bool* is_simple_parameter_list, bool* ok) { // Arguments :: // '(' (AssignmentExpression)*[','] ')' Scanner::Location spread_arg = Scanner::Location::invalid(); ExpressionListT result = impl()->NewExpressionList(4); Expect(Token::LPAREN, CHECK_OK_CUSTOM(NullExpressionList)); bool done = (peek() == Token::RPAREN); while (!done) { int start_pos = peek_position(); bool is_spread = Check(Token::ELLIPSIS); int expr_pos = peek_position(); ExpressionT argument = ParseAssignmentExpression(true, CHECK_OK_CUSTOM(NullExpressionList)); if (!impl()->IsIdentifier(argument) && is_simple_parameter_list != nullptr) { *is_simple_parameter_list = false; } if (!maybe_arrow) { ValidateExpression(CHECK_OK_CUSTOM(NullExpressionList)); } if (is_spread) { if (is_simple_parameter_list != nullptr) { *is_simple_parameter_list = false; } if (!spread_arg.IsValid()) { spread_arg.beg_pos = start_pos; spread_arg.end_pos = peek_position(); } if (argument->IsAssignment()) { classifier()->RecordAsyncArrowFormalParametersError( scanner()->location(), MessageTemplate::kRestDefaultInitializer); } argument = factory()->NewSpread(argument, start_pos, expr_pos); } result->Add(argument, zone_); if (result->length() > Code::kMaxArguments) { ReportMessage(MessageTemplate::kTooManyArguments); *ok = false; return impl()->NullExpressionList(); } done = (peek() != Token::COMMA); if (!done) { Next(); if (argument->IsSpread()) { classifier()->RecordAsyncArrowFormalParametersError( scanner()->location(), MessageTemplate::kParamAfterRest); } if (peek() == Token::RPAREN) { // allow trailing comma done = true; } } } Scanner::Location location = scanner_->location(); if (Token::RPAREN != Next()) { impl()->ReportMessageAt(location, MessageTemplate::kUnterminatedArgList); *ok = false; return impl()->NullExpressionList(); } *first_spread_arg_loc = spread_arg; if (!maybe_arrow || peek() != Token::ARROW) { if (maybe_arrow) { ValidateExpression(CHECK_OK_CUSTOM(NullExpressionList)); } } return result; } // Precedence = 2 template <typename Impl> typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN, bool* ok) { // AssignmentExpression :: // ConditionalExpression // ArrowFunction // YieldExpression // LeftHandSideExpression AssignmentOperator AssignmentExpression int lhs_beg_pos = peek_position(); if (peek() == Token::YIELD && is_generator()) { return ParseYieldExpression(accept_IN, ok); } FuncNameInferrer::State fni_state(fni_); ExpressionClassifier arrow_formals_classifier( this, classifier()->duplicate_finder()); Scope::Snapshot scope_snapshot(scope()); int rewritable_length = static_cast<int>( function_state_->destructuring_assignments_to_rewrite().size()); bool is_async = peek() == Token::ASYNC && !scanner()->HasLineTerminatorAfterNext() && IsValidArrowFormalParametersStart(PeekAhead()); bool parenthesized_formals = peek() == Token::LPAREN; if (!is_async && !parenthesized_formals) { ArrowFormalParametersUnexpectedToken(); } // Parse a simple, faster sub-grammar (primary expression) if it's evident // that we have only a trivial expression to parse. ExpressionT expression; if (IsTrivialExpression()) { expression = ParsePrimaryExpression(&is_async, CHECK_OK); } else { expression = ParseConditionalExpression(accept_IN, CHECK_OK); } if (is_async && impl()->IsIdentifier(expression) && peek_any_identifier() && PeekAhead() == Token::ARROW) { // async Identifier => AsyncConciseBody IdentifierT name = ParseAndClassifyIdentifier(CHECK_OK); expression = impl()->ExpressionFromIdentifier(name, position(), InferName::kNo); if (fni_) { // Remove `async` keyword from inferred name stack. fni_->RemoveAsyncKeywordFromEnd(); } } if (peek() == Token::ARROW) { Scanner::Location arrow_loc = scanner()->peek_location(); ValidateArrowFormalParameters(expression, parenthesized_formals, is_async, CHECK_OK); // This reads strangely, but is correct: it checks whether any // sub-expression of the parameter list failed to be a valid formal // parameter initializer. Since YieldExpressions are banned anywhere // in an arrow parameter list, this is correct. // TODO(adamk): Rename "FormalParameterInitializerError" to refer to // "YieldExpression", which is its only use. ValidateFormalParameterInitializer(ok); Scanner::Location loc(lhs_beg_pos, scanner()->location().end_pos); DeclarationScope* scope = NewFunctionScope(is_async ? FunctionKind::kAsyncArrowFunction : FunctionKind::kArrowFunction); // Because the arrow's parameters were parsed in the outer scope, // we need to fix up the scope chain appropriately. scope_snapshot.Reparent(scope); FormalParametersT parameters(scope); if (!classifier()->is_simple_parameter_list()) { scope->SetHasNonSimpleParameters(); parameters.is_simple = false; } scope->set_start_position(lhs_beg_pos); Scanner::Location duplicate_loc = Scanner::Location::invalid(); impl()->DeclareArrowFunctionFormalParameters(¶meters, expression, loc, &duplicate_loc, CHECK_OK); if (duplicate_loc.IsValid()) { classifier()->RecordDuplicateFormalParameterError(duplicate_loc); } expression = ParseArrowFunctionLiteral(accept_IN, parameters, rewritable_length, CHECK_OK); Accumulate(ExpressionClassifier::AsyncArrowFormalParametersProduction); classifier()->RecordPatternError(arrow_loc, MessageTemplate::kUnexpectedToken, Token::String(Token::ARROW)); if (fni_ != nullptr) fni_->Infer(); return expression; } // "expression" was not itself an arrow function parameter list, but it might // form part of one. Propagate speculative formal parameter error locations // (including those for binding patterns, since formal parameters can // themselves contain binding patterns). unsigned productions = ExpressionClassifier::AllProductions & ~ExpressionClassifier::ArrowFormalParametersProduction; // Parenthesized identifiers and property references are allowed as part // of a larger assignment pattern, even though parenthesized patterns // themselves are not allowed, e.g., "[(x)] = []". Only accumulate // assignment pattern errors if the parsed expression is more complex. if (IsValidReferenceExpression(expression)) { productions &= ~ExpressionClassifier::AssignmentPatternProduction; } const bool is_destructuring_assignment = IsValidPattern(expression) && peek() == Token::ASSIGN; if (is_destructuring_assignment) { // This is definitely not an expression so don't accumulate // expression-related errors. productions &= ~ExpressionClassifier::ExpressionProduction; } Accumulate(productions); if (!Token::IsAssignmentOp(peek())) return expression; if (is_destructuring_assignment) { ValidateAssignmentPattern(CHECK_OK); } else { expression = CheckAndRewriteReferenceExpression( expression, lhs_beg_pos, scanner()->location().end_pos, MessageTemplate::kInvalidLhsInAssignment, CHECK_OK); } impl()->MarkExpressionAsAssigned(expression); Token::Value op = Next(); // Get assignment operator. if (op != Token::ASSIGN) { classifier()->RecordPatternError(scanner()->location(), MessageTemplate::kUnexpectedToken, Token::String(op)); } int pos = position(); ExpressionClassifier rhs_classifier(this); ExpressionT right = ParseAssignmentExpression(accept_IN, CHECK_OK); ValidateExpression(CHECK_OK); AccumulateFormalParameterContainmentErrors(); // We try to estimate the set of properties set by constructors. We define a // new property whenever there is an assignment to a property of 'this'. We // should probably only add properties if we haven't seen them // before. Otherwise we'll probably overestimate the number of properties. if (op == Token::ASSIGN && impl()->IsThisProperty(expression)) { function_state_->AddProperty(); } impl()->CheckAssigningFunctionLiteralToProperty(expression, right); if (fni_ != nullptr) { // Check if the right hand side is a call to avoid inferring a // name if we're dealing with "a = function(){...}();"-like // expression. if (op == Token::ASSIGN && !right->IsCall() && !right->IsCallNew()) { fni_->Infer(); } else { fni_->RemoveLastFunction(); } } if (op == Token::ASSIGN) { impl()->SetFunctionNameFromIdentifierRef(right, expression); } DCHECK_NE(op, Token::INIT); ExpressionT result = factory()->NewAssignment(op, expression, right, pos); if (is_destructuring_assignment) { DCHECK_NE(op, Token::ASSIGN_EXP); auto rewritable = factory()->NewRewritableExpression(result, scope()); impl()->QueueDestructuringAssignmentForRewriting(rewritable); result = rewritable; } return result; } template <typename Impl> typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseYieldExpression( bool accept_IN, bool* ok) { // YieldExpression :: // 'yield' ([no line terminator] '*'? AssignmentExpression)? int pos = peek_position(); classifier()->RecordPatternError( scanner()->peek_location(), MessageTemplate::kInvalidDestructuringTarget); classifier()->RecordFormalParameterInitializerError( scanner()->peek_location(), MessageTemplate::kYieldInParameter); Expect(Token::YIELD, CHECK_OK); // The following initialization is necessary. ExpressionT expression = impl()->NullExpression(); bool delegating = false; // yield* if (!scanner()->HasLineTerminatorBeforeNext()) { if (Check(Token::MUL)) delegating = true; switch (peek()) { case Token::EOS: case Token::SEMICOLON: case Token::RBRACE: case Token::RBRACK: case Token::RPAREN: case Token::COLON: case Token::COMMA: case Token::IN: // The above set of tokens is the complete set of tokens that can appear // after an AssignmentExpression, and none of them can start an // AssignmentExpression. This allows us to avoid looking for an RHS for // a regular yield, given only one look-ahead token. if (!delegating) break; // Delegating yields require an RHS; fall through. V8_FALLTHROUGH; default: expression = ParseAssignmentExpression(accept_IN, CHECK_OK); ValidateExpression(CHECK_OK); break; } } if (delegating) { ExpressionT yieldstar = factory()->NewYieldStar(expression, pos); impl()->RecordSuspendSourceRange(yieldstar, PositionAfterSemicolon()); function_state_->AddSuspend(); if (IsAsyncGeneratorFunction(function_state_->kind())) { // iterator_close and delegated_iterator_output suspend ids. function_state_->AddSuspend(); function_state_->AddSuspend(); } return yieldstar; } // Hackily disambiguate o from o.next and o [Symbol.iterator](). // TODO(verwaest): Come up with a better solution. ExpressionT yield = factory()->NewYield(expression, pos, Suspend::kOnExceptionThrow); impl()->RecordSuspendSourceRange(yield, PositionAfterSemicolon()); function_state_->AddSuspend(); return yield; } // Precedence = 3 template <typename Impl> typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseConditionalExpression(bool accept_IN, bool* ok) { // ConditionalExpression :: // LogicalOrExpression // LogicalOrExpression '?' AssignmentExpression ':' AssignmentExpression SourceRange then_range, else_range; int pos = peek_position(); // We start using the binary expression parser for prec >= 4 only! ExpressionT expression = ParseBinaryExpression(4, accept_IN, CHECK_OK); if (peek() != Token::CONDITIONAL) return expression; ValidateExpression(CHECK_OK); BindingPatternUnexpectedToken(); ArrowFormalParametersUnexpectedToken(); ExpressionT left; { SourceRangeScope range_scope(scanner(), &then_range); Consume(Token::CONDITIONAL); ExpressionClassifier classifier(this); // In parsing the first assignment expression in conditional // expressions we always accept the 'in' keyword; see ECMA-262, // section 11.12, page 58. left = ParseAssignmentExpression(true, CHECK_OK); AccumulateNonBindingPatternErrors(); } ValidateExpression(CHECK_OK); ExpressionT right; { SourceRangeScope range_scope(scanner(), &else_range); Expect(Token::COLON, CHECK_OK); ExpressionClassifier classifier(this); right = ParseAssignmentExpression(accept_IN, CHECK_OK); AccumulateNonBindingPatternErrors(); } ValidateExpression(CHECK_OK); ExpressionT expr = factory()->NewConditional(expression, left, right, pos); impl()->RecordConditionalSourceRange(expr, then_range, else_range); return expr; } // Precedence >= 4 template <typename Impl> typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseBinaryExpression( int prec, bool accept_IN, bool* ok) { DCHECK_GE(prec, 4); SourceRange right_range; ExpressionT x = ParseUnaryExpression(CHECK_OK); for (int prec1 = Precedence(peek(), accept_IN); prec1 >= prec; prec1--) { // prec1 >= 4 while (Precedence(peek(), accept_IN) == prec1) { ValidateExpression(CHECK_OK); BindingPatternUnexpectedToken(); ArrowFormalParametersUnexpectedToken(); SourceRangeScope right_range_scope(scanner(), &right_range); Token::Value op = Next(); int pos = position(); const bool is_right_associative = op == Token::EXP; const int next_prec = is_right_associative ? prec1 : prec1 + 1; ExpressionT y = ParseBinaryExpression(next_prec, accept_IN, CHECK_OK); right_range_scope.Finalize(); ValidateExpression(CHECK_OK); if (impl()->ShortcutNumericLiteralBinaryExpression(&x, y, op, pos)) { continue; } // For now we distinguish between comparisons and other binary // operations. (We could combine the two and get rid of this // code and AST node eventually.) if (Token::IsCompareOp(op)) { // We have a comparison. Token::Value cmp = op; switch (op) { case Token::NE: cmp = Token::EQ; break; case Token::NE_STRICT: cmp = Token::EQ_STRICT; break; default: break; } x = factory()->NewCompareOperation(cmp, x, y, pos); if (cmp != op) { // The comparison was negated - add a NOT. x = factory()->NewUnaryOperation(Token::NOT, x, pos); } } else if (impl()->CollapseNaryExpression(&x, y, op, pos, right_range)) { continue; } else { // We have a "normal" binary operation. x = factory()->NewBinaryOperation(op, x, y, pos); if (op == Token::OR || op == Token::AND) { impl()->RecordBinaryOperationSourceRange(x, right_range); } } } } return x; } template <typename Impl> typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseUnaryExpression( bool* ok) { // UnaryExpression :: // PostfixExpression // 'delete' UnaryExpression // 'void' UnaryExpression // 'typeof' UnaryExpression // '++' UnaryExpression // '--' UnaryExpression // '+' UnaryExpression // '-' UnaryExpression // '~' UnaryExpression // '!' UnaryExpression // [+Await] AwaitExpression[?Yield] Token::Value op = peek(); if (Token::IsUnaryOp(op)) { BindingPatternUnexpectedToken(); ArrowFormalParametersUnexpectedToken(); op = Next(); int pos = position(); // Assume "! function ..." indicates the function is likely to be called. if (op == Token::NOT && peek() == Token::FUNCTION) { function_state_->set_next_function_is_likely_called(); } ExpressionT expression = ParseUnaryExpression(CHECK_OK); ValidateExpression(CHECK_OK); if (op == Token::DELETE) { if (impl()->IsIdentifier(expression) && is_strict(language_mode())) { // "delete identifier" is a syntax error in strict mode. ReportMessage(MessageTemplate::kStrictDelete); *ok = false; return impl()->NullExpression(); } if (impl()->IsPropertyWithPrivateFieldKey(expression)) { ReportMessage(MessageTemplate::kDeletePrivateField); *ok = false; return impl()->NullExpression(); } } if (peek() == Token::EXP) { ReportUnexpectedToken(Next()); *ok = false; return impl()->NullExpression(); } // Allow the parser's implementation to rewrite the expression. return impl()->BuildUnaryExpression(expression, op, pos); } else if (Token::IsCountOp(op)) { BindingPatternUnexpectedToken(); ArrowFormalParametersUnexpectedToken(); op = Next(); int beg_pos = peek_position(); ExpressionT expression = ParseUnaryExpression(CHECK_OK); expression = CheckAndRewriteReferenceExpression( expression, beg_pos, scanner()->location().end_pos, MessageTemplate::kInvalidLhsInPrefixOp, CHECK_OK); impl()->MarkExpressionAsAssigned(expression); ValidateExpression(CHECK_OK); return factory()->NewCountOperation(op, true /* prefix */, expression, position()); } else if (is_async_function() && peek() == Token::AWAIT) { classifier()->RecordFormalParameterInitializerError( scanner()->peek_location(), MessageTemplate::kAwaitExpressionFormalParameter); int await_pos = peek_position(); Consume(Token::AWAIT); ExpressionT value = ParseUnaryExpression(CHECK_OK); classifier()->RecordBindingPatternError( Scanner::Location(await_pos, scanner()->location().end_pos), MessageTemplate::kInvalidDestructuringTarget); ExpressionT expr = factory()->NewAwait(value, await_pos); function_state_->AddSuspend(); impl()->RecordSuspendSourceRange(expr, PositionAfterSemicolon()); return expr; } else { return ParsePostfixExpression(ok); } } template <typename Impl> typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePostfixExpression( bool* ok) { // PostfixExpression :: // LeftHandSideExpression ('++' | '--')? int lhs_beg_pos = peek_position(); ExpressionT expression = ParseLeftHandSideExpression(CHECK_OK); if (!scanner()->HasLineTerminatorBeforeNext() && Token::IsCountOp(peek())) { BindingPatternUnexpectedToken(); ArrowFormalParametersUnexpectedToken(); expression = CheckAndRewriteReferenceExpression( expression, lhs_beg_pos, scanner()->location().end_pos, MessageTemplate::kInvalidLhsInPostfixOp, CHECK_OK); impl()->MarkExpressionAsAssigned(expression); ValidateExpression(CHECK_OK); Token::Value next = Next(); expression = factory()->NewCountOperation(next, false /* postfix */, expression, position()); } return expression; } template <typename Impl> typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseLeftHandSideExpression(bool* ok) { // LeftHandSideExpression :: // (NewExpression | MemberExpression) ... bool is_async = false; ExpressionT result = ParseMemberWithNewPrefixesExpression(&is_async, CHECK_OK); while (true) { switch (peek()) { case Token::LBRACK: { ValidateExpression(CHECK_OK); BindingPatternUnexpectedToken(); ArrowFormalParametersUnexpectedToken(); Consume(Token::LBRACK); int pos = position(); ExpressionT index = ParseExpressionCoverGrammar(true, CHECK_OK); ValidateExpression(CHECK_OK); result = factory()->NewProperty(result, index, pos); Expect(Token::RBRACK, CHECK_OK); break; } case Token::LPAREN: { int pos; ValidateExpression(CHECK_OK); BindingPatternUnexpectedToken(); if (scanner()->current_token() == Token::IDENTIFIER || scanner()->current_token() == Token::SUPER || scanner()->current_token() == Token::ASYNC) { // For call of an identifier we want to report position of // the identifier as position of the call in the stack trace. pos = position(); } else { // For other kinds of calls we record position of the parenthesis as // position of the call. Note that this is extremely important for // expressions of the form function(){...}() for which call position // should not point to the closing brace otherwise it will intersect // with positions recorded for function literal and confuse debugger. pos = peek_position(); // Also the trailing parenthesis are a hint that the function will // be called immediately. If we happen to have parsed a preceding // function literal eagerly, we can also compile it eagerly. if (result->IsFunctionLiteral()) { result->AsFunctionLiteral()->SetShouldEagerCompile(); result->AsFunctionLiteral()->mark_as_iife(); } } Scanner::Location spread_pos; ExpressionListT args; if (V8_UNLIKELY(is_async && impl()->IsIdentifier(result))) { ExpressionClassifier async_classifier(this); bool is_simple_parameter_list = true; args = ParseArguments(&spread_pos, true, &is_simple_parameter_list, CHECK_OK); if (peek() == Token::ARROW) { if (fni_) { fni_->RemoveAsyncKeywordFromEnd(); } ValidateBindingPattern(CHECK_OK); ValidateFormalParameterInitializer(CHECK_OK); if (!classifier()->is_valid_async_arrow_formal_parameters()) { ReportClassifierError( classifier()->async_arrow_formal_parameters_error()); *ok = false; return impl()->NullExpression(); } if (args->length()) { // async ( Arguments ) => ... if (!is_simple_parameter_list) { async_classifier.previous()->RecordNonSimpleParameter(); } return impl()->ExpressionListToExpression(args); } // async () => ... return factory()->NewEmptyParentheses(pos); } else { AccumulateFormalParameterContainmentErrors(); } } else { args = ParseArguments(&spread_pos, CHECK_OK); } ArrowFormalParametersUnexpectedToken(); // Keep track of eval() calls since they disable all local variable // optimizations. // The calls that need special treatment are the // direct eval calls. These calls are all of the form eval(...), with // no explicit receiver. // These calls are marked as potentially direct eval calls. Whether // they are actually direct calls to eval is determined at run time. Call::PossiblyEval is_possibly_eval = CheckPossibleEvalCall(result, scope()); if (spread_pos.IsValid()) { result = impl()->SpreadCall(result, args, pos, is_possibly_eval); } else { result = factory()->NewCall(result, args, pos, is_possibly_eval); } if (fni_ != nullptr) fni_->RemoveLastFunction(); break; } case Token::PERIOD: { ValidateExpression(CHECK_OK); BindingPatternUnexpectedToken(); ArrowFormalParametersUnexpectedToken(); Consume(Token::PERIOD); int pos = position(); ExpressionT key = ParseIdentifierNameOrPrivateName(CHECK_OK); result = factory()->NewProperty(result, key, pos); break; } case Token::TEMPLATE_SPAN: case Token::TEMPLATE_TAIL: { ValidateExpression(CHECK_OK); BindingPatternUnexpectedToken(); ArrowFormalParametersUnexpectedToken(); result = ParseTemplateLiteral(result, position(), true, CHECK_OK); break; } default: return result; } } } template <typename Impl> typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseMemberWithNewPrefixesExpression(bool* is_async, bool* ok) { // NewExpression :: // ('new')+ MemberExpression // // NewTarget :: // 'new' '.' 'target' // The grammar for new expressions is pretty warped. We can have several 'new' // keywords following each other, and then a MemberExpression. When we see '(' // after the MemberExpression, it's associated with the rightmost unassociated // 'new' to create a NewExpression with arguments. However, a NewExpression // can also occur without arguments. // Examples of new expression: // new foo.bar().baz means (new (foo.bar)()).baz // new foo()() means (new foo())() // new new foo()() means (new (new foo())()) // new new foo means new (new foo) // new new foo() means new (new foo()) // new new foo().bar().baz means (new (new foo()).bar()).baz if (peek() == Token::NEW) { BindingPatternUnexpectedToken(); ArrowFormalParametersUnexpectedToken(); Consume(Token::NEW); int new_pos = position(); ExpressionT result; if (peek() == Token::SUPER) { const bool is_new = true; result = ParseSuperExpression(is_new, CHECK_OK); } else if (allow_harmony_dynamic_import() && peek() == Token::IMPORT && (!allow_harmony_import_meta() || PeekAhead() == Token::LPAREN)) { impl()->ReportMessageAt(scanner()->peek_location(), MessageTemplate::kImportCallNotNewExpression); *ok = false; return impl()->NullExpression(); } else if (peek() == Token::PERIOD) { *is_async = false; result = ParseNewTargetExpression(CHECK_OK); return ParseMemberExpressionContinuation(result, is_async, CHECK_OK); } else { result = ParseMemberWithNewPrefixesExpression(is_async, CHECK_OK); } ValidateExpression(CHECK_OK); if (peek() == Token::LPAREN) { // NewExpression with arguments. Scanner::Location spread_pos; ExpressionListT args = ParseArguments(&spread_pos, CHECK_OK); if (spread_pos.IsValid()) { result = impl()->SpreadCallNew(result, args, new_pos); } else { result = factory()->NewCallNew(result, args, new_pos); } // The expression can still continue with . or [ after the arguments. result = ParseMemberExpressionContinuation(result, is_async, CHECK_OK); return result; } // NewExpression without arguments. return factory()->NewCallNew(result, impl()->NewExpressionList(0), new_pos); } // No 'new' or 'super' keyword. return ParseMemberExpression(is_async, ok); } template <typename Impl> typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseMemberExpression( bool* is_async, bool* ok) { // MemberExpression :: // (PrimaryExpression | FunctionLiteral | ClassLiteral) // ('[' Expression ']' | '.' Identifier | Arguments | TemplateLiteral)* // // CallExpression :: // (SuperCall | ImportCall) // ('[' Expression ']' | '.' Identifier | Arguments | TemplateLiteral)* // // The '[' Expression ']' and '.' Identifier parts are parsed by // ParseMemberExpressionContinuation, and the Arguments part is parsed by the // caller. // Parse the initial primary or function expression. ExpressionT result; if (peek() == Token::FUNCTION) { BindingPatternUnexpectedToken(); ArrowFormalParametersUnexpectedToken(); Consume(Token::FUNCTION); int function_token_position = position(); FunctionKind function_kind = Check(Token::MUL) ? FunctionKind::kGeneratorFunction : FunctionKind::kNormalFunction; IdentifierT name = impl()->NullIdentifier(); bool is_strict_reserved_name = false; Scanner::Location function_name_location = Scanner::Location::invalid(); FunctionLiteral::FunctionType function_type = FunctionLiteral::kAnonymousExpression; if (impl()->ParsingDynamicFunctionDeclaration()) { // We don't want dynamic functions to actually declare their name // "anonymous". We just want that name in the toString(). if (stack_overflow()) { *ok = false; return impl()->NullExpression(); } Consume(Token::IDENTIFIER); DCHECK(scanner()->CurrentMatchesContextual(Token::ANONYMOUS)); } else if (peek_any_identifier()) { bool is_await = false; name = ParseIdentifierOrStrictReservedWord( function_kind, &is_strict_reserved_name, &is_await, CHECK_OK); function_name_location = scanner()->location(); function_type = FunctionLiteral::kNamedExpression; } result = impl()->ParseFunctionLiteral( name, function_name_location, is_strict_reserved_name ? kFunctionNameIsStrictReserved : kFunctionNameValidityUnknown, function_kind, function_token_position, function_type, language_mode(), nullptr, CHECK_OK); } else if (peek() == Token::SUPER) { const bool is_new = false; result = ParseSuperExpression(is_new, CHECK_OK); } else if (allow_harmony_dynamic_import() && peek() == Token::IMPORT) { result = ParseImportExpressions(CHECK_OK); } else { result = ParsePrimaryExpression(is_async, CHECK_OK); } result = ParseMemberExpressionContinuation(result, is_async, CHECK_OK); return result; } template <typename Impl> typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseImportExpressions( bool* ok) { DCHECK(allow_harmony_dynamic_import()); classifier()->RecordPatternError(scanner()->peek_location(), MessageTemplate::kUnexpectedToken, Token::String(Token::IMPORT)); Consume(Token::IMPORT); int pos = position(); if (allow_harmony_import_meta() && peek() == Token::PERIOD) { ExpectMetaProperty(Token::META, "import.meta", pos, CHECK_OK); if (!parsing_module_) { impl()->ReportMessageAt(scanner()->location(), MessageTemplate::kImportMetaOutsideModule); *ok = false; return impl()->NullExpression(); } return impl()->ImportMetaExpression(pos); } Expect(Token::LPAREN, CHECK_OK); if (peek() == Token::RPAREN) { impl()->ReportMessageAt(scanner()->location(), MessageTemplate::kImportMissingSpecifier); *ok = false; return impl()->NullExpression(); } ExpressionT arg = ParseAssignmentExpression(true, CHECK_OK); Expect(Token::RPAREN, CHECK_OK); return factory()->NewImportCallExpression(arg, pos); } template <typename Impl> typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseSuperExpression( bool is_new, bool* ok) { Expect(Token::SUPER, CHECK_OK); int pos = position(); DeclarationScope* scope = GetReceiverScope(); FunctionKind kind = scope->function_kind(); if (IsConciseMethod(kind) || IsAccessorFunction(kind) || IsClassConstructor(kind)) { if (peek() == Token::PERIOD || peek() == Token::LBRACK) { scope->RecordSuperPropertyUsage(); return impl()->NewSuperPropertyReference(pos); } // new super() is never allowed. // super() is only allowed in derived constructor if (!is_new && peek() == Token::LPAREN && IsDerivedConstructor(kind)) { // TODO(rossberg): This might not be the correct FunctionState for the // method here. return impl()->NewSuperCallReference(pos); } } impl()->ReportMessageAt(scanner()->location(), MessageTemplate::kUnexpectedSuper); *ok = false; return impl()->NullExpression(); } template <typename Impl> void ParserBase<Impl>::ExpectMetaProperty(Token::Value property_name, const char* full_name, int pos, bool* ok) { Consume(Token::PERIOD); ExpectContextualKeyword(property_name, CHECK_OK_CUSTOM(Void)); if (scanner()->literal_contains_escapes()) { impl()->ReportMessageAt( Scanner::Location(pos, scanner()->location().end_pos), MessageTemplate::kInvalidEscapedMetaProperty, full_name); *ok = false; } } template <typename Impl> typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseNewTargetExpression(bool* ok) { int pos = position(); ExpectMetaProperty(Token::TARGET, "new.target", pos, CHECK_OK); classifier()->RecordAssignmentPatternError( Scanner::Location(pos, scanner()->location().end_pos), MessageTemplate::kInvalidDestructuringTarget); if (!GetReceiverScope()->is_function_scope()) { impl()->ReportMessageAt(scanner()->location(), MessageTemplate::kUnexpectedNewTarget); *ok = false; return impl()->NullExpression(); } return impl()->NewTargetExpression(pos); } template <typename Impl> typename ParserBase<Impl>::ExpressionT 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; ValidateExpression(CHECK_OK); BindingPatternUnexpectedToken(); ArrowFormalParametersUnexpectedToken(); Consume(Token::LBRACK); int pos = position(); ExpressionT index = ParseExpressionCoverGrammar(true, CHECK_OK); ValidateExpression(CHECK_OK); expression = factory()->NewProperty(expression, index, pos); impl()->PushPropertyName(index); Expect(Token::RBRACK, CHECK_OK); break; } case Token::PERIOD: { *is_async = false; ValidateExpression(CHECK_OK); BindingPatternUnexpectedToken(); ArrowFormalParametersUnexpectedToken(); Consume(Token::PERIOD); int pos = peek_position(); ExpressionT key = ParseIdentifierNameOrPrivateName(CHECK_OK); expression = factory()->NewProperty(expression, key, pos); break; } case Token::TEMPLATE_SPAN: case Token::TEMPLATE_TAIL: { *is_async = false; ValidateExpression(CHECK_OK); BindingPatternUnexpectedToken(); ArrowFormalParametersUnexpectedToken(); int pos; if (scanner()->current_token() == Token::IDENTIFIER) { pos = position(); } else { pos = peek_position(); if (expression->IsFunctionLiteral()) { // If the tag function looks like an IIFE, set_parenthesized() to // force eager compilation. expression->AsFunctionLiteral()->SetShouldEagerCompile(); } } expression = ParseTemplateLiteral(expression, pos, true, CHECK_OK); break; } case Token::ILLEGAL: { ReportUnexpectedTokenAt(scanner()->peek_location(), Token::ILLEGAL); *ok = false; return impl()->NullExpression(); } default: return expression; } } DCHECK(false); return impl()->NullExpression(); } template <typename Impl> void ParserBase<Impl>::ParseFormalParameter(FormalParametersT* parameters, bool* ok) { // FormalParameter[Yield,GeneratorParameter] : // BindingElement[?Yield, ?GeneratorParameter] bool is_rest = parameters->has_rest; FuncNameInferrer::State fni_state(fni_); ExpressionT pattern = ParsePrimaryExpression(CHECK_OK_CUSTOM(Void)); ValidateBindingPattern(CHECK_OK_CUSTOM(Void)); if (!impl()->IsIdentifier(pattern)) { parameters->is_simple = false; ValidateFormalParameterInitializer(CHECK_OK_CUSTOM(Void)); classifier()->RecordNonSimpleParameter(); } ExpressionT initializer = impl()->NullExpression(); if (Check(Token::ASSIGN)) { if (is_rest) { ReportMessage(MessageTemplate::kRestDefaultInitializer); *ok = false; return; } ExpressionClassifier init_classifier(this); initializer = ParseAssignmentExpression(true, CHECK_OK_CUSTOM(Void)); ValidateExpression(CHECK_OK_CUSTOM(Void)); ValidateFormalParameterInitializer(CHECK_OK_CUSTOM(Void)); parameters->is_simple = false; DiscardExpressionClassifier(); classifier()->RecordNonSimpleParameter(); impl()->SetFunctionNameFromIdentifierRef(initializer, pattern); } impl()->AddFormalParameter(parameters, pattern, initializer, scanner()->location().end_pos, is_rest); } template <typename Impl> void ParserBase<Impl>::ParseFormalParameterList(FormalParametersT* parameters, bool* ok) { // FormalParameters[Yield] : // [empty] // FunctionRestParameter[?Yield] // FormalParameterList[?Yield] // FormalParameterList[?Yield] , // FormalParameterList[?Yield] , FunctionRestParameter[?Yield] // // FormalParameterList[Yield] : // FormalParameter[?Yield] // FormalParameterList[?Yield] , FormalParameter[?Yield] DCHECK_EQ(0, parameters->arity); if (peek() != Token::RPAREN) { while (true) { if (parameters->arity > Code::kMaxArguments) { ReportMessage(MessageTemplate::kTooManyParameters); *ok = false; return; } parameters->has_rest = Check(Token::ELLIPSIS); ParseFormalParameter(parameters, CHECK_OK_CUSTOM(Void)); if (parameters->has_rest) { parameters->is_simple = false; classifier()->RecordNonSimpleParameter(); if (peek() == Token::COMMA) { impl()->ReportMessageAt(scanner()->peek_location(), MessageTemplate::kParamAfterRest); *ok = false; return; } break; } if (!Check(Token::COMMA)) break; if (peek() == Token::RPAREN) { // allow the trailing comma break; } } } impl()->DeclareFormalParameters(parameters->scope, parameters->params, parameters->is_simple); } template <typename Impl> typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseVariableDeclarations( VariableDeclarationContext var_context, DeclarationParsingResult* parsing_result, ZonePtrList<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()->NullStatement(); if (var_context != kForStatement) { init_block = factory()->NewBlock(1, true); } switch (peek()) { case Token::VAR: parsing_result->descriptor.mode = VariableMode::kVar; Consume(Token::VAR); break; case Token::CONST: Consume(Token::CONST); DCHECK_NE(var_context, kStatement); parsing_result->descriptor.mode = VariableMode::kConst; break; case Token::LET: Consume(Token::LET); DCHECK_NE(var_context, kStatement); parsing_result->descriptor.mode = VariableMode::kLet; break; default: UNREACHABLE(); // by current callers break; } parsing_result->descriptor.scope = scope(); int bindings_start = peek_position(); do { // Parse binding pattern. FuncNameInferrer::State fni_state(fni_); ExpressionT pattern = impl()->NullExpression(); int decl_pos = peek_position(); { ExpressionClassifier pattern_classifier(this); pattern = ParsePrimaryExpression(CHECK_OK_CUSTOM(NullStatement)); ValidateBindingPattern(CHECK_OK_CUSTOM(NullStatement)); if (IsLexicalVariableMode(parsing_result->descriptor.mode)) { ValidateLetPattern(CHECK_OK_CUSTOM(NullStatement)); } } Scanner::Location variable_loc = scanner()->location(); bool single_name = impl()->IsIdentifier(pattern); if (single_name) { impl()->PushVariableName(impl()->AsIdentifier(pattern)); } ExpressionT value = impl()->NullExpression(); int initializer_position = kNoSourcePosition; int value_beg_position = kNoSourcePosition; if (Check(Token::ASSIGN)) { value_beg_position = peek_position(); ExpressionClassifier classifier(this); value = ParseAssignmentExpression(var_context != kForStatement, CHECK_OK_CUSTOM(NullStatement)); ValidateExpression(CHECK_OK_CUSTOM(NullStatement)); 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 == VariableMode::kConst || !impl()->IsIdentifier(pattern)) { impl()->ReportMessageAt( Scanner::Location(decl_pos, scanner()->location().end_pos), MessageTemplate::kDeclarationMissingInitializer, !impl()->IsIdentifier(pattern) ? "destructuring" : "const"); *ok = false; return impl()->NullStatement(); } // 'let x' initializes 'x' to undefined. if (parsing_result->descriptor.mode == VariableMode::kLet) { value = factory()->NewUndefinedLiteral(position()); } } // End position of the initializer is after the variable. initializer_position = position(); } typename DeclarationParsingResult::Declaration decl( pattern, initializer_position, value); decl.value_beg_position = value_beg_position; if (var_context == kForStatement) { // Save the declaration for further handling in ParseForStatement. parsing_result->declarations.push_back(decl); } else { // Immediately declare the variable otherwise. This avoids O(N^2) // behavior (where N is the number of variables in a single // declaration) in the PatternRewriter having to do with removing // and adding VariableProxies to the Scope (see bug 4699). impl()->DeclareAndInitializeVariables( init_block, &parsing_result->descriptor, &decl, names, CHECK_OK_CUSTOM(NullStatement)); } } 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)) { impl()->ReportMessageAt( scanner()->location(), MessageTemplate::kGeneratorInSingleStatementContext); *ok = false; return impl()->NullStatement(); } return ParseHoistableDeclaration(pos, flags, nullptr, false, ok); } template <typename Impl> typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseHoistableDeclaration( ZonePtrList<const AstRawString>* names, bool default_export, bool* ok) { Expect(Token::FUNCTION, CHECK_OK_CUSTOM(NullStatement)); 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, ZonePtrList<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. bool is_generator = flags & ParseFunctionFlags::kIsGenerator; const bool is_async = flags & ParseFunctionFlags::kIsAsync; DCHECK(!is_generator || !is_async); if (is_async && Check(Token::MUL)) { // Async generator is_generator = true; } 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; bool is_await = false; name = ParseIdentifierOrStrictReservedWord(&is_strict_reserved, &is_await, CHECK_OK_CUSTOM(NullStatement)); name_validity = is_strict_reserved ? kFunctionNameIsStrictReserved : kFunctionNameValidityUnknown; variable_name = name; } FuncNameInferrer::State fni_state(fni_); impl()->PushEnclosingName(name); FunctionKind kind = FunctionKindFor(is_generator, is_async); FunctionLiteralT function = impl()->ParseFunctionLiteral( name, scanner()->location(), name_validity, kind, pos, FunctionLiteral::kDeclaration, language_mode(), nullptr, CHECK_OK_CUSTOM(NullStatement)); // In ES6, a function behaves as a lexical binding, except in // a script scope, or the initial scope of eval or another function. VariableMode mode = (!scope()->is_declaration_scope() || scope()->is_module_scope()) ? VariableMode::kLet : VariableMode::kVar; // Async functions don't undergo sloppy mode block scoped hoisting, and don't // allow duplicates in a block. Both are represented by the // sloppy_block_function_map. Don't add them to the map for async functions. // Generators are also supposed to be prohibited; currently doing this behind // a flag and UseCounting violations to assess web compatibility. bool is_sloppy_block_function = is_sloppy(language_mode()) && !scope()->is_declaration_scope() && !is_async && !is_generator; return impl()->DeclareFunction(variable_name, function, mode, pos, is_sloppy_block_function, names, ok); } template <typename Impl> typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseClassDeclaration( ZonePtrList<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()->NullIdentifier(); bool is_strict_reserved = false; IdentifierT variable_name = impl()->NullIdentifier(); if (default_export && (peek() == Token::EXTENDS || peek() == Token::LBRACE)) { impl()->GetDefaultStrings(&name, &variable_name); } else { bool is_await = false; name = ParseIdentifierOrStrictReservedWord(&is_strict_reserved, &is_await, CHECK_OK_CUSTOM(NullStatement)); 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) { function_state_->DisableOptimization(BailoutReason::kNativeFunctionLiteral); 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( ZonePtrList<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()->HasLineTerminatorBeforeNext()) { *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> void ParserBase<Impl>::ParseFunctionBody( typename ParserBase<Impl>::StatementListT result, IdentifierT function_name, int pos, const FormalParametersT& parameters, FunctionKind kind, FunctionLiteral::FunctionType function_type, bool* ok) { DeclarationScope* function_scope = scope()->AsDeclarationScope(); DeclarationScope* inner_scope = function_scope; BlockT inner_block = impl()->NullStatement(); StatementListT body = result; if (!parameters.is_simple) { inner_scope = NewVarblockScope(); inner_scope->set_start_position(scanner()->location().beg_pos); inner_block = factory()->NewBlock(8, true); inner_block->set_scope(inner_scope); body = inner_block->statements(); } // If we are parsing the source as if it is wrapped in a function, the source // ends without a closing brace. Token::Value closing_token = function_type == FunctionLiteral::kWrapped ? Token::EOS : Token::RBRACE; { BlockState block_state(&scope_, inner_scope); if (IsResumableFunction(kind)) impl()->PrepareGeneratorVariables(); if (IsAsyncGeneratorFunction(kind)) { impl()->ParseAndRewriteAsyncGeneratorFunctionBody(pos, kind, body, ok); } else if (IsGeneratorFunction(kind)) { impl()->ParseAndRewriteGeneratorFunctionBody(pos, kind, body, ok); } else if (IsAsyncFunction(kind)) { ParseAsyncFunctionBody(inner_scope, body, CHECK_OK_VOID); } else { ParseStatementList(body, closing_token, CHECK_OK_VOID); } if (IsDerivedConstructor(kind)) { body->Add(factory()->NewReturnStatement(impl()->ThisExpression(), kNoSourcePosition), zone()); } } Expect(closing_token, CHECK_OK_VOID); scope()->set_end_position(scanner()->location().end_pos); if (!parameters.is_simple) { DCHECK_NOT_NULL(inner_scope); DCHECK_EQ(function_scope, scope()); DCHECK_EQ(function_scope, inner_scope->outer_scope()); impl()->SetLanguageMode(function_scope, inner_scope->language_mode()); BlockT init_block = impl()->BuildParameterInitializationBlock(parameters, CHECK_OK_VOID); if (is_sloppy(inner_scope->language_mode())) { impl()->InsertSloppyBlockFunctionVarBindings(inner_scope); } // TODO(littledan): Merge the two rejection blocks into one if (IsAsyncFunction(kind) && !IsAsyncGeneratorFunction(kind)) { init_block = impl()->BuildRejectPromiseOnException(init_block); } inner_scope->set_end_position(scanner()->location().end_pos); if (inner_scope->FinalizeBlockScope() != nullptr) { impl()->CheckConflictingVarDeclarations(inner_scope, CHECK_OK_VOID); impl()->InsertShadowingVarBindingInitializers(inner_block); } else { inner_block->set_scope(nullptr); } inner_scope = nullptr; result->Add(init_block, zone()); result->Add(inner_block, zone()); } else { DCHECK_EQ(inner_scope, function_scope); if (is_sloppy(function_scope->language_mode())) { impl()->InsertSloppyBlockFunctionVarBindings(function_scope); } } if (!IsArrowFunction(kind)) { // Declare arguments after parsing the function since lexical 'arguments' // masks the arguments object. Declare arguments before declaring the // function var since the arguments object masks 'function arguments'. function_scope->DeclareArguments(ast_value_factory()); } impl()->DeclareFunctionNameVar(function_name, function_type, function_scope); } template <typename Impl> void ParserBase<Impl>::CheckArityRestrictions(int param_count, FunctionKind function_kind, bool has_rest, int formals_start_pos, int formals_end_pos, bool* ok) { if (IsGetterFunction(function_kind)) { if (param_count != 0) { impl()->ReportMessageAt( Scanner::Location(formals_start_pos, formals_end_pos), MessageTemplate::kBadGetterArity); *ok = false; } } else if (IsSetterFunction(function_kind)) { if (param_count != 1) { impl()->ReportMessageAt( Scanner::Location(formals_start_pos, formals_end_pos), MessageTemplate::kBadSetterArity); *ok = false; } if (has_rest) { impl()->ReportMessageAt( Scanner::Location(formals_start_pos, formals_end_pos), MessageTemplate::kBadSetterRestParameter); *ok = false; } } } template <typename Impl> bool ParserBase<Impl>::IsNextLetKeyword() { DCHECK(peek() == Token::LET); Token::Value next_next = PeekAhead(); switch (next_next) { case Token::LBRACE: case Token::LBRACK: case Token::IDENTIFIER: case Token::STATIC: case Token::LET: // `let let;` is disallowed by static semantics, but the // token must be first interpreted as a keyword in order // for those semantics to apply. This ensures that ASI is // not honored when a LineTerminator separates the // tokens. case Token::YIELD: case Token::AWAIT: case Token::ASYNC: return true; case Token::FUTURE_STRICT_RESERVED_WORD: return is_sloppy(language_mode()); default: return false; } } template <typename Impl> bool ParserBase<Impl>::IsTrivialExpression() { Token::Value peek_token = peek(); if (peek_token == Token::SMI || peek_token == Token::NUMBER || peek_token == Token::BIGINT || peek_token == Token::NULL_LITERAL || peek_token == Token::TRUE_LITERAL || peek_token == Token::FALSE_LITERAL || peek_token == Token::STRING || peek_token == Token::IDENTIFIER || peek_token == Token::THIS) { // PeekAhead() is expensive & may not always be called, so we only call it // after checking peek(). Token::Value peek_ahead = PeekAhead(); if (peek_ahead == Token::COMMA || peek_ahead == Token::RPAREN || peek_ahead == Token::SEMICOLON || peek_ahead == Token::RBRACK) { return true; } } return false; } template <typename Impl> typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseArrowFunctionLiteral( bool accept_IN, const FormalParametersT& formal_parameters, int rewritable_length, bool* ok) { const RuntimeCallCounterId counters[2][2] = { {RuntimeCallCounterId::kParseBackgroundArrowFunctionLiteral, RuntimeCallCounterId::kParseArrowFunctionLiteral}, {RuntimeCallCounterId::kPreParseBackgroundArrowFunctionLiteral, RuntimeCallCounterId::kPreParseArrowFunctionLiteral}}; RuntimeCallTimerScope runtime_timer( runtime_call_stats_, counters[Impl::IsPreParser()][parsing_on_main_thread_]); base::ElapsedTimer timer; if (V8_UNLIKELY(FLAG_log_function_events)) timer.Start(); if (peek() == Token::ARROW && scanner_->HasLineTerminatorBeforeNext()) { // ASI inserts `;` after arrow parameters if a line terminator is found. // `=> ...` is never a valid expression, so report as syntax error. // If next token is not `=>`, it's a syntax error anyways. ReportUnexpectedTokenAt(scanner_->peek_location(), Token::ARROW); *ok = false; return impl()->NullExpression(); } StatementListT body = impl()->NullStatementList(); int expected_property_count = -1; int suspend_count = 0; int function_literal_id = GetNextFunctionLiteralId(); FunctionKind kind = formal_parameters.scope->function_kind(); FunctionLiteral::EagerCompileHint eager_compile_hint = default_eager_compile_hint_; bool can_preparse = impl()->parse_lazily() && eager_compile_hint == FunctionLiteral::kShouldLazyCompile; // TODO(marja): consider lazy-parsing inner arrow functions too. is_this // handling in Scope::ResolveVariable needs to change. bool is_lazy_top_level_function = can_preparse && impl()->AllowsLazyParsingWithoutUnresolvedVariables(); bool has_braces = true; ProducedPreParsedScopeData* produced_preparsed_scope_data = nullptr; { FunctionState function_state(&function_state_, &scope_, formal_parameters.scope); // Move any queued destructuring assignments which appeared // in this function's parameter list into its own function_state. function_state.AdoptDestructuringAssignmentsFromParentState( rewritable_length); Expect(Token::ARROW, CHECK_OK); if (peek() == Token::LBRACE) { // Multiple statement body DCHECK_EQ(scope(), formal_parameters.scope); if (is_lazy_top_level_function) { // FIXME(marja): Arrow function parameters will be parsed even if the // body is preparsed; move relevant parts of parameter handling to // simulate consistent parameter handling. // For arrow functions, we don't need to retrieve data about function // parameters. int dummy_num_parameters = -1; DCHECK_NE(kind & FunctionKind::kArrowFunction, 0); LazyParsingResult result = impl()->SkipFunction( nullptr, kind, FunctionLiteral::kAnonymousExpression, formal_parameters.scope, &dummy_num_parameters, &produced_preparsed_scope_data, false, false, CHECK_OK); DCHECK_NE(result, kLazyParsingAborted); DCHECK_NULL(produced_preparsed_scope_data); USE(result); formal_parameters.scope->ResetAfterPreparsing(ast_value_factory_, false); // Discard any queued destructuring assignments which appeared // in this function's parameter list, and which were adopted // into this function state, above. function_state.RewindDestructuringAssignments(0); } else { Consume(Token::LBRACE); body = impl()->NewStatementList(8); ParseFunctionBody(body, impl()->NullIdentifier(), kNoSourcePosition, formal_parameters, kind, FunctionLiteral::kAnonymousExpression, CHECK_OK); expected_property_count = function_state.expected_property_count(); } } else { // Single-expression body has_braces = false; const bool is_async = IsAsyncFunction(kind); body = impl()->NewStatementList(1); impl()->AddParameterInitializationBlock(formal_parameters, body, is_async, CHECK_OK); ParseSingleExpressionFunctionBody(body, is_async, accept_IN, CHECK_OK); expected_property_count = function_state.expected_property_count(); } formal_parameters.scope->set_end_position(scanner()->location().end_pos); // Arrow function formal parameters are parsed as StrictFormalParameterList, // which is not the same as "parameters of a strict function"; it only means // that duplicates are not allowed. Of course, the arrow function may // itself be strict as well. const bool allow_duplicate_parameters = false; ValidateFormalParameters(language_mode(), allow_duplicate_parameters, CHECK_OK); // Validate strict mode. if (is_strict(language_mode())) { CheckStrictOctalLiteral(formal_parameters.scope->start_position(), scanner()->location().end_pos, CHECK_OK); } impl()->CheckConflictingVarDeclarations(formal_parameters.scope, CHECK_OK); impl()->RewriteDestructuringAssignments(); suspend_count = function_state.suspend_count(); } FunctionLiteralT function_literal = factory()->NewFunctionLiteral( impl()->EmptyIdentifierString(), formal_parameters.scope, body, expected_property_count, formal_parameters.num_parameters(), formal_parameters.function_length, FunctionLiteral::kNoDuplicateParameters, FunctionLiteral::kAnonymousExpression, eager_compile_hint, formal_parameters.scope->start_position(), has_braces, function_literal_id, produced_preparsed_scope_data); function_literal->set_suspend_count(suspend_count); function_literal->set_function_token_position( formal_parameters.scope->start_position()); impl()->AddFunctionForNameInference(function_literal); if (V8_UNLIKELY((FLAG_log_function_events))) { Scope* scope = formal_parameters.scope; double ms = timer.Elapsed().InMillisecondsF(); const char* event_name = is_lazy_top_level_function ? "preparse-no-resolution" : "parse"; const char* name = "arrow function"; logger_->FunctionEvent(event_name, script_id(), ms, scope->start_position(), scope->end_position(), name, strlen(name)); } 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) { bool is_anonymous = impl()->IsNull(name); // All parts of a ClassDeclaration and ClassExpression are strict code. if (!is_anonymous) { if (name_is_strict_reserved) { impl()->ReportMessageAt(class_name_location, MessageTemplate::kUnexpectedStrictReserved); *ok = false; return impl()->NullExpression(); } if (impl()->IsEvalOrArguments(name)) { impl()->ReportMessageAt(class_name_location, MessageTemplate::kStrictEvalArguments); *ok = false; return impl()->NullExpression(); } } Scope* block_scope = NewScope(BLOCK_SCOPE); BlockState block_state(&scope_, block_scope); RaiseLanguageMode(LanguageMode::kStrict); ClassInfo class_info(this); class_info.is_anonymous = is_anonymous; impl()->DeclareClassVariable(name, &class_info, class_token_pos, CHECK_OK); scope()->set_start_position(scanner()->location().end_pos); if (Check(Token::EXTENDS)) { FuncNameInferrer::State fni_state(fni_); ExpressionClassifier extends_classifier(this); class_info.extends = ParseLeftHandSideExpression(CHECK_OK); ValidateExpression(CHECK_OK); AccumulateFormalParameterContainmentErrors(); } ClassLiteralChecker checker(this); Expect(Token::LBRACE, CHECK_OK); const bool has_extends = !impl()->IsNull(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. bool is_static; ClassLiteralProperty::Kind property_kind; ExpressionClassifier property_classifier(this); IdentifierT property_name; // If we haven't seen the constructor yet, it potentially is the next // property. bool is_constructor = !class_info.has_seen_constructor; ClassLiteralPropertyT property = ParseClassPropertyDefinition( &checker, &class_info, &property_name, has_extends, &is_computed_name, &property_kind, &is_static, CHECK_OK); if (!class_info.has_static_computed_names && is_static && is_computed_name) { class_info.has_static_computed_names = true; } if (is_computed_name && property_kind == ClassLiteralProperty::PUBLIC_FIELD) { class_info.computed_field_count++; } is_constructor &= class_info.has_seen_constructor; ValidateExpression(CHECK_OK); AccumulateFormalParameterContainmentErrors(); impl()->DeclareClassProperty(name, property, property_name, property_kind, is_static, is_constructor, is_computed_name, &class_info, CHECK_OK); impl()->InferFunctionName(); } Expect(Token::RBRACE, CHECK_OK); int end_pos = scanner()->location().end_pos; block_scope->set_end_position(end_pos); return impl()->RewriteClassLiteral(block_scope, name, &class_info, class_token_pos, end_pos, ok); } template <typename Impl> void ParserBase<Impl>::ParseSingleExpressionFunctionBody(StatementListT body, bool is_async, bool accept_IN, bool* ok) { if (is_async) impl()->PrepareGeneratorVariables(); ExpressionClassifier classifier(this); ExpressionT expression = ParseAssignmentExpression(accept_IN, CHECK_OK_VOID); ValidateExpression(CHECK_OK_VOID); if (is_async) { BlockT block = factory()->NewBlock(1, true); impl()->RewriteAsyncFunctionBody(body, block, expression, CHECK_OK_VOID); } else { body->Add(BuildReturnStatement(expression, expression->position()), zone()); } } template <typename Impl> void ParserBase<Impl>::ParseAsyncFunctionBody(Scope* scope, StatementListT body, bool* ok) { BlockT block = factory()->NewBlock(8, true); ParseStatementList(block->statements(), Token::RBRACE, CHECK_OK_VOID); impl()->RewriteAsyncFunctionBody( body, block, factory()->NewUndefinedLiteral(kNoSourcePosition), CHECK_OK_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()->NullIdentifier(); FunctionLiteral::FunctionType type = FunctionLiteral::kAnonymousExpression; bool is_generator = Check(Token::MUL); const bool kIsAsync = true; const FunctionKind kind = FunctionKindFor(is_generator, kIsAsync); if (impl()->ParsingDynamicFunctionDeclaration()) { // We don't want dynamic functions to actually declare their name // "anonymous". We just want that name in the toString(). if (stack_overflow()) { *ok = false; return impl()->NullExpression(); } Consume(Token::IDENTIFIER); DCHECK(scanner()->CurrentMatchesContextual(Token::ANONYMOUS)); } else if (peek_any_identifier()) { type = FunctionLiteral::kNamedExpression; bool is_await = false; name = ParseIdentifierOrStrictReservedWord(kind, &is_strict_reserved, &is_await, CHECK_OK); // If the function name is "await", ParseIdentifierOrStrictReservedWord // recognized the error. DCHECK(!is_await); } return impl()->ParseFunctionLiteral( name, scanner()->location(), is_strict_reserved ? kFunctionNameIsStrictReserved : kFunctionNameValidityUnknown, kind, pos, type, language_mode(), nullptr, CHECK_OK); } template <typename Impl> typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseTemplateLiteral( ExpressionT tag, int start, bool tagged, 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. // // In terms of draft language, TEMPLATE_SPAN may be either the TemplateHead or // TemplateMiddle productions, while TEMPLATE_TAIL is either TemplateTail, or // NoSubstitutionTemplate. // // When parsing a TemplateLiteral, we must have scanned either an initial // TEMPLATE_SPAN, or a TEMPLATE_TAIL. DCHECK(peek() == Token::TEMPLATE_SPAN || peek() == Token::TEMPLATE_TAIL); if (tagged) { // TaggedTemplate expressions prevent the eval compilation cache from being // used. This flag is only used if an eval is being parsed. set_allow_eval_cache(false); } bool forbid_illegal_escapes = !tagged; // If we reach a TEMPLATE_TAIL first, we are parsing a NoSubstitutionTemplate. // In this case we may simply consume the token and build a template with a // single TEMPLATE_SPAN and no expressions. if (peek() == Token::TEMPLATE_TAIL) { Consume(Token::TEMPLATE_TAIL); int pos = position(); typename Impl::TemplateLiteralState ts = impl()->OpenTemplateLiteral(pos); bool is_valid = CheckTemplateEscapes(forbid_illegal_escapes, CHECK_OK); impl()->AddTemplateSpan(&ts, is_valid, true); return impl()->CloseTemplateLiteral(&ts, start, tag); } Consume(Token::TEMPLATE_SPAN); int pos = position(); typename Impl::TemplateLiteralState ts = impl()->OpenTemplateLiteral(pos); bool is_valid = CheckTemplateEscapes(forbid_illegal_escapes, CHECK_OK); impl()->AddTemplateSpan(&ts, is_valid, false); Token::Value next; // If we open with a TEMPLATE_SPAN, we must scan the subsequent expression, // and repeat if the following token is a TEMPLATE_SPAN as well (in this // case, representing a TemplateMiddle). do { next = peek(); if (next == Token::EOS) { impl()->ReportMessageAt(Scanner::Location(start, peek_position()), MessageTemplate::kUnterminatedTemplate); *ok = false; return impl()->NullExpression(); } else if (next == Token::ILLEGAL) { impl()->ReportMessageAt( Scanner::Location(position() + 1, peek_position()), MessageTemplate::kUnexpectedToken, "ILLEGAL", kSyntaxError); *ok = false; return impl()->NullExpression(); } int expr_pos = peek_position(); ExpressionT expression = ParseExpressionCoverGrammar(true, CHECK_OK); ValidateExpression(CHECK_OK); impl()->AddTemplateExpression(&ts, expression); if (peek() != Token::RBRACE) { impl()->ReportMessageAt(Scanner::Location(expr_pos, peek_position()), MessageTemplate::kUnterminatedTemplateExpr); *ok = false; return impl()->NullExpression(); } // If we didn't die parsing that expression, our next token should be a // TEMPLATE_SPAN or TEMPLATE_TAIL. next = scanner()->ScanTemplateContinuation(); Next(); pos = position(); if (next == Token::EOS) { impl()->ReportMessageAt(Scanner::Location(start, pos), MessageTemplate::kUnterminatedTemplate); *ok = false; return impl()->NullExpression(); } else if (next == Token::ILLEGAL) { impl()->ReportMessageAt( Scanner::Location(position() + 1, peek_position()), MessageTemplate::kUnexpectedToken, "ILLEGAL", kSyntaxError); *ok = false; return impl()->NullExpression(); } bool is_valid = CheckTemplateEscapes(forbid_illegal_escapes, CHECK_OK); impl()->AddTemplateSpan(&ts, is_valid, next == Token::TEMPLATE_TAIL); } while (next == Token::TEMPLATE_SPAN); DCHECK_EQ(next, Token::TEMPLATE_TAIL); // Once we've reached a TEMPLATE_TAIL, we can close the TemplateLiteral. return impl()->CloseTemplateLiteral(&ts, start, tag); } template <typename Impl> typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::CheckAndRewriteReferenceExpression( ExpressionT expression, int beg_pos, int end_pos, MessageTemplate::Template message, bool* ok) { return CheckAndRewriteReferenceExpression(expression, beg_pos, end_pos, message, kReferenceError, ok); } template <typename Impl> typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::CheckAndRewriteReferenceExpression( ExpressionT expression, int beg_pos, int end_pos, MessageTemplate::Template message, ParseErrorType type, bool* ok) { if (impl()->IsIdentifier(expression) && is_strict(language_mode()) && impl()->IsEvalOrArguments(impl()->AsIdentifier(expression))) { ReportMessageAt(Scanner::Location(beg_pos, end_pos), MessageTemplate::kStrictEvalArguments, kSyntaxError); *ok = false; return impl()->NullExpression(); } if (expression->IsValidReferenceExpression()) { return expression; } if (expression->IsCall() && !expression->AsCall()->is_tagged_template()) { // If it is a call, make it a runtime error for legacy web compatibility. // Bug: https://bugs.chromium.org/p/v8/issues/detail?id=4480 // Rewrite `expr' to `expr[throw ReferenceError]'. impl()->CountUsage( is_strict(language_mode()) ? v8::Isolate::kAssigmentExpressionLHSIsCallInStrict : v8::Isolate::kAssigmentExpressionLHSIsCallInSloppy); 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 impl()->NullExpression(); } template <typename Impl> bool ParserBase<Impl>::IsValidReferenceExpression(ExpressionT expression) { return IsAssignableIdentifier(expression) || expression->IsProperty(); } template <typename Impl> void ParserBase<Impl>::CheckDestructuringElement(ExpressionT expression, int begin, int end) { if (!IsValidPattern(expression) && !expression->IsAssignment() && !IsValidReferenceExpression(expression)) { classifier()->RecordAssignmentPatternError( Scanner::Location(begin, end), 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); if (spread_pos.IsValid()) { *ok = false; ReportMessageAt(spread_pos, MessageTemplate::kIntrinsicWithSpread, kSyntaxError); return impl()->NullExpression(); } 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 #define CHECK_OK CHECK_OK_CUSTOM(NullStatement) template <typename Impl> typename ParserBase<Impl>::LazyParsingResult ParserBase<Impl>::ParseStatementList(StatementListT body, Token::Value end_token, bool may_abort, bool* ok) { // 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()->IsNull(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()->IsNull(stat) || stat->IsEmptyStatement()) { directive_prologue = false; // End of directive prologue. continue; } if (directive_prologue) { // The length of the token is used to distinguish between strings literals // that evaluate equal to directives but contain either escape sequences // (e.g., "use \x73trict") or line continuations (e.g., "use \(newline) // strict"). if (impl()->IsUseStrictDirective(stat) && token_loc.end_pos - token_loc.beg_pos == sizeof("use strict") + 1) { // Directive "use strict" (ES5 14.1). RaiseLanguageMode(LanguageMode::kStrict); if (!scope()->HasSimpleParameters()) { // TC39 deemed "use strict" directives to be an error when occurring // in the body of a function with non-simple parameter list, on // 29/7/2015. https://goo.gl/ueA7Ln impl()->ReportMessageAt( token_loc, MessageTemplate::kIllegalLanguageModeDirective, "use strict"); *ok = false; return kLazyParsingComplete; } } else if (impl()->IsUseAsmDirective(stat) && token_loc.end_pos - token_loc.beg_pos == sizeof("use asm") + 1) { // Directive "use asm". impl()->SetAsmModule(); } else if (impl()->IsStringLiteral(stat)) { // Possibly an unknown directive. // Should not change mode, but will increment usage counters // as appropriate. Ditto usages below. RaiseLanguageMode(LanguageMode::kSloppy); } else { // End of the directive prologue. directive_prologue = false; RaiseLanguageMode(LanguageMode::kSloppy); } } else { RaiseLanguageMode(LanguageMode::kSloppy); } // If we're allowed to abort, we will do so when we see a "long and // trivial" function. Our current definition of "long and trivial" is: // - over kLazyParseTrialLimit statements // - all starting with an identifier (i.e., no if, for, while, etc.) if (may_abort) { if (!starts_with_identifier) { may_abort = false; } else if (++count_statements > kLazyParseTrialLimit) { return kLazyParsingAborted; } } body->Add(stat, zone()); } 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 (PeekAhead() == Token::FUNCTION && !scanner()->HasLineTerminatorAfterNext()) { Consume(Token::ASYNC); return ParseAsyncFunctionDeclaration(nullptr, false, ok); } break; default: break; } return ParseStatement(nullptr, nullptr, kAllowLabelledFunctionStatement, ok); } template <typename Impl> typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStatement( ZonePtrList<const AstRawString>* labels, ZonePtrList<const AstRawString>* own_labels, AllowLabelledFunctionStatement allow_function, bool* ok) { // Statement :: // Block // VariableStatement // EmptyStatement // ExpressionStatement // IfStatement // IterationStatement // ContinueStatement // BreakStatement // ReturnStatement // WithStatement // LabelledStatement // SwitchStatement // ThrowStatement // TryStatement // DebuggerStatement // {own_labels} is always a subset of {labels}. DCHECK_IMPLIES(labels == nullptr, own_labels == nullptr); // 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, own_labels, ok); case Token::WHILE: return ParseWhileStatement(labels, own_labels, ok); case Token::FOR: if (V8_UNLIKELY(is_async_function() && PeekAhead() == Token::AWAIT)) { return ParseForAwaitStatement(labels, own_labels, ok); } return ParseForStatement(labels, own_labels, ok); 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: { // It is somewhat complicated to have labels on try-statements. // When breaking out of a try-finally statement, one must take // great care not to treat it as a fall-through. It is much easier // just to wrap the entire try-statement in a statement block and // put the labels there. if (labels == nullptr) return ParseTryStatement(ok); BlockT result = factory()->NewBlock(1, false, labels); typename Types::Target target(this, result); StatementT statement = ParseTryStatement(CHECK_OK); result->statements()->Add(statement, zone()); 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); case Token::ASYNC: if (!scanner()->HasLineTerminatorAfterNext() && PeekAhead() == Token::FUNCTION) { impl()->ReportMessageAt( scanner()->peek_location(), MessageTemplate::kAsyncFunctionInSingleStatementContext); *ok = false; return impl()->NullStatement(); } V8_FALLTHROUGH; default: return ParseExpressionOrLabelledStatement(labels, own_labels, allow_function, ok); } } template <typename Impl> typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseBlock( ZonePtrList<const AstRawString>* labels, bool* ok) { // Block :: // '{' StatementList '}' // Construct block expecting 16 statements. BlockT body = factory()->NewBlock(16, false, labels); // Parse the statements and collect escaping labels. Expect(Token::LBRACE, CHECK_OK_CUSTOM(NullStatement)); { BlockState block_state(zone(), &scope_); scope()->set_start_position(scanner()->location().beg_pos); typename Types::Target target(this, body); while (peek() != Token::RBRACE) { StatementT stat = ParseStatementListItem(CHECK_OK_CUSTOM(NullStatement)); if (!impl()->IsNull(stat) && !stat->IsEmptyStatement()) { body->statements()->Add(stat, zone()); } } Expect(Token::RBRACE, CHECK_OK_CUSTOM(NullStatement)); int end_pos = scanner()->location().end_pos; scope()->set_end_position(end_pos); impl()->RecordBlockSourceRange(body, end_pos); body->set_scope(scope()->FinalizeBlockScope()); } return body; } template <typename Impl> typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseScopedStatement( ZonePtrList<const AstRawString>* labels, bool* ok) { if (is_strict(language_mode()) || peek() != Token::FUNCTION) { return ParseStatement(labels, nullptr, ok); } else { // Make a block around the statement for a lexical binding // is introduced by a FunctionDeclaration. BlockState block_state(zone(), &scope_); scope()->set_start_position(scanner()->location().beg_pos); BlockT block = factory()->NewBlock(1, false); StatementT body = ParseFunctionDeclaration(CHECK_OK); block->statements()->Add(body, zone()); scope()->set_end_position(scanner()->location().end_pos); block->set_scope(scope()->FinalizeBlockScope()); return block; } } template <typename Impl> typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseVariableStatement( VariableDeclarationContext var_context, ZonePtrList<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( ZonePtrList<const AstRawString>* labels, ZonePtrList<const AstRawString>* own_labels, AllowLabelledFunctionStatement allow_function, bool* ok) { // ExpressionStatement | LabelledStatement :: // Expression ';' // Identifier ':' Statement // // ExpressionStatement[Yield] : // [lookahead notin {{, 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(); case Token::LET: { Token::Value next_next = PeekAhead(); // "let" followed by either "[", "{" or an identifier means a lexical // declaration, which should not appear here. // However, ASI may insert a line break before an identifier or a brace. if (next_next != Token::LBRACK && ((next_next != Token::LBRACE && next_next != Token::IDENTIFIER) || scanner_->HasLineTerminatorAfterNext())) { break; } impl()->ReportMessageAt(scanner()->peek_location(), MessageTemplate::kUnexpectedLexicalDeclaration); *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. impl()->DeclareLabel(&labels, &own_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()) && allow_function == kAllowLabelledFunctionStatement) { return ParseFunctionDeclaration(ok); } return ParseStatement(labels, own_labels, allow_function, 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()->HasLineTerminatorBeforeNext() && 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( ZonePtrList<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); SourceRange then_range, else_range; StatementT then_statement = impl()->NullStatement(); { SourceRangeScope range_scope(scanner(), &then_range); then_statement = ParseScopedStatement(labels, CHECK_OK); } StatementT else_statement = impl()->NullStatement(); if (Check(Token::ELSE)) { else_range = SourceRange::ContinuationOf(then_range); else_statement = ParseScopedStatement(labels, CHECK_OK); else_range.end = scanner_->location().end_pos; } else { else_statement = factory()->NewEmptyStatement(kNoSourcePosition); } StatementT stmt = factory()->NewIfStatement(condition, then_statement, else_statement, pos); impl()->RecordIfStatementSourceRange(stmt, then_range, else_range); return stmt; } 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()->NullIdentifier(); Token::Value tok = peek(); if (!scanner()->HasLineTerminatorBeforeNext() && 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()->IsNull(target)) { // Illegal continue statement. MessageTemplate::Template message = MessageTemplate::kIllegalContinue; typename Types::BreakableStatement breakable_target = impl()->LookupBreakTarget(label, CHECK_OK); if (impl()->IsNull(label)) { message = MessageTemplate::kNoIterationStatement; } else if (impl()->IsNull(breakable_target)) { message = MessageTemplate::kUnknownLabel; } ReportMessage(message, label); *ok = false; return impl()->NullStatement(); } ExpectSemicolon(CHECK_OK); StatementT stmt = factory()->NewContinueStatement(target, pos); impl()->RecordJumpStatementSourceRange(stmt, scanner_->location().end_pos); return stmt; } template <typename Impl> typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseBreakStatement( ZonePtrList<const AstRawString>* labels, bool* ok) { // BreakStatement :: // 'break' Identifier? ';' int pos = peek_position(); Expect(Token::BREAK, CHECK_OK); IdentifierT label = impl()->NullIdentifier(); Token::Value tok = peek(); if (!scanner()->HasLineTerminatorBeforeNext() && 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()->IsNull(label) && impl()->ContainsLabel(labels, label)) { ExpectSemicolon(CHECK_OK); return factory()->NewEmptyStatement(pos); } typename Types::BreakableStatement target = impl()->LookupBreakTarget(label, CHECK_OK); if (impl()->IsNull(target)) { // Illegal break statement. MessageTemplate::Template message = MessageTemplate::kIllegalBreak; if (!impl()->IsNull(label)) { message = MessageTemplate::kUnknownLabel; } ReportMessage(message, label); *ok = false; return impl()->NullStatement(); } ExpectSemicolon(CHECK_OK); StatementT stmt = factory()->NewBreakStatement(target, pos); impl()->RecordJumpStatementSourceRange(stmt, scanner_->location().end_pos); return stmt; } 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()->NullExpression(); if (scanner()->HasLineTerminatorBeforeNext() || tok == Token::SEMICOLON || tok == Token::RBRACE || tok == Token::EOS) { if (IsDerivedConstructor(function_state_->kind())) { return_value = impl()->ThisExpression(loc.beg_pos); } } else { return_value = ParseExpression(true, CHECK_OK); } ExpectSemicolon(CHECK_OK); return_value = impl()->RewriteReturn(return_value, loc.beg_pos); int continuation_pos = scanner_->location().end_pos; StatementT stmt = BuildReturnStatement(return_value, loc.beg_pos, continuation_pos); impl()->RecordJumpStatementSourceRange(stmt, scanner_->location().end_pos); return stmt; } template <typename Impl> typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseWithStatement( ZonePtrList<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_, with_scope); with_scope->set_start_position(scanner()->peek_location().beg_pos); body = ParseStatement(labels, nullptr, 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( ZonePtrList<const AstRawString>* labels, ZonePtrList<const AstRawString>* own_labels, bool* ok) { // DoStatement :: // 'do' Statement 'while' '(' Expression ')' ';' auto loop = factory()->NewDoWhileStatement(labels, own_labels, peek_position()); typename Types::Target target(this, loop); SourceRange body_range; StatementT body = impl()->NullStatement(); Expect(Token::DO, CHECK_OK); { SourceRangeScope range_scope(scanner(), &body_range); body = ParseStatement(nullptr, nullptr, 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); impl()->RecordIterationStatementSourceRange(loop, body_range); return loop; } template <typename Impl> typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseWhileStatement( ZonePtrList<const AstRawString>* labels, ZonePtrList<const AstRawString>* own_labels, bool* ok) { // WhileStatement :: // 'while' '(' Expression ')' Statement auto loop = factory()->NewWhileStatement(labels, own_labels, peek_position()); typename Types::Target target(this, loop); SourceRange body_range; StatementT body = impl()->NullStatement(); Expect(Token::WHILE, CHECK_OK); Expect(Token::LPAREN, CHECK_OK); ExpressionT cond = ParseExpression(true, CHECK_OK); Expect(Token::RPAREN, CHECK_OK); { SourceRangeScope range_scope(scanner(), &body_range); body = ParseStatement(nullptr, nullptr, CHECK_OK); } loop->Initialize(cond, body); impl()->RecordIterationStatementSourceRange(loop, body_range); 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()->HasLineTerminatorBeforeNext()) { ReportMessage(MessageTemplate::kNewlineAfterThrow); *ok = false; return impl()->NullStatement(); } ExpressionT exception = ParseExpression(true, CHECK_OK); ExpectSemicolon(CHECK_OK); StatementT stmt = impl()->NewThrowStatement(exception, pos); impl()->RecordThrowSourceRange(stmt, scanner_->location().end_pos); return stmt; } template <typename Impl> typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseSwitchStatement( ZonePtrList<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, tag, switch_pos); { BlockState cases_block_state(zone(), &scope_); scope()->set_start_position(switch_pos); scope()->SetNonlinear(); typename Types::Target target(this, switch_statement); bool default_seen = false; Expect(Token::LBRACE, CHECK_OK); while (peek() != Token::RBRACE) { // An empty label indicates the default case. ExpressionT label = impl()->NullExpression(); SourceRange clause_range; SourceRangeScope range_scope(scanner(), &clause_range); 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); StatementListT statements = impl()->NewStatementList(5); while (peek() != Token::CASE && peek() != Token::DEFAULT && peek() != Token::RBRACE) { StatementT stat = ParseStatementListItem(CHECK_OK); statements->Add(stat, zone()); } auto clause = factory()->NewCaseClause(label, statements); impl()->RecordCaseClauseSourceRange(clause, range_scope.Finalize()); switch_statement->cases()->Add(clause, zone()); } Expect(Token::RBRACE, CHECK_OK); int end_position = scanner()->location().end_pos; scope()->set_end_position(end_position); impl()->RecordSwitchStatementSourceRange(switch_statement, end_position); Scope* switch_scope = scope()->FinalizeBlockScope(); if (switch_scope != nullptr) { return impl()->RewriteSwitchStatement(switch_statement, switch_scope); } return switch_statement; } } 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 = ParseBlock(nullptr, CHECK_OK); CatchInfo catch_info(this); if (peek() != Token::CATCH && peek() != Token::FINALLY) { ReportMessage(MessageTemplate::kNoCatchOrFinally); *ok = false; return impl()->NullStatement(); } SourceRange catch_range, finally_range; BlockT catch_block = impl()->NullStatement(); { SourceRangeScope catch_range_scope(scanner(), &catch_range); if (Check(Token::CATCH)) { bool has_binding; has_binding = Check(Token::LPAREN); if (has_binding) { catch_info.scope = NewScope(CATCH_SCOPE); catch_info.scope->set_start_position(scanner()->location().beg_pos); { BlockState catch_block_state(&scope_, catch_info.scope); catch_block = factory()->NewBlock(16, false); // Create a block scope to hold any lexical declarations created // as part of destructuring the catch parameter. { BlockState catch_variable_block_state(zone(), &scope_); scope()->set_start_position(scanner()->location().beg_pos); // 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()->IsNull(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); scope()->set_end_position(scanner()->location().end_pos); catch_block->set_scope(scope()->FinalizeBlockScope()); } } catch_info.scope->set_end_position(scanner()->location().end_pos); } else { catch_block = ParseBlock(nullptr, CHECK_OK); } } } BlockT finally_block = impl()->NullStatement(); DCHECK(peek() == Token::FINALLY || !impl()->IsNull(catch_block)); { SourceRangeScope range_scope(scanner(), &finally_range); if (Check(Token::FINALLY)) { finally_block = ParseBlock(nullptr, CHECK_OK); } } return impl()->RewriteTryStatement(try_block, catch_block, catch_range, finally_block, finally_range, catch_info, pos); } template <typename Impl> typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement( ZonePtrList<const AstRawString>* labels, ZonePtrList<const AstRawString>* own_labels, bool* ok) { // Either a standard for loop // for (<init>; <cond>; <next>) { ... } // or a for-each loop // for (<each> of|in <iterable>) { ... } // // We parse a declaration/expression after the 'for (' and then read the first // expression/declaration before we know if this is a for or a for-each. int stmt_pos = peek_position(); ForInfo for_info(this); Expect(Token::FOR, CHECK_OK); Expect(Token::LPAREN, CHECK_OK); if (peek() == Token::CONST || (peek() == Token::LET && IsNextLetKeyword())) { // The initializer contains lexical declarations, // so create an in-between scope. BlockState for_state(zone(), &scope_); scope()->set_start_position(scanner()->location().beg_pos); // Also record whether inner functions or evals are found inside // this loop, as this information is used to simplify the desugaring // if none are found. typename FunctionState::FunctionOrEvalRecordingScope recording_scope( function_state_); // Create an inner block scope which will be the parent scope of scopes // possibly created by ParseVariableDeclarations. Scope* inner_block_scope = NewScope(BLOCK_SCOPE); { BlockState inner_state(&scope_, inner_block_scope); ParseVariableDeclarations(kForStatement, &for_info.parsing_result, nullptr, CHECK_OK); } DCHECK(IsLexicalVariableMode(for_info.parsing_result.descriptor.mode)); for_info.position = scanner()->location().beg_pos; if (CheckInOrOf(&for_info.mode)) { scope()->set_is_hidden(); return ParseForEachStatementWithDeclarations( stmt_pos, &for_info, labels, own_labels, inner_block_scope, ok); } Expect(Token::SEMICOLON, CHECK_OK); StatementT init = impl()->BuildInitializationBlock( &for_info.parsing_result, &for_info.bound_names, CHECK_OK); Scope* finalized = inner_block_scope->FinalizeBlockScope(); // No variable declarations will have been created in inner_block_scope. DCHECK_NULL(finalized); USE(finalized); return ParseStandardForLoopWithLexicalDeclarations( stmt_pos, init, &for_info, labels, own_labels, ok); } StatementT init = impl()->NullStatement(); if (peek() == Token::VAR) { ParseVariableDeclarations(kForStatement, &for_info.parsing_result, nullptr, CHECK_OK); DCHECK_EQ(for_info.parsing_result.descriptor.mode, VariableMode::kVar); for_info.position = scanner()->location().beg_pos; if (CheckInOrOf(&for_info.mode)) { return ParseForEachStatementWithDeclarations(stmt_pos, &for_info, labels, own_labels, nullptr, ok); } init = impl()->BuildInitializationBlock(&for_info.parsing_result, nullptr, CHECK_OK); } else if (peek() != Token::SEMICOLON) { // The initializer does not contain declarations. int lhs_beg_pos = peek_position(); ExpressionClassifier classifier(this); ExpressionT expression = ParseExpressionCoverGrammar(false, CHECK_OK); int lhs_end_pos = 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 { ValidateExpression(CHECK_OK); } if (is_for_each) { return ParseForEachStatementWithoutDeclarations( stmt_pos, expression, lhs_beg_pos, lhs_end_pos, &for_info, labels, own_labels, ok); } // Initializer is just an expression. init = factory()->NewExpressionStatement(expression, lhs_beg_pos); } Expect(Token::SEMICOLON, CHECK_OK); // Standard 'for' loop, we have parsed the initializer at this point. ExpressionT cond = impl()->NullExpression(); StatementT next = impl()->NullStatement(); StatementT body = impl()->NullStatement(); ForStatementT loop = ParseStandardForLoop(stmt_pos, labels, own_labels, &cond, &next, &body, CHECK_OK); loop->Initialize(init, cond, next, body); return loop; } template <typename Impl> typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForEachStatementWithDeclarations( int stmt_pos, ForInfo* for_info, ZonePtrList<const AstRawString>* labels, ZonePtrList<const AstRawString>* own_labels, Scope* inner_block_scope, bool* ok) { // Just one declaration followed by in/of. if (for_info->parsing_result.declarations.size() != 1) { impl()->ReportMessageAt(for_info->parsing_result.bindings_loc, MessageTemplate::kForInOfLoopMultiBindings, ForEachStatement::VisitModeString(for_info->mode)); *ok = false; return impl()->NullStatement(); } if (for_info->parsing_result.first_initializer_loc.IsValid() && (is_strict(language_mode()) || for_info->mode == ForEachStatement::ITERATE || IsLexicalVariableMode(for_info->parsing_result.descriptor.mode) || !impl()->IsIdentifier( for_info->parsing_result.declarations[0].pattern))) { impl()->ReportMessageAt(for_info->parsing_result.first_initializer_loc, MessageTemplate::kForInOfLoopInitializer, ForEachStatement::VisitModeString(for_info->mode)); *ok = false; return impl()->NullStatement(); } // Reset the declaration_kind to ensure proper processing during declaration. for_info->parsing_result.descriptor.declaration_kind = DeclarationDescriptor::FOR_EACH; BlockT init_block = impl()->RewriteForVarInLegacy(*for_info); auto loop = factory()->NewForEachStatement(for_info->mode, labels, own_labels, stmt_pos); typename Types::Target target(this, loop); ExpressionT enumerable = impl()->NullExpression(); if (for_info->mode == ForEachStatement::ITERATE) { ExpressionClassifier classifier(this); enumerable = ParseAssignmentExpression(true, CHECK_OK); ValidateExpression(CHECK_OK); } else { enumerable = ParseExpression(true, CHECK_OK); } Expect(Token::RPAREN, CHECK_OK); Scope* for_scope = nullptr; if (inner_block_scope != nullptr) { for_scope = inner_block_scope->outer_scope(); DCHECK(for_scope == scope()); inner_block_scope->set_start_position(scanner()->location().beg_pos); } ExpressionT each_variable = impl()->NullExpression(); BlockT body_block = impl()->NullStatement(); { BlockState block_state( &scope_, inner_block_scope != nullptr ? inner_block_scope : scope_); SourceRange body_range; SourceRangeScope range_scope(scanner(), &body_range); StatementT body = ParseStatement(nullptr, nullptr, CHECK_OK); impl()->RecordIterationStatementSourceRange(loop, range_scope.Finalize()); impl()->DesugarBindingInForEachStatement(for_info, &body_block, &each_variable, CHECK_OK); body_block->statements()->Add(body, zone()); if (inner_block_scope != nullptr) { inner_block_scope->set_end_position(scanner()->location().end_pos); body_block->set_scope(inner_block_scope->FinalizeBlockScope()); } } StatementT final_loop = impl()->InitializeForEachStatement( loop, each_variable, enumerable, body_block); init_block = impl()->CreateForEachStatementTDZ(init_block, *for_info, ok); if (for_scope != nullptr) { for_scope->set_end_position(scanner()->location().end_pos); for_scope = for_scope->FinalizeBlockScope(); } // Parsed for-in loop w/ variable declarations. if (!impl()->IsNull(init_block)) { init_block->statements()->Add(final_loop, zone()); init_block->set_scope(for_scope); return init_block; } DCHECK_NULL(for_scope); return final_loop; } template <typename Impl> typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForEachStatementWithoutDeclarations( int stmt_pos, ExpressionT expression, int lhs_beg_pos, int lhs_end_pos, ForInfo* for_info, ZonePtrList<const AstRawString>* labels, ZonePtrList<const AstRawString>* own_labels, bool* ok) { // Initializer is reference followed by in/of. if (!expression->IsArrayLiteral() && !expression->IsObjectLiteral()) { expression = CheckAndRewriteReferenceExpression( expression, lhs_beg_pos, lhs_end_pos, MessageTemplate::kInvalidLhsInFor, kSyntaxError, CHECK_OK); } auto loop = factory()->NewForEachStatement(for_info->mode, labels, own_labels, stmt_pos); typename Types::Target target(this, loop); ExpressionT enumerable = impl()->NullExpression(); if (for_info->mode == ForEachStatement::ITERATE) { ExpressionClassifier classifier(this); enumerable = ParseAssignmentExpression(true, CHECK_OK); ValidateExpression(CHECK_OK); } else { enumerable = ParseExpression(true, CHECK_OK); } Expect(Token::RPAREN, CHECK_OK); StatementT body = impl()->NullStatement(); { SourceRange body_range; SourceRangeScope range_scope(scanner(), &body_range); body = ParseStatement(nullptr, nullptr, CHECK_OK); impl()->RecordIterationStatementSourceRange(loop, range_scope.Finalize()); } return impl()->InitializeForEachStatement(loop, expression, enumerable, body); } template <typename Impl> typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStandardForLoopWithLexicalDeclarations( int stmt_pos, StatementT init, ForInfo* for_info, ZonePtrList<const AstRawString>* labels, ZonePtrList<const AstRawString>* own_labels, bool* ok) { // The condition and the next statement of the for loop must be parsed // in a new scope. Scope* inner_scope = NewScope(BLOCK_SCOPE); ForStatementT loop = impl()->NullStatement(); ExpressionT cond = impl()->NullExpression(); StatementT next = impl()->NullStatement(); StatementT body = impl()->NullStatement(); { BlockState block_state(&scope_, inner_scope); scope()->set_start_position(scanner()->location().beg_pos); loop = ParseStandardForLoop(stmt_pos, labels, own_labels, &cond, &next, &body, CHECK_OK); scope()->set_end_position(scanner()->location().end_pos); } scope()->set_end_position(scanner()->location().end_pos); if (for_info->bound_names.length() > 0 && function_state_->contains_function_or_eval()) { scope()->set_is_hidden(); return impl()->DesugarLexicalBindingsInForStatement( loop, init, cond, next, body, inner_scope, *for_info, ok); } else { inner_scope = inner_scope->FinalizeBlockScope(); DCHECK_NULL(inner_scope); USE(inner_scope); } Scope* for_scope = scope()->FinalizeBlockScope(); 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 // } // DCHECK(!impl()->IsNull(init)); BlockT block = factory()->NewBlock(2, false); block->statements()->Add(init, zone()); block->statements()->Add(loop, zone()); block->set_scope(for_scope); loop->Initialize(impl()->NullStatement(), cond, next, body); return block; } loop->Initialize(init, cond, next, body); return loop; } template <typename Impl> typename ParserBase<Impl>::ForStatementT ParserBase<Impl>::ParseStandardForLoop( int stmt_pos, ZonePtrList<const AstRawString>* labels, ZonePtrList<const AstRawString>* own_labels, ExpressionT* cond, StatementT* next, StatementT* body, bool* ok) { ForStatementT loop = factory()->NewForStatement(labels, own_labels, stmt_pos); typename Types::Target target(this, loop); 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); SourceRange body_range; { SourceRangeScope range_scope(scanner(), &body_range); *body = ParseStatement(nullptr, nullptr, CHECK_OK); } impl()->RecordIterationStatementSourceRange(loop, body_range); return loop; } template <typename Impl> void ParserBase<Impl>::MarkLoopVariableAsAssigned( Scope* scope, Variable* var, typename DeclarationDescriptor::Kind declaration_kind) { if (!IsLexicalVariableMode(var->mode()) && (!scope->is_function_scope() || declaration_kind == DeclarationDescriptor::FOR_EACH)) { var->set_maybe_assigned(); } } template <typename Impl> typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForAwaitStatement( ZonePtrList<const AstRawString>* labels, ZonePtrList<const AstRawString>* own_labels, bool* ok) { // for await '(' ForDeclaration of AssignmentExpression ')' DCHECK(is_async_function()); int stmt_pos = peek_position(); ForInfo for_info(this); for_info.mode = ForEachStatement::ITERATE; // Create an in-between scope for let-bound iteration variables. BlockState for_state(zone(), &scope_); Expect(Token::FOR, CHECK_OK); Expect(Token::AWAIT, CHECK_OK); Expect(Token::LPAREN, CHECK_OK); scope()->set_start_position(scanner()->location().beg_pos); scope()->set_is_hidden(); auto loop = factory()->NewForOfStatement(labels, own_labels, stmt_pos); typename Types::Target target(this, loop); ExpressionT each_variable = impl()->NullExpression(); bool has_declarations = false; Scope* inner_block_scope = NewScope(BLOCK_SCOPE); if (peek() == Token::VAR || peek() == Token::CONST || (peek() == Token::LET && IsNextLetKeyword())) { // The initializer contains declarations // 'for' 'await' '(' ForDeclaration 'of' AssignmentExpression ')' // Statement // 'for' 'await' '(' 'var' ForBinding 'of' AssignmentExpression ')' // Statement has_declarations = true; { BlockState inner_state(&scope_, inner_block_scope); ParseVariableDeclarations(kForStatement, &for_info.parsing_result, nullptr, CHECK_OK); } for_info.position = scanner()->location().beg_pos; // Only a single declaration is allowed in for-await-of loops if (for_info.parsing_result.declarations.size() != 1) { impl()->ReportMessageAt(for_info.parsing_result.bindings_loc, MessageTemplate::kForInOfLoopMultiBindings, "for-await-of"); *ok = false; return impl()->NullStatement(); } // for-await-of's declarations do not permit initializers. if (for_info.parsing_result.first_initializer_loc.IsValid()) { impl()->ReportMessageAt(for_info.parsing_result.first_initializer_loc, MessageTemplate::kForInOfLoopInitializer, "for-await-of"); *ok = false; return impl()->NullStatement(); } } else { // The initializer does not contain declarations. // 'for' 'await' '(' LeftHandSideExpression 'of' AssignmentExpression ')' // Statement int lhs_beg_pos = peek_position(); BlockState inner_state(&scope_, inner_block_scope); ExpressionClassifier classifier(this); ExpressionT lhs = each_variable = ParseLeftHandSideExpression(CHECK_OK); int lhs_end_pos = scanner()->location().end_pos; if (lhs->IsArrayLiteral() || lhs->IsObjectLiteral()) { ValidateAssignmentPattern(CHECK_OK); } else { ValidateExpression(CHECK_OK); each_variable = CheckAndRewriteReferenceExpression( lhs, lhs_beg_pos, lhs_end_pos, MessageTemplate::kInvalidLhsInFor, kSyntaxError, CHECK_OK); } } ExpectContextualKeyword(Token::OF, CHECK_OK); int each_keyword_pos = scanner()->location().beg_pos; const bool kAllowIn = true; ExpressionT iterable = impl()->NullExpression(); { ExpressionClassifier classifier(this); iterable = ParseAssignmentExpression(kAllowIn, CHECK_OK); ValidateExpression(CHECK_OK); } Expect(Token::RPAREN, CHECK_OK); StatementT body = impl()->NullStatement(); { BlockState block_state(&scope_, inner_block_scope); scope()->set_start_position(scanner()->location().beg_pos); SourceRange body_range; SourceRangeScope range_scope(scanner(), &body_range); body = ParseStatement(nullptr, nullptr, CHECK_OK); scope()->set_end_position(scanner()->location().end_pos); impl()->RecordIterationStatementSourceRange(loop, range_scope.Finalize()); if (has_declarations) { BlockT body_block = impl()->NullStatement(); impl()->DesugarBindingInForEachStatement(&for_info, &body_block, &each_variable, CHECK_OK); body_block->statements()->Add(body, zone()); body_block->set_scope(scope()->FinalizeBlockScope()); body = body_block; } else { Scope* block_scope = scope()->FinalizeBlockScope(); DCHECK_NULL(block_scope); USE(block_scope); } } const bool finalize = true; StatementT final_loop = impl()->InitializeForOfStatement( loop, each_variable, iterable, body, finalize, IteratorType::kAsync, each_keyword_pos); if (!has_declarations) { Scope* for_scope = scope()->FinalizeBlockScope(); DCHECK_NULL(for_scope); USE(for_scope); return final_loop; } BlockT init_block = impl()->CreateForEachStatementTDZ(impl()->NullStatement(), for_info, ok); scope()->set_end_position(scanner()->location().end_pos); Scope* for_scope = scope()->FinalizeBlockScope(); // Parsed for-in loop w/ variable declarations. if (!impl()->IsNull(init_block)) { init_block->statements()->Add(final_loop, zone()); init_block->set_scope(for_scope); return init_block; } DCHECK_NULL(for_scope); return final_loop; } template <typename Impl> void ParserBase<Impl>::ObjectLiteralChecker::CheckDuplicateProto( Token::Value property) { if (property == Token::SMI || property == Token::NUMBER) return; if (IsProto()) { if (has_seen_proto_) { this->parser()->classifier()->RecordExpressionError( this->scanner()->location(), MessageTemplate::kDuplicateProto); return; } has_seen_proto_ = true; } } template <typename Impl> 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 (is_static) { if (IsPrototype()) { this->parser()->ReportMessage(MessageTemplate::kStaticPrototype); *ok = false; return; } } else if (IsConstructor()) { if (is_generator || is_async || type == PropertyKind::kAccessorProperty) { MessageTemplate::Template msg = is_generator ? MessageTemplate::kConstructorIsGenerator : is_async ? MessageTemplate::kConstructorIsAsync : MessageTemplate::kConstructorIsAccessor; this->parser()->ReportMessage(msg); *ok = false; return; } if (has_seen_constructor_) { this->parser()->ReportMessage(MessageTemplate::kDuplicateConstructor); *ok = false; return; } has_seen_constructor_ = true; return; } } template <typename Impl> void ParserBase<Impl>::ClassLiteralChecker::CheckClassFieldName(bool is_static, bool* ok) { if (is_static && IsPrototype()) { this->parser()->ReportMessage(MessageTemplate::kStaticPrototype); *ok = false; return; } if (IsConstructor() || IsPrivateConstructor()) { this->parser()->ReportMessage(MessageTemplate::kConstructorClassField); *ok = false; return; } } #undef CHECK_OK #undef CHECK_OK_CUSTOM #undef CHECK_OK_VOID } // namespace internal } // namespace v8 #endif // V8_PARSING_PARSER_BASE_H_