| // 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/preparse-data.h" |
| #include "src/pending-compilation-error-handler.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 Empty() { |
| return PreParserIdentifier(kEmptyIdentifier); |
| } |
| static PreParserIdentifier Eval() { |
| return PreParserIdentifier(kEvalIdentifier); |
| } |
| static PreParserIdentifier Arguments() { |
| return PreParserIdentifier(kArgumentsIdentifier); |
| } |
| static PreParserIdentifier Undefined() { |
| return PreParserIdentifier(kUndefinedIdentifier); |
| } |
| static PreParserIdentifier FutureReserved() { |
| return PreParserIdentifier(kFutureReservedIdentifier); |
| } |
| static PreParserIdentifier FutureStrictReserved() { |
| return PreParserIdentifier(kFutureStrictReservedIdentifier); |
| } |
| static PreParserIdentifier Let() { |
| return PreParserIdentifier(kLetIdentifier); |
| } |
| static PreParserIdentifier Static() { |
| return PreParserIdentifier(kStaticIdentifier); |
| } |
| static PreParserIdentifier Yield() { |
| return PreParserIdentifier(kYieldIdentifier); |
| } |
| static PreParserIdentifier Prototype() { |
| return PreParserIdentifier(kPrototypeIdentifier); |
| } |
| static PreParserIdentifier Constructor() { |
| return PreParserIdentifier(kConstructorIdentifier); |
| } |
| static PreParserIdentifier Enum() { |
| return PreParserIdentifier(kEnumIdentifier); |
| } |
| static PreParserIdentifier Await() { |
| return PreParserIdentifier(kAwaitIdentifier); |
| } |
| static PreParserIdentifier Async() { |
| return PreParserIdentifier(kAsyncIdentifier); |
| } |
| static PreParserIdentifier Name() { |
| return PreParserIdentifier(kNameIdentifier); |
| } |
| bool IsEmpty() const { return type_ == kEmptyIdentifier; } |
| bool IsEval() const { return type_ == kEvalIdentifier; } |
| bool IsArguments() const { return type_ == kArgumentsIdentifier; } |
| bool IsEvalOrArguments() const { return IsEval() || IsArguments(); } |
| bool IsUndefined() const { return type_ == kUndefinedIdentifier; } |
| bool IsLet() const { return type_ == kLetIdentifier; } |
| bool IsStatic() const { return type_ == kStaticIdentifier; } |
| bool IsYield() const { return type_ == kYieldIdentifier; } |
| bool IsPrototype() const { return type_ == kPrototypeIdentifier; } |
| bool IsConstructor() const { return type_ == kConstructorIdentifier; } |
| bool IsEnum() const { return type_ == kEnumIdentifier; } |
| bool IsAwait() const { return type_ == kAwaitIdentifier; } |
| bool IsName() const { return type_ == kNameIdentifier; } |
| |
| // Allow identifier->name()[->length()] to work. The preparser |
| // does not need the actual positions/lengths of the identifiers. |
| const PreParserIdentifier* operator->() const { return this; } |
| const PreParserIdentifier raw_name() const { return *this; } |
| |
| int position() const { return 0; } |
| int length() const { return 0; } |
| |
| private: |
| enum Type { |
| kEmptyIdentifier, |
| kUnknownIdentifier, |
| kFutureReservedIdentifier, |
| kFutureStrictReservedIdentifier, |
| kLetIdentifier, |
| kStaticIdentifier, |
| kYieldIdentifier, |
| kEvalIdentifier, |
| kArgumentsIdentifier, |
| kUndefinedIdentifier, |
| kPrototypeIdentifier, |
| kConstructorIdentifier, |
| kEnumIdentifier, |
| kAwaitIdentifier, |
| kAsyncIdentifier, |
| kNameIdentifier |
| }; |
| |
| explicit PreParserIdentifier(Type type) : type_(type), string_(nullptr) {} |
| Type type_; |
| // Only non-nullptr when PreParser.track_unresolved_variables_ is true. |
| const AstRawString* string_; |
| friend class PreParserExpression; |
| friend class PreParser; |
| friend class PreParserFactory; |
| }; |
| |
| |
| class PreParserExpression { |
| public: |
| PreParserExpression() |
| : code_(TypeField::encode(kEmpty)), variables_(nullptr) {} |
| |
| static PreParserExpression Empty() { return PreParserExpression(); } |
| |
| static PreParserExpression Default( |
| ZoneList<VariableProxy*>* variables = nullptr) { |
| return PreParserExpression(TypeField::encode(kExpression), variables); |
| } |
| |
| static PreParserExpression Spread(PreParserExpression expression) { |
| return PreParserExpression(TypeField::encode(kSpreadExpression), |
| expression.variables_); |
| } |
| |
| static PreParserExpression FromIdentifier(PreParserIdentifier id, |
| VariableProxy* variable, |
| Zone* zone) { |
| PreParserExpression expression(TypeField::encode(kIdentifierExpression) | |
| IdentifierTypeField::encode(id.type_)); |
| expression.AddVariable(variable, zone); |
| return expression; |
| } |
| |
| static PreParserExpression BinaryOperation(PreParserExpression left, |
| Token::Value op, |
| 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(ZoneList<VariableProxy*>* variables) { |
| return PreParserExpression(TypeField::encode(kExpression) | |
| ExpressionTypeField::encode(kAssignment), |
| variables); |
| } |
| |
| static PreParserExpression NewTargetExpression() { |
| return PreParserExpression(TypeField::encode(kExpression) | |
| ExpressionTypeField::encode(kNewTarget)); |
| } |
| |
| static PreParserExpression ObjectLiteral( |
| ZoneList<VariableProxy*>* variables) { |
| return PreParserExpression(TypeField::encode(kObjectLiteralExpression), |
| variables); |
| } |
| |
| static PreParserExpression ArrayLiteral(ZoneList<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(ZoneList<VariableProxy*>* variables) { |
| return PreParserExpression(TypeField::encode(kExpression) | |
| ExpressionTypeField::encode(kThisExpression), |
| variables); |
| } |
| |
| static PreParserExpression ThisProperty() { |
| return PreParserExpression( |
| TypeField::encode(kExpression) | |
| ExpressionTypeField::encode(kThisPropertyExpression)); |
| } |
| |
| static PreParserExpression Property() { |
| return PreParserExpression( |
| TypeField::encode(kExpression) | |
| ExpressionTypeField::encode(kPropertyExpression)); |
| } |
| |
| static PreParserExpression Call() { |
| return PreParserExpression(TypeField::encode(kExpression) | |
| ExpressionTypeField::encode(kCallExpression)); |
| } |
| |
| static PreParserExpression CallEval() { |
| return PreParserExpression( |
| TypeField::encode(kExpression) | |
| ExpressionTypeField::encode(kCallEvalExpression)); |
| } |
| |
| static PreParserExpression SuperCallReference() { |
| return PreParserExpression( |
| TypeField::encode(kExpression) | |
| ExpressionTypeField::encode(kSuperCallReference)); |
| } |
| |
| static PreParserExpression NoTemplateTag() { |
| return PreParserExpression( |
| TypeField::encode(kExpression) | |
| ExpressionTypeField::encode(kNoTemplateTagExpression)); |
| } |
| |
| bool IsEmpty() const { return TypeField::decode(code_) == kEmpty; } |
| |
| 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; |
| } |
| |
| bool IsProperty() const { |
| return TypeField::decode(code_) == kExpression && |
| (ExpressionTypeField::decode(code_) == kPropertyExpression || |
| ExpressionTypeField::decode(code_) == kThisPropertyExpression); |
| } |
| |
| bool IsCall() const { |
| return TypeField::decode(code_) == kExpression && |
| (ExpressionTypeField::decode(code_) == kCallExpression || |
| ExpressionTypeField::decode(code_) == kCallEvalExpression); |
| } |
| |
| 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 IsNoTemplateTag() const { |
| return TypeField::decode(code_) == kExpression && |
| ExpressionTypeField::decode(code_) == kNoTemplateTagExpression; |
| } |
| |
| 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; } |
| |
| // More dummy implementations of things PreParser doesn't need to track: |
| void SetShouldEagerCompile() {} |
| void set_should_be_used_once_hint() {} |
| |
| int position() const { return kNoSourcePosition; } |
| void set_function_token_position(int position) {} |
| |
| private: |
| enum Type { |
| kEmpty, |
| kExpression, |
| kIdentifierExpression, |
| kStringLiteralExpression, |
| kSpreadExpression, |
| kObjectLiteralExpression, |
| kArrayLiteralExpression |
| }; |
| |
| enum ExpressionType { |
| kThisExpression, |
| kThisPropertyExpression, |
| kPropertyExpression, |
| kCallExpression, |
| kCallEvalExpression, |
| kSuperCallReference, |
| kNoTemplateTagExpression, |
| kAssignment, |
| kNewTarget |
| }; |
| |
| explicit PreParserExpression(uint32_t expression_code, |
| ZoneList<VariableProxy*>* variables = nullptr) |
| : code_(expression_code), variables_(variables) {} |
| |
| void AddVariable(VariableProxy* variable, Zone* zone) { |
| if (variable == nullptr) { |
| return; |
| } |
| if (variables_ == nullptr) { |
| variables_ = new (zone) ZoneList<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, 10> |
| 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. |
| ZoneList<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_; |
| ZoneList<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(zone != nullptr); |
| if (variables_ == nullptr) { |
| variables_ = new (zone) ZoneList<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( |
| 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 IsNullStatement() { return code_ == kNullStatement; } |
| |
| bool IsEmptyStatement() { return code_ == kEmptyStatement; } |
| |
| // Dummy implementation for making statement->somefunc() work in both Parser |
| // and PreParser. |
| PreParserStatement* operator->() { return this; } |
| |
| PreParserStatementList statements() { return PreParserStatementList(); } |
| void set_scope(Scope* scope) {} |
| void Initialize(PreParserExpression cond, PreParserStatement body, |
| const SourceRange& body_range = {}) {} |
| void Initialize(PreParserStatement init, 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(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 NewRegExpLiteral(PreParserIdentifier js_pattern, |
| int js_flags, int pos) { |
| return PreParserExpression::Default(); |
| } |
| PreParserExpression NewArrayLiteral(PreParserExpressionList values, |
| int first_spread_index, int pos) { |
| return PreParserExpression::ArrayLiteral(values.variables_); |
| } |
| PreParserExpression NewClassLiteralProperty(PreParserExpression key, |
| PreParserExpression value, |
| ClassLiteralProperty::Kind kind, |
| bool is_static, |
| bool is_computed_name) { |
| return PreParserExpression::Default(); |
| } |
| PreParserExpression NewObjectLiteralProperty(PreParserExpression key, |
| PreParserExpression value, |
| ObjectLiteralProperty::Kind kind, |
| bool is_computed_name) { |
| return PreParserExpression::Default(value.variables_); |
| } |
| PreParserExpression NewObjectLiteralProperty(PreParserExpression key, |
| PreParserExpression value, |
| bool is_computed_name) { |
| return PreParserExpression::Default(value.variables_); |
| } |
| PreParserExpression NewObjectLiteral(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(PreParserExpression obj, |
| PreParserExpression key, |
| int pos) { |
| if (obj.IsThis()) { |
| return PreParserExpression::ThisProperty(); |
| } |
| return PreParserExpression::Property(); |
| } |
| PreParserExpression NewUnaryOperation(Token::Value op, |
| PreParserExpression expression, |
| int pos) { |
| return PreParserExpression::Default(); |
| } |
| PreParserExpression NewBinaryOperation(Token::Value op, |
| PreParserExpression left, |
| PreParserExpression right, int pos) { |
| return PreParserExpression::BinaryOperation(left, op, right, zone_); |
| } |
| PreParserExpression NewCompareOperation(Token::Value op, |
| PreParserExpression left, |
| PreParserExpression right, int pos) { |
| return PreParserExpression::Default(); |
| } |
| PreParserExpression NewRewritableExpression(PreParserExpression expression) { |
| return expression; |
| } |
| PreParserExpression NewAssignment(Token::Value op, |
| PreParserExpression left, |
| 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 NewSuspend(PreParserExpression expression, int pos, |
| Suspend::OnAbruptResume on_abrupt_resume, |
| SuspendFlags flags) { |
| return PreParserExpression::Default(); |
| } |
| PreParserExpression NewAwait(PreParserExpression expression, int pos, |
| SuspendFlags flags) { |
| return PreParserExpression::Default(); |
| } |
| PreParserExpression NewConditional(PreParserExpression condition, |
| PreParserExpression then_expression, |
| PreParserExpression else_expression, |
| int pos) { |
| return PreParserExpression::Default(); |
| } |
| PreParserExpression NewCountOperation(Token::Value op, |
| bool is_prefix, |
| PreParserExpression expression, |
| int pos) { |
| return PreParserExpression::Default(); |
| } |
| PreParserExpression NewCall( |
| PreParserExpression expression, 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 NewCallNew(PreParserExpression expression, |
| PreParserExpressionList arguments, |
| int pos) { |
| return PreParserExpression::Default(); |
| } |
| PreParserStatement NewReturnStatement( |
| PreParserExpression expression, int pos, |
| int continuation_pos = kNoSourcePosition) { |
| return PreParserStatement::Jump(); |
| } |
| PreParserStatement NewAsyncReturnStatement( |
| PreParserExpression expression, int pos, |
| int continuation_pos = kNoSourcePosition) { |
| return PreParserStatement::Jump(); |
| } |
| PreParserExpression NewFunctionLiteral( |
| 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(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(ZoneList<const AstRawString*>* labels, |
| int capacity, bool ignore_completion_value, |
| int pos) { |
| return PreParserStatement::Default(); |
| } |
| |
| PreParserStatement NewDebuggerStatement(int pos) { |
| return PreParserStatement::Default(); |
| } |
| |
| PreParserStatement NewExpressionStatement(PreParserExpression expr, int pos) { |
| return PreParserStatement::ExpressionStatement(expr); |
| } |
| |
| PreParserStatement NewIfStatement(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, |
| PreParserExpression expression, |
| PreParserStatement statement, int pos) { |
| return PreParserStatement::Default(); |
| } |
| |
| PreParserStatement NewDoWhileStatement(ZoneList<const AstRawString*>* labels, |
| int pos) { |
| return PreParserStatement::Default(); |
| } |
| |
| PreParserStatement NewWhileStatement(ZoneList<const AstRawString*>* labels, |
| int pos) { |
| return PreParserStatement::Default(); |
| } |
| |
| PreParserStatement NewSwitchStatement(ZoneList<const AstRawString*>* labels, |
| int pos) { |
| return PreParserStatement::Default(); |
| } |
| |
| PreParserStatement NewCaseClause(PreParserExpression label, |
| PreParserStatementList statements, int pos) { |
| return PreParserStatement::Default(); |
| } |
| |
| PreParserStatement NewForStatement(ZoneList<const AstRawString*>* labels, |
| int pos) { |
| return PreParserStatement::Default(); |
| } |
| |
| PreParserStatement NewForEachStatement(ForEachStatement::VisitMode visit_mode, |
| ZoneList<const AstRawString*>* labels, |
| int pos) { |
| return PreParserStatement::Default(); |
| } |
| |
| PreParserStatement NewForOfStatement(ZoneList<const AstRawString*>* labels, |
| int pos) { |
| return PreParserStatement::Default(); |
| } |
| |
| PreParserExpression NewCallRuntime(Runtime::FunctionId id, |
| ZoneList<PreParserExpression>* arguments, |
| int pos) { |
| return PreParserExpression::Default(); |
| } |
| |
| PreParserExpression NewImportCallExpression(PreParserExpression args, |
| int pos) { |
| return PreParserExpression::Default(); |
| } |
| |
| // Return the object itself as AstVisitor and implement the needed |
| // dummy method right in this class. |
| PreParserFactory* visitor() { return this; } |
| int* ast_properties() { |
| static int dummy = 42; |
| return &dummy; |
| } |
| |
| 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(ZoneList<VariableProxy*>* variables, bool is_rest) |
| : variables_(variables), is_rest(is_rest) {} |
| Parameter** next() { return &next_parameter; } |
| Parameter* const* next() const { return &next_parameter; } |
| |
| ZoneList<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 Await; |
| 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; |
| |
| // 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, |
| bool parsing_on_main_thread = true) |
| : ParserBase<PreParser>(zone, scanner, stack_limit, nullptr, |
| ast_value_factory, runtime_call_stats, |
| parsing_on_main_thread), |
| use_counts_(nullptr), |
| track_unresolved_variables_(false), |
| pending_error_handler_(pending_error_handler), |
| 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(bool is_module = false); |
| |
| // 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 parsing_module, |
| bool track_unresolved_variables, bool may_abort, int* use_counts, |
| ProducedPreParsedScopeData** produced_preparser_scope_data); |
| |
| 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; } |
| |
| 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, bool* ok); |
| 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, |
| PreParserExpression expression) {} |
| V8_INLINE void AddTemplateSpan(TemplateLiteralState* state, bool should_cook, |
| bool tail) {} |
| V8_INLINE PreParserExpression CloseTemplateLiteral( |
| TemplateLiteralState* state, int start, PreParserExpression tag); |
| 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 void MarkCollectedTailCallExpressions() {} |
| V8_INLINE void MarkTailPosition(PreParserExpression expression) {} |
| |
| V8_INLINE PreParserExpression SpreadCall(PreParserExpression function, |
| PreParserExpressionList args, |
| int pos, |
| Call::PossiblyEval possibly_eval); |
| V8_INLINE PreParserExpression SpreadCallNew(PreParserExpression function, |
| PreParserExpressionList args, |
| int pos); |
| |
| V8_INLINE void RewriteDestructuringAssignments() {} |
| |
| V8_INLINE PreParserExpression RewriteExponentiation(PreParserExpression left, |
| PreParserExpression right, |
| int pos) { |
| return left; |
| } |
| V8_INLINE PreParserExpression RewriteAssignExponentiation( |
| PreParserExpression left, PreParserExpression right, int pos) { |
| return left; |
| } |
| |
| V8_INLINE void PrepareAsyncFunctionBody(PreParserStatementList body, |
| FunctionKind kind, int pos) {} |
| V8_INLINE void RewriteAsyncFunctionBody(PreParserStatementList body, |
| PreParserStatement block, |
| PreParserExpression return_value, |
| bool* ok) {} |
| V8_INLINE PreParserExpression RewriteYieldStar(PreParserExpression expression, |
| int pos) { |
| return PreParserExpression::Default(); |
| } |
| V8_INLINE void RewriteNonPattern(bool* ok) { ValidateExpression(ok); } |
| |
| void DeclareAndInitializeVariables( |
| PreParserStatement block, |
| const DeclarationDescriptor* declaration_descriptor, |
| const DeclarationParsingResult::Declaration* declaration, |
| ZoneList<const AstRawString*>* names, bool* ok); |
| |
| V8_INLINE ZoneList<const AstRawString*>* DeclareLabel( |
| ZoneList<const AstRawString*>* labels, PreParserExpression expr, |
| bool* ok) { |
| DCHECK(!expr.AsIdentifier().IsEnum()); |
| DCHECK(!parsing_module_ || !expr.AsIdentifier().IsAwait()); |
| DCHECK(IsIdentifier(expr)); |
| return labels; |
| } |
| |
| // TODO(nikolaos): The preparser currently does not keep track of labels. |
| V8_INLINE bool ContainsLabel(ZoneList<const AstRawString*>* labels, |
| PreParserIdentifier label) { |
| return false; |
| } |
| |
| V8_INLINE PreParserExpression RewriteReturn(PreParserExpression return_value, |
| int pos) { |
| return return_value; |
| } |
| V8_INLINE PreParserStatement RewriteSwitchStatement( |
| PreParserExpression tag, PreParserStatement switch_statement, |
| PreParserStatementList cases, 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(); |
| } |
| // Unlike in the parser, we need to declare the catch variable as LET |
| // variable, so that it won't get hoisted out of the scope. (Parser uses |
| // DeclareLocal instead of DeclareVariable to prevent hoisting.) Another |
| // solution would've been to add DeclareLocalName just for this purpose. |
| catch_info->scope->DeclareVariableName(catch_name, LET); |
| |
| if (catch_info->pattern.variables_ != nullptr) { |
| for (auto variable : *catch_info->pattern.variables_) { |
| scope()->DeclareVariableName(variable->raw_name(), LET); |
| } |
| } |
| } |
| } |
| |
| 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 CreateFunctionNameAssignment( |
| const AstRawString* function_name, |
| FunctionLiteral::FunctionType function_type, |
| DeclarationScope* function_scope) { |
| if (track_unresolved_variables_ && |
| function_type == FunctionLiteral::kNamedExpression) { |
| if (function_scope->LookupLocal(function_name) == nullptr) { |
| DCHECK_EQ(function_scope, scope()); |
| Variable* fvar = function_scope->DeclareFunctionVar(function_name); |
| fvar->set_is_used(); |
| } |
| } |
| } |
| |
| V8_INLINE void CreateFunctionNameAssignment( |
| PreParserIdentifier function_name, int pos, |
| FunctionLiteral::FunctionType function_type, |
| DeclarationScope* function_scope, PreParserStatementList result, |
| int index) { |
| CreateFunctionNameAssignment(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(PreParserIdentifier label, |
| bool* ok) { |
| return PreParserStatement::Default(); |
| } |
| V8_INLINE PreParserStatement LookupContinueTarget(PreParserIdentifier label, |
| bool* ok) { |
| return PreParserStatement::Default(); |
| } |
| |
| V8_INLINE PreParserStatement DeclareFunction( |
| PreParserIdentifier variable_name, PreParserExpression function, |
| VariableMode mode, int pos, bool is_sloppy_block_function, |
| ZoneList<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(PreParserIdentifier variable_name, PreParserExpression value, |
| ZoneList<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_, LET); |
| } |
| return PreParserStatement::Default(); |
| } |
| V8_INLINE void DeclareClassVariable(PreParserIdentifier name, |
| ClassInfo* class_info, |
| int class_token_pos, bool* ok) { |
| if (name.string_ != nullptr) { |
| DCHECK(track_unresolved_variables_); |
| scope()->DeclareVariableName(name.string_, CONST); |
| } |
| } |
| V8_INLINE void DeclareClassProperty(PreParserIdentifier class_name, |
| PreParserExpression property, |
| ClassLiteralProperty::Kind kind, |
| bool is_static, bool is_constructor, |
| ClassInfo* class_info, bool* ok) { |
| } |
| V8_INLINE PreParserExpression RewriteClassLiteral(Scope* scope, |
| 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) GetNextFunctionLiteralId(); |
| return PreParserExpression::Default(); |
| } |
| |
| V8_INLINE PreParserStatement DeclareNative(PreParserIdentifier name, int pos, |
| bool* ok) { |
| return PreParserStatement::Default(); |
| } |
| |
| V8_INLINE void QueueDestructuringAssignmentForRewriting( |
| PreParserExpression assignment) {} |
| V8_INLINE void QueueNonPatternForRewriting(PreParserExpression expr, |
| bool* ok) {} |
| |
| // Helper functions for recursive descent. |
| V8_INLINE bool IsEval(PreParserIdentifier identifier) const { |
| return identifier.IsEval(); |
| } |
| |
| V8_INLINE bool IsArguments(PreParserIdentifier identifier) const { |
| return identifier.IsArguments(); |
| } |
| |
| V8_INLINE bool IsEvalOrArguments(PreParserIdentifier identifier) const { |
| return identifier.IsEvalOrArguments(); |
| } |
| |
| V8_INLINE bool IsUndefined(PreParserIdentifier identifier) const { |
| return identifier.IsUndefined(); |
| } |
| |
| V8_INLINE bool IsAwait(PreParserIdentifier identifier) const { |
| return identifier.IsAwait(); |
| } |
| |
| // Returns true if the expression is of type "this.foo". |
| V8_INLINE static bool IsThisProperty(PreParserExpression expression) { |
| return expression.IsThisProperty(); |
| } |
| |
| V8_INLINE static bool IsIdentifier(PreParserExpression expression) { |
| return expression.IsIdentifier(); |
| } |
| |
| V8_INLINE static PreParserIdentifier AsIdentifier( |
| PreParserExpression expression) { |
| return expression.AsIdentifier(); |
| } |
| |
| V8_INLINE static PreParserExpression AsIdentifierExpression( |
| PreParserExpression expression) { |
| return expression; |
| } |
| |
| V8_INLINE bool IsPrototype(PreParserIdentifier identifier) const { |
| return identifier.IsPrototype(); |
| } |
| |
| V8_INLINE bool IsConstructor(PreParserIdentifier identifier) const { |
| return identifier.IsConstructor(); |
| } |
| |
| V8_INLINE bool IsName(PreParserIdentifier identifier) const { |
| return identifier.IsName(); |
| } |
| |
| V8_INLINE static bool IsBoilerplateProperty(PreParserExpression property) { |
| // PreParser doesn't count boilerplate properties. |
| return false; |
| } |
| |
| V8_INLINE bool IsNative(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(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 PreParserExpression GetPropertyValue( |
| PreParserExpression property) { |
| return PreParserExpression::Default(); |
| } |
| |
| 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(PreParserIdentifier id) {} |
| V8_INLINE static void PushVariableName(PreParserIdentifier id) {} |
| V8_INLINE void PushPropertyName(PreParserExpression expression) {} |
| V8_INLINE void PushEnclosingName(PreParserIdentifier name) {} |
| V8_INLINE static void AddFunctionForNameInference( |
| PreParserExpression expression) {} |
| V8_INLINE static void InferFunctionName() {} |
| |
| V8_INLINE static void CheckAssigningFunctionLiteralToProperty( |
| PreParserExpression left, PreParserExpression right) {} |
| |
| V8_INLINE void MarkExpressionAsAssigned(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, |
| PreParserExpression y, |
| Token::Value op, |
| int pos) { |
| return false; |
| } |
| |
| V8_INLINE PreParserExpression BuildUnaryExpression( |
| PreParserExpression expression, Token::Value op, int pos) { |
| return PreParserExpression::Default(); |
| } |
| |
| V8_INLINE PreParserStatement |
| BuildInitializationBlock(DeclarationParsingResult* parsing_result, |
| ZoneList<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, PreParserExpression each, |
| PreParserExpression subject, PreParserStatement body) { |
| MarkExpressionAsAssigned(each); |
| return stmt; |
| } |
| |
| V8_INLINE PreParserStatement InitializeForOfStatement( |
| PreParserStatement stmt, PreParserExpression each, |
| 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(for_info->parsing_result.declarations.length() == 1); |
| bool is_for_var_of = |
| for_info->mode == ForEachStatement::ITERATE && |
| for_info->parsing_result.descriptor.mode == VariableMode::VAR; |
| 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, LET); |
| } |
| return PreParserStatement::Default(); |
| } |
| } |
| return init_block; |
| } |
| |
| V8_INLINE StatementT DesugarLexicalBindingsInForStatement( |
| PreParserStatement loop, PreParserStatement init, |
| PreParserExpression cond, PreParserStatement next, |
| PreParserStatement body, const SourceRange& body_range, |
| 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; |
| } |
| |
| V8_INLINE PreParserStatement BuildParameterInitializationBlock( |
| const PreParserFormalParameters& parameters, bool* ok) { |
| return PreParserStatement::Default(); |
| } |
| |
| 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, PreParserIdentifier arg, int pos) { |
| return PreParserExpression::Default(); |
| } |
| |
| V8_INLINE PreParserExpression NewThrowTypeError( |
| MessageTemplate::Template message, PreParserIdentifier arg, int pos) { |
| return PreParserExpression::Default(); |
| } |
| |
| // Reporting errors. |
| V8_INLINE void ReportMessageAt(Scanner::Location source_location, |
| MessageTemplate::Template message, |
| const char* arg = NULL, |
| 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, |
| PreParserIdentifier arg, |
| ParseErrorType error_type = kSyntaxError) { |
| UNREACHABLE(); |
| } |
| |
| // "null" return type creators. |
| V8_INLINE static PreParserIdentifier EmptyIdentifier() { |
| return PreParserIdentifier::Empty(); |
| } |
| V8_INLINE static bool IsEmptyIdentifier(PreParserIdentifier name) { |
| return name.IsEmpty(); |
| } |
| V8_INLINE static PreParserExpression EmptyExpression() { |
| return PreParserExpression::Empty(); |
| } |
| V8_INLINE static PreParserExpression EmptyLiteral() { |
| return PreParserExpression::Default(); |
| } |
| V8_INLINE static PreParserExpression EmptyObjectLiteralProperty() { |
| return PreParserExpression::Default(); |
| } |
| V8_INLINE static PreParserExpression EmptyClassLiteralProperty() { |
| return PreParserExpression::Default(); |
| } |
| V8_INLINE static PreParserExpression EmptyFunctionLiteral() { |
| return PreParserExpression::Default(); |
| } |
| |
| V8_INLINE static bool IsEmptyExpression(PreParserExpression expr) { |
| return expr.IsEmpty(); |
| } |
| |
| V8_INLINE static PreParserExpressionList NullExpressionList() { |
| return PreParserExpressionList::Null(); |
| } |
| |
| V8_INLINE static bool IsNullExpressionList(PreParserExpressionList exprs) { |
| return exprs.IsNull(); |
| } |
| |
| V8_INLINE static PreParserStatementList NullStatementList() { |
| return PreParserStatementList::Null(); |
| } |
| |
| V8_INLINE static bool IsNullStatementList(PreParserStatementList stmts) { |
| return stmts.IsNull(); |
| } |
| |
| V8_INLINE static PreParserStatement NullStatement() { |
| return PreParserStatement::Null(); |
| } |
| |
| V8_INLINE bool IsNullStatement(PreParserStatement stmt) { |
| return stmt.IsNullStatement(); |
| } |
| |
| V8_INLINE bool IsEmptyStatement(PreParserStatement stmt) { |
| return stmt.IsEmptyStatement(); |
| } |
| |
| V8_INLINE static PreParserStatement NullBlock() { |
| return PreParserStatement::Null(); |
| } |
| |
| V8_INLINE PreParserIdentifier EmptyIdentifierString() const { |
| return PreParserIdentifier::Default(); |
| } |
| |
| // Odd-ball literal creators. |
| V8_INLINE PreParserExpression GetLiteralTheHole(int position) { |
| return PreParserExpression::Default(); |
| } |
| |
| V8_INLINE PreParserExpression GetLiteralUndefined(int position) { |
| return PreParserExpression::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) { |
| ZoneList<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()) ZoneList<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 FunctionSentExpression(int pos) { |
| return PreParserExpression::Default(); |
| } |
| |
| V8_INLINE PreParserExpression ExpressionFromLiteral(Token::Value token, |
| int pos) { |
| return PreParserExpression::Default(); |
| } |
| |
| PreParserExpression ExpressionFromIdentifier( |
| 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(); |
| } |
| |
| PreParserStatementList NewCaseClauseList(int size) { |
| return PreParserStatementList(); |
| } |
| |
| V8_INLINE PreParserExpression |
| NewV8Intrinsic(PreParserIdentifier name, PreParserExpressionList arguments, |
| int pos, bool* ok) { |
| return PreParserExpression::Default(); |
| } |
| |
| V8_INLINE PreParserStatement NewThrowStatement(PreParserExpression exception, |
| int pos) { |
| return PreParserStatement::Jump(); |
| } |
| |
| V8_INLINE void AddParameterInitializationBlock( |
| const PreParserFormalParameters& parameters, PreParserStatementList body, |
| bool is_async, bool* ok) {} |
| |
| V8_INLINE void AddFormalParameter(PreParserFormalParameters* parameters, |
| PreParserExpression pattern, |
| 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.IsEmpty(), 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, 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(), VAR); |
| } |
| } |
| } |
| } |
| |
| V8_INLINE PreParserExpression NoTemplateTag() { |
| return PreParserExpression::NoTemplateTag(); |
| } |
| |
| V8_INLINE static bool IsTaggedTemplate(const PreParserExpression tag) { |
| return !tag.IsNoTemplateTag(); |
| } |
| |
| V8_INLINE PreParserExpression |
| ExpressionListToExpression(PreParserExpressionList args) { |
| return PreParserExpression::Default(args.variables_); |
| } |
| |
| V8_INLINE void SetFunctionNameFromPropertyName( |
| PreParserExpression property, PreParserIdentifier name, |
| const AstRawString* prefix = nullptr) {} |
| V8_INLINE void SetFunctionNameFromIdentifierRef( |
| PreParserExpression value, PreParserExpression identifier) {} |
| |
| V8_INLINE ZoneList<typename ExpressionClassifier::Error>* |
| GetReportedErrorList() const { |
| return function_state_->GetReportedErrorList(); |
| } |
| |
| V8_INLINE ZoneList<PreParserExpression>* GetNonPatternList() const { |
| return function_state_->non_patterns_to_rewrite(); |
| } |
| |
| V8_INLINE void CountUsage(v8::Isolate::UseCounterFeature feature) { |
| if (use_counts_ != nullptr) ++use_counts_[feature]; |
| } |
| |
| V8_INLINE bool ParsingDynamicFunctionDeclaration() const { return false; } |
| |
| V8_INLINE void RecordBlockSourceRange(PreParserStatement node, |
| int32_t continuation_position) {} |
| V8_INLINE void RecordCaseClauseSourceRange(PreParserStatement node, |
| const SourceRange& body_range) {} |
| V8_INLINE void RecordIfStatementSourceRange(PreParserStatement node, |
| const SourceRange& then_range, |
| const SourceRange& else_range) {} |
| V8_INLINE void RecordJumpStatementSourceRange(PreParserStatement node, |
| int32_t continuation_position) { |
| } |
| V8_INLINE void RecordIterationStatementSourceRange( |
| PreParserStatement node, const SourceRange& body_range) {} |
| V8_INLINE void RecordSwitchStatementSourceRange( |
| PreParserStatement node, int32_t continuation_position) {} |
| V8_INLINE void RecordThrowSourceRange(PreParserStatement node, |
| int32_t continuation_position) {} |
| V8_INLINE void RecordTryCatchStatementSourceRange( |
| PreParserStatement node, const SourceRange& body_range) {} |
| V8_INLINE void RecordTryFinallyStatementSourceRange( |
| PreParserStatement node, const SourceRange& body_range) {} |
| |
| // Preparser's private field members. |
| |
| int* use_counts_; |
| bool track_unresolved_variables_; |
| PreParserLogger log_; |
| PendingCompilationErrorHandler* pending_error_handler_; |
| |
| ProducedPreParsedScopeData* produced_preparsed_scope_data_; |
| }; |
| |
| PreParserExpression PreParser::SpreadCall(PreParserExpression function, |
| PreParserExpressionList args, int pos, |
| Call::PossiblyEval possibly_eval) { |
| return factory()->NewCall(function, args, pos, possibly_eval); |
| } |
| |
| PreParserExpression PreParser::SpreadCallNew(PreParserExpression function, |
| PreParserExpressionList args, |
| int pos) { |
| return factory()->NewCallNew(function, args, pos); |
| } |
| |
| PreParserExpression PreParser::CloseTemplateLiteral(TemplateLiteralState* state, |
| int start, |
| PreParserExpression tag) { |
| return EmptyExpression(); |
| } |
| |
| } // namespace internal |
| } // namespace v8 |
| |
| #endif // V8_PARSING_PREPARSER_H |