// 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_H_ #define V8_PARSING_PARSER_H_ #include <cstddef> #include "src/ast/ast-source-ranges.h" #include "src/ast/ast-value-factory.h" #include "src/ast/ast.h" #include "src/ast/scopes.h" #include "src/base/compiler-specific.h" #include "src/base/threaded-list.h" #include "src/common/globals.h" #include "src/parsing/parse-info.h" #include "src/parsing/parser-base.h" #include "src/parsing/parsing.h" #include "src/parsing/preparser.h" #include "src/utils/pointer-with-payload.h" #include "src/zone/zone-chunk-list.h" namespace v8 { class ScriptCompiler; namespace internal { class ConsumedPreparseData; class ParseInfo; class ParserTarget; class ParserTargetScope; class PendingCompilationErrorHandler; class PreparseData; // ---------------------------------------------------------------------------- // JAVASCRIPT PARSING class Parser; struct ParserFormalParameters : FormalParametersBase { struct Parameter : public ZoneObject { Parameter(Expression* pattern, Expression* initializer, int position, int initializer_end_position, bool is_rest) : initializer_and_is_rest(initializer, is_rest), pattern(pattern), position(position), initializer_end_position(initializer_end_position) {} PointerWithPayload<Expression, bool, 1> initializer_and_is_rest; Expression* pattern; Expression* initializer() const { return initializer_and_is_rest.GetPointer(); } int position; int initializer_end_position; inline bool is_rest() const { return initializer_and_is_rest.GetPayload(); } Parameter* next_parameter = nullptr; bool is_simple() const { return pattern->IsVariableProxy() && initializer() == nullptr && !is_rest(); } const AstRawString* name() const { DCHECK(is_simple()); return pattern->AsVariableProxy()->raw_name(); } Parameter** next() { return &next_parameter; } Parameter* const* next() const { return &next_parameter; } }; void set_strict_parameter_error(const Scanner::Location& loc, MessageTemplate message) { strict_error_loc = loc; strict_error_message = message; } bool has_duplicate() const { return duplicate_loc.IsValid(); } void ValidateDuplicate(Parser* parser) const; void ValidateStrictMode(Parser* parser) const; explicit ParserFormalParameters(DeclarationScope* scope) : FormalParametersBase(scope) {} base::ThreadedList<Parameter> params; Scanner::Location duplicate_loc = Scanner::Location::invalid(); Scanner::Location strict_error_loc = Scanner::Location::invalid(); MessageTemplate strict_error_message = MessageTemplate::kNone; }; template <> struct ParserTypes<Parser> { using Base = ParserBase<Parser>; using Impl = Parser; // Return types for traversing functions. using Block = v8::internal::Block*; using BreakableStatement = v8::internal::BreakableStatement*; using ClassLiteralProperty = ClassLiteral::Property*; using ClassPropertyList = ZonePtrList<ClassLiteral::Property>*; using Expression = v8::internal::Expression*; using ExpressionList = ScopedPtrList<v8::internal::Expression>; using FormalParameters = ParserFormalParameters; using ForStatement = v8::internal::ForStatement*; using FunctionLiteral = v8::internal::FunctionLiteral*; using Identifier = const AstRawString*; using IterationStatement = v8::internal::IterationStatement*; using ObjectLiteralProperty = ObjectLiteral::Property*; using ObjectPropertyList = ScopedPtrList<v8::internal::ObjectLiteralProperty>; using Statement = v8::internal::Statement*; using StatementList = ScopedPtrList<v8::internal::Statement>; using Suspend = v8::internal::Suspend*; // For constructing objects returned by the traversing functions. using Factory = AstNodeFactory; // Other implementation-specific functions. using FuncNameInferrer = v8::internal::FuncNameInferrer; using SourceRange = v8::internal::SourceRange; using SourceRangeScope = v8::internal::SourceRangeScope; }; class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { public: explicit Parser(ParseInfo* info); ~Parser() { delete reusable_preparser_; reusable_preparser_ = nullptr; } static bool IsPreParser() { return false; } // Sets the literal on |info| if parsing succeeded. void ParseOnBackground(ParseInfo* info, int start_position, int end_position, int function_literal_id); // Initializes an empty scope chain for top-level scripts, or scopes which // consist of only the native context. void InitializeEmptyScopeChain(ParseInfo* info); // Deserialize the scope chain prior to parsing in which the script is going // to be executed. If the script is a top-level script, or the scope chain // consists of only a native context, maybe_outer_scope_info should be an // empty handle. // // This only deserializes the scope chain, but doesn't connect the scopes to // their corresponding scope infos. Therefore, looking up variables in the // deserialized scopes is not possible. void DeserializeScopeChain(Isolate* isolate, ParseInfo* info, MaybeHandle<ScopeInfo> maybe_outer_scope_info, Scope::DeserializationMode mode = Scope::DeserializationMode::kScopesOnly); // Move statistics to Isolate void UpdateStatistics(Isolate* isolate, Handle<Script> script); template <typename LocalIsolate> void HandleSourceURLComments(LocalIsolate* isolate, Handle<Script> script); private: friend class ParserBase<Parser>; friend struct ParserFormalParameters; friend class i::ExpressionScope<ParserTypes<Parser>>; friend class i::VariableDeclarationParsingScope<ParserTypes<Parser>>; friend class i::ParameterDeclarationParsingScope<ParserTypes<Parser>>; friend class i::ArrowHeadParsingScope<ParserTypes<Parser>>; friend bool v8::internal::parsing::ParseProgram( ParseInfo*, Handle<Script>, MaybeHandle<ScopeInfo> maybe_outer_scope_info, Isolate*, parsing::ReportStatisticsMode stats_mode); friend bool v8::internal::parsing::ParseFunction( ParseInfo*, Handle<SharedFunctionInfo> shared_info, Isolate*, parsing::ReportStatisticsMode stats_mode); bool AllowsLazyParsingWithoutUnresolvedVariables() const { return !MaybeParsingArrowhead() && scope()->AllowsLazyParsingWithoutUnresolvedVariables( original_scope_); } bool parse_lazily() const { return mode_ == PARSE_LAZILY; } enum Mode { PARSE_LAZILY, PARSE_EAGERLY }; class ParsingModeScope { public: ParsingModeScope(Parser* parser, Mode mode) : parser_(parser), old_mode_(parser->mode_) { parser_->mode_ = mode; } ~ParsingModeScope() { parser_->mode_ = old_mode_; } private: Parser* parser_; Mode old_mode_; }; // Runtime encoding of different completion modes. enum CompletionKind { kNormalCompletion, kThrowCompletion, kAbruptCompletion }; Variable* NewTemporary(const AstRawString* name) { return scope()->NewTemporary(name); } void PrepareGeneratorVariables(); // Sets the literal on |info| if parsing succeeded. void ParseProgram(Isolate* isolate, Handle<Script> script, ParseInfo* info, MaybeHandle<ScopeInfo> maybe_outer_scope_info); // Sets the literal on |info| if parsing succeeded. void ParseFunction(Isolate* isolate, ParseInfo* info, Handle<SharedFunctionInfo> shared_info); void PostProcessParseResult(Isolate* isolate, ParseInfo* info, FunctionLiteral* literal); FunctionLiteral* DoParseFunction(Isolate* isolate, ParseInfo* info, int start_position, int end_position, int function_literal_id, const AstRawString* raw_name); // Called by ParseProgram after setting up the scanner. FunctionLiteral* DoParseProgram(Isolate* isolate, ParseInfo* info); // Parse with the script as if the source is implicitly wrapped in a function. // We manually construct the AST and scopes for a top-level function and the // function wrapper. void ParseWrapped(Isolate* isolate, ParseInfo* info, ScopedPtrList<Statement>* body, DeclarationScope* scope, Zone* zone); void ParseREPLProgram(ParseInfo* info, ScopedPtrList<Statement>* body, DeclarationScope* scope); Expression* WrapREPLResult(Expression* value); ZonePtrList<const AstRawString>* PrepareWrappedArguments(Isolate* isolate, ParseInfo* info, Zone* zone); PreParser* reusable_preparser() { if (reusable_preparser_ == nullptr) { reusable_preparser_ = new PreParser( &preparser_zone_, &scanner_, stack_limit_, ast_value_factory(), pending_error_handler(), runtime_call_stats_, logger_, flags(), parsing_on_main_thread_); reusable_preparser_->set_allow_eval_cache(allow_eval_cache()); preparse_data_buffer_.reserve(128); } return reusable_preparser_; } void ParseModuleItemList(ScopedPtrList<Statement>* body); Statement* ParseModuleItem(); const AstRawString* ParseModuleSpecifier(); void ParseImportDeclaration(); Statement* ParseExportDeclaration(); Statement* ParseExportDefault(); void ParseExportStar(); struct ExportClauseData { const AstRawString* export_name; const AstRawString* local_name; Scanner::Location location; }; ZoneChunkList<ExportClauseData>* ParseExportClause( Scanner::Location* reserved_loc); struct NamedImport : public ZoneObject { const AstRawString* import_name; const AstRawString* local_name; const Scanner::Location location; NamedImport(const AstRawString* import_name, const AstRawString* local_name, Scanner::Location location) : import_name(import_name), local_name(local_name), location(location) {} }; ZonePtrList<const NamedImport>* ParseNamedImports(int pos); Statement* BuildInitializationBlock(DeclarationParsingResult* parsing_result); Expression* RewriteReturn(Expression* return_value, int pos); Statement* RewriteSwitchStatement(SwitchStatement* switch_statement, Scope* scope); Block* RewriteCatchPattern(CatchInfo* catch_info); void ReportVarRedeclarationIn(const AstRawString* name, Scope* scope); Statement* RewriteTryStatement(Block* try_block, Block* catch_block, const SourceRange& catch_range, Block* finally_block, const SourceRange& finally_range, const CatchInfo& catch_info, int pos); void ParseAndRewriteGeneratorFunctionBody(int pos, FunctionKind kind, ScopedPtrList<Statement>* body); void ParseAndRewriteAsyncGeneratorFunctionBody( int pos, FunctionKind kind, ScopedPtrList<Statement>* body); void DeclareFunctionNameVar(const AstRawString* function_name, FunctionSyntaxKind function_syntax_kind, DeclarationScope* function_scope); Statement* DeclareFunction(const AstRawString* variable_name, FunctionLiteral* function, VariableMode mode, VariableKind kind, int beg_pos, int end_pos, ZonePtrList<const AstRawString>* names); Variable* CreateSyntheticContextVariable(const AstRawString* synthetic_name); Variable* CreatePrivateNameVariable(ClassScope* scope, VariableMode mode, IsStaticFlag is_static_flag, const AstRawString* name); FunctionLiteral* CreateInitializerFunction( const char* name, DeclarationScope* scope, ZonePtrList<ClassLiteral::Property>* fields); bool IdentifierEquals(const AstRawString* identifier, const AstRawString* other) { return identifier == other; } Statement* DeclareClass(const AstRawString* variable_name, Expression* value, ZonePtrList<const AstRawString>* names, int class_token_pos, int end_pos); void DeclareClassVariable(ClassScope* scope, const AstRawString* name, ClassInfo* class_info, int class_token_pos); void DeclareClassBrandVariable(ClassScope* scope, ClassInfo* class_info, int class_token_pos); void DeclarePrivateClassMember(ClassScope* scope, const AstRawString* property_name, ClassLiteralProperty* property, ClassLiteralProperty::Kind kind, bool is_static, ClassInfo* class_info); void DeclarePublicClassMethod(const AstRawString* class_name, ClassLiteralProperty* property, bool is_constructor, ClassInfo* class_info); void DeclarePublicClassField(ClassScope* scope, ClassLiteralProperty* property, bool is_static, bool is_computed_name, ClassInfo* class_info); void DeclareClassProperty(ClassScope* scope, const AstRawString* class_name, ClassLiteralProperty* property, bool is_constructor, ClassInfo* class_info); void DeclareClassField(ClassScope* scope, ClassLiteralProperty* property, const AstRawString* property_name, bool is_static, bool is_computed_name, bool is_private, ClassInfo* class_info); Expression* RewriteClassLiteral(ClassScope* block_scope, const AstRawString* name, ClassInfo* class_info, int pos, int end_pos); Statement* DeclareNative(const AstRawString* name, int pos); Block* IgnoreCompletion(Statement* statement); Scope* NewHiddenCatchScope(); bool HasCheckedSyntax() { return scope()->GetDeclarationScope()->has_checked_syntax(); } void InitializeVariables( ScopedPtrList<Statement>* statements, VariableKind kind, const DeclarationParsingResult::Declaration* declaration); Block* RewriteForVarInLegacy(const ForInfo& for_info); void DesugarBindingInForEachStatement(ForInfo* for_info, Block** body_block, Expression** each_variable); Block* CreateForEachStatementTDZ(Block* init_block, const ForInfo& for_info); Statement* DesugarLexicalBindingsInForStatement( ForStatement* loop, Statement* init, Expression* cond, Statement* next, Statement* body, Scope* inner_scope, const ForInfo& for_info); FunctionLiteral* ParseFunctionLiteral( const AstRawString* name, Scanner::Location function_name_location, FunctionNameValidity function_name_validity, FunctionKind kind, int function_token_position, FunctionSyntaxKind type, LanguageMode language_mode, ZonePtrList<const AstRawString>* arguments_for_wrapped_function); ObjectLiteral* InitializeObjectLiteral(ObjectLiteral* object_literal) { object_literal->CalculateEmitStore(main_zone()); return object_literal; } // Insert initializer statements for var-bindings shadowing parameter bindings // from a non-simple parameter list. void InsertShadowingVarBindingInitializers(Block* block); // Implement sloppy block-scoped functions, ES2015 Annex B 3.3 void InsertSloppyBlockFunctionVarBindings(DeclarationScope* scope); void DeclareUnboundVariable(const AstRawString* name, VariableMode mode, InitializationFlag init, int pos); V8_WARN_UNUSED_RESULT VariableProxy* DeclareBoundVariable(const AstRawString* name, VariableMode mode, int pos); void DeclareAndBindVariable(VariableProxy* proxy, VariableKind kind, VariableMode mode, Scope* declaration_scope, bool* was_added, int initializer_position); V8_WARN_UNUSED_RESULT Variable* DeclareVariable(const AstRawString* name, VariableKind kind, VariableMode mode, InitializationFlag init, Scope* declaration_scope, bool* was_added, int begin, int end = kNoSourcePosition); void Declare(Declaration* declaration, const AstRawString* name, VariableKind kind, VariableMode mode, InitializationFlag init, Scope* declaration_scope, bool* was_added, int var_begin_pos, int var_end_pos = kNoSourcePosition); // Factory methods. FunctionLiteral* DefaultConstructor(const AstRawString* name, bool call_super, int pos, int end_pos); // Skip over a lazy function, either using cached data if we have it, or // by parsing the function with PreParser. Consumes the ending }. // In case the preparser detects an error it cannot identify, it resets the // scanner- and preparser state to the initial one, before PreParsing the // function. // SkipFunction returns true if it correctly parsed the function, including // cases where we detect an error. It returns false, if we needed to stop // parsing or could not identify an error correctly, meaning the caller needs // to fully reparse. In this case it resets the scanner and preparser state. bool SkipFunction(const AstRawString* function_name, FunctionKind kind, FunctionSyntaxKind function_syntax_kind, DeclarationScope* function_scope, int* num_parameters, int* function_length, ProducedPreparseData** produced_preparsed_scope_data); Block* BuildParameterInitializationBlock( const ParserFormalParameters& parameters); Block* BuildRejectPromiseOnException(Block* block, REPLMode repl_mode = REPLMode::kNo); void ParseFunction( ScopedPtrList<Statement>* body, const AstRawString* function_name, int pos, FunctionKind kind, FunctionSyntaxKind function_syntax_kind, DeclarationScope* function_scope, int* num_parameters, int* function_length, bool* has_duplicate_parameters, int* expected_property_count, int* suspend_count, ZonePtrList<const AstRawString>* arguments_for_wrapped_function); void ThrowPendingError(Isolate* isolate, Handle<Script> script); class TemplateLiteral : public ZoneObject { public: TemplateLiteral(Zone* zone, int pos) : cooked_(8, zone), raw_(8, zone), expressions_(8, zone), pos_(pos) {} const ZonePtrList<const AstRawString>* cooked() const { return &cooked_; } const ZonePtrList<const AstRawString>* raw() const { return &raw_; } const ZonePtrList<Expression>* expressions() const { return &expressions_; } int position() const { return pos_; } void AddTemplateSpan(const AstRawString* cooked, const AstRawString* raw, int end, Zone* zone) { DCHECK_NOT_NULL(raw); cooked_.Add(cooked, zone); raw_.Add(raw, zone); } void AddExpression(Expression* expression, Zone* zone) { expressions_.Add(expression, zone); } private: ZonePtrList<const AstRawString> cooked_; ZonePtrList<const AstRawString> raw_; ZonePtrList<Expression> expressions_; int pos_; }; using TemplateLiteralState = TemplateLiteral*; TemplateLiteralState OpenTemplateLiteral(int pos); // "should_cook" means that the span can be "cooked": in tagged template // literals, both the raw and "cooked" representations are available to user // code ("cooked" meaning that escape sequences are converted to their // interpreted values). Invalid escape sequences cause the cooked span // to be represented by undefined, instead of being a syntax error. // "tail" indicates that this span is the last in the literal. void AddTemplateSpan(TemplateLiteralState* state, bool should_cook, bool tail); void AddTemplateExpression(TemplateLiteralState* state, Expression* expression); Expression* CloseTemplateLiteral(TemplateLiteralState* state, int start, Expression* tag); ArrayLiteral* ArrayLiteralFromListWithSpread( const ScopedPtrList<Expression>& list); Expression* SpreadCall(Expression* function, const ScopedPtrList<Expression>& args, int pos, Call::PossiblyEval is_possibly_eval, bool optional_chain); Expression* SpreadCallNew(Expression* function, const ScopedPtrList<Expression>& args, int pos); Expression* RewriteSuperCall(Expression* call_expression); void SetLanguageMode(Scope* scope, LanguageMode mode); void SetAsmModule(); Expression* RewriteSpreads(ArrayLiteral* lit); Expression* BuildInitialYield(int pos, FunctionKind kind); Assignment* BuildCreateJSGeneratorObject(int pos, FunctionKind kind); // Generic AST generator for throwing errors from compiled code. Expression* NewThrowError(Runtime::FunctionId function_id, MessageTemplate message, const AstRawString* arg, int pos); Statement* CheckCallable(Variable* var, Expression* error, int pos); void RewriteAsyncFunctionBody(ScopedPtrList<Statement>* body, Block* block, Expression* return_value, REPLMode repl_mode = REPLMode::kNo); void AddArrowFunctionFormalParameters(ParserFormalParameters* parameters, Expression* params, int end_pos); void SetFunctionName(Expression* value, const AstRawString* name, const AstRawString* prefix = nullptr); // Helper functions for recursive descent. V8_INLINE bool IsEval(const AstRawString* identifier) const { return identifier == ast_value_factory()->eval_string(); } V8_INLINE bool IsAsync(const AstRawString* identifier) const { return identifier == ast_value_factory()->async_string(); } V8_INLINE bool IsArguments(const AstRawString* identifier) const { return identifier == ast_value_factory()->arguments_string(); } V8_INLINE bool IsEvalOrArguments(const AstRawString* identifier) const { return IsEval(identifier) || IsArguments(identifier); } // Returns true if the expression is of type "this.foo". V8_INLINE static bool IsThisProperty(Expression* expression) { DCHECK_NOT_NULL(expression); Property* property = expression->AsProperty(); return property != nullptr && property->obj()->IsThisExpression(); } // Returns true if the expression is of type "obj.#foo" or "obj?.#foo". V8_INLINE static bool IsPrivateReference(Expression* expression) { DCHECK_NOT_NULL(expression); Property* property = expression->AsProperty(); if (expression->IsOptionalChain()) { Expression* expr_inner = expression->AsOptionalChain()->expression(); property = expr_inner->AsProperty(); } return property != nullptr && property->IsPrivateReference(); } // This returns true if the expression is an indentifier (wrapped // inside a variable proxy). We exclude the case of 'this', which // has been converted to a variable proxy. V8_INLINE static bool IsIdentifier(Expression* expression) { VariableProxy* operand = expression->AsVariableProxy(); return operand != nullptr && !operand->is_new_target(); } V8_INLINE static const AstRawString* AsIdentifier(Expression* expression) { DCHECK(IsIdentifier(expression)); return expression->AsVariableProxy()->raw_name(); } V8_INLINE VariableProxy* AsIdentifierExpression(Expression* expression) { return expression->AsVariableProxy(); } V8_INLINE bool IsConstructor(const AstRawString* identifier) const { return identifier == ast_value_factory()->constructor_string(); } V8_INLINE bool IsName(const AstRawString* identifier) const { return identifier == ast_value_factory()->name_string(); } V8_INLINE static bool IsBoilerplateProperty( ObjectLiteral::Property* property) { return !property->IsPrototype(); } V8_INLINE bool IsNative(Expression* expr) const { DCHECK_NOT_NULL(expr); return expr->IsVariableProxy() && expr->AsVariableProxy()->raw_name() == ast_value_factory()->native_string(); } V8_INLINE static bool IsArrayIndex(const AstRawString* string, uint32_t* index) { return string->AsArrayIndex(index); } // Returns true if the statement is an expression statement containing // a single string literal. If a second argument is given, the literal // is also compared with it and the result is true only if they are equal. V8_INLINE bool IsStringLiteral(Statement* statement, const AstRawString* arg = nullptr) const { ExpressionStatement* e_stat = statement->AsExpressionStatement(); if (e_stat == nullptr) return false; Literal* literal = e_stat->expression()->AsLiteral(); if (literal == nullptr || !literal->IsString()) return false; return arg == nullptr || literal->AsRawString() == arg; } V8_INLINE void GetDefaultStrings(const AstRawString** default_string, const AstRawString** dot_default_string) { *default_string = ast_value_factory()->default_string(); *dot_default_string = ast_value_factory()->dot_default_string(); } // Functions for encapsulating the differences between parsing and preparsing; // operations interleaved with the recursive descent. V8_INLINE void PushLiteralName(const AstRawString* id) { fni_.PushLiteralName(id); } V8_INLINE void PushVariableName(const AstRawString* id) { fni_.PushVariableName(id); } V8_INLINE void PushPropertyName(Expression* expression) { if (expression->IsPropertyName()) { fni_.PushLiteralName(expression->AsLiteral()->AsRawPropertyName()); } else { fni_.PushLiteralName(ast_value_factory()->computed_string()); } } V8_INLINE void PushEnclosingName(const AstRawString* name) { fni_.PushEnclosingName(name); } V8_INLINE void AddFunctionForNameInference(FunctionLiteral* func_to_infer) { fni_.AddFunction(func_to_infer); } V8_INLINE void InferFunctionName() { fni_.Infer(); } // If we assign a function literal to a property we pretenure the // literal so it can be added as a constant function property. V8_INLINE static void CheckAssigningFunctionLiteralToProperty( Expression* left, Expression* right) { DCHECK_NOT_NULL(left); if (left->IsProperty() && right->IsFunctionLiteral()) { right->AsFunctionLiteral()->set_pretenure(); } } // A shortcut for performing a ToString operation V8_INLINE Expression* ToString(Expression* expr) { if (expr->IsStringLiteral()) return expr; ScopedPtrList<Expression> args(pointer_buffer()); args.Add(expr); return factory()->NewCallRuntime(Runtime::kInlineToStringRT, args, expr->position()); } // Returns true if we have a binary expression between two numeric // literals. In that case, *x will be changed to an expression which is the // computed value. bool ShortcutNumericLiteralBinaryExpression(Expression** x, Expression* y, Token::Value op, int pos); // Returns true if we have a binary operation between a binary/n-ary // expression (with the same operation) and a value, which can be collapsed // into a single n-ary expression. In that case, *x will be changed to an // n-ary expression. bool CollapseNaryExpression(Expression** x, Expression* y, Token::Value op, int pos, const SourceRange& range); // Returns a UnaryExpression or, in one of the following cases, a Literal. // ! <literal> -> true / false // + <Number literal> -> <Number literal> // - <Number literal> -> <Number literal with value negated> // ~ <literal> -> true / false Expression* BuildUnaryExpression(Expression* expression, Token::Value op, int pos); // Generate AST node that throws a ReferenceError with the given type. V8_INLINE Expression* NewThrowReferenceError(MessageTemplate message, int pos) { return NewThrowError(Runtime::kNewReferenceError, message, ast_value_factory()->empty_string(), pos); } // Generate AST node that throws a SyntaxError with the given // type. The first argument may be null (in the handle sense) in // which case no arguments are passed to the constructor. V8_INLINE Expression* NewThrowSyntaxError(MessageTemplate message, const AstRawString* arg, int pos) { return NewThrowError(Runtime::kNewSyntaxError, message, arg, pos); } // Generate AST node that throws a TypeError with the given // type. Both arguments must be non-null (in the handle sense). V8_INLINE Expression* NewThrowTypeError(MessageTemplate message, const AstRawString* arg, int pos) { return NewThrowError(Runtime::kNewTypeError, message, arg, pos); } // Reporting errors. void ReportMessageAt(Scanner::Location source_location, MessageTemplate message, const char* arg = nullptr) { pending_error_handler()->ReportMessageAt( source_location.beg_pos, source_location.end_pos, message, arg); scanner_.set_parser_error(); } // Dummy implementation. The parser should never have a unidentifiable // error. V8_INLINE void ReportUnidentifiableError() { UNREACHABLE(); } void ReportMessageAt(Scanner::Location source_location, MessageTemplate message, const AstRawString* arg) { pending_error_handler()->ReportMessageAt( source_location.beg_pos, source_location.end_pos, message, arg); scanner_.set_parser_error(); } const AstRawString* GetRawNameFromIdentifier(const AstRawString* arg) { return arg; } IterationStatement* AsIterationStatement(BreakableStatement* s) { return s->AsIterationStatement(); } void ReportUnexpectedTokenAt( Scanner::Location location, Token::Value token, MessageTemplate message = MessageTemplate::kUnexpectedToken); // "null" return type creators. V8_INLINE static std::nullptr_t NullIdentifier() { return nullptr; } V8_INLINE static std::nullptr_t NullExpression() { return nullptr; } V8_INLINE static std::nullptr_t NullLiteralProperty() { return nullptr; } V8_INLINE static ZonePtrList<Expression>* NullExpressionList() { return nullptr; } V8_INLINE static ZonePtrList<Statement>* NullStatementList() { return nullptr; } V8_INLINE static std::nullptr_t NullStatement() { return nullptr; } V8_INLINE static std::nullptr_t NullBlock() { return nullptr; } Expression* FailureExpression() { return factory()->FailureExpression(); } template <typename T> V8_INLINE static bool IsNull(T subject) { return subject == nullptr; } V8_INLINE static bool IsIterationStatement(Statement* subject) { return subject->AsIterationStatement() != nullptr; } // Non-null empty string. V8_INLINE const AstRawString* EmptyIdentifierString() const { return ast_value_factory()->empty_string(); } // Producing data during the recursive descent. V8_INLINE const AstRawString* GetSymbol() const { const AstRawString* result = scanner()->CurrentSymbol(ast_value_factory()); DCHECK_NOT_NULL(result); return result; } V8_INLINE const AstRawString* GetIdentifier() const { return GetSymbol(); } V8_INLINE const AstRawString* GetNextSymbol() const { return scanner()->NextSymbol(ast_value_factory()); } V8_INLINE const AstRawString* GetNumberAsSymbol() const { double double_value = scanner()->DoubleValue(); char array[100]; const char* string = DoubleToCString(double_value, ArrayVector(array)); return ast_value_factory()->GetOneByteString(string); } class ThisExpression* ThisExpression() { UseThis(); return factory()->ThisExpression(); } Expression* NewSuperPropertyReference(int pos); Expression* NewSuperCallReference(int pos); Expression* NewTargetExpression(int pos); Expression* ImportMetaExpression(int pos); Expression* ExpressionFromLiteral(Token::Value token, int pos); V8_INLINE VariableProxy* ExpressionFromPrivateName( PrivateNameScopeIterator* private_name_scope, const AstRawString* name, int start_position) { VariableProxy* proxy = factory()->ast_node_factory()->NewVariableProxy( name, NORMAL_VARIABLE, start_position); private_name_scope->AddUnresolvedPrivateName(proxy); return proxy; } V8_INLINE VariableProxy* ExpressionFromIdentifier( const AstRawString* name, int start_position, InferName infer = InferName::kYes) { if (infer == InferName::kYes) { fni_.PushVariableName(name); } return expression_scope()->NewVariable(name, start_position); } V8_INLINE void DeclareIdentifier(const AstRawString* name, int start_position) { expression_scope()->Declare(name, start_position); } V8_INLINE Variable* DeclareCatchVariableName(Scope* scope, const AstRawString* name) { return scope->DeclareCatchVariableName(name); } V8_INLINE ZonePtrList<Expression>* NewExpressionList(int size) const { return zone()->New<ZonePtrList<Expression>>(size, zone()); } V8_INLINE ZonePtrList<ObjectLiteral::Property>* NewObjectPropertyList( int size) const { return zone()->New<ZonePtrList<ObjectLiteral::Property>>(size, zone()); } V8_INLINE ZonePtrList<ClassLiteral::Property>* NewClassPropertyList( int size) const { return zone()->New<ZonePtrList<ClassLiteral::Property>>(size, zone()); } V8_INLINE ZonePtrList<Statement>* NewStatementList(int size) const { return zone()->New<ZonePtrList<Statement>>(size, zone()); } Expression* NewV8Intrinsic(const AstRawString* name, const ScopedPtrList<Expression>& args, int pos); Expression* NewV8RuntimeFunctionForFuzzing( const Runtime::Function* function, const ScopedPtrList<Expression>& args, int pos); V8_INLINE Statement* NewThrowStatement(Expression* exception, int pos) { return factory()->NewExpressionStatement( factory()->NewThrow(exception, pos), pos); } V8_INLINE void AddFormalParameter(ParserFormalParameters* parameters, Expression* pattern, Expression* initializer, int initializer_end_position, bool is_rest) { parameters->UpdateArityAndFunctionLength(initializer != nullptr, is_rest); auto parameter = parameters->scope->zone()->New<ParserFormalParameters::Parameter>( pattern, initializer, scanner()->location().beg_pos, initializer_end_position, is_rest); parameters->params.Add(parameter); } V8_INLINE void DeclareFormalParameters(ParserFormalParameters* parameters) { bool is_simple = parameters->is_simple; DeclarationScope* scope = parameters->scope; if (!is_simple) scope->MakeParametersNonSimple(); for (auto parameter : parameters->params) { bool is_optional = parameter->initializer() != nullptr; // If the parameter list is simple, declare the parameters normally with // their names. If the parameter list is not simple, declare a temporary // for each parameter - the corresponding named variable is declared by // BuildParamerterInitializationBlock. scope->DeclareParameter( is_simple ? parameter->name() : ast_value_factory()->empty_string(), is_simple ? VariableMode::kVar : VariableMode::kTemporary, is_optional, parameter->is_rest(), ast_value_factory(), parameter->position); } } void DeclareArrowFunctionFormalParameters( ParserFormalParameters* parameters, Expression* params, const Scanner::Location& params_loc); Expression* ExpressionListToExpression(const ScopedPtrList<Expression>& args); void SetFunctionNameFromPropertyName(LiteralProperty* property, const AstRawString* name, const AstRawString* prefix = nullptr); void SetFunctionNameFromPropertyName(ObjectLiteralProperty* property, const AstRawString* name, const AstRawString* prefix = nullptr); void SetFunctionNameFromIdentifierRef(Expression* value, Expression* identifier); V8_INLINE void CountUsage(v8::Isolate::UseCounterFeature feature) { ++use_counts_[feature]; } // Returns true iff we're parsing the first function literal during // CreateDynamicFunction(). V8_INLINE bool ParsingDynamicFunctionDeclaration() const { return parameters_end_pos_ != kNoSourcePosition; } V8_INLINE void ConvertBinaryToNaryOperationSourceRange( BinaryOperation* binary_op, NaryOperation* nary_op) { if (source_range_map_ == nullptr) return; DCHECK_NULL(source_range_map_->Find(nary_op)); BinaryOperationSourceRanges* ranges = static_cast<BinaryOperationSourceRanges*>( source_range_map_->Find(binary_op)); if (ranges == nullptr) return; SourceRange range = ranges->GetRange(SourceRangeKind::kRight); source_range_map_->Insert( nary_op, zone()->New<NaryOperationSourceRanges>(zone(), range)); } V8_INLINE void AppendNaryOperationSourceRange(NaryOperation* node, const SourceRange& range) { if (source_range_map_ == nullptr) return; NaryOperationSourceRanges* ranges = static_cast<NaryOperationSourceRanges*>(source_range_map_->Find(node)); if (ranges == nullptr) return; ranges->AddRange(range); DCHECK_EQ(node->subsequent_length(), ranges->RangeCount()); } V8_INLINE void RecordBlockSourceRange(Block* node, int32_t continuation_position) { if (source_range_map_ == nullptr) return; source_range_map_->Insert( node, zone()->New<BlockSourceRanges>(continuation_position)); } V8_INLINE void RecordCaseClauseSourceRange(CaseClause* node, const SourceRange& body_range) { if (source_range_map_ == nullptr) return; source_range_map_->Insert(node, zone()->New<CaseClauseSourceRanges>(body_range)); } V8_INLINE void RecordConditionalSourceRange(Expression* node, const SourceRange& then_range, const SourceRange& else_range) { if (source_range_map_ == nullptr) return; source_range_map_->Insert( node->AsConditional(), zone()->New<ConditionalSourceRanges>(then_range, else_range)); } V8_INLINE void RecordFunctionLiteralSourceRange(FunctionLiteral* node) { if (source_range_map_ == nullptr) return; source_range_map_->Insert(node, zone()->New<FunctionLiteralSourceRanges>()); } V8_INLINE void RecordBinaryOperationSourceRange( Expression* node, const SourceRange& right_range) { if (source_range_map_ == nullptr) return; source_range_map_->Insert( node->AsBinaryOperation(), zone()->New<BinaryOperationSourceRanges>(right_range)); } V8_INLINE void RecordJumpStatementSourceRange(Statement* node, int32_t continuation_position) { if (source_range_map_ == nullptr) return; source_range_map_->Insert( static_cast<JumpStatement*>(node), zone()->New<JumpStatementSourceRanges>(continuation_position)); } V8_INLINE void RecordIfStatementSourceRange(Statement* node, const SourceRange& then_range, const SourceRange& else_range) { if (source_range_map_ == nullptr) return; source_range_map_->Insert( node->AsIfStatement(), zone()->New<IfStatementSourceRanges>(then_range, else_range)); } V8_INLINE void RecordIterationStatementSourceRange( IterationStatement* node, const SourceRange& body_range) { if (source_range_map_ == nullptr) return; source_range_map_->Insert( node, zone()->New<IterationStatementSourceRanges>(body_range)); } V8_INLINE void RecordSuspendSourceRange(Expression* node, int32_t continuation_position) { if (source_range_map_ == nullptr) return; source_range_map_->Insert( static_cast<Suspend*>(node), zone()->New<SuspendSourceRanges>(continuation_position)); } V8_INLINE void RecordSwitchStatementSourceRange( Statement* node, int32_t continuation_position) { if (source_range_map_ == nullptr) return; source_range_map_->Insert( node->AsSwitchStatement(), zone()->New<SwitchStatementSourceRanges>(continuation_position)); } V8_INLINE void RecordThrowSourceRange(Statement* node, int32_t continuation_position) { if (source_range_map_ == nullptr) return; ExpressionStatement* expr_stmt = static_cast<ExpressionStatement*>(node); Throw* throw_expr = expr_stmt->expression()->AsThrow(); source_range_map_->Insert( throw_expr, zone()->New<ThrowSourceRanges>(continuation_position)); } V8_INLINE void RecordTryCatchStatementSourceRange( TryCatchStatement* node, const SourceRange& body_range) { if (source_range_map_ == nullptr) return; source_range_map_->Insert( node, zone()->New<TryCatchStatementSourceRanges>(body_range)); } V8_INLINE void RecordTryFinallyStatementSourceRange( TryFinallyStatement* node, const SourceRange& body_range) { if (source_range_map_ == nullptr) return; source_range_map_->Insert( node, zone()->New<TryFinallyStatementSourceRanges>(body_range)); } // Generate the next internal variable name for binding an exported namespace // object (used to implement the "export * as" syntax). const AstRawString* NextInternalNamespaceExportName(); ParseInfo* info() const { return info_; } std::vector<uint8_t>* preparse_data_buffer() { return &preparse_data_buffer_; } // Parser's private field members. friend class PreParserZoneScope; // Uses reusable_preparser(). friend class PreparseDataBuilder; // Uses preparse_data_buffer() ParseInfo* info_; Scanner scanner_; Zone preparser_zone_; PreParser* reusable_preparser_; Mode mode_; MaybeHandle<FixedArray> maybe_wrapped_arguments_; SourceRangeMap* source_range_map_ = nullptr; friend class ParserTargetScope; ScriptCompiler::CompileOptions compile_options_; // For NextInternalNamespaceExportName(). int number_of_named_namespace_exports_ = 0; // Other information which will be stored in Parser and moved to Isolate after // parsing. int use_counts_[v8::Isolate::kUseCounterFeatureCount]; int total_preparse_skipped_; bool allow_lazy_; bool temp_zoned_; ConsumedPreparseData* consumed_preparse_data_; std::vector<uint8_t> preparse_data_buffer_; // If not kNoSourcePosition, indicates that the first function literal // encountered is a dynamic function, see CreateDynamicFunction(). This field // indicates the correct position of the ')' that closes the parameter list. // After that ')' is encountered, this field is reset to kNoSourcePosition. int parameters_end_pos_; }; } // namespace internal } // namespace v8 #endif // V8_PARSING_PARSER_H_