| // 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.h" | |
| #include "src/ast/scopes.h" | |
| #include "src/base/compiler-specific.h" | |
| #include "src/globals.h" | |
| #include "src/parsing/parser-base.h" | |
| #include "src/parsing/parsing.h" | |
| #include "src/parsing/preparser.h" | |
| #include "src/utils.h" | |
| #include "src/zone/zone-chunk-list.h" | |
| namespace v8 { | |
| class ScriptCompiler; | |
| namespace internal { | |
| class ConsumedPreParsedScopeData; | |
| class ParseInfo; | |
| class ParserTarget; | |
| class ParserTargetScope; | |
| class PendingCompilationErrorHandler; | |
| class PreParsedScopeData; | |
| class FunctionEntry BASE_EMBEDDED { | |
| public: | |
| enum { | |
| kStartPositionIndex, | |
| kEndPositionIndex, | |
| kNumParametersIndex, | |
| kFlagsIndex, | |
| kNumInnerFunctionsIndex, | |
| kSize | |
| }; | |
| explicit FunctionEntry(Vector<unsigned> backing) | |
| : backing_(backing) { } | |
| FunctionEntry() : backing_() { } | |
| class LanguageModeField : public BitField<LanguageMode, 0, 1> {}; | |
| class UsesSuperPropertyField | |
| : public BitField<bool, LanguageModeField::kNext, 1> {}; | |
| static uint32_t EncodeFlags(LanguageMode language_mode, | |
| bool uses_super_property) { | |
| return LanguageModeField::encode(language_mode) | | |
| UsesSuperPropertyField::encode(uses_super_property); | |
| } | |
| int start_pos() const { return backing_[kStartPositionIndex]; } | |
| int end_pos() const { return backing_[kEndPositionIndex]; } | |
| int num_parameters() const { return backing_[kNumParametersIndex]; } | |
| LanguageMode language_mode() const { | |
| return LanguageModeField::decode(backing_[kFlagsIndex]); | |
| } | |
| bool uses_super_property() const { | |
| return UsesSuperPropertyField::decode(backing_[kFlagsIndex]); | |
| } | |
| int num_inner_functions() const { return backing_[kNumInnerFunctionsIndex]; } | |
| bool is_valid() const { return !backing_.is_empty(); } | |
| private: | |
| Vector<unsigned> backing_; | |
| }; | |
| // ---------------------------------------------------------------------------- | |
| // JAVASCRIPT PARSING | |
| class Parser; | |
| struct ParserFormalParameters : FormalParametersBase { | |
| struct Parameter : public ZoneObject { | |
| Parameter(const AstRawString* name, Expression* pattern, | |
| Expression* initializer, int position, | |
| int initializer_end_position, bool is_rest) | |
| : name(name), | |
| pattern(pattern), | |
| initializer(initializer), | |
| position(position), | |
| initializer_end_position(initializer_end_position), | |
| is_rest(is_rest) {} | |
| const AstRawString* name; | |
| Expression* pattern; | |
| Expression* initializer; | |
| int position; | |
| int initializer_end_position; | |
| bool is_rest; | |
| Parameter* next_parameter = nullptr; | |
| bool is_simple() const { | |
| return pattern->IsVariableProxy() && initializer == nullptr && !is_rest; | |
| } | |
| Parameter** next() { return &next_parameter; } | |
| Parameter* const* next() const { return &next_parameter; } | |
| }; | |
| explicit ParserFormalParameters(DeclarationScope* scope) | |
| : FormalParametersBase(scope) {} | |
| ThreadedList<Parameter> params; | |
| }; | |
| template <> | |
| struct ParserTypes<Parser> { | |
| typedef ParserBase<Parser> Base; | |
| typedef Parser Impl; | |
| // Return types for traversing functions. | |
| typedef const AstRawString* Identifier; | |
| typedef v8::internal::Expression* Expression; | |
| typedef v8::internal::FunctionLiteral* FunctionLiteral; | |
| typedef ObjectLiteral::Property* ObjectLiteralProperty; | |
| typedef ClassLiteral::Property* ClassLiteralProperty; | |
| typedef v8::internal::Suspend* Suspend; | |
| typedef v8::internal::RewritableExpression* RewritableExpression; | |
| typedef ZonePtrList<v8::internal::Expression>* ExpressionList; | |
| typedef ZonePtrList<ObjectLiteral::Property>* ObjectPropertyList; | |
| typedef ZonePtrList<ClassLiteral::Property>* ClassPropertyList; | |
| typedef ParserFormalParameters FormalParameters; | |
| typedef v8::internal::Statement* Statement; | |
| typedef ZonePtrList<v8::internal::Statement>* StatementList; | |
| typedef v8::internal::Block* Block; | |
| typedef v8::internal::BreakableStatement* BreakableStatement; | |
| typedef v8::internal::ForStatement* ForStatement; | |
| typedef v8::internal::IterationStatement* IterationStatement; | |
| // For constructing objects returned by the traversing functions. | |
| typedef AstNodeFactory Factory; | |
| typedef ParserTarget Target; | |
| typedef ParserTargetScope TargetScope; | |
| }; | |
| 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; } | |
| void ParseOnBackground(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); | |
| // Move statistics to Isolate | |
| void UpdateStatistics(Isolate* isolate, Handle<Script> script); | |
| void HandleSourceURLComments(Isolate* isolate, Handle<Script> script); | |
| private: | |
| friend class ParserBase<Parser>; | |
| friend class v8::internal::ExpressionClassifier<ParserTypes<Parser>>; | |
| friend bool v8::internal::parsing::ParseProgram(ParseInfo*, Isolate*); | |
| friend bool v8::internal::parsing::ParseFunction( | |
| ParseInfo*, Handle<SharedFunctionInfo> shared_info, Isolate*); | |
| bool AllowsLazyParsingWithoutUnresolvedVariables() const { | |
| return scope()->AllowsLazyParsingWithoutUnresolvedVariables( | |
| original_scope_); | |
| } | |
| bool parse_lazily() const { return mode_ == PARSE_LAZILY; } | |
| enum Mode { PARSE_LAZILY, PARSE_EAGERLY }; | |
| class ParsingModeScope BASE_EMBEDDED { | |
| 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(); | |
| // Returns nullptr if parsing failed. | |
| FunctionLiteral* ParseProgram(Isolate* isolate, ParseInfo* info); | |
| FunctionLiteral* ParseFunction(Isolate* isolate, ParseInfo* info, | |
| Handle<SharedFunctionInfo> shared_info); | |
| FunctionLiteral* DoParseFunction(Isolate* isolate, ParseInfo* info, | |
| 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, | |
| ZonePtrList<Statement>* body, DeclarationScope* scope, | |
| Zone* zone, bool* ok); | |
| ZonePtrList<const AstRawString>* PrepareWrappedArguments(Isolate* isolate, | |
| ParseInfo* info, | |
| Zone* zone); | |
| void StitchAst(ParseInfo* top_level_parse_info, Isolate* isolate); | |
| PreParser* reusable_preparser() { | |
| if (reusable_preparser_ == nullptr) { | |
| reusable_preparser_ = | |
| new PreParser(zone(), &scanner_, stack_limit_, ast_value_factory(), | |
| pending_error_handler(), runtime_call_stats_, logger_, | |
| -1, parsing_module_, parsing_on_main_thread_); | |
| #define SET_ALLOW(name) reusable_preparser_->set_allow_##name(allow_##name()); | |
| SET_ALLOW(natives); | |
| SET_ALLOW(harmony_do_expressions); | |
| SET_ALLOW(harmony_public_fields); | |
| SET_ALLOW(harmony_static_fields); | |
| SET_ALLOW(harmony_dynamic_import); | |
| SET_ALLOW(harmony_import_meta); | |
| SET_ALLOW(harmony_bigint); | |
| SET_ALLOW(harmony_private_fields); | |
| SET_ALLOW(eval_cache); | |
| #undef SET_ALLOW | |
| } | |
| return reusable_preparser_; | |
| } | |
| void ParseModuleItemList(ZonePtrList<Statement>* body, bool* ok); | |
| Statement* ParseModuleItem(bool* ok); | |
| const AstRawString* ParseModuleSpecifier(bool* ok); | |
| void ParseImportDeclaration(bool* ok); | |
| Statement* ParseExportDeclaration(bool* ok); | |
| Statement* ParseExportDefault(bool* ok); | |
| struct ExportClauseData { | |
| const AstRawString* export_name; | |
| const AstRawString* local_name; | |
| Scanner::Location location; | |
| }; | |
| ZoneChunkList<ExportClauseData>* ParseExportClause( | |
| Scanner::Location* reserved_loc, bool* ok); | |
| 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, bool* ok); | |
| Block* BuildInitializationBlock(DeclarationParsingResult* parsing_result, | |
| ZonePtrList<const AstRawString>* names, | |
| bool* ok); | |
| void DeclareLabel(ZonePtrList<const AstRawString>** labels, | |
| ZonePtrList<const AstRawString>** own_labels, | |
| VariableProxy* expr, bool* ok); | |
| bool ContainsLabel(ZonePtrList<const AstRawString>* labels, | |
| const AstRawString* label); | |
| Expression* RewriteReturn(Expression* return_value, int pos); | |
| Statement* RewriteSwitchStatement(SwitchStatement* switch_statement, | |
| Scope* scope); | |
| void RewriteCatchPattern(CatchInfo* catch_info, bool* ok); | |
| void ValidateCatchBlock(const CatchInfo& catch_info, bool* ok); | |
| 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, | |
| ZonePtrList<Statement>* body, | |
| bool* ok); | |
| void ParseAndRewriteAsyncGeneratorFunctionBody(int pos, FunctionKind kind, | |
| ZonePtrList<Statement>* body, | |
| bool* ok); | |
| void DeclareFunctionNameVar(const AstRawString* function_name, | |
| FunctionLiteral::FunctionType function_type, | |
| DeclarationScope* function_scope); | |
| Statement* DeclareFunction(const AstRawString* variable_name, | |
| FunctionLiteral* function, VariableMode mode, | |
| int pos, bool is_sloppy_block_function, | |
| ZonePtrList<const AstRawString>* names, bool* ok); | |
| Variable* CreateSyntheticContextVariable(const AstRawString* synthetic_name, | |
| bool* ok); | |
| FunctionLiteral* CreateInitializerFunction( | |
| DeclarationScope* scope, ZonePtrList<ClassLiteral::Property>* fields); | |
| V8_INLINE Statement* DeclareClass(const AstRawString* variable_name, | |
| Expression* value, | |
| ZonePtrList<const AstRawString>* names, | |
| int class_token_pos, int end_pos, bool* ok); | |
| V8_INLINE void DeclareClassVariable(const AstRawString* name, | |
| ClassInfo* class_info, | |
| int class_token_pos, bool* ok); | |
| V8_INLINE void DeclareClassProperty(const AstRawString* class_name, | |
| ClassLiteralProperty* property, | |
| const AstRawString* property_name, | |
| ClassLiteralProperty::Kind kind, | |
| bool is_static, bool is_constructor, | |
| bool is_computed_name, | |
| ClassInfo* class_info, bool* ok); | |
| V8_INLINE Expression* RewriteClassLiteral(Scope* block_scope, | |
| const AstRawString* name, | |
| ClassInfo* class_info, int pos, | |
| int end_pos, bool* ok); | |
| V8_INLINE Statement* DeclareNative(const AstRawString* name, int pos, | |
| bool* ok); | |
| V8_INLINE Block* IgnoreCompletion(Statement* statement); | |
| V8_INLINE Scope* NewHiddenCatchScope(); | |
| // PatternRewriter and associated methods defined in pattern-rewriter.cc. | |
| friend class PatternRewriter; | |
| void DeclareAndInitializeVariables( | |
| Block* block, const DeclarationDescriptor* declaration_descriptor, | |
| const DeclarationParsingResult::Declaration* declaration, | |
| ZonePtrList<const AstRawString>* names, bool* ok); | |
| void RewriteDestructuringAssignment(RewritableExpression* expr); | |
| Expression* RewriteDestructuringAssignment(Assignment* assignment); | |
| // [if (IteratorType == kAsync)] | |
| // !%_IsJSReceiver(result = Await(next.[[Call]](iterator, « »)) && | |
| // %ThrowIteratorResultNotAnObject(result) | |
| // [else] | |
| // !%_IsJSReceiver(result = next.[[Call]](iterator, « »)) && | |
| // %ThrowIteratorResultNotAnObject(result) | |
| // [endif] | |
| Expression* BuildIteratorNextResult(VariableProxy* iterator, | |
| VariableProxy* next, Variable* result, | |
| IteratorType type, int pos); | |
| // Initialize the components of a for-in / for-of statement. | |
| Statement* InitializeForEachStatement(ForEachStatement* stmt, | |
| Expression* each, Expression* subject, | |
| Statement* body); | |
| Statement* InitializeForOfStatement(ForOfStatement* stmt, Expression* each, | |
| Expression* iterable, Statement* body, | |
| bool finalize, IteratorType type, | |
| int next_result_pos = kNoSourcePosition); | |
| Block* RewriteForVarInLegacy(const ForInfo& for_info); | |
| void DesugarBindingInForEachStatement(ForInfo* for_info, Block** body_block, | |
| Expression** each_variable, bool* ok); | |
| Block* CreateForEachStatementTDZ(Block* init_block, const ForInfo& for_info, | |
| bool* ok); | |
| Statement* DesugarLexicalBindingsInForStatement( | |
| ForStatement* loop, Statement* init, Expression* cond, Statement* next, | |
| Statement* body, Scope* inner_scope, const ForInfo& for_info, bool* ok); | |
| Expression* RewriteDoExpression(Block* body, int pos, bool* ok); | |
| FunctionLiteral* ParseFunctionLiteral( | |
| const AstRawString* name, Scanner::Location function_name_location, | |
| FunctionNameValidity function_name_validity, FunctionKind kind, | |
| int function_token_position, FunctionLiteral::FunctionType type, | |
| LanguageMode language_mode, | |
| ZonePtrList<const AstRawString>* arguments_for_wrapped_function, | |
| bool* ok); | |
| ObjectLiteral* InitializeObjectLiteral(ObjectLiteral* object_literal) { | |
| object_literal->CalculateEmitStore(main_zone()); | |
| return object_literal; | |
| } | |
| // Check if the scope has conflicting var/let declarations from different | |
| // scopes. This covers for example | |
| // | |
| // function f() { { { var x; } let x; } } | |
| // function g() { { var x; let x; } } | |
| // | |
| // The var declarations are hoisted to the function scope, but originate from | |
| // a scope where the name has also been let bound or the var declaration is | |
| // hoisted over such a scope. | |
| void CheckConflictingVarDeclarations(Scope* scope, bool* ok); | |
| bool IsPropertyWithPrivateFieldKey(Expression* property); | |
| // 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); | |
| VariableProxy* NewUnresolved(const AstRawString* name, int begin_pos, | |
| VariableKind kind = NORMAL_VARIABLE); | |
| VariableProxy* NewUnresolved(const AstRawString* name); | |
| Variable* Declare(Declaration* declaration, | |
| DeclarationDescriptor::Kind declaration_kind, | |
| VariableMode mode, InitializationFlag init, bool* ok, | |
| Scope* declaration_scope = nullptr, | |
| int var_end_pos = kNoSourcePosition); | |
| Declaration* DeclareVariable(const AstRawString* name, VariableMode mode, | |
| int pos, bool* ok); | |
| Declaration* DeclareVariable(const AstRawString* name, VariableMode mode, | |
| InitializationFlag init, int pos, bool* ok); | |
| bool TargetStackContainsLabel(const AstRawString* label); | |
| BreakableStatement* LookupBreakTarget(const AstRawString* label, bool* ok); | |
| IterationStatement* LookupContinueTarget(const AstRawString* label, bool* ok); | |
| Statement* BuildAssertIsCoercible(Variable* var, ObjectLiteral* pattern); | |
| // 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 }. | |
| // If may_abort == true, the (pre-)parser may decide to abort skipping | |
| // in order to force the function to be eagerly parsed, after all. | |
| LazyParsingResult SkipFunction( | |
| const AstRawString* function_name, FunctionKind kind, | |
| FunctionLiteral::FunctionType function_type, | |
| DeclarationScope* function_scope, int* num_parameters, | |
| ProducedPreParsedScopeData** produced_preparsed_scope_data, | |
| bool is_inner_function, bool may_abort, bool* ok); | |
| Block* BuildParameterInitializationBlock( | |
| const ParserFormalParameters& parameters, bool* ok); | |
| Block* BuildRejectPromiseOnException(Block* block); | |
| ZonePtrList<Statement>* ParseFunction( | |
| const AstRawString* function_name, int pos, FunctionKind kind, | |
| FunctionLiteral::FunctionType function_type, | |
| 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, | |
| bool* ok); | |
| 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) { | |
| DCHECK_NOT_NULL(expression); | |
| expressions_.Add(expression, zone); | |
| } | |
| private: | |
| ZonePtrList<const AstRawString> cooked_; | |
| ZonePtrList<const AstRawString> raw_; | |
| ZonePtrList<Expression> expressions_; | |
| int pos_; | |
| }; | |
| typedef TemplateLiteral* TemplateLiteralState; | |
| 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(ZonePtrList<Expression>* list); | |
| Expression* SpreadCall(Expression* function, ZonePtrList<Expression>* args, | |
| int pos, Call::PossiblyEval is_possibly_eval); | |
| Expression* SpreadCallNew(Expression* function, ZonePtrList<Expression>* args, | |
| int pos); | |
| Expression* RewriteSuperCall(Expression* call_expression); | |
| void SetLanguageMode(Scope* scope, LanguageMode mode); | |
| void SetAsmModule(); | |
| // Rewrite all DestructuringAssignments in the current FunctionState. | |
| V8_INLINE void RewriteDestructuringAssignments(); | |
| Expression* RewriteSpreads(ArrayLiteral* lit); | |
| V8_INLINE void QueueDestructuringAssignmentForRewriting( | |
| RewritableExpression* assignment); | |
| friend class InitializerRewriter; | |
| void RewriteParameterInitializer(Expression* expr); | |
| Expression* BuildInitialYield(int pos, FunctionKind kind); | |
| Assignment* BuildCreateJSGeneratorObject(int pos, FunctionKind kind); | |
| Expression* BuildResolvePromise(Expression* value, int pos); | |
| Expression* BuildRejectPromise(Expression* value, int pos); | |
| Variable* PromiseVariable(); | |
| Variable* AsyncGeneratorAwaitVariable(); | |
| // Generic AST generator for throwing errors from compiled code. | |
| Expression* NewThrowError(Runtime::FunctionId function_id, | |
| MessageTemplate::Template message, | |
| const AstRawString* arg, int pos); | |
| void FinalizeIteratorUse(Variable* completion, Expression* condition, | |
| Variable* iter, Block* iterator_use, Block* result, | |
| IteratorType type); | |
| Statement* FinalizeForOfStatement(ForOfStatement* loop, Variable* completion, | |
| IteratorType type, int pos); | |
| void BuildIteratorClose(ZonePtrList<Statement>* statements, | |
| Variable* iterator, Variable* input, Variable* output, | |
| IteratorType type); | |
| void BuildIteratorCloseForCompletion(ZonePtrList<Statement>* statements, | |
| Variable* iterator, | |
| Expression* completion, | |
| IteratorType type); | |
| Statement* CheckCallable(Variable* var, Expression* error, int pos); | |
| V8_INLINE void RewriteAsyncFunctionBody(ZonePtrList<Statement>* body, | |
| Block* block, | |
| Expression* return_value, bool* ok); | |
| void AddArrowFunctionFormalParameters(ParserFormalParameters* parameters, | |
| Expression* params, int end_pos, | |
| bool* ok); | |
| 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 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()->IsVariableProxy() && | |
| property->obj()->AsVariableProxy()->is_this(); | |
| } | |
| // 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) { | |
| DCHECK_NOT_NULL(expression); | |
| VariableProxy* operand = expression->AsVariableProxy(); | |
| return operand != nullptr && !operand->is_this() && | |
| !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); | |
| } | |
| V8_INLINE bool IsUseStrictDirective(Statement* statement) const { | |
| return IsStringLiteral(statement, ast_value_factory()->use_strict_string()); | |
| } | |
| V8_INLINE bool IsUseAsmDirective(Statement* statement) const { | |
| return IsStringLiteral(statement, ast_value_factory()->use_asm_string()); | |
| } | |
| // 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** star_default_star_string) { | |
| *default_string = ast_value_factory()->default_string(); | |
| *star_default_star_string = ast_value_factory()->star_default_star_string(); | |
| } | |
| // Functions for encapsulating the differences between parsing and preparsing; | |
| // operations interleaved with the recursive descent. | |
| V8_INLINE void PushLiteralName(const AstRawString* id) { | |
| DCHECK_NOT_NULL(fni_); | |
| fni_->PushLiteralName(id); | |
| } | |
| V8_INLINE void PushVariableName(const AstRawString* id) { | |
| DCHECK_NOT_NULL(fni_); | |
| fni_->PushVariableName(id); | |
| } | |
| V8_INLINE void PushPropertyName(Expression* expression) { | |
| DCHECK_NOT_NULL(fni_); | |
| if (expression->IsPropertyName()) { | |
| fni_->PushLiteralName(expression->AsLiteral()->AsRawPropertyName()); | |
| } else { | |
| fni_->PushLiteralName(ast_value_factory()->anonymous_function_string()); | |
| } | |
| } | |
| V8_INLINE void PushEnclosingName(const AstRawString* name) { | |
| DCHECK_NOT_NULL(fni_); | |
| fni_->PushEnclosingName(name); | |
| } | |
| V8_INLINE void AddFunctionForNameInference(FunctionLiteral* func_to_infer) { | |
| DCHECK_NOT_NULL(fni_); | |
| fni_->AddFunction(func_to_infer); | |
| } | |
| V8_INLINE void InferFunctionName() { | |
| DCHECK_NOT_NULL(fni_); | |
| 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(); | |
| } | |
| } | |
| // Determine if the expression is a variable proxy and mark it as being used | |
| // in an assignment or with a increment/decrement operator. | |
| V8_INLINE static void MarkExpressionAsAssigned(Expression* expression) { | |
| DCHECK_NOT_NULL(expression); | |
| if (expression->IsVariableProxy()) { | |
| expression->AsVariableProxy()->set_is_assigned(); | |
| } | |
| } | |
| // A shortcut for performing a ToString operation | |
| V8_INLINE Expression* ToString(Expression* expr) { | |
| if (expr->IsStringLiteral()) return expr; | |
| ZonePtrList<Expression>* args = | |
| new (zone()) ZonePtrList<Expression>(1, zone()); | |
| args->Add(expr, zone()); | |
| return factory()->NewCallRuntime(Runtime::kInlineToString, 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::Template 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::Template 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::Template message, | |
| const AstRawString* arg, int pos) { | |
| return NewThrowError(Runtime::kNewTypeError, message, arg, pos); | |
| } | |
| // Reporting errors. | |
| void ReportMessageAt(Scanner::Location source_location, | |
| MessageTemplate::Template message, | |
| const char* arg = nullptr, | |
| ParseErrorType error_type = kSyntaxError) { | |
| if (stack_overflow()) { | |
| // Suppress the error message (syntax error or such) in the presence of a | |
| // stack overflow. The isolate allows only one pending exception at at | |
| // time | |
| // and we want to report the stack overflow later. | |
| return; | |
| } | |
| pending_error_handler()->ReportMessageAt(source_location.beg_pos, | |
| source_location.end_pos, message, | |
| arg, error_type); | |
| } | |
| void ReportMessageAt(Scanner::Location source_location, | |
| MessageTemplate::Template message, | |
| const AstRawString* arg, | |
| ParseErrorType error_type = kSyntaxError) { | |
| if (stack_overflow()) { | |
| // Suppress the error message (syntax error or such) in the presence of a | |
| // stack overflow. The isolate allows only one pending exception at at | |
| // time | |
| // and we want to report the stack overflow later. | |
| return; | |
| } | |
| pending_error_handler()->ReportMessageAt(source_location.beg_pos, | |
| source_location.end_pos, message, | |
| arg, error_type); | |
| } | |
| // "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; } | |
| template <typename T> | |
| V8_INLINE static bool IsNull(T subject) { | |
| return subject == 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* 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); | |
| } | |
| V8_INLINE Expression* ThisExpression(int pos = kNoSourcePosition) { | |
| return NewUnresolved(ast_value_factory()->this_string(), pos, | |
| THIS_VARIABLE); | |
| } | |
| Expression* NewSuperPropertyReference(int pos); | |
| Expression* NewSuperCallReference(int pos); | |
| Expression* NewTargetExpression(int pos); | |
| Expression* ImportMetaExpression(int pos); | |
| Literal* ExpressionFromLiteral(Token::Value token, int pos); | |
| V8_INLINE VariableProxy* ExpressionFromIdentifier( | |
| const AstRawString* name, int start_position, | |
| InferName infer = InferName::kYes) { | |
| if (infer == InferName::kYes) { | |
| fni_->PushVariableName(name); | |
| } | |
| return NewUnresolved(name, start_position); | |
| } | |
| V8_INLINE Expression* ExpressionFromString(int pos) { | |
| const AstRawString* symbol = GetSymbol(); | |
| fni_->PushLiteralName(symbol); | |
| return factory()->NewStringLiteral(symbol, pos); | |
| } | |
| V8_INLINE ZonePtrList<Expression>* NewExpressionList(int size) const { | |
| return new (zone()) ZonePtrList<Expression>(size, zone()); | |
| } | |
| V8_INLINE ZonePtrList<ObjectLiteral::Property>* NewObjectPropertyList( | |
| int size) const { | |
| return new (zone()) ZonePtrList<ObjectLiteral::Property>(size, zone()); | |
| } | |
| V8_INLINE ZonePtrList<ClassLiteral::Property>* NewClassPropertyList( | |
| int size) const { | |
| return new (zone()) ZonePtrList<ClassLiteral::Property>(size, zone()); | |
| } | |
| V8_INLINE ZonePtrList<Statement>* NewStatementList(int size) const { | |
| return new (zone()) ZonePtrList<Statement>(size, zone()); | |
| } | |
| V8_INLINE Expression* NewV8Intrinsic(const AstRawString* name, | |
| ZonePtrList<Expression>* args, int pos, | |
| bool* ok); | |
| V8_INLINE Statement* NewThrowStatement(Expression* exception, int pos) { | |
| return factory()->NewExpressionStatement( | |
| factory()->NewThrow(exception, pos), pos); | |
| } | |
| V8_INLINE void AddParameterInitializationBlock( | |
| const ParserFormalParameters& parameters, ZonePtrList<Statement>* body, | |
| bool is_async, bool* ok) { | |
| if (parameters.is_simple) return; | |
| auto* init_block = BuildParameterInitializationBlock(parameters, ok); | |
| if (!*ok) return; | |
| if (is_async) { | |
| init_block = BuildRejectPromiseOnException(init_block); | |
| } | |
| body->Add(init_block, zone()); | |
| } | |
| V8_INLINE void AddFormalParameter(ParserFormalParameters* parameters, | |
| Expression* pattern, | |
| Expression* initializer, | |
| int initializer_end_position, | |
| bool is_rest) { | |
| parameters->UpdateArityAndFunctionLength(initializer != nullptr, is_rest); | |
| bool has_simple_name = pattern->IsVariableProxy() && initializer == nullptr; | |
| const AstRawString* name = has_simple_name | |
| ? pattern->AsVariableProxy()->raw_name() | |
| : ast_value_factory()->empty_string(); | |
| auto parameter = new (parameters->scope->zone()) | |
| ParserFormalParameters::Parameter(name, pattern, initializer, | |
| scanner()->location().beg_pos, | |
| initializer_end_position, is_rest); | |
| parameters->params.Add(parameter); | |
| } | |
| V8_INLINE void DeclareFormalParameters( | |
| DeclarationScope* scope, | |
| const ThreadedList<ParserFormalParameters::Parameter>& parameters, | |
| bool is_simple, bool* has_duplicate = nullptr) { | |
| if (!is_simple) scope->SetHasNonSimpleParameters(); | |
| for (auto parameter : parameters) { | |
| 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, has_duplicate, ast_value_factory(), | |
| parameter->position); | |
| } | |
| } | |
| void DeclareArrowFunctionFormalParameters(ParserFormalParameters* parameters, | |
| Expression* params, | |
| const Scanner::Location& params_loc, | |
| Scanner::Location* duplicate_loc, | |
| bool* ok); | |
| Expression* ExpressionListToExpression(ZonePtrList<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 ZoneVector<typename ExpressionClassifier::Error>* | |
| GetReportedErrorList() const { | |
| return function_state_->GetReportedErrorList(); | |
| } | |
| 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, new (zone()) 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, new (zone()) BlockSourceRanges(continuation_position)); | |
| } | |
| V8_INLINE void RecordCaseClauseSourceRange(CaseClause* node, | |
| const SourceRange& body_range) { | |
| if (source_range_map_ == nullptr) return; | |
| source_range_map_->Insert(node, | |
| new (zone()) 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(), | |
| new (zone()) ConditionalSourceRanges(then_range, else_range)); | |
| } | |
| V8_INLINE void RecordBinaryOperationSourceRange( | |
| Expression* node, const SourceRange& right_range) { | |
| if (source_range_map_ == nullptr) return; | |
| source_range_map_->Insert(node->AsBinaryOperation(), | |
| new (zone()) | |
| 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), | |
| new (zone()) 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(), | |
| new (zone()) 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, new (zone()) 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), | |
| new (zone()) | |
| 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(), | |
| new (zone()) 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, new (zone()) ThrowSourceRanges(continuation_position)); | |
| } | |
| V8_INLINE void RecordTryCatchStatementSourceRange( | |
| TryCatchStatement* node, const SourceRange& body_range) { | |
| if (source_range_map_ == nullptr) return; | |
| source_range_map_->Insert( | |
| node, new (zone()) TryCatchStatementSourceRanges(body_range)); | |
| } | |
| V8_INLINE void RecordTryFinallyStatementSourceRange( | |
| TryFinallyStatement* node, const SourceRange& body_range) { | |
| if (source_range_map_ == nullptr) return; | |
| source_range_map_->Insert( | |
| node, new (zone()) TryFinallyStatementSourceRanges(body_range)); | |
| } | |
| // Parser's private field members. | |
| friend class DiscardableZoneScope; // Uses reusable_preparser_. | |
| // FIXME(marja): Make reusable_preparser_ always use its own temp Zone (call | |
| // DeleteAll after each function), so this won't be needed. | |
| Scanner scanner_; | |
| PreParser* reusable_preparser_; | |
| Mode mode_; | |
| SourceRangeMap* source_range_map_ = nullptr; | |
| friend class ParserTarget; | |
| friend class ParserTargetScope; | |
| ParserTarget* target_stack_; // for break, continue statements | |
| ScriptCompiler::CompileOptions compile_options_; | |
| // 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_; | |
| ConsumedPreParsedScopeData* consumed_preparsed_scope_data_; | |
| // 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_; | |
| }; | |
| // ---------------------------------------------------------------------------- | |
| // Target is a support class to facilitate manipulation of the | |
| // Parser's target_stack_ (the stack of potential 'break' and | |
| // 'continue' statement targets). Upon construction, a new target is | |
| // added; it is removed upon destruction. | |
| class ParserTarget BASE_EMBEDDED { | |
| public: | |
| ParserTarget(ParserBase<Parser>* parser, BreakableStatement* statement) | |
| : variable_(&parser->impl()->target_stack_), | |
| statement_(statement), | |
| previous_(parser->impl()->target_stack_) { | |
| parser->impl()->target_stack_ = this; | |
| } | |
| ~ParserTarget() { *variable_ = previous_; } | |
| ParserTarget* previous() { return previous_; } | |
| BreakableStatement* statement() { return statement_; } | |
| private: | |
| ParserTarget** variable_; | |
| BreakableStatement* statement_; | |
| ParserTarget* previous_; | |
| }; | |
| class ParserTargetScope BASE_EMBEDDED { | |
| public: | |
| explicit ParserTargetScope(ParserBase<Parser>* parser) | |
| : variable_(&parser->impl()->target_stack_), | |
| previous_(parser->impl()->target_stack_) { | |
| parser->impl()->target_stack_ = nullptr; | |
| } | |
| ~ParserTargetScope() { *variable_ = previous_; } | |
| private: | |
| ParserTarget** variable_; | |
| ParserTarget* previous_; | |
| }; | |
| } // namespace internal | |
| } // namespace v8 | |
| #endif // V8_PARSING_PARSER_H_ |