| // 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_PREPARSER_H_ | |
| #define V8_PARSING_PREPARSER_H_ | |
| #include "src/ast/ast.h" | |
| #include "src/ast/scopes.h" | |
| #include "src/parsing/parser-base.h" | |
| #include "src/parsing/preparser-logger.h" | |
| #include "src/pending-compilation-error-handler.h" | |
| #include "src/zone/zone-containers.h" | |
| namespace v8 { | |
| namespace internal { | |
| // Whereas the Parser generates AST during the recursive descent, | |
| // the PreParser doesn't create a tree. Instead, it passes around minimal | |
| // data objects (PreParserExpression, PreParserIdentifier etc.) which contain | |
| // just enough data for the upper layer functions. PreParserFactory is | |
| // responsible for creating these dummy objects. It provides a similar kind of | |
| // interface as AstNodeFactory, so ParserBase doesn't need to care which one is | |
| // used. | |
| class ProducedPreParsedScopeData; | |
| class PreParserIdentifier { | |
| public: | |
| PreParserIdentifier() : type_(kUnknownIdentifier) {} | |
| static PreParserIdentifier Default() { | |
| return PreParserIdentifier(kUnknownIdentifier); | |
| } | |
| static PreParserIdentifier Null() { | |
| return PreParserIdentifier(kNullIdentifier); | |
| } | |
| static PreParserIdentifier Eval() { | |
| return PreParserIdentifier(kEvalIdentifier); | |
| } | |
| static PreParserIdentifier Arguments() { | |
| return PreParserIdentifier(kArgumentsIdentifier); | |
| } | |
| static PreParserIdentifier Constructor() { | |
| return PreParserIdentifier(kConstructorIdentifier); | |
| } | |
| static PreParserIdentifier Await() { | |
| return PreParserIdentifier(kAwaitIdentifier); | |
| } | |
| static PreParserIdentifier Async() { | |
| return PreParserIdentifier(kAsyncIdentifier); | |
| } | |
| static PreParserIdentifier Name() { | |
| return PreParserIdentifier(kNameIdentifier); | |
| } | |
| static PreParserIdentifier PrivateName() { | |
| return PreParserIdentifier(kPrivateNameIdentifier); | |
| } | |
| bool IsNull() const { return type_ == kNullIdentifier; } | |
| bool IsEval() const { return type_ == kEvalIdentifier; } | |
| bool IsArguments() const { return type_ == kArgumentsIdentifier; } | |
| bool IsEvalOrArguments() const { return IsEval() || IsArguments(); } | |
| bool IsConstructor() const { return type_ == kConstructorIdentifier; } | |
| bool IsAwait() const { return type_ == kAwaitIdentifier; } | |
| bool IsName() const { return type_ == kNameIdentifier; } | |
| bool IsPrivateName() const { return type_ == kPrivateNameIdentifier; } | |
| private: | |
| enum Type : uint8_t { | |
| kNullIdentifier, | |
| kUnknownIdentifier, | |
| kEvalIdentifier, | |
| kArgumentsIdentifier, | |
| kConstructorIdentifier, | |
| kAwaitIdentifier, | |
| kAsyncIdentifier, | |
| kNameIdentifier, | |
| kPrivateNameIdentifier | |
| }; | |
| explicit PreParserIdentifier(Type type) : string_(nullptr), type_(type) {} | |
| // Only non-nullptr when PreParser.track_unresolved_variables_ is true. | |
| const AstRawString* string_; | |
| Type type_; | |
| friend class PreParserExpression; | |
| friend class PreParser; | |
| friend class PreParserFactory; | |
| }; | |
| class PreParserExpression { | |
| public: | |
| PreParserExpression() | |
| : code_(TypeField::encode(kNull)), variables_(nullptr) {} | |
| static PreParserExpression Null() { return PreParserExpression(); } | |
| static PreParserExpression Default( | |
| ZonePtrList<VariableProxy>* variables = nullptr) { | |
| return PreParserExpression(TypeField::encode(kExpression), variables); | |
| } | |
| static PreParserExpression Spread(const PreParserExpression& expression) { | |
| return PreParserExpression(TypeField::encode(kSpreadExpression), | |
| expression.variables_); | |
| } | |
| static PreParserExpression FromIdentifier(const PreParserIdentifier& id, | |
| VariableProxy* variable, | |
| Zone* zone) { | |
| PreParserExpression expression(TypeField::encode(kIdentifierExpression) | | |
| IdentifierTypeField::encode(id.type_)); | |
| expression.AddVariable(variable, zone); | |
| return expression; | |
| } | |
| static PreParserExpression BinaryOperation(const PreParserExpression& left, | |
| Token::Value op, | |
| const PreParserExpression& right, | |
| Zone* zone) { | |
| if (op == Token::COMMA) { | |
| // Possibly an arrow function parameter list. | |
| if (left.variables_ == nullptr) { | |
| return PreParserExpression(TypeField::encode(kExpression), | |
| right.variables_); | |
| } | |
| if (right.variables_ != nullptr) { | |
| for (auto variable : *right.variables_) { | |
| left.variables_->Add(variable, zone); | |
| } | |
| } | |
| return PreParserExpression(TypeField::encode(kExpression), | |
| left.variables_); | |
| } | |
| return PreParserExpression(TypeField::encode(kExpression)); | |
| } | |
| static PreParserExpression Assignment(ZonePtrList<VariableProxy>* variables) { | |
| return PreParserExpression(TypeField::encode(kExpression) | | |
| ExpressionTypeField::encode(kAssignment), | |
| variables); | |
| } | |
| static PreParserExpression NewTargetExpression() { | |
| return PreParserExpression::Default(); | |
| } | |
| static PreParserExpression ObjectLiteral( | |
| ZonePtrList<VariableProxy>* variables) { | |
| return PreParserExpression(TypeField::encode(kObjectLiteralExpression), | |
| variables); | |
| } | |
| static PreParserExpression ArrayLiteral( | |
| ZonePtrList<VariableProxy>* variables) { | |
| return PreParserExpression(TypeField::encode(kArrayLiteralExpression), | |
| variables); | |
| } | |
| static PreParserExpression StringLiteral() { | |
| return PreParserExpression(TypeField::encode(kStringLiteralExpression)); | |
| } | |
| static PreParserExpression UseStrictStringLiteral() { | |
| return PreParserExpression(TypeField::encode(kStringLiteralExpression) | | |
| IsUseStrictField::encode(true)); | |
| } | |
| static PreParserExpression UseAsmStringLiteral() { | |
| return PreParserExpression(TypeField::encode(kStringLiteralExpression) | | |
| IsUseAsmField::encode(true)); | |
| } | |
| static PreParserExpression This(ZonePtrList<VariableProxy>* variables) { | |
| return PreParserExpression(TypeField::encode(kExpression) | | |
| ExpressionTypeField::encode(kThisExpression), | |
| variables); | |
| } | |
| static PreParserExpression ThisPropertyWithPrivateFieldKey() { | |
| return PreParserExpression(TypeField::encode(kExpression) | | |
| ExpressionTypeField::encode( | |
| kThisPropertyExpressionWithPrivateFieldKey)); | |
| } | |
| static PreParserExpression ThisProperty() { | |
| return PreParserExpression( | |
| TypeField::encode(kExpression) | | |
| ExpressionTypeField::encode(kThisPropertyExpression)); | |
| } | |
| static PreParserExpression Property() { | |
| return PreParserExpression( | |
| TypeField::encode(kExpression) | | |
| ExpressionTypeField::encode(kPropertyExpression)); | |
| } | |
| static PreParserExpression PropertyWithPrivateFieldKey() { | |
| return PreParserExpression( | |
| TypeField::encode(kExpression) | | |
| ExpressionTypeField::encode(kPropertyExpressionWithPrivateFieldKey)); | |
| } | |
| static PreParserExpression Call() { | |
| return PreParserExpression(TypeField::encode(kExpression) | | |
| ExpressionTypeField::encode(kCallExpression)); | |
| } | |
| static PreParserExpression CallEval() { | |
| return PreParserExpression( | |
| TypeField::encode(kExpression) | | |
| ExpressionTypeField::encode(kCallEvalExpression)); | |
| } | |
| static PreParserExpression CallTaggedTemplate() { | |
| return PreParserExpression( | |
| TypeField::encode(kExpression) | | |
| ExpressionTypeField::encode(kCallTaggedTemplateExpression)); | |
| } | |
| bool is_tagged_template() const { | |
| DCHECK(IsCall()); | |
| return ExpressionTypeField::decode(code_) == kCallTaggedTemplateExpression; | |
| } | |
| static PreParserExpression SuperCallReference() { | |
| return PreParserExpression( | |
| TypeField::encode(kExpression) | | |
| ExpressionTypeField::encode(kSuperCallReference)); | |
| } | |
| bool IsNull() const { return TypeField::decode(code_) == kNull; } | |
| bool IsIdentifier() const { | |
| return TypeField::decode(code_) == kIdentifierExpression; | |
| } | |
| PreParserIdentifier AsIdentifier() const { | |
| DCHECK(IsIdentifier()); | |
| return PreParserIdentifier(IdentifierTypeField::decode(code_)); | |
| } | |
| bool IsAssignment() const { | |
| return TypeField::decode(code_) == kExpression && | |
| ExpressionTypeField::decode(code_) == kAssignment; | |
| } | |
| bool IsObjectLiteral() const { | |
| return TypeField::decode(code_) == kObjectLiteralExpression; | |
| } | |
| bool IsArrayLiteral() const { | |
| return TypeField::decode(code_) == kArrayLiteralExpression; | |
| } | |
| bool IsStringLiteral() const { | |
| return TypeField::decode(code_) == kStringLiteralExpression; | |
| } | |
| bool IsUseStrictLiteral() const { | |
| return TypeField::decode(code_) == kStringLiteralExpression && | |
| IsUseStrictField::decode(code_); | |
| } | |
| bool IsUseAsmLiteral() const { | |
| return TypeField::decode(code_) == kStringLiteralExpression && | |
| IsUseAsmField::decode(code_); | |
| } | |
| bool IsThis() const { | |
| return TypeField::decode(code_) == kExpression && | |
| ExpressionTypeField::decode(code_) == kThisExpression; | |
| } | |
| bool IsThisProperty() const { | |
| return TypeField::decode(code_) == kExpression && | |
| (ExpressionTypeField::decode(code_) == kThisPropertyExpression || | |
| ExpressionTypeField::decode(code_) == | |
| kThisPropertyExpressionWithPrivateFieldKey); | |
| } | |
| bool IsProperty() const { | |
| return TypeField::decode(code_) == kExpression && | |
| (ExpressionTypeField::decode(code_) == kPropertyExpression || | |
| ExpressionTypeField::decode(code_) == kThisPropertyExpression || | |
| ExpressionTypeField::decode(code_) == | |
| kPropertyExpressionWithPrivateFieldKey || | |
| ExpressionTypeField::decode(code_) == | |
| kThisPropertyExpressionWithPrivateFieldKey); | |
| } | |
| bool IsPropertyWithPrivateFieldKey() const { | |
| return TypeField::decode(code_) == kExpression && | |
| (ExpressionTypeField::decode(code_) == | |
| kPropertyExpressionWithPrivateFieldKey || | |
| ExpressionTypeField::decode(code_) == | |
| kThisPropertyExpressionWithPrivateFieldKey); | |
| } | |
| bool IsCall() const { | |
| return TypeField::decode(code_) == kExpression && | |
| (ExpressionTypeField::decode(code_) == kCallExpression || | |
| ExpressionTypeField::decode(code_) == kCallEvalExpression || | |
| ExpressionTypeField::decode(code_) == | |
| kCallTaggedTemplateExpression); | |
| } | |
| PreParserExpression* AsCall() { | |
| if (IsCall()) return this; | |
| return nullptr; | |
| } | |
| bool IsSuperCallReference() const { | |
| return TypeField::decode(code_) == kExpression && | |
| ExpressionTypeField::decode(code_) == kSuperCallReference; | |
| } | |
| bool IsValidReferenceExpression() const { | |
| return IsIdentifier() || IsProperty(); | |
| } | |
| // At the moment PreParser doesn't track these expression types. | |
| bool IsFunctionLiteral() const { return false; } | |
| bool IsCallNew() const { return false; } | |
| bool IsSpread() const { | |
| return TypeField::decode(code_) == kSpreadExpression; | |
| } | |
| PreParserExpression AsFunctionLiteral() { return *this; } | |
| // Dummy implementation for making expression->somefunc() work in both Parser | |
| // and PreParser. | |
| PreParserExpression* operator->() { return this; } | |
| void set_is_private_field() { | |
| if (variables_ != nullptr) { | |
| DCHECK(IsIdentifier()); | |
| DCHECK(AsIdentifier().IsPrivateName()); | |
| DCHECK_EQ(1, variables_->length()); | |
| variables_->first()->set_is_private_field(); | |
| } | |
| } | |
| // More dummy implementations of things PreParser doesn't need to track: | |
| void SetShouldEagerCompile() {} | |
| void mark_as_iife() {} | |
| int position() const { return kNoSourcePosition; } | |
| void set_function_token_position(int position) {} | |
| void set_scope(Scope* scope) {} | |
| void set_suspend_count(int suspend_count) {} | |
| private: | |
| enum Type { | |
| kNull, | |
| kExpression, | |
| kIdentifierExpression, | |
| kStringLiteralExpression, | |
| kSpreadExpression, | |
| kObjectLiteralExpression, | |
| kArrayLiteralExpression | |
| }; | |
| enum ExpressionType { | |
| kThisExpression, | |
| kThisPropertyExpression, | |
| kThisPropertyExpressionWithPrivateFieldKey, | |
| kPropertyExpression, | |
| kPropertyExpressionWithPrivateFieldKey, | |
| kCallExpression, | |
| kCallEvalExpression, | |
| kCallTaggedTemplateExpression, | |
| kSuperCallReference, | |
| kAssignment | |
| }; | |
| explicit PreParserExpression(uint32_t expression_code, | |
| ZonePtrList<VariableProxy>* variables = nullptr) | |
| : code_(expression_code), variables_(variables) {} | |
| void AddVariable(VariableProxy* variable, Zone* zone) { | |
| if (variable == nullptr) { | |
| return; | |
| } | |
| if (variables_ == nullptr) { | |
| variables_ = new (zone) ZonePtrList<VariableProxy>(1, zone); | |
| } | |
| variables_->Add(variable, zone); | |
| } | |
| // The first three bits are for the Type. | |
| typedef BitField<Type, 0, 3> TypeField; | |
| // The high order bit applies only to nodes which would inherit from the | |
| // Expression ASTNode --- This is by necessity, due to the fact that | |
| // Expression nodes may be represented as multiple Types, not exclusively | |
| // through kExpression. | |
| // TODO(caitp, adamk): clean up PreParserExpression bitfields. | |
| typedef BitField<bool, 31, 1> ParenthesizedField; | |
| // The rest of the bits are interpreted depending on the value | |
| // of the Type field, so they can share the storage. | |
| typedef BitField<ExpressionType, TypeField::kNext, 4> ExpressionTypeField; | |
| typedef BitField<bool, TypeField::kNext, 1> IsUseStrictField; | |
| typedef BitField<bool, IsUseStrictField::kNext, 1> IsUseAsmField; | |
| typedef BitField<PreParserIdentifier::Type, TypeField::kNext, 8> | |
| IdentifierTypeField; | |
| typedef BitField<bool, TypeField::kNext, 1> HasCoverInitializedNameField; | |
| uint32_t code_; | |
| // If the PreParser is used in the variable tracking mode, PreParserExpression | |
| // accumulates variables in that expression. | |
| ZonePtrList<VariableProxy>* variables_; | |
| friend class PreParser; | |
| friend class PreParserFactory; | |
| template <typename T> | |
| friend class PreParserList; | |
| }; | |
| // The pre-parser doesn't need to build lists of expressions, identifiers, or | |
| // the like. If the PreParser is used in variable tracking mode, it needs to | |
| // build lists of variables though. | |
| template <typename T> | |
| class PreParserList { | |
| public: | |
| // These functions make list->Add(some_expression) work (and do nothing). | |
| PreParserList() : length_(0), variables_(nullptr) {} | |
| PreParserList* operator->() { return this; } | |
| void Add(const T& element, Zone* zone); | |
| int length() const { return length_; } | |
| static PreParserList Null() { return PreParserList(-1); } | |
| bool IsNull() const { return length_ == -1; } | |
| void Set(int index, const T& element) {} | |
| private: | |
| explicit PreParserList(int n) : length_(n), variables_(nullptr) {} | |
| int length_; | |
| ZonePtrList<VariableProxy>* variables_; | |
| friend class PreParser; | |
| friend class PreParserFactory; | |
| }; | |
| template <> | |
| inline void PreParserList<PreParserExpression>::Add( | |
| const PreParserExpression& expression, Zone* zone) { | |
| if (expression.variables_ != nullptr) { | |
| DCHECK(FLAG_lazy_inner_functions); | |
| DCHECK_NOT_NULL(zone); | |
| if (variables_ == nullptr) { | |
| variables_ = new (zone) ZonePtrList<VariableProxy>(1, zone); | |
| } | |
| for (auto identifier : (*expression.variables_)) { | |
| variables_->Add(identifier, zone); | |
| } | |
| } | |
| ++length_; | |
| } | |
| template <typename T> | |
| void PreParserList<T>::Add(const T& element, Zone* zone) { | |
| ++length_; | |
| } | |
| typedef PreParserList<PreParserExpression> PreParserExpressionList; | |
| class PreParserStatement; | |
| typedef PreParserList<PreParserStatement> PreParserStatementList; | |
| class PreParserStatement { | |
| public: | |
| static PreParserStatement Default() { | |
| return PreParserStatement(kUnknownStatement); | |
| } | |
| static PreParserStatement Null() { | |
| return PreParserStatement(kNullStatement); | |
| } | |
| static PreParserStatement Empty() { | |
| return PreParserStatement(kEmptyStatement); | |
| } | |
| static PreParserStatement Jump() { | |
| return PreParserStatement(kJumpStatement); | |
| } | |
| // Creates expression statement from expression. | |
| // Preserves being an unparenthesized string literal, possibly | |
| // "use strict". | |
| static PreParserStatement ExpressionStatement( | |
| const PreParserExpression& expression) { | |
| if (expression.IsUseStrictLiteral()) { | |
| return PreParserStatement(kUseStrictExpressionStatement); | |
| } | |
| if (expression.IsUseAsmLiteral()) { | |
| return PreParserStatement(kUseAsmExpressionStatement); | |
| } | |
| if (expression.IsStringLiteral()) { | |
| return PreParserStatement(kStringLiteralExpressionStatement); | |
| } | |
| return Default(); | |
| } | |
| bool IsStringLiteral() { | |
| return code_ == kStringLiteralExpressionStatement || IsUseStrictLiteral() || | |
| IsUseAsmLiteral(); | |
| } | |
| bool IsUseStrictLiteral() { | |
| return code_ == kUseStrictExpressionStatement; | |
| } | |
| bool IsUseAsmLiteral() { return code_ == kUseAsmExpressionStatement; } | |
| bool IsJumpStatement() { | |
| return code_ == kJumpStatement; | |
| } | |
| bool IsNull() { return code_ == kNullStatement; } | |
| bool IsEmptyStatement() { | |
| DCHECK(!IsNull()); | |
| return code_ == kEmptyStatement; | |
| } | |
| // Dummy implementation for making statement->somefunc() work in both Parser | |
| // and PreParser. | |
| PreParserStatement* operator->() { return this; } | |
| // TODO(adamk): These should return something even lighter-weight than | |
| // PreParserStatementList. | |
| PreParserStatementList statements() { return PreParserStatementList(); } | |
| PreParserStatementList cases() { return PreParserStatementList(); } | |
| void set_scope(Scope* scope) {} | |
| void Initialize(const PreParserExpression& cond, PreParserStatement body, | |
| const SourceRange& body_range = {}) {} | |
| void Initialize(PreParserStatement init, const PreParserExpression& cond, | |
| PreParserStatement next, PreParserStatement body, | |
| const SourceRange& body_range = {}) {} | |
| private: | |
| enum Type { | |
| kNullStatement, | |
| kEmptyStatement, | |
| kUnknownStatement, | |
| kJumpStatement, | |
| kStringLiteralExpressionStatement, | |
| kUseStrictExpressionStatement, | |
| kUseAsmExpressionStatement, | |
| }; | |
| explicit PreParserStatement(Type code) : code_(code) {} | |
| Type code_; | |
| }; | |
| class PreParserFactory { | |
| public: | |
| explicit PreParserFactory(AstValueFactory* ast_value_factory, Zone* zone) | |
| : ast_node_factory_(ast_value_factory, zone), zone_(zone) {} | |
| void set_zone(Zone* zone) { | |
| ast_node_factory_.set_zone(zone); | |
| zone_ = zone; | |
| } | |
| AstNodeFactory* ast_node_factory() { return &ast_node_factory_; } | |
| PreParserExpression NewStringLiteral(const PreParserIdentifier& identifier, | |
| int pos) { | |
| // This is needed for object literal property names. Property names are | |
| // normalized to string literals during object literal parsing. | |
| PreParserExpression expression = PreParserExpression::Default(); | |
| if (identifier.string_ != nullptr) { | |
| DCHECK(FLAG_lazy_inner_functions); | |
| VariableProxy* variable = ast_node_factory_.NewVariableProxy( | |
| identifier.string_, NORMAL_VARIABLE); | |
| expression.AddVariable(variable, zone_); | |
| } | |
| return expression; | |
| } | |
| PreParserExpression NewNumberLiteral(double number, | |
| int pos) { | |
| return PreParserExpression::Default(); | |
| } | |
| PreParserExpression NewUndefinedLiteral(int pos) { | |
| return PreParserExpression::Default(); | |
| } | |
| PreParserExpression NewTheHoleLiteral() { | |
| return PreParserExpression::Default(); | |
| } | |
| PreParserExpression NewRegExpLiteral(const PreParserIdentifier& js_pattern, | |
| int js_flags, int pos) { | |
| return PreParserExpression::Default(); | |
| } | |
| PreParserExpression NewArrayLiteral(const PreParserExpressionList& values, | |
| int first_spread_index, int pos) { | |
| return PreParserExpression::ArrayLiteral(values.variables_); | |
| } | |
| PreParserExpression NewClassLiteralProperty(const PreParserExpression& key, | |
| const PreParserExpression& value, | |
| ClassLiteralProperty::Kind kind, | |
| bool is_static, | |
| bool is_computed_name) { | |
| return PreParserExpression::Default(); | |
| } | |
| PreParserExpression NewObjectLiteralProperty(const PreParserExpression& key, | |
| const PreParserExpression& value, | |
| ObjectLiteralProperty::Kind kind, | |
| bool is_computed_name) { | |
| return PreParserExpression::Default(value.variables_); | |
| } | |
| PreParserExpression NewObjectLiteralProperty(const PreParserExpression& key, | |
| const PreParserExpression& value, | |
| bool is_computed_name) { | |
| return PreParserExpression::Default(value.variables_); | |
| } | |
| PreParserExpression NewObjectLiteral( | |
| const PreParserExpressionList& properties, int boilerplate_properties, | |
| int pos, bool has_rest_property) { | |
| return PreParserExpression::ObjectLiteral(properties.variables_); | |
| } | |
| PreParserExpression NewVariableProxy(void* variable) { | |
| return PreParserExpression::Default(); | |
| } | |
| PreParserExpression NewProperty(const PreParserExpression& obj, | |
| const PreParserExpression& key, int pos) { | |
| if (key.IsIdentifier() && key.AsIdentifier().IsPrivateName()) { | |
| if (obj.IsThis()) { | |
| return PreParserExpression::ThisPropertyWithPrivateFieldKey(); | |
| } | |
| return PreParserExpression::PropertyWithPrivateFieldKey(); | |
| } | |
| if (obj.IsThis()) { | |
| return PreParserExpression::ThisProperty(); | |
| } | |
| return PreParserExpression::Property(); | |
| } | |
| PreParserExpression NewUnaryOperation(Token::Value op, | |
| const PreParserExpression& expression, | |
| int pos) { | |
| return PreParserExpression::Default(); | |
| } | |
| PreParserExpression NewBinaryOperation(Token::Value op, | |
| const PreParserExpression& left, | |
| const PreParserExpression& right, | |
| int pos) { | |
| return PreParserExpression::BinaryOperation(left, op, right, zone_); | |
| } | |
| PreParserExpression NewCompareOperation(Token::Value op, | |
| const PreParserExpression& left, | |
| const PreParserExpression& right, | |
| int pos) { | |
| return PreParserExpression::Default(); | |
| } | |
| PreParserExpression NewRewritableExpression( | |
| const PreParserExpression& expression, Scope* scope) { | |
| return expression; | |
| } | |
| PreParserExpression NewAssignment(Token::Value op, | |
| const PreParserExpression& left, | |
| const PreParserExpression& right, int pos) { | |
| // Identifiers need to be tracked since this might be a parameter with a | |
| // default value inside an arrow function parameter list. | |
| return PreParserExpression::Assignment(left.variables_); | |
| } | |
| PreParserExpression NewYield(const PreParserExpression& expression, int pos, | |
| Suspend::OnAbruptResume on_abrupt_resume) { | |
| return PreParserExpression::Default(); | |
| } | |
| PreParserExpression NewAwait(const PreParserExpression& expression, int pos) { | |
| return PreParserExpression::Default(); | |
| } | |
| PreParserExpression NewYieldStar(const PreParserExpression& iterable, | |
| int pos) { | |
| return PreParserExpression::Default(); | |
| } | |
| PreParserExpression NewConditional(const PreParserExpression& condition, | |
| const PreParserExpression& then_expression, | |
| const PreParserExpression& else_expression, | |
| int pos) { | |
| return PreParserExpression::Default(); | |
| } | |
| PreParserExpression NewCountOperation(Token::Value op, bool is_prefix, | |
| const PreParserExpression& expression, | |
| int pos) { | |
| return PreParserExpression::Default(); | |
| } | |
| PreParserExpression NewCall( | |
| PreParserExpression expression, const PreParserExpressionList& arguments, | |
| int pos, Call::PossiblyEval possibly_eval = Call::NOT_EVAL) { | |
| if (possibly_eval == Call::IS_POSSIBLY_EVAL) { | |
| DCHECK(expression.IsIdentifier() && expression.AsIdentifier().IsEval()); | |
| return PreParserExpression::CallEval(); | |
| } | |
| return PreParserExpression::Call(); | |
| } | |
| PreParserExpression NewTaggedTemplate( | |
| PreParserExpression expression, const PreParserExpressionList& arguments, | |
| int pos) { | |
| return PreParserExpression::CallTaggedTemplate(); | |
| } | |
| PreParserExpression NewCallNew(const PreParserExpression& expression, | |
| const PreParserExpressionList& arguments, | |
| int pos) { | |
| return PreParserExpression::Default(); | |
| } | |
| PreParserStatement NewReturnStatement( | |
| const PreParserExpression& expression, int pos, | |
| int continuation_pos = kNoSourcePosition) { | |
| return PreParserStatement::Jump(); | |
| } | |
| PreParserStatement NewAsyncReturnStatement( | |
| const PreParserExpression& expression, int pos, | |
| int continuation_pos = kNoSourcePosition) { | |
| return PreParserStatement::Jump(); | |
| } | |
| PreParserExpression NewFunctionLiteral( | |
| const PreParserIdentifier& name, Scope* scope, | |
| PreParserStatementList body, int expected_property_count, | |
| int parameter_count, int function_length, | |
| FunctionLiteral::ParameterFlag has_duplicate_parameters, | |
| FunctionLiteral::FunctionType function_type, | |
| FunctionLiteral::EagerCompileHint eager_compile_hint, int position, | |
| bool has_braces, int function_literal_id, | |
| ProducedPreParsedScopeData* produced_preparsed_scope_data = nullptr) { | |
| DCHECK_NULL(produced_preparsed_scope_data); | |
| return PreParserExpression::Default(); | |
| } | |
| PreParserExpression NewSpread(const PreParserExpression& expression, int pos, | |
| int expr_pos) { | |
| return PreParserExpression::Spread(expression); | |
| } | |
| PreParserExpression NewEmptyParentheses(int pos) { | |
| return PreParserExpression::Default(); | |
| } | |
| PreParserStatement NewEmptyStatement(int pos) { | |
| return PreParserStatement::Default(); | |
| } | |
| PreParserStatement NewBlock( | |
| int capacity, bool ignore_completion_value, | |
| ZonePtrList<const AstRawString>* labels = nullptr) { | |
| return PreParserStatement::Default(); | |
| } | |
| PreParserStatement NewDebuggerStatement(int pos) { | |
| return PreParserStatement::Default(); | |
| } | |
| PreParserStatement NewExpressionStatement(const PreParserExpression& expr, | |
| int pos) { | |
| return PreParserStatement::ExpressionStatement(expr); | |
| } | |
| PreParserStatement NewIfStatement(const PreParserExpression& condition, | |
| PreParserStatement then_statement, | |
| PreParserStatement else_statement, int pos, | |
| SourceRange then_range = {}, | |
| SourceRange else_range = {}) { | |
| // This must return a jump statement iff both clauses are jump statements. | |
| return else_statement.IsJumpStatement() ? then_statement : else_statement; | |
| } | |
| PreParserStatement NewBreakStatement( | |
| PreParserStatement target, int pos, | |
| int continuation_pos = kNoSourcePosition) { | |
| return PreParserStatement::Jump(); | |
| } | |
| PreParserStatement NewContinueStatement( | |
| PreParserStatement target, int pos, | |
| int continuation_pos = kNoSourcePosition) { | |
| return PreParserStatement::Jump(); | |
| } | |
| PreParserStatement NewWithStatement(Scope* scope, | |
| const PreParserExpression& expression, | |
| PreParserStatement statement, int pos) { | |
| return PreParserStatement::Default(); | |
| } | |
| PreParserStatement NewDoWhileStatement( | |
| ZonePtrList<const AstRawString>* labels, | |
| ZonePtrList<const AstRawString>* own_labels, int pos) { | |
| return PreParserStatement::Default(); | |
| } | |
| PreParserStatement NewWhileStatement( | |
| ZonePtrList<const AstRawString>* labels, | |
| ZonePtrList<const AstRawString>* own_labels, int pos) { | |
| return PreParserStatement::Default(); | |
| } | |
| PreParserStatement NewSwitchStatement(ZonePtrList<const AstRawString>* labels, | |
| const PreParserExpression& tag, | |
| int pos) { | |
| return PreParserStatement::Default(); | |
| } | |
| PreParserStatement NewCaseClause(const PreParserExpression& label, | |
| PreParserStatementList statements) { | |
| return PreParserStatement::Default(); | |
| } | |
| PreParserStatement NewForStatement( | |
| ZonePtrList<const AstRawString>* labels, | |
| ZonePtrList<const AstRawString>* own_labels, int pos) { | |
| return PreParserStatement::Default(); | |
| } | |
| PreParserStatement NewForEachStatement( | |
| ForEachStatement::VisitMode visit_mode, | |
| ZonePtrList<const AstRawString>* labels, | |
| ZonePtrList<const AstRawString>* own_labels, int pos) { | |
| return PreParserStatement::Default(); | |
| } | |
| PreParserStatement NewForOfStatement( | |
| ZonePtrList<const AstRawString>* labels, | |
| ZonePtrList<const AstRawString>* own_labels, int pos) { | |
| return PreParserStatement::Default(); | |
| } | |
| PreParserExpression NewCallRuntime( | |
| Runtime::FunctionId id, ZoneChunkList<PreParserExpression>* arguments, | |
| int pos) { | |
| return PreParserExpression::Default(); | |
| } | |
| PreParserExpression NewImportCallExpression(const PreParserExpression& args, | |
| int pos) { | |
| return PreParserExpression::Default(); | |
| } | |
| private: | |
| // For creating VariableProxy objects (if | |
| // PreParser::track_unresolved_variables_ is used). | |
| AstNodeFactory ast_node_factory_; | |
| Zone* zone_; | |
| }; | |
| struct PreParserFormalParameters : FormalParametersBase { | |
| struct Parameter : public ZoneObject { | |
| Parameter(ZonePtrList<VariableProxy>* variables, bool is_rest) | |
| : variables_(variables), is_rest(is_rest) {} | |
| Parameter** next() { return &next_parameter; } | |
| Parameter* const* next() const { return &next_parameter; } | |
| ZonePtrList<VariableProxy>* variables_; | |
| Parameter* next_parameter = nullptr; | |
| bool is_rest : 1; | |
| }; | |
| explicit PreParserFormalParameters(DeclarationScope* scope) | |
| : FormalParametersBase(scope) {} | |
| ThreadedList<Parameter> params; | |
| }; | |
| class PreParser; | |
| class PreParserTarget { | |
| public: | |
| PreParserTarget(ParserBase<PreParser>* preparser, | |
| PreParserStatement statement) {} | |
| }; | |
| class PreParserTargetScope { | |
| public: | |
| explicit PreParserTargetScope(ParserBase<PreParser>* preparser) {} | |
| }; | |
| template <> | |
| struct ParserTypes<PreParser> { | |
| typedef ParserBase<PreParser> Base; | |
| typedef PreParser Impl; | |
| // Return types for traversing functions. | |
| typedef PreParserIdentifier Identifier; | |
| typedef PreParserExpression Expression; | |
| typedef PreParserExpression FunctionLiteral; | |
| typedef PreParserExpression ObjectLiteralProperty; | |
| typedef PreParserExpression ClassLiteralProperty; | |
| typedef PreParserExpression Suspend; | |
| typedef PreParserExpression RewritableExpression; | |
| typedef PreParserExpressionList ExpressionList; | |
| typedef PreParserExpressionList ObjectPropertyList; | |
| typedef PreParserExpressionList ClassPropertyList; | |
| typedef PreParserFormalParameters FormalParameters; | |
| typedef PreParserStatement Statement; | |
| typedef PreParserStatementList StatementList; | |
| typedef PreParserStatement Block; | |
| typedef PreParserStatement BreakableStatement; | |
| typedef PreParserStatement IterationStatement; | |
| typedef PreParserStatement ForStatement; | |
| // For constructing objects returned by the traversing functions. | |
| typedef PreParserFactory Factory; | |
| typedef PreParserTarget Target; | |
| typedef PreParserTargetScope TargetScope; | |
| }; | |
| // Preparsing checks a JavaScript program and emits preparse-data that helps | |
| // a later parsing to be faster. | |
| // See preparse-data-format.h for the data format. | |
| // The PreParser checks that the syntax follows the grammar for JavaScript, | |
| // and collects some information about the program along the way. | |
| // The grammar check is only performed in order to understand the program | |
| // sufficiently to deduce some information about it, that can be used | |
| // to speed up later parsing. Finding errors is not the goal of pre-parsing, | |
| // rather it is to speed up properly written and correct programs. | |
| // That means that contextual checks (like a label being declared where | |
| // it is used) are generally omitted. | |
| class PreParser : public ParserBase<PreParser> { | |
| friend class ParserBase<PreParser>; | |
| friend class v8::internal::ExpressionClassifier<ParserTypes<PreParser>>; | |
| public: | |
| typedef PreParserIdentifier Identifier; | |
| typedef PreParserExpression Expression; | |
| typedef PreParserStatement Statement; | |
| enum PreParseResult { | |
| kPreParseStackOverflow, | |
| kPreParseAbort, | |
| kPreParseSuccess | |
| }; | |
| PreParser(Zone* zone, Scanner* scanner, uintptr_t stack_limit, | |
| AstValueFactory* ast_value_factory, | |
| PendingCompilationErrorHandler* pending_error_handler, | |
| RuntimeCallStats* runtime_call_stats, Logger* logger, | |
| int script_id = -1, bool parsing_module = false, | |
| bool parsing_on_main_thread = true) | |
| : ParserBase<PreParser>(zone, scanner, stack_limit, nullptr, | |
| ast_value_factory, pending_error_handler, | |
| runtime_call_stats, logger, script_id, | |
| parsing_module, parsing_on_main_thread), | |
| use_counts_(nullptr), | |
| track_unresolved_variables_(false), | |
| produced_preparsed_scope_data_(nullptr) {} | |
| static bool IsPreParser() { return true; } | |
| PreParserLogger* logger() { return &log_; } | |
| // Pre-parse the program from the character stream; returns true on | |
| // success (even if parsing failed, the pre-parse data successfully | |
| // captured the syntax error), and false if a stack-overflow happened | |
| // during parsing. | |
| PreParseResult PreParseProgram(); | |
| // Parses a single function literal, from the opening parentheses before | |
| // parameters to the closing brace after the body. | |
| // Returns a FunctionEntry describing the body of the function in enough | |
| // detail that it can be lazily compiled. | |
| // The scanner is expected to have matched the "function" or "function*" | |
| // keyword and parameters, and have consumed the initial '{'. | |
| // At return, unless an error occurred, the scanner is positioned before the | |
| // the final '}'. | |
| PreParseResult PreParseFunction( | |
| const AstRawString* function_name, FunctionKind kind, | |
| FunctionLiteral::FunctionType function_type, | |
| DeclarationScope* function_scope, bool track_unresolved_variables, | |
| bool may_abort, int* use_counts, | |
| ProducedPreParsedScopeData** produced_preparser_scope_data, | |
| int script_id); | |
| ProducedPreParsedScopeData* produced_preparsed_scope_data() const { | |
| return produced_preparsed_scope_data_; | |
| } | |
| void set_produced_preparsed_scope_data( | |
| ProducedPreParsedScopeData* produced_preparsed_scope_data) { | |
| produced_preparsed_scope_data_ = produced_preparsed_scope_data; | |
| } | |
| private: | |
| // These types form an algebra over syntactic categories that is just | |
| // rich enough to let us recognize and propagate the constructs that | |
| // are either being counted in the preparser data, or is important | |
| // to throw the correct syntax error exceptions. | |
| // 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. | |
| // Indicates that we won't switch from the preparser to the preparser; we'll | |
| // just stay where we are. | |
| bool AllowsLazyParsingWithoutUnresolvedVariables() const { return false; } | |
| bool parse_lazily() const { return false; } | |
| PendingCompilationErrorHandler* pending_error_handler() { | |
| return pending_error_handler_; | |
| } | |
| V8_INLINE LazyParsingResult | |
| SkipFunction(const AstRawString* 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) { | |
| UNREACHABLE(); | |
| } | |
| Expression ParseFunctionLiteral( | |
| Identifier name, Scanner::Location function_name_location, | |
| FunctionNameValidity function_name_validity, FunctionKind kind, | |
| int function_token_pos, FunctionLiteral::FunctionType function_type, | |
| LanguageMode language_mode, | |
| ZonePtrList<const AstRawString>* arguments_for_wrapped_function, | |
| bool* ok); | |
| PreParserExpression InitializeObjectLiteral(PreParserExpression literal) { | |
| return literal; | |
| } | |
| LazyParsingResult ParseStatementListAndLogFunction( | |
| PreParserFormalParameters* formals, bool maybe_abort, bool* ok); | |
| struct TemplateLiteralState {}; | |
| V8_INLINE TemplateLiteralState OpenTemplateLiteral(int pos) { | |
| return TemplateLiteralState(); | |
| } | |
| V8_INLINE void AddTemplateExpression(TemplateLiteralState* state, | |
| const PreParserExpression& expression) {} | |
| V8_INLINE void AddTemplateSpan(TemplateLiteralState* state, bool should_cook, | |
| bool tail) {} | |
| V8_INLINE PreParserExpression CloseTemplateLiteral( | |
| TemplateLiteralState* state, int start, const PreParserExpression& tag) { | |
| return PreParserExpression::Default(); | |
| } | |
| V8_INLINE bool IsPropertyWithPrivateFieldKey( | |
| const PreParserExpression& expression) { | |
| return expression.IsPropertyWithPrivateFieldKey(); | |
| } | |
| V8_INLINE void CheckConflictingVarDeclarations(Scope* scope, bool* ok) {} | |
| V8_INLINE void SetLanguageMode(Scope* scope, LanguageMode mode) { | |
| scope->SetLanguageMode(mode); | |
| } | |
| V8_INLINE void SetAsmModule() {} | |
| V8_INLINE PreParserExpression SpreadCall(const PreParserExpression& function, | |
| const PreParserExpressionList& args, | |
| int pos, | |
| Call::PossiblyEval possibly_eval); | |
| V8_INLINE PreParserExpression | |
| SpreadCallNew(const PreParserExpression& function, | |
| const PreParserExpressionList& args, int pos); | |
| V8_INLINE void RewriteDestructuringAssignments() {} | |
| V8_INLINE void PrepareGeneratorVariables() {} | |
| V8_INLINE void RewriteAsyncFunctionBody( | |
| PreParserStatementList body, PreParserStatement block, | |
| const PreParserExpression& return_value, bool* ok) {} | |
| void DeclareAndInitializeVariables( | |
| PreParserStatement block, | |
| const DeclarationDescriptor* declaration_descriptor, | |
| const DeclarationParsingResult::Declaration* declaration, | |
| ZonePtrList<const AstRawString>* names, bool* ok); | |
| V8_INLINE void DeclareLabel(ZonePtrList<const AstRawString>** labels, | |
| ZonePtrList<const AstRawString>** own_labels, | |
| const PreParserExpression& expr, bool* ok) { | |
| DCHECK(!parsing_module_ || !expr.AsIdentifier().IsAwait()); | |
| DCHECK(IsIdentifier(expr)); | |
| } | |
| // TODO(nikolaos): The preparser currently does not keep track of labels. | |
| V8_INLINE bool ContainsLabel(ZonePtrList<const AstRawString>* labels, | |
| const PreParserIdentifier& label) { | |
| return false; | |
| } | |
| V8_INLINE PreParserExpression | |
| RewriteReturn(const PreParserExpression& return_value, int pos) { | |
| return return_value; | |
| } | |
| V8_INLINE PreParserStatement | |
| RewriteSwitchStatement(PreParserStatement switch_statement, Scope* scope) { | |
| return PreParserStatement::Default(); | |
| } | |
| V8_INLINE void RewriteCatchPattern(CatchInfo* catch_info, bool* ok) { | |
| if (track_unresolved_variables_) { | |
| const AstRawString* catch_name = catch_info->name.string_; | |
| if (catch_name == nullptr) { | |
| catch_name = ast_value_factory()->dot_catch_string(); | |
| } | |
| catch_info->scope->DeclareCatchVariableName(catch_name); | |
| if (catch_info->pattern.variables_ != nullptr) { | |
| for (auto variable : *catch_info->pattern.variables_) { | |
| scope()->DeclareVariableName(variable->raw_name(), | |
| VariableMode::kLet); | |
| } | |
| } | |
| } | |
| } | |
| V8_INLINE void ValidateCatchBlock(const CatchInfo& catch_info, bool* ok) {} | |
| V8_INLINE PreParserStatement RewriteTryStatement( | |
| PreParserStatement try_block, PreParserStatement catch_block, | |
| const SourceRange& catch_range, PreParserStatement finally_block, | |
| const SourceRange& finally_range, const CatchInfo& catch_info, int pos) { | |
| return PreParserStatement::Default(); | |
| } | |
| V8_INLINE void ParseAndRewriteGeneratorFunctionBody( | |
| int pos, FunctionKind kind, PreParserStatementList body, bool* ok) { | |
| ParseStatementList(body, Token::RBRACE, ok); | |
| } | |
| V8_INLINE void ParseAndRewriteAsyncGeneratorFunctionBody( | |
| int pos, FunctionKind kind, PreParserStatementList body, bool* ok) { | |
| ParseStatementList(body, Token::RBRACE, ok); | |
| } | |
| V8_INLINE void DeclareFunctionNameVar( | |
| const AstRawString* function_name, | |
| FunctionLiteral::FunctionType function_type, | |
| DeclarationScope* function_scope) { | |
| if (track_unresolved_variables_ && | |
| function_type == FunctionLiteral::kNamedExpression && | |
| function_scope->LookupLocal(function_name) == nullptr) { | |
| DCHECK_EQ(function_scope, scope()); | |
| function_scope->DeclareFunctionVar(function_name); | |
| } | |
| } | |
| V8_INLINE void DeclareFunctionNameVar( | |
| const PreParserIdentifier& function_name, | |
| FunctionLiteral::FunctionType function_type, | |
| DeclarationScope* function_scope) { | |
| DeclareFunctionNameVar(function_name.string_, function_type, | |
| function_scope); | |
| } | |
| V8_INLINE PreParserExpression RewriteDoExpression(PreParserStatement body, | |
| int pos, bool* ok) { | |
| return PreParserExpression::Default(); | |
| } | |
| // TODO(nikolaos): The preparser currently does not keep track of labels | |
| // and targets. | |
| V8_INLINE PreParserStatement | |
| LookupBreakTarget(const PreParserIdentifier& label, bool* ok) { | |
| return PreParserStatement::Default(); | |
| } | |
| V8_INLINE PreParserStatement | |
| LookupContinueTarget(const PreParserIdentifier& label, bool* ok) { | |
| return PreParserStatement::Default(); | |
| } | |
| V8_INLINE PreParserStatement | |
| DeclareFunction(const PreParserIdentifier& variable_name, | |
| const PreParserExpression& function, VariableMode mode, | |
| int pos, bool is_sloppy_block_function, | |
| ZonePtrList<const AstRawString>* names, bool* ok) { | |
| DCHECK_NULL(names); | |
| if (variable_name.string_ != nullptr) { | |
| DCHECK(track_unresolved_variables_); | |
| scope()->DeclareVariableName(variable_name.string_, mode); | |
| if (is_sloppy_block_function) { | |
| GetDeclarationScope()->DeclareSloppyBlockFunction(variable_name.string_, | |
| scope()); | |
| } | |
| } | |
| return Statement::Default(); | |
| } | |
| V8_INLINE PreParserStatement DeclareClass( | |
| const PreParserIdentifier& variable_name, | |
| const PreParserExpression& value, ZonePtrList<const AstRawString>* names, | |
| int class_token_pos, int end_pos, bool* ok) { | |
| // Preparser shouldn't be used in contexts where we need to track the names. | |
| DCHECK_NULL(names); | |
| if (variable_name.string_ != nullptr) { | |
| DCHECK(track_unresolved_variables_); | |
| scope()->DeclareVariableName(variable_name.string_, VariableMode::kLet); | |
| } | |
| return PreParserStatement::Default(); | |
| } | |
| V8_INLINE void DeclareClassVariable(const PreParserIdentifier& name, | |
| ClassInfo* class_info, | |
| int class_token_pos, bool* ok) { | |
| if (name.string_ != nullptr) { | |
| DCHECK(track_unresolved_variables_); | |
| scope()->DeclareVariableName(name.string_, VariableMode::kConst); | |
| } | |
| } | |
| V8_INLINE void DeclareClassProperty(const PreParserIdentifier& class_name, | |
| const PreParserExpression& property, | |
| const PreParserIdentifier& property_name, | |
| ClassLiteralProperty::Kind kind, | |
| bool is_static, bool is_constructor, | |
| bool is_computed_name, | |
| ClassInfo* class_info, bool* ok) { | |
| if (kind == ClassLiteralProperty::PUBLIC_FIELD && is_computed_name) { | |
| scope()->DeclareVariableName( | |
| ClassFieldVariableName(ast_value_factory(), | |
| class_info->computed_field_count), | |
| VariableMode::kConst); | |
| } | |
| if (kind == ClassLiteralProperty::PRIVATE_FIELD && | |
| property_name.string_ != nullptr) { | |
| DCHECK(track_unresolved_variables_); | |
| scope()->DeclareVariableName(property_name.string_, VariableMode::kConst); | |
| } | |
| } | |
| V8_INLINE PreParserExpression | |
| RewriteClassLiteral(Scope* scope, const PreParserIdentifier& name, | |
| ClassInfo* class_info, int pos, int end_pos, bool* ok) { | |
| bool has_default_constructor = !class_info->has_seen_constructor; | |
| // Account for the default constructor. | |
| if (has_default_constructor) { | |
| // Creating and disposing of a FunctionState makes tracking of | |
| // next_function_is_likely_called match what Parser does. TODO(marja): | |
| // Make the lazy function + next_function_is_likely_called + default ctor | |
| // logic less surprising. Default ctors shouldn't affect the laziness of | |
| // functions. | |
| bool has_extends = class_info->extends.IsNull(); | |
| FunctionKind kind = has_extends ? FunctionKind::kDefaultDerivedConstructor | |
| : FunctionKind::kDefaultBaseConstructor; | |
| DeclarationScope* function_scope = NewFunctionScope(kind); | |
| SetLanguageMode(function_scope, LanguageMode::kStrict); | |
| function_scope->set_start_position(pos); | |
| function_scope->set_end_position(pos); | |
| FunctionState function_state(&function_state_, &scope_, function_scope); | |
| GetNextFunctionLiteralId(); | |
| } | |
| if (class_info->has_static_class_fields) { | |
| GetNextFunctionLiteralId(); | |
| } | |
| if (class_info->has_instance_class_fields) { | |
| GetNextFunctionLiteralId(); | |
| } | |
| return PreParserExpression::Default(); | |
| } | |
| V8_INLINE PreParserStatement DeclareNative(const PreParserIdentifier& name, | |
| int pos, bool* ok) { | |
| return PreParserStatement::Default(); | |
| } | |
| V8_INLINE void QueueDestructuringAssignmentForRewriting( | |
| PreParserExpression assignment) {} | |
| // Helper functions for recursive descent. | |
| V8_INLINE bool IsEval(const PreParserIdentifier& identifier) const { | |
| return identifier.IsEval(); | |
| } | |
| V8_INLINE bool IsArguments(const PreParserIdentifier& identifier) const { | |
| return identifier.IsArguments(); | |
| } | |
| V8_INLINE bool IsEvalOrArguments( | |
| const PreParserIdentifier& identifier) const { | |
| return identifier.IsEvalOrArguments(); | |
| } | |
| V8_INLINE bool IsAwait(const PreParserIdentifier& identifier) const { | |
| return identifier.IsAwait(); | |
| } | |
| // Returns true if the expression is of type "this.foo". | |
| V8_INLINE static bool IsThisProperty(const PreParserExpression& expression) { | |
| return expression.IsThisProperty(); | |
| } | |
| V8_INLINE static bool IsIdentifier(const PreParserExpression& expression) { | |
| return expression.IsIdentifier(); | |
| } | |
| V8_INLINE static PreParserIdentifier AsIdentifier( | |
| const PreParserExpression& expression) { | |
| return expression.AsIdentifier(); | |
| } | |
| V8_INLINE static PreParserExpression AsIdentifierExpression( | |
| const PreParserExpression& expression) { | |
| return expression; | |
| } | |
| V8_INLINE bool IsConstructor(const PreParserIdentifier& identifier) const { | |
| return identifier.IsConstructor(); | |
| } | |
| V8_INLINE bool IsName(const PreParserIdentifier& identifier) const { | |
| return identifier.IsName(); | |
| } | |
| V8_INLINE static bool IsBoilerplateProperty( | |
| const PreParserExpression& property) { | |
| // PreParser doesn't count boilerplate properties. | |
| return false; | |
| } | |
| V8_INLINE bool IsNative(const PreParserExpression& expr) const { | |
| // Preparsing is disabled for extensions (because the extension | |
| // details aren't passed to lazily compiled functions), so we | |
| // don't accept "native function" in the preparser and there is | |
| // no need to keep track of "native". | |
| return false; | |
| } | |
| V8_INLINE static bool IsArrayIndex(const PreParserIdentifier& string, | |
| uint32_t* index) { | |
| return false; | |
| } | |
| V8_INLINE bool IsUseStrictDirective(PreParserStatement statement) const { | |
| return statement.IsUseStrictLiteral(); | |
| } | |
| V8_INLINE bool IsUseAsmDirective(PreParserStatement statement) const { | |
| return statement.IsUseAsmLiteral(); | |
| } | |
| V8_INLINE bool IsStringLiteral(PreParserStatement statement) const { | |
| return statement.IsStringLiteral(); | |
| } | |
| V8_INLINE static void GetDefaultStrings( | |
| PreParserIdentifier* default_string, | |
| PreParserIdentifier* star_default_star_string) {} | |
| // Functions for encapsulating the differences between parsing and preparsing; | |
| // operations interleaved with the recursive descent. | |
| V8_INLINE static void PushLiteralName(const PreParserIdentifier& id) {} | |
| V8_INLINE static void PushVariableName(const PreParserIdentifier& id) {} | |
| V8_INLINE void PushPropertyName(const PreParserExpression& expression) {} | |
| V8_INLINE void PushEnclosingName(const PreParserIdentifier& name) {} | |
| V8_INLINE static void AddFunctionForNameInference( | |
| const PreParserExpression& expression) {} | |
| V8_INLINE static void InferFunctionName() {} | |
| V8_INLINE static void CheckAssigningFunctionLiteralToProperty( | |
| const PreParserExpression& left, const PreParserExpression& right) {} | |
| V8_INLINE void MarkExpressionAsAssigned( | |
| const PreParserExpression& expression) { | |
| // TODO(marja): To be able to produce the same errors, the preparser needs | |
| // to start tracking which expressions are variables and which are assigned. | |
| if (expression.variables_ != nullptr) { | |
| DCHECK(FLAG_lazy_inner_functions); | |
| DCHECK(track_unresolved_variables_); | |
| for (auto variable : *expression.variables_) { | |
| variable->set_is_assigned(); | |
| } | |
| } | |
| } | |
| V8_INLINE bool ShortcutNumericLiteralBinaryExpression( | |
| PreParserExpression* x, const PreParserExpression& y, Token::Value op, | |
| int pos) { | |
| return false; | |
| } | |
| V8_INLINE NaryOperation* CollapseNaryExpression(PreParserExpression* x, | |
| PreParserExpression y, | |
| Token::Value op, int pos, | |
| const SourceRange& range) { | |
| return nullptr; | |
| } | |
| V8_INLINE PreParserExpression BuildUnaryExpression( | |
| const PreParserExpression& expression, Token::Value op, int pos) { | |
| return PreParserExpression::Default(); | |
| } | |
| V8_INLINE PreParserStatement | |
| BuildInitializationBlock(DeclarationParsingResult* parsing_result, | |
| ZonePtrList<const AstRawString>* names, bool* ok) { | |
| for (auto declaration : parsing_result->declarations) { | |
| DeclareAndInitializeVariables(PreParserStatement::Default(), | |
| &(parsing_result->descriptor), &declaration, | |
| names, ok); | |
| } | |
| return PreParserStatement::Default(); | |
| } | |
| V8_INLINE PreParserStatement InitializeForEachStatement( | |
| PreParserStatement stmt, const PreParserExpression& each, | |
| const PreParserExpression& subject, PreParserStatement body) { | |
| MarkExpressionAsAssigned(each); | |
| return stmt; | |
| } | |
| V8_INLINE PreParserStatement InitializeForOfStatement( | |
| PreParserStatement stmt, const PreParserExpression& each, | |
| const PreParserExpression& iterable, PreParserStatement body, | |
| bool finalize, IteratorType type, | |
| int next_result_pos = kNoSourcePosition) { | |
| MarkExpressionAsAssigned(each); | |
| return stmt; | |
| } | |
| V8_INLINE PreParserStatement RewriteForVarInLegacy(const ForInfo& for_info) { | |
| return PreParserStatement::Null(); | |
| } | |
| V8_INLINE void DesugarBindingInForEachStatement( | |
| ForInfo* for_info, PreParserStatement* body_block, | |
| PreParserExpression* each_variable, bool* ok) { | |
| if (track_unresolved_variables_) { | |
| DCHECK_EQ(1, for_info->parsing_result.declarations.size()); | |
| bool is_for_var_of = | |
| for_info->mode == ForEachStatement::ITERATE && | |
| for_info->parsing_result.descriptor.mode == VariableMode::kVar; | |
| bool collect_names = | |
| IsLexicalVariableMode(for_info->parsing_result.descriptor.mode) || | |
| is_for_var_of; | |
| DeclareAndInitializeVariables( | |
| PreParserStatement::Default(), &for_info->parsing_result.descriptor, | |
| &for_info->parsing_result.declarations[0], | |
| collect_names ? &for_info->bound_names : nullptr, ok); | |
| } | |
| } | |
| V8_INLINE PreParserStatement CreateForEachStatementTDZ( | |
| PreParserStatement init_block, const ForInfo& for_info, bool* ok) { | |
| if (track_unresolved_variables_) { | |
| if (IsLexicalVariableMode(for_info.parsing_result.descriptor.mode)) { | |
| for (auto name : for_info.bound_names) { | |
| scope()->DeclareVariableName(name, VariableMode::kLet); | |
| } | |
| return PreParserStatement::Default(); | |
| } | |
| } | |
| return init_block; | |
| } | |
| V8_INLINE StatementT DesugarLexicalBindingsInForStatement( | |
| PreParserStatement loop, PreParserStatement init, | |
| const PreParserExpression& cond, PreParserStatement next, | |
| PreParserStatement body, Scope* inner_scope, const ForInfo& for_info, | |
| bool* ok) { | |
| // See Parser::DesugarLexicalBindingsInForStatement. | |
| if (track_unresolved_variables_) { | |
| for (auto name : for_info.bound_names) { | |
| inner_scope->DeclareVariableName( | |
| name, for_info.parsing_result.descriptor.mode); | |
| } | |
| } | |
| return loop; | |
| } | |
| PreParserStatement BuildParameterInitializationBlock( | |
| const PreParserFormalParameters& parameters, bool* ok); | |
| V8_INLINE PreParserStatement | |
| BuildRejectPromiseOnException(PreParserStatement init_block) { | |
| return PreParserStatement::Default(); | |
| } | |
| V8_INLINE void InsertSloppyBlockFunctionVarBindings(DeclarationScope* scope) { | |
| scope->HoistSloppyBlockFunctions(nullptr); | |
| } | |
| V8_INLINE void InsertShadowingVarBindingInitializers( | |
| PreParserStatement block) {} | |
| V8_INLINE PreParserExpression | |
| NewThrowReferenceError(MessageTemplate::Template message, int pos) { | |
| return PreParserExpression::Default(); | |
| } | |
| V8_INLINE PreParserExpression | |
| NewThrowSyntaxError(MessageTemplate::Template message, | |
| const PreParserIdentifier& arg, int pos) { | |
| return PreParserExpression::Default(); | |
| } | |
| V8_INLINE PreParserExpression | |
| NewThrowTypeError(MessageTemplate::Template message, | |
| const PreParserIdentifier& arg, int pos) { | |
| return PreParserExpression::Default(); | |
| } | |
| // Reporting errors. | |
| void ReportMessageAt(Scanner::Location source_location, | |
| MessageTemplate::Template message, | |
| const char* arg = nullptr, | |
| ParseErrorType error_type = kSyntaxError) { | |
| pending_error_handler()->ReportMessageAt(source_location.beg_pos, | |
| source_location.end_pos, message, | |
| arg, error_type); | |
| } | |
| V8_INLINE void ReportMessageAt(Scanner::Location source_location, | |
| MessageTemplate::Template message, | |
| const PreParserIdentifier& arg, | |
| ParseErrorType error_type = kSyntaxError) { | |
| UNREACHABLE(); | |
| } | |
| // "null" return type creators. | |
| V8_INLINE static PreParserIdentifier NullIdentifier() { | |
| return PreParserIdentifier::Null(); | |
| } | |
| V8_INLINE static PreParserExpression NullExpression() { | |
| return PreParserExpression::Null(); | |
| } | |
| V8_INLINE static PreParserExpression NullLiteralProperty() { | |
| return PreParserExpression::Null(); | |
| } | |
| V8_INLINE static PreParserExpressionList NullExpressionList() { | |
| return PreParserExpressionList::Null(); | |
| } | |
| V8_INLINE static PreParserStatementList NullStatementList() { | |
| return PreParserStatementList::Null(); | |
| } | |
| V8_INLINE static PreParserStatement NullStatement() { | |
| return PreParserStatement::Null(); | |
| } | |
| template <typename T> | |
| V8_INLINE static bool IsNull(T subject) { | |
| return subject.IsNull(); | |
| } | |
| V8_INLINE PreParserIdentifier EmptyIdentifierString() const { | |
| return PreParserIdentifier::Default(); | |
| } | |
| // Producing data during the recursive descent. | |
| PreParserIdentifier GetSymbol() const; | |
| V8_INLINE PreParserIdentifier GetNextSymbol() const { | |
| return PreParserIdentifier::Default(); | |
| } | |
| V8_INLINE PreParserIdentifier GetNumberAsSymbol() const { | |
| return PreParserIdentifier::Default(); | |
| } | |
| V8_INLINE PreParserExpression ThisExpression(int pos = kNoSourcePosition) { | |
| ZonePtrList<VariableProxy>* variables = nullptr; | |
| if (track_unresolved_variables_) { | |
| VariableProxy* proxy = scope()->NewUnresolved( | |
| factory()->ast_node_factory(), ast_value_factory()->this_string(), | |
| pos, THIS_VARIABLE); | |
| variables = new (zone()) ZonePtrList<VariableProxy>(1, zone()); | |
| variables->Add(proxy, zone()); | |
| } | |
| return PreParserExpression::This(variables); | |
| } | |
| V8_INLINE PreParserExpression NewSuperPropertyReference(int pos) { | |
| if (track_unresolved_variables_) { | |
| scope()->NewUnresolved(factory()->ast_node_factory(), | |
| ast_value_factory()->this_function_string(), pos, | |
| NORMAL_VARIABLE); | |
| scope()->NewUnresolved(factory()->ast_node_factory(), | |
| ast_value_factory()->this_string(), pos, | |
| THIS_VARIABLE); | |
| } | |
| return PreParserExpression::Default(); | |
| } | |
| V8_INLINE PreParserExpression NewSuperCallReference(int pos) { | |
| if (track_unresolved_variables_) { | |
| scope()->NewUnresolved(factory()->ast_node_factory(), | |
| ast_value_factory()->this_function_string(), pos, | |
| NORMAL_VARIABLE); | |
| scope()->NewUnresolved(factory()->ast_node_factory(), | |
| ast_value_factory()->new_target_string(), pos, | |
| NORMAL_VARIABLE); | |
| scope()->NewUnresolved(factory()->ast_node_factory(), | |
| ast_value_factory()->this_string(), pos, | |
| THIS_VARIABLE); | |
| } | |
| return PreParserExpression::SuperCallReference(); | |
| } | |
| V8_INLINE PreParserExpression NewTargetExpression(int pos) { | |
| return PreParserExpression::NewTargetExpression(); | |
| } | |
| V8_INLINE PreParserExpression ImportMetaExpression(int pos) { | |
| return PreParserExpression::Default(); | |
| } | |
| V8_INLINE PreParserExpression ExpressionFromLiteral(Token::Value token, | |
| int pos) { | |
| return PreParserExpression::Default(); | |
| } | |
| PreParserExpression ExpressionFromIdentifier( | |
| const PreParserIdentifier& name, int start_position, | |
| InferName infer = InferName::kYes); | |
| V8_INLINE PreParserExpression ExpressionFromString(int pos) { | |
| if (scanner()->IsUseStrict()) { | |
| return PreParserExpression::UseStrictStringLiteral(); | |
| } | |
| return PreParserExpression::StringLiteral(); | |
| } | |
| V8_INLINE PreParserExpressionList NewExpressionList(int size) const { | |
| return PreParserExpressionList(); | |
| } | |
| V8_INLINE PreParserExpressionList NewObjectPropertyList(int size) const { | |
| return PreParserExpressionList(); | |
| } | |
| V8_INLINE PreParserExpressionList NewClassPropertyList(int size) const { | |
| return PreParserExpressionList(); | |
| } | |
| V8_INLINE PreParserStatementList NewStatementList(int size) const { | |
| return PreParserStatementList(); | |
| } | |
| V8_INLINE PreParserExpression | |
| NewV8Intrinsic(const PreParserIdentifier& name, | |
| const PreParserExpressionList& arguments, int pos, bool* ok) { | |
| return PreParserExpression::Default(); | |
| } | |
| V8_INLINE PreParserStatement | |
| NewThrowStatement(const PreParserExpression& exception, int pos) { | |
| return PreParserStatement::Jump(); | |
| } | |
| V8_INLINE void AddParameterInitializationBlock( | |
| const PreParserFormalParameters& parameters, PreParserStatementList body, | |
| bool is_async, bool* ok) { | |
| if (!parameters.is_simple) { | |
| BuildParameterInitializationBlock(parameters, ok); | |
| } | |
| } | |
| V8_INLINE void AddFormalParameter(PreParserFormalParameters* parameters, | |
| const PreParserExpression& pattern, | |
| const PreParserExpression& initializer, | |
| int initializer_end_position, | |
| bool is_rest) { | |
| if (track_unresolved_variables_) { | |
| DCHECK(FLAG_lazy_inner_functions); | |
| parameters->params.Add(new (zone()) PreParserFormalParameters::Parameter( | |
| pattern.variables_, is_rest)); | |
| } | |
| parameters->UpdateArityAndFunctionLength(!initializer.IsNull(), is_rest); | |
| } | |
| V8_INLINE void DeclareFormalParameters( | |
| DeclarationScope* scope, | |
| const ThreadedList<PreParserFormalParameters::Parameter>& parameters, | |
| bool is_simple) { | |
| if (!is_simple) scope->SetHasNonSimpleParameters(); | |
| if (track_unresolved_variables_) { | |
| DCHECK(FLAG_lazy_inner_functions); | |
| for (auto parameter : parameters) { | |
| DCHECK_IMPLIES(is_simple, parameter->variables_ != nullptr); | |
| DCHECK_IMPLIES(is_simple, parameter->variables_->length() == 1); | |
| // Make sure each parameter is added only once even if it's a | |
| // destructuring parameter which contains multiple names. | |
| bool add_parameter = true; | |
| if (parameter->variables_ != nullptr) { | |
| for (auto variable : (*parameter->variables_)) { | |
| // We declare the parameter name for all names, but only create a | |
| // parameter entry for the first one. | |
| scope->DeclareParameterName(variable->raw_name(), | |
| parameter->is_rest, ast_value_factory(), | |
| true, add_parameter); | |
| add_parameter = false; | |
| } | |
| } | |
| if (add_parameter) { | |
| // No names were declared; declare a dummy one here to up the | |
| // parameter count. | |
| DCHECK(!is_simple); | |
| scope->DeclareParameterName(ast_value_factory()->empty_string(), | |
| parameter->is_rest, ast_value_factory(), | |
| false, add_parameter); | |
| } | |
| } | |
| } | |
| } | |
| V8_INLINE void DeclareArrowFunctionFormalParameters( | |
| PreParserFormalParameters* parameters, const PreParserExpression& params, | |
| const Scanner::Location& params_loc, Scanner::Location* duplicate_loc, | |
| bool* ok) { | |
| // TODO(wingo): Detect duplicated identifiers in paramlists. Detect | |
| // parameter lists that are too long. | |
| if (track_unresolved_variables_) { | |
| DCHECK(FLAG_lazy_inner_functions); | |
| if (params.variables_ != nullptr) { | |
| for (auto variable : *params.variables_) { | |
| parameters->scope->DeclareVariableName(variable->raw_name(), | |
| VariableMode::kVar); | |
| } | |
| } | |
| } | |
| } | |
| V8_INLINE PreParserExpression | |
| ExpressionListToExpression(const PreParserExpressionList& args) { | |
| return PreParserExpression::Default(args.variables_); | |
| } | |
| V8_INLINE void SetFunctionNameFromPropertyName( | |
| const PreParserExpression& property, const PreParserIdentifier& name, | |
| const AstRawString* prefix = nullptr) {} | |
| V8_INLINE void SetFunctionNameFromIdentifierRef( | |
| const PreParserExpression& value, const PreParserExpression& identifier) { | |
| } | |
| V8_INLINE ZoneVector<typename ExpressionClassifier::Error>* | |
| GetReportedErrorList() const { | |
| return function_state_->GetReportedErrorList(); | |
| } | |
| V8_INLINE void CountUsage(v8::Isolate::UseCounterFeature feature) { | |
| if (use_counts_ != nullptr) ++use_counts_[feature]; | |
| } | |
| V8_INLINE bool ParsingDynamicFunctionDeclaration() const { return false; } | |
| // Generate empty functions here as the preparser does not collect source | |
| // ranges for block coverage. | |
| #define DEFINE_RECORD_SOURCE_RANGE(Name) \ | |
| template <typename... Ts> \ | |
| V8_INLINE void Record##Name##SourceRange(Ts... args) {} | |
| AST_SOURCE_RANGE_LIST(DEFINE_RECORD_SOURCE_RANGE) | |
| #undef DEFINE_RECORD_SOURCE_RANGE | |
| // Preparser's private field members. | |
| int* use_counts_; | |
| bool track_unresolved_variables_; | |
| PreParserLogger log_; | |
| ProducedPreParsedScopeData* produced_preparsed_scope_data_; | |
| }; | |
| PreParserExpression PreParser::SpreadCall(const PreParserExpression& function, | |
| const PreParserExpressionList& args, | |
| int pos, | |
| Call::PossiblyEval possibly_eval) { | |
| return factory()->NewCall(function, args, pos, possibly_eval); | |
| } | |
| PreParserExpression PreParser::SpreadCallNew( | |
| const PreParserExpression& function, const PreParserExpressionList& args, | |
| int pos) { | |
| return factory()->NewCallNew(function, args, pos); | |
| } | |
| } // namespace internal | |
| } // namespace v8 | |
| #endif // V8_PARSING_PREPARSER_H_ |