// Copyright 2012 the V8 project authors. All rights reserved.
|
// Use of this source code is governed by a BSD-style license that can be
|
// found in the LICENSE file.
|
|
#ifndef V8_PARSING_PARSER_H_
|
#define V8_PARSING_PARSER_H_
|
|
#include <cstddef>
|
|
#include "src/ast/ast-source-ranges.h"
|
#include "src/ast/ast.h"
|
#include "src/ast/scopes.h"
|
#include "src/base/compiler-specific.h"
|
#include "src/globals.h"
|
#include "src/parsing/parser-base.h"
|
#include "src/parsing/parsing.h"
|
#include "src/parsing/preparser.h"
|
#include "src/utils.h"
|
#include "src/zone/zone-chunk-list.h"
|
|
namespace v8 {
|
|
class ScriptCompiler;
|
|
namespace internal {
|
|
class ConsumedPreParsedScopeData;
|
class ParseInfo;
|
class ParserTarget;
|
class ParserTargetScope;
|
class PendingCompilationErrorHandler;
|
class PreParsedScopeData;
|
|
class FunctionEntry BASE_EMBEDDED {
|
public:
|
enum {
|
kStartPositionIndex,
|
kEndPositionIndex,
|
kNumParametersIndex,
|
kFlagsIndex,
|
kNumInnerFunctionsIndex,
|
kSize
|
};
|
|
explicit FunctionEntry(Vector<unsigned> backing)
|
: backing_(backing) { }
|
|
FunctionEntry() : backing_() { }
|
|
class LanguageModeField : public BitField<LanguageMode, 0, 1> {};
|
class UsesSuperPropertyField
|
: public BitField<bool, LanguageModeField::kNext, 1> {};
|
|
static uint32_t EncodeFlags(LanguageMode language_mode,
|
bool uses_super_property) {
|
return LanguageModeField::encode(language_mode) |
|
UsesSuperPropertyField::encode(uses_super_property);
|
}
|
|
int start_pos() const { return backing_[kStartPositionIndex]; }
|
int end_pos() const { return backing_[kEndPositionIndex]; }
|
int num_parameters() const { return backing_[kNumParametersIndex]; }
|
LanguageMode language_mode() const {
|
return LanguageModeField::decode(backing_[kFlagsIndex]);
|
}
|
bool uses_super_property() const {
|
return UsesSuperPropertyField::decode(backing_[kFlagsIndex]);
|
}
|
int num_inner_functions() const { return backing_[kNumInnerFunctionsIndex]; }
|
|
bool is_valid() const { return !backing_.is_empty(); }
|
|
private:
|
Vector<unsigned> backing_;
|
};
|
|
|
// ----------------------------------------------------------------------------
|
// JAVASCRIPT PARSING
|
|
class Parser;
|
|
|
struct ParserFormalParameters : FormalParametersBase {
|
struct Parameter : public ZoneObject {
|
Parameter(const AstRawString* name, Expression* pattern,
|
Expression* initializer, int position,
|
int initializer_end_position, bool is_rest)
|
: name(name),
|
pattern(pattern),
|
initializer(initializer),
|
position(position),
|
initializer_end_position(initializer_end_position),
|
is_rest(is_rest) {}
|
const AstRawString* name;
|
Expression* pattern;
|
Expression* initializer;
|
int position;
|
int initializer_end_position;
|
bool is_rest;
|
Parameter* next_parameter = nullptr;
|
bool is_simple() const {
|
return pattern->IsVariableProxy() && initializer == nullptr && !is_rest;
|
}
|
|
Parameter** next() { return &next_parameter; }
|
Parameter* const* next() const { return &next_parameter; }
|
};
|
|
explicit ParserFormalParameters(DeclarationScope* scope)
|
: FormalParametersBase(scope) {}
|
ThreadedList<Parameter> params;
|
};
|
|
template <>
|
struct ParserTypes<Parser> {
|
typedef ParserBase<Parser> Base;
|
typedef Parser Impl;
|
|
// Return types for traversing functions.
|
typedef const AstRawString* Identifier;
|
typedef v8::internal::Expression* Expression;
|
typedef v8::internal::FunctionLiteral* FunctionLiteral;
|
typedef ObjectLiteral::Property* ObjectLiteralProperty;
|
typedef ClassLiteral::Property* ClassLiteralProperty;
|
typedef v8::internal::Suspend* Suspend;
|
typedef v8::internal::RewritableExpression* RewritableExpression;
|
typedef ZonePtrList<v8::internal::Expression>* ExpressionList;
|
typedef ZonePtrList<ObjectLiteral::Property>* ObjectPropertyList;
|
typedef ZonePtrList<ClassLiteral::Property>* ClassPropertyList;
|
typedef ParserFormalParameters FormalParameters;
|
typedef v8::internal::Statement* Statement;
|
typedef ZonePtrList<v8::internal::Statement>* StatementList;
|
typedef v8::internal::Block* Block;
|
typedef v8::internal::BreakableStatement* BreakableStatement;
|
typedef v8::internal::ForStatement* ForStatement;
|
typedef v8::internal::IterationStatement* IterationStatement;
|
|
// For constructing objects returned by the traversing functions.
|
typedef AstNodeFactory Factory;
|
|
typedef ParserTarget Target;
|
typedef ParserTargetScope TargetScope;
|
};
|
|
class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
|
public:
|
explicit Parser(ParseInfo* info);
|
~Parser() {
|
delete reusable_preparser_;
|
reusable_preparser_ = nullptr;
|
}
|
|
static bool IsPreParser() { return false; }
|
|
void ParseOnBackground(ParseInfo* info);
|
|
// Deserialize the scope chain prior to parsing in which the script is going
|
// to be executed. If the script is a top-level script, or the scope chain
|
// consists of only a native context, maybe_outer_scope_info should be an
|
// empty handle.
|
//
|
// This only deserializes the scope chain, but doesn't connect the scopes to
|
// their corresponding scope infos. Therefore, looking up variables in the
|
// deserialized scopes is not possible.
|
void DeserializeScopeChain(Isolate* isolate, ParseInfo* info,
|
MaybeHandle<ScopeInfo> maybe_outer_scope_info);
|
|
// Move statistics to Isolate
|
void UpdateStatistics(Isolate* isolate, Handle<Script> script);
|
void HandleSourceURLComments(Isolate* isolate, Handle<Script> script);
|
|
private:
|
friend class ParserBase<Parser>;
|
friend class v8::internal::ExpressionClassifier<ParserTypes<Parser>>;
|
friend bool v8::internal::parsing::ParseProgram(ParseInfo*, Isolate*);
|
friend bool v8::internal::parsing::ParseFunction(
|
ParseInfo*, Handle<SharedFunctionInfo> shared_info, Isolate*);
|
|
bool AllowsLazyParsingWithoutUnresolvedVariables() const {
|
return scope()->AllowsLazyParsingWithoutUnresolvedVariables(
|
original_scope_);
|
}
|
|
bool parse_lazily() const { return mode_ == PARSE_LAZILY; }
|
enum Mode { PARSE_LAZILY, PARSE_EAGERLY };
|
|
class ParsingModeScope BASE_EMBEDDED {
|
public:
|
ParsingModeScope(Parser* parser, Mode mode)
|
: parser_(parser), old_mode_(parser->mode_) {
|
parser_->mode_ = mode;
|
}
|
~ParsingModeScope() { parser_->mode_ = old_mode_; }
|
|
private:
|
Parser* parser_;
|
Mode old_mode_;
|
};
|
|
// Runtime encoding of different completion modes.
|
enum CompletionKind {
|
kNormalCompletion,
|
kThrowCompletion,
|
kAbruptCompletion
|
};
|
|
Variable* NewTemporary(const AstRawString* name) {
|
return scope()->NewTemporary(name);
|
}
|
|
void PrepareGeneratorVariables();
|
|
// Returns nullptr if parsing failed.
|
FunctionLiteral* ParseProgram(Isolate* isolate, ParseInfo* info);
|
|
FunctionLiteral* ParseFunction(Isolate* isolate, ParseInfo* info,
|
Handle<SharedFunctionInfo> shared_info);
|
FunctionLiteral* DoParseFunction(Isolate* isolate, ParseInfo* info,
|
const AstRawString* raw_name);
|
|
// Called by ParseProgram after setting up the scanner.
|
FunctionLiteral* DoParseProgram(Isolate* isolate, ParseInfo* info);
|
|
// Parse with the script as if the source is implicitly wrapped in a function.
|
// We manually construct the AST and scopes for a top-level function and the
|
// function wrapper.
|
void ParseWrapped(Isolate* isolate, ParseInfo* info,
|
ZonePtrList<Statement>* body, DeclarationScope* scope,
|
Zone* zone, bool* ok);
|
|
ZonePtrList<const AstRawString>* PrepareWrappedArguments(Isolate* isolate,
|
ParseInfo* info,
|
Zone* zone);
|
|
void StitchAst(ParseInfo* top_level_parse_info, Isolate* isolate);
|
|
PreParser* reusable_preparser() {
|
if (reusable_preparser_ == nullptr) {
|
reusable_preparser_ =
|
new PreParser(zone(), &scanner_, stack_limit_, ast_value_factory(),
|
pending_error_handler(), runtime_call_stats_, logger_,
|
-1, parsing_module_, parsing_on_main_thread_);
|
#define SET_ALLOW(name) reusable_preparser_->set_allow_##name(allow_##name());
|
SET_ALLOW(natives);
|
SET_ALLOW(harmony_do_expressions);
|
SET_ALLOW(harmony_public_fields);
|
SET_ALLOW(harmony_static_fields);
|
SET_ALLOW(harmony_dynamic_import);
|
SET_ALLOW(harmony_import_meta);
|
SET_ALLOW(harmony_bigint);
|
SET_ALLOW(harmony_private_fields);
|
SET_ALLOW(eval_cache);
|
#undef SET_ALLOW
|
}
|
return reusable_preparser_;
|
}
|
|
void ParseModuleItemList(ZonePtrList<Statement>* body, bool* ok);
|
Statement* ParseModuleItem(bool* ok);
|
const AstRawString* ParseModuleSpecifier(bool* ok);
|
void ParseImportDeclaration(bool* ok);
|
Statement* ParseExportDeclaration(bool* ok);
|
Statement* ParseExportDefault(bool* ok);
|
struct ExportClauseData {
|
const AstRawString* export_name;
|
const AstRawString* local_name;
|
Scanner::Location location;
|
};
|
ZoneChunkList<ExportClauseData>* ParseExportClause(
|
Scanner::Location* reserved_loc, bool* ok);
|
struct NamedImport : public ZoneObject {
|
const AstRawString* import_name;
|
const AstRawString* local_name;
|
const Scanner::Location location;
|
NamedImport(const AstRawString* import_name, const AstRawString* local_name,
|
Scanner::Location location)
|
: import_name(import_name),
|
local_name(local_name),
|
location(location) {}
|
};
|
ZonePtrList<const NamedImport>* ParseNamedImports(int pos, bool* ok);
|
Block* BuildInitializationBlock(DeclarationParsingResult* parsing_result,
|
ZonePtrList<const AstRawString>* names,
|
bool* ok);
|
void DeclareLabel(ZonePtrList<const AstRawString>** labels,
|
ZonePtrList<const AstRawString>** own_labels,
|
VariableProxy* expr, bool* ok);
|
bool ContainsLabel(ZonePtrList<const AstRawString>* labels,
|
const AstRawString* label);
|
Expression* RewriteReturn(Expression* return_value, int pos);
|
Statement* RewriteSwitchStatement(SwitchStatement* switch_statement,
|
Scope* scope);
|
void RewriteCatchPattern(CatchInfo* catch_info, bool* ok);
|
void ValidateCatchBlock(const CatchInfo& catch_info, bool* ok);
|
Statement* RewriteTryStatement(Block* try_block, Block* catch_block,
|
const SourceRange& catch_range,
|
Block* finally_block,
|
const SourceRange& finally_range,
|
const CatchInfo& catch_info, int pos);
|
void ParseAndRewriteGeneratorFunctionBody(int pos, FunctionKind kind,
|
ZonePtrList<Statement>* body,
|
bool* ok);
|
void ParseAndRewriteAsyncGeneratorFunctionBody(int pos, FunctionKind kind,
|
ZonePtrList<Statement>* body,
|
bool* ok);
|
void DeclareFunctionNameVar(const AstRawString* function_name,
|
FunctionLiteral::FunctionType function_type,
|
DeclarationScope* function_scope);
|
|
Statement* DeclareFunction(const AstRawString* variable_name,
|
FunctionLiteral* function, VariableMode mode,
|
int pos, bool is_sloppy_block_function,
|
ZonePtrList<const AstRawString>* names, bool* ok);
|
Variable* CreateSyntheticContextVariable(const AstRawString* synthetic_name,
|
bool* ok);
|
FunctionLiteral* CreateInitializerFunction(
|
DeclarationScope* scope, ZonePtrList<ClassLiteral::Property>* fields);
|
V8_INLINE Statement* DeclareClass(const AstRawString* variable_name,
|
Expression* value,
|
ZonePtrList<const AstRawString>* names,
|
int class_token_pos, int end_pos, bool* ok);
|
V8_INLINE void DeclareClassVariable(const AstRawString* name,
|
ClassInfo* class_info,
|
int class_token_pos, bool* ok);
|
V8_INLINE void DeclareClassProperty(const AstRawString* class_name,
|
ClassLiteralProperty* property,
|
const AstRawString* property_name,
|
ClassLiteralProperty::Kind kind,
|
bool is_static, bool is_constructor,
|
bool is_computed_name,
|
ClassInfo* class_info, bool* ok);
|
V8_INLINE Expression* RewriteClassLiteral(Scope* block_scope,
|
const AstRawString* name,
|
ClassInfo* class_info, int pos,
|
int end_pos, bool* ok);
|
V8_INLINE Statement* DeclareNative(const AstRawString* name, int pos,
|
bool* ok);
|
|
V8_INLINE Block* IgnoreCompletion(Statement* statement);
|
|
V8_INLINE Scope* NewHiddenCatchScope();
|
|
// PatternRewriter and associated methods defined in pattern-rewriter.cc.
|
friend class PatternRewriter;
|
void DeclareAndInitializeVariables(
|
Block* block, const DeclarationDescriptor* declaration_descriptor,
|
const DeclarationParsingResult::Declaration* declaration,
|
ZonePtrList<const AstRawString>* names, bool* ok);
|
void RewriteDestructuringAssignment(RewritableExpression* expr);
|
Expression* RewriteDestructuringAssignment(Assignment* assignment);
|
|
// [if (IteratorType == kAsync)]
|
// !%_IsJSReceiver(result = Await(next.[[Call]](iterator, « »)) &&
|
// %ThrowIteratorResultNotAnObject(result)
|
// [else]
|
// !%_IsJSReceiver(result = next.[[Call]](iterator, « »)) &&
|
// %ThrowIteratorResultNotAnObject(result)
|
// [endif]
|
Expression* BuildIteratorNextResult(VariableProxy* iterator,
|
VariableProxy* next, Variable* result,
|
IteratorType type, int pos);
|
|
// Initialize the components of a for-in / for-of statement.
|
Statement* InitializeForEachStatement(ForEachStatement* stmt,
|
Expression* each, Expression* subject,
|
Statement* body);
|
Statement* InitializeForOfStatement(ForOfStatement* stmt, Expression* each,
|
Expression* iterable, Statement* body,
|
bool finalize, IteratorType type,
|
int next_result_pos = kNoSourcePosition);
|
|
Block* RewriteForVarInLegacy(const ForInfo& for_info);
|
void DesugarBindingInForEachStatement(ForInfo* for_info, Block** body_block,
|
Expression** each_variable, bool* ok);
|
Block* CreateForEachStatementTDZ(Block* init_block, const ForInfo& for_info,
|
bool* ok);
|
|
Statement* DesugarLexicalBindingsInForStatement(
|
ForStatement* loop, Statement* init, Expression* cond, Statement* next,
|
Statement* body, Scope* inner_scope, const ForInfo& for_info, bool* ok);
|
|
Expression* RewriteDoExpression(Block* body, int pos, bool* ok);
|
|
FunctionLiteral* ParseFunctionLiteral(
|
const AstRawString* name, Scanner::Location function_name_location,
|
FunctionNameValidity function_name_validity, FunctionKind kind,
|
int function_token_position, FunctionLiteral::FunctionType type,
|
LanguageMode language_mode,
|
ZonePtrList<const AstRawString>* arguments_for_wrapped_function,
|
bool* ok);
|
|
ObjectLiteral* InitializeObjectLiteral(ObjectLiteral* object_literal) {
|
object_literal->CalculateEmitStore(main_zone());
|
return object_literal;
|
}
|
|
// Check if the scope has conflicting var/let declarations from different
|
// scopes. This covers for example
|
//
|
// function f() { { { var x; } let x; } }
|
// function g() { { var x; let x; } }
|
//
|
// The var declarations are hoisted to the function scope, but originate from
|
// a scope where the name has also been let bound or the var declaration is
|
// hoisted over such a scope.
|
void CheckConflictingVarDeclarations(Scope* scope, bool* ok);
|
|
bool IsPropertyWithPrivateFieldKey(Expression* property);
|
|
// Insert initializer statements for var-bindings shadowing parameter bindings
|
// from a non-simple parameter list.
|
void InsertShadowingVarBindingInitializers(Block* block);
|
|
// Implement sloppy block-scoped functions, ES2015 Annex B 3.3
|
void InsertSloppyBlockFunctionVarBindings(DeclarationScope* scope);
|
|
VariableProxy* NewUnresolved(const AstRawString* name, int begin_pos,
|
VariableKind kind = NORMAL_VARIABLE);
|
VariableProxy* NewUnresolved(const AstRawString* name);
|
Variable* Declare(Declaration* declaration,
|
DeclarationDescriptor::Kind declaration_kind,
|
VariableMode mode, InitializationFlag init, bool* ok,
|
Scope* declaration_scope = nullptr,
|
int var_end_pos = kNoSourcePosition);
|
Declaration* DeclareVariable(const AstRawString* name, VariableMode mode,
|
int pos, bool* ok);
|
Declaration* DeclareVariable(const AstRawString* name, VariableMode mode,
|
InitializationFlag init, int pos, bool* ok);
|
|
bool TargetStackContainsLabel(const AstRawString* label);
|
BreakableStatement* LookupBreakTarget(const AstRawString* label, bool* ok);
|
IterationStatement* LookupContinueTarget(const AstRawString* label, bool* ok);
|
|
Statement* BuildAssertIsCoercible(Variable* var, ObjectLiteral* pattern);
|
|
// Factory methods.
|
FunctionLiteral* DefaultConstructor(const AstRawString* name, bool call_super,
|
int pos, int end_pos);
|
|
// Skip over a lazy function, either using cached data if we have it, or
|
// by parsing the function with PreParser. Consumes the ending }.
|
// If may_abort == true, the (pre-)parser may decide to abort skipping
|
// in order to force the function to be eagerly parsed, after all.
|
LazyParsingResult SkipFunction(
|
const AstRawString* function_name, FunctionKind kind,
|
FunctionLiteral::FunctionType function_type,
|
DeclarationScope* function_scope, int* num_parameters,
|
ProducedPreParsedScopeData** produced_preparsed_scope_data,
|
bool is_inner_function, bool may_abort, bool* ok);
|
|
Block* BuildParameterInitializationBlock(
|
const ParserFormalParameters& parameters, bool* ok);
|
Block* BuildRejectPromiseOnException(Block* block);
|
|
ZonePtrList<Statement>* ParseFunction(
|
const AstRawString* function_name, int pos, FunctionKind kind,
|
FunctionLiteral::FunctionType function_type,
|
DeclarationScope* function_scope, int* num_parameters,
|
int* function_length, bool* has_duplicate_parameters,
|
int* expected_property_count, int* suspend_count,
|
ZonePtrList<const AstRawString>* arguments_for_wrapped_function,
|
bool* ok);
|
|
void ThrowPendingError(Isolate* isolate, Handle<Script> script);
|
|
class TemplateLiteral : public ZoneObject {
|
public:
|
TemplateLiteral(Zone* zone, int pos)
|
: cooked_(8, zone), raw_(8, zone), expressions_(8, zone), pos_(pos) {}
|
|
const ZonePtrList<const AstRawString>* cooked() const { return &cooked_; }
|
const ZonePtrList<const AstRawString>* raw() const { return &raw_; }
|
const ZonePtrList<Expression>* expressions() const { return &expressions_; }
|
int position() const { return pos_; }
|
|
void AddTemplateSpan(const AstRawString* cooked, const AstRawString* raw,
|
int end, Zone* zone) {
|
DCHECK_NOT_NULL(raw);
|
cooked_.Add(cooked, zone);
|
raw_.Add(raw, zone);
|
}
|
|
void AddExpression(Expression* expression, Zone* zone) {
|
DCHECK_NOT_NULL(expression);
|
expressions_.Add(expression, zone);
|
}
|
|
private:
|
ZonePtrList<const AstRawString> cooked_;
|
ZonePtrList<const AstRawString> raw_;
|
ZonePtrList<Expression> expressions_;
|
int pos_;
|
};
|
|
typedef TemplateLiteral* TemplateLiteralState;
|
|
TemplateLiteralState OpenTemplateLiteral(int pos);
|
// "should_cook" means that the span can be "cooked": in tagged template
|
// literals, both the raw and "cooked" representations are available to user
|
// code ("cooked" meaning that escape sequences are converted to their
|
// interpreted values). Invalid escape sequences cause the cooked span
|
// to be represented by undefined, instead of being a syntax error.
|
// "tail" indicates that this span is the last in the literal.
|
void AddTemplateSpan(TemplateLiteralState* state, bool should_cook,
|
bool tail);
|
void AddTemplateExpression(TemplateLiteralState* state,
|
Expression* expression);
|
Expression* CloseTemplateLiteral(TemplateLiteralState* state, int start,
|
Expression* tag);
|
|
ArrayLiteral* ArrayLiteralFromListWithSpread(ZonePtrList<Expression>* list);
|
Expression* SpreadCall(Expression* function, ZonePtrList<Expression>* args,
|
int pos, Call::PossiblyEval is_possibly_eval);
|
Expression* SpreadCallNew(Expression* function, ZonePtrList<Expression>* args,
|
int pos);
|
Expression* RewriteSuperCall(Expression* call_expression);
|
|
void SetLanguageMode(Scope* scope, LanguageMode mode);
|
void SetAsmModule();
|
|
// Rewrite all DestructuringAssignments in the current FunctionState.
|
V8_INLINE void RewriteDestructuringAssignments();
|
|
Expression* RewriteSpreads(ArrayLiteral* lit);
|
|
V8_INLINE void QueueDestructuringAssignmentForRewriting(
|
RewritableExpression* assignment);
|
|
friend class InitializerRewriter;
|
void RewriteParameterInitializer(Expression* expr);
|
|
Expression* BuildInitialYield(int pos, FunctionKind kind);
|
Assignment* BuildCreateJSGeneratorObject(int pos, FunctionKind kind);
|
Expression* BuildResolvePromise(Expression* value, int pos);
|
Expression* BuildRejectPromise(Expression* value, int pos);
|
Variable* PromiseVariable();
|
Variable* AsyncGeneratorAwaitVariable();
|
|
// Generic AST generator for throwing errors from compiled code.
|
Expression* NewThrowError(Runtime::FunctionId function_id,
|
MessageTemplate::Template message,
|
const AstRawString* arg, int pos);
|
|
void FinalizeIteratorUse(Variable* completion, Expression* condition,
|
Variable* iter, Block* iterator_use, Block* result,
|
IteratorType type);
|
|
Statement* FinalizeForOfStatement(ForOfStatement* loop, Variable* completion,
|
IteratorType type, int pos);
|
void BuildIteratorClose(ZonePtrList<Statement>* statements,
|
Variable* iterator, Variable* input, Variable* output,
|
IteratorType type);
|
void BuildIteratorCloseForCompletion(ZonePtrList<Statement>* statements,
|
Variable* iterator,
|
Expression* completion,
|
IteratorType type);
|
Statement* CheckCallable(Variable* var, Expression* error, int pos);
|
|
V8_INLINE void RewriteAsyncFunctionBody(ZonePtrList<Statement>* body,
|
Block* block,
|
Expression* return_value, bool* ok);
|
|
void AddArrowFunctionFormalParameters(ParserFormalParameters* parameters,
|
Expression* params, int end_pos,
|
bool* ok);
|
void SetFunctionName(Expression* value, const AstRawString* name,
|
const AstRawString* prefix = nullptr);
|
|
// Helper functions for recursive descent.
|
V8_INLINE bool IsEval(const AstRawString* identifier) const {
|
return identifier == ast_value_factory()->eval_string();
|
}
|
|
V8_INLINE bool IsArguments(const AstRawString* identifier) const {
|
return identifier == ast_value_factory()->arguments_string();
|
}
|
|
V8_INLINE bool IsEvalOrArguments(const AstRawString* identifier) const {
|
return IsEval(identifier) || IsArguments(identifier);
|
}
|
|
// Returns true if the expression is of type "this.foo".
|
V8_INLINE static bool IsThisProperty(Expression* expression) {
|
DCHECK_NOT_NULL(expression);
|
Property* property = expression->AsProperty();
|
return property != nullptr && property->obj()->IsVariableProxy() &&
|
property->obj()->AsVariableProxy()->is_this();
|
}
|
|
// This returns true if the expression is an indentifier (wrapped
|
// inside a variable proxy). We exclude the case of 'this', which
|
// has been converted to a variable proxy.
|
V8_INLINE static bool IsIdentifier(Expression* expression) {
|
DCHECK_NOT_NULL(expression);
|
VariableProxy* operand = expression->AsVariableProxy();
|
return operand != nullptr && !operand->is_this() &&
|
!operand->is_new_target();
|
}
|
|
V8_INLINE static const AstRawString* AsIdentifier(Expression* expression) {
|
DCHECK(IsIdentifier(expression));
|
return expression->AsVariableProxy()->raw_name();
|
}
|
|
V8_INLINE VariableProxy* AsIdentifierExpression(Expression* expression) {
|
return expression->AsVariableProxy();
|
}
|
|
V8_INLINE bool IsConstructor(const AstRawString* identifier) const {
|
return identifier == ast_value_factory()->constructor_string();
|
}
|
|
V8_INLINE bool IsName(const AstRawString* identifier) const {
|
return identifier == ast_value_factory()->name_string();
|
}
|
|
V8_INLINE static bool IsBoilerplateProperty(
|
ObjectLiteral::Property* property) {
|
return !property->IsPrototype();
|
}
|
|
V8_INLINE bool IsNative(Expression* expr) const {
|
DCHECK_NOT_NULL(expr);
|
return expr->IsVariableProxy() &&
|
expr->AsVariableProxy()->raw_name() ==
|
ast_value_factory()->native_string();
|
}
|
|
V8_INLINE static bool IsArrayIndex(const AstRawString* string,
|
uint32_t* index) {
|
return string->AsArrayIndex(index);
|
}
|
|
V8_INLINE bool IsUseStrictDirective(Statement* statement) const {
|
return IsStringLiteral(statement, ast_value_factory()->use_strict_string());
|
}
|
|
V8_INLINE bool IsUseAsmDirective(Statement* statement) const {
|
return IsStringLiteral(statement, ast_value_factory()->use_asm_string());
|
}
|
|
// Returns true if the statement is an expression statement containing
|
// a single string literal. If a second argument is given, the literal
|
// is also compared with it and the result is true only if they are equal.
|
V8_INLINE bool IsStringLiteral(Statement* statement,
|
const AstRawString* arg = nullptr) const {
|
ExpressionStatement* e_stat = statement->AsExpressionStatement();
|
if (e_stat == nullptr) return false;
|
Literal* literal = e_stat->expression()->AsLiteral();
|
if (literal == nullptr || !literal->IsString()) return false;
|
return arg == nullptr || literal->AsRawString() == arg;
|
}
|
|
V8_INLINE void GetDefaultStrings(
|
const AstRawString** default_string,
|
const AstRawString** star_default_star_string) {
|
*default_string = ast_value_factory()->default_string();
|
*star_default_star_string = ast_value_factory()->star_default_star_string();
|
}
|
|
// Functions for encapsulating the differences between parsing and preparsing;
|
// operations interleaved with the recursive descent.
|
V8_INLINE void PushLiteralName(const AstRawString* id) {
|
DCHECK_NOT_NULL(fni_);
|
fni_->PushLiteralName(id);
|
}
|
|
V8_INLINE void PushVariableName(const AstRawString* id) {
|
DCHECK_NOT_NULL(fni_);
|
fni_->PushVariableName(id);
|
}
|
|
V8_INLINE void PushPropertyName(Expression* expression) {
|
DCHECK_NOT_NULL(fni_);
|
if (expression->IsPropertyName()) {
|
fni_->PushLiteralName(expression->AsLiteral()->AsRawPropertyName());
|
} else {
|
fni_->PushLiteralName(ast_value_factory()->anonymous_function_string());
|
}
|
}
|
|
V8_INLINE void PushEnclosingName(const AstRawString* name) {
|
DCHECK_NOT_NULL(fni_);
|
fni_->PushEnclosingName(name);
|
}
|
|
V8_INLINE void AddFunctionForNameInference(FunctionLiteral* func_to_infer) {
|
DCHECK_NOT_NULL(fni_);
|
fni_->AddFunction(func_to_infer);
|
}
|
|
V8_INLINE void InferFunctionName() {
|
DCHECK_NOT_NULL(fni_);
|
fni_->Infer();
|
}
|
|
// If we assign a function literal to a property we pretenure the
|
// literal so it can be added as a constant function property.
|
V8_INLINE static void CheckAssigningFunctionLiteralToProperty(
|
Expression* left, Expression* right) {
|
DCHECK_NOT_NULL(left);
|
if (left->IsProperty() && right->IsFunctionLiteral()) {
|
right->AsFunctionLiteral()->set_pretenure();
|
}
|
}
|
|
// Determine if the expression is a variable proxy and mark it as being used
|
// in an assignment or with a increment/decrement operator.
|
V8_INLINE static void MarkExpressionAsAssigned(Expression* expression) {
|
DCHECK_NOT_NULL(expression);
|
if (expression->IsVariableProxy()) {
|
expression->AsVariableProxy()->set_is_assigned();
|
}
|
}
|
|
// A shortcut for performing a ToString operation
|
V8_INLINE Expression* ToString(Expression* expr) {
|
if (expr->IsStringLiteral()) return expr;
|
ZonePtrList<Expression>* args =
|
new (zone()) ZonePtrList<Expression>(1, zone());
|
args->Add(expr, zone());
|
return factory()->NewCallRuntime(Runtime::kInlineToString, args,
|
expr->position());
|
}
|
|
// Returns true if we have a binary expression between two numeric
|
// literals. In that case, *x will be changed to an expression which is the
|
// computed value.
|
bool ShortcutNumericLiteralBinaryExpression(Expression** x, Expression* y,
|
Token::Value op, int pos);
|
|
// Returns true if we have a binary operation between a binary/n-ary
|
// expression (with the same operation) and a value, which can be collapsed
|
// into a single n-ary expression. In that case, *x will be changed to an
|
// n-ary expression.
|
bool CollapseNaryExpression(Expression** x, Expression* y, Token::Value op,
|
int pos, const SourceRange& range);
|
|
// Returns a UnaryExpression or, in one of the following cases, a Literal.
|
// ! <literal> -> true / false
|
// + <Number literal> -> <Number literal>
|
// - <Number literal> -> <Number literal with value negated>
|
// ~ <literal> -> true / false
|
Expression* BuildUnaryExpression(Expression* expression, Token::Value op,
|
int pos);
|
|
// Generate AST node that throws a ReferenceError with the given type.
|
V8_INLINE Expression* NewThrowReferenceError(
|
MessageTemplate::Template message, int pos) {
|
return NewThrowError(Runtime::kNewReferenceError, message,
|
ast_value_factory()->empty_string(), pos);
|
}
|
|
// Generate AST node that throws a SyntaxError with the given
|
// type. The first argument may be null (in the handle sense) in
|
// which case no arguments are passed to the constructor.
|
V8_INLINE Expression* NewThrowSyntaxError(MessageTemplate::Template message,
|
const AstRawString* arg, int pos) {
|
return NewThrowError(Runtime::kNewSyntaxError, message, arg, pos);
|
}
|
|
// Generate AST node that throws a TypeError with the given
|
// type. Both arguments must be non-null (in the handle sense).
|
V8_INLINE Expression* NewThrowTypeError(MessageTemplate::Template message,
|
const AstRawString* arg, int pos) {
|
return NewThrowError(Runtime::kNewTypeError, message, arg, pos);
|
}
|
|
// Reporting errors.
|
void ReportMessageAt(Scanner::Location source_location,
|
MessageTemplate::Template message,
|
const char* arg = nullptr,
|
ParseErrorType error_type = kSyntaxError) {
|
if (stack_overflow()) {
|
// Suppress the error message (syntax error or such) in the presence of a
|
// stack overflow. The isolate allows only one pending exception at at
|
// time
|
// and we want to report the stack overflow later.
|
return;
|
}
|
pending_error_handler()->ReportMessageAt(source_location.beg_pos,
|
source_location.end_pos, message,
|
arg, error_type);
|
}
|
|
void ReportMessageAt(Scanner::Location source_location,
|
MessageTemplate::Template message,
|
const AstRawString* arg,
|
ParseErrorType error_type = kSyntaxError) {
|
if (stack_overflow()) {
|
// Suppress the error message (syntax error or such) in the presence of a
|
// stack overflow. The isolate allows only one pending exception at at
|
// time
|
// and we want to report the stack overflow later.
|
return;
|
}
|
pending_error_handler()->ReportMessageAt(source_location.beg_pos,
|
source_location.end_pos, message,
|
arg, error_type);
|
}
|
|
// "null" return type creators.
|
V8_INLINE static std::nullptr_t NullIdentifier() { return nullptr; }
|
V8_INLINE static std::nullptr_t NullExpression() { return nullptr; }
|
V8_INLINE static std::nullptr_t NullLiteralProperty() { return nullptr; }
|
V8_INLINE static ZonePtrList<Expression>* NullExpressionList() {
|
return nullptr;
|
}
|
V8_INLINE static ZonePtrList<Statement>* NullStatementList() {
|
return nullptr;
|
}
|
V8_INLINE static std::nullptr_t NullStatement() { return nullptr; }
|
|
template <typename T>
|
V8_INLINE static bool IsNull(T subject) {
|
return subject == nullptr;
|
}
|
|
// Non-null empty string.
|
V8_INLINE const AstRawString* EmptyIdentifierString() const {
|
return ast_value_factory()->empty_string();
|
}
|
|
// Producing data during the recursive descent.
|
V8_INLINE const AstRawString* GetSymbol() const {
|
const AstRawString* result = scanner()->CurrentSymbol(ast_value_factory());
|
DCHECK_NOT_NULL(result);
|
return result;
|
}
|
|
V8_INLINE const AstRawString* GetNextSymbol() const {
|
return scanner()->NextSymbol(ast_value_factory());
|
}
|
|
V8_INLINE const AstRawString* GetNumberAsSymbol() const {
|
double double_value = scanner()->DoubleValue();
|
char array[100];
|
const char* string = DoubleToCString(double_value, ArrayVector(array));
|
return ast_value_factory()->GetOneByteString(string);
|
}
|
|
V8_INLINE Expression* ThisExpression(int pos = kNoSourcePosition) {
|
return NewUnresolved(ast_value_factory()->this_string(), pos,
|
THIS_VARIABLE);
|
}
|
|
Expression* NewSuperPropertyReference(int pos);
|
Expression* NewSuperCallReference(int pos);
|
Expression* NewTargetExpression(int pos);
|
Expression* ImportMetaExpression(int pos);
|
|
Literal* ExpressionFromLiteral(Token::Value token, int pos);
|
|
V8_INLINE VariableProxy* ExpressionFromIdentifier(
|
const AstRawString* name, int start_position,
|
InferName infer = InferName::kYes) {
|
if (infer == InferName::kYes) {
|
fni_->PushVariableName(name);
|
}
|
return NewUnresolved(name, start_position);
|
}
|
|
V8_INLINE Expression* ExpressionFromString(int pos) {
|
const AstRawString* symbol = GetSymbol();
|
fni_->PushLiteralName(symbol);
|
return factory()->NewStringLiteral(symbol, pos);
|
}
|
|
V8_INLINE ZonePtrList<Expression>* NewExpressionList(int size) const {
|
return new (zone()) ZonePtrList<Expression>(size, zone());
|
}
|
V8_INLINE ZonePtrList<ObjectLiteral::Property>* NewObjectPropertyList(
|
int size) const {
|
return new (zone()) ZonePtrList<ObjectLiteral::Property>(size, zone());
|
}
|
V8_INLINE ZonePtrList<ClassLiteral::Property>* NewClassPropertyList(
|
int size) const {
|
return new (zone()) ZonePtrList<ClassLiteral::Property>(size, zone());
|
}
|
V8_INLINE ZonePtrList<Statement>* NewStatementList(int size) const {
|
return new (zone()) ZonePtrList<Statement>(size, zone());
|
}
|
|
V8_INLINE Expression* NewV8Intrinsic(const AstRawString* name,
|
ZonePtrList<Expression>* args, int pos,
|
bool* ok);
|
|
V8_INLINE Statement* NewThrowStatement(Expression* exception, int pos) {
|
return factory()->NewExpressionStatement(
|
factory()->NewThrow(exception, pos), pos);
|
}
|
|
V8_INLINE void AddParameterInitializationBlock(
|
const ParserFormalParameters& parameters, ZonePtrList<Statement>* body,
|
bool is_async, bool* ok) {
|
if (parameters.is_simple) return;
|
auto* init_block = BuildParameterInitializationBlock(parameters, ok);
|
if (!*ok) return;
|
if (is_async) {
|
init_block = BuildRejectPromiseOnException(init_block);
|
}
|
body->Add(init_block, zone());
|
}
|
|
V8_INLINE void AddFormalParameter(ParserFormalParameters* parameters,
|
Expression* pattern,
|
Expression* initializer,
|
int initializer_end_position,
|
bool is_rest) {
|
parameters->UpdateArityAndFunctionLength(initializer != nullptr, is_rest);
|
bool has_simple_name = pattern->IsVariableProxy() && initializer == nullptr;
|
const AstRawString* name = has_simple_name
|
? pattern->AsVariableProxy()->raw_name()
|
: ast_value_factory()->empty_string();
|
auto parameter = new (parameters->scope->zone())
|
ParserFormalParameters::Parameter(name, pattern, initializer,
|
scanner()->location().beg_pos,
|
initializer_end_position, is_rest);
|
|
parameters->params.Add(parameter);
|
}
|
|
V8_INLINE void DeclareFormalParameters(
|
DeclarationScope* scope,
|
const ThreadedList<ParserFormalParameters::Parameter>& parameters,
|
bool is_simple, bool* has_duplicate = nullptr) {
|
if (!is_simple) scope->SetHasNonSimpleParameters();
|
for (auto parameter : parameters) {
|
bool is_optional = parameter->initializer != nullptr;
|
// If the parameter list is simple, declare the parameters normally with
|
// their names. If the parameter list is not simple, declare a temporary
|
// for each parameter - the corresponding named variable is declared by
|
// BuildParamerterInitializationBlock.
|
scope->DeclareParameter(
|
is_simple ? parameter->name : ast_value_factory()->empty_string(),
|
is_simple ? VariableMode::kVar : VariableMode::kTemporary,
|
is_optional, parameter->is_rest, has_duplicate, ast_value_factory(),
|
parameter->position);
|
}
|
}
|
|
void DeclareArrowFunctionFormalParameters(ParserFormalParameters* parameters,
|
Expression* params,
|
const Scanner::Location& params_loc,
|
Scanner::Location* duplicate_loc,
|
bool* ok);
|
|
Expression* ExpressionListToExpression(ZonePtrList<Expression>* args);
|
|
void SetFunctionNameFromPropertyName(LiteralProperty* property,
|
const AstRawString* name,
|
const AstRawString* prefix = nullptr);
|
void SetFunctionNameFromPropertyName(ObjectLiteralProperty* property,
|
const AstRawString* name,
|
const AstRawString* prefix = nullptr);
|
|
void SetFunctionNameFromIdentifierRef(Expression* value,
|
Expression* identifier);
|
|
V8_INLINE ZoneVector<typename ExpressionClassifier::Error>*
|
GetReportedErrorList() const {
|
return function_state_->GetReportedErrorList();
|
}
|
|
V8_INLINE void CountUsage(v8::Isolate::UseCounterFeature feature) {
|
++use_counts_[feature];
|
}
|
|
// Returns true iff we're parsing the first function literal during
|
// CreateDynamicFunction().
|
V8_INLINE bool ParsingDynamicFunctionDeclaration() const {
|
return parameters_end_pos_ != kNoSourcePosition;
|
}
|
|
V8_INLINE void ConvertBinaryToNaryOperationSourceRange(
|
BinaryOperation* binary_op, NaryOperation* nary_op) {
|
if (source_range_map_ == nullptr) return;
|
DCHECK_NULL(source_range_map_->Find(nary_op));
|
|
BinaryOperationSourceRanges* ranges =
|
static_cast<BinaryOperationSourceRanges*>(
|
source_range_map_->Find(binary_op));
|
if (ranges == nullptr) return;
|
|
SourceRange range = ranges->GetRange(SourceRangeKind::kRight);
|
source_range_map_->Insert(
|
nary_op, new (zone()) NaryOperationSourceRanges(zone(), range));
|
}
|
|
V8_INLINE void AppendNaryOperationSourceRange(NaryOperation* node,
|
const SourceRange& range) {
|
if (source_range_map_ == nullptr) return;
|
NaryOperationSourceRanges* ranges =
|
static_cast<NaryOperationSourceRanges*>(source_range_map_->Find(node));
|
if (ranges == nullptr) return;
|
|
ranges->AddRange(range);
|
DCHECK_EQ(node->subsequent_length(), ranges->RangeCount());
|
}
|
|
V8_INLINE void RecordBlockSourceRange(Block* node,
|
int32_t continuation_position) {
|
if (source_range_map_ == nullptr) return;
|
source_range_map_->Insert(
|
node, new (zone()) BlockSourceRanges(continuation_position));
|
}
|
|
V8_INLINE void RecordCaseClauseSourceRange(CaseClause* node,
|
const SourceRange& body_range) {
|
if (source_range_map_ == nullptr) return;
|
source_range_map_->Insert(node,
|
new (zone()) CaseClauseSourceRanges(body_range));
|
}
|
|
V8_INLINE void RecordConditionalSourceRange(Expression* node,
|
const SourceRange& then_range,
|
const SourceRange& else_range) {
|
if (source_range_map_ == nullptr) return;
|
source_range_map_->Insert(
|
node->AsConditional(),
|
new (zone()) ConditionalSourceRanges(then_range, else_range));
|
}
|
|
V8_INLINE void RecordBinaryOperationSourceRange(
|
Expression* node, const SourceRange& right_range) {
|
if (source_range_map_ == nullptr) return;
|
source_range_map_->Insert(node->AsBinaryOperation(),
|
new (zone())
|
BinaryOperationSourceRanges(right_range));
|
}
|
|
V8_INLINE void RecordJumpStatementSourceRange(Statement* node,
|
int32_t continuation_position) {
|
if (source_range_map_ == nullptr) return;
|
source_range_map_->Insert(
|
static_cast<JumpStatement*>(node),
|
new (zone()) JumpStatementSourceRanges(continuation_position));
|
}
|
|
V8_INLINE void RecordIfStatementSourceRange(Statement* node,
|
const SourceRange& then_range,
|
const SourceRange& else_range) {
|
if (source_range_map_ == nullptr) return;
|
source_range_map_->Insert(
|
node->AsIfStatement(),
|
new (zone()) IfStatementSourceRanges(then_range, else_range));
|
}
|
|
V8_INLINE void RecordIterationStatementSourceRange(
|
IterationStatement* node, const SourceRange& body_range) {
|
if (source_range_map_ == nullptr) return;
|
source_range_map_->Insert(
|
node, new (zone()) IterationStatementSourceRanges(body_range));
|
}
|
|
V8_INLINE void RecordSuspendSourceRange(Expression* node,
|
int32_t continuation_position) {
|
if (source_range_map_ == nullptr) return;
|
source_range_map_->Insert(static_cast<Suspend*>(node),
|
new (zone())
|
SuspendSourceRanges(continuation_position));
|
}
|
|
V8_INLINE void RecordSwitchStatementSourceRange(
|
Statement* node, int32_t continuation_position) {
|
if (source_range_map_ == nullptr) return;
|
source_range_map_->Insert(
|
node->AsSwitchStatement(),
|
new (zone()) SwitchStatementSourceRanges(continuation_position));
|
}
|
|
V8_INLINE void RecordThrowSourceRange(Statement* node,
|
int32_t continuation_position) {
|
if (source_range_map_ == nullptr) return;
|
ExpressionStatement* expr_stmt = static_cast<ExpressionStatement*>(node);
|
Throw* throw_expr = expr_stmt->expression()->AsThrow();
|
source_range_map_->Insert(
|
throw_expr, new (zone()) ThrowSourceRanges(continuation_position));
|
}
|
|
V8_INLINE void RecordTryCatchStatementSourceRange(
|
TryCatchStatement* node, const SourceRange& body_range) {
|
if (source_range_map_ == nullptr) return;
|
source_range_map_->Insert(
|
node, new (zone()) TryCatchStatementSourceRanges(body_range));
|
}
|
|
V8_INLINE void RecordTryFinallyStatementSourceRange(
|
TryFinallyStatement* node, const SourceRange& body_range) {
|
if (source_range_map_ == nullptr) return;
|
source_range_map_->Insert(
|
node, new (zone()) TryFinallyStatementSourceRanges(body_range));
|
}
|
|
// Parser's private field members.
|
friend class DiscardableZoneScope; // Uses reusable_preparser_.
|
// FIXME(marja): Make reusable_preparser_ always use its own temp Zone (call
|
// DeleteAll after each function), so this won't be needed.
|
|
Scanner scanner_;
|
PreParser* reusable_preparser_;
|
Mode mode_;
|
|
SourceRangeMap* source_range_map_ = nullptr;
|
|
friend class ParserTarget;
|
friend class ParserTargetScope;
|
ParserTarget* target_stack_; // for break, continue statements
|
|
ScriptCompiler::CompileOptions compile_options_;
|
|
// Other information which will be stored in Parser and moved to Isolate after
|
// parsing.
|
int use_counts_[v8::Isolate::kUseCounterFeatureCount];
|
int total_preparse_skipped_;
|
bool allow_lazy_;
|
bool temp_zoned_;
|
ConsumedPreParsedScopeData* consumed_preparsed_scope_data_;
|
|
// If not kNoSourcePosition, indicates that the first function literal
|
// encountered is a dynamic function, see CreateDynamicFunction(). This field
|
// indicates the correct position of the ')' that closes the parameter list.
|
// After that ')' is encountered, this field is reset to kNoSourcePosition.
|
int parameters_end_pos_;
|
};
|
|
// ----------------------------------------------------------------------------
|
// Target is a support class to facilitate manipulation of the
|
// Parser's target_stack_ (the stack of potential 'break' and
|
// 'continue' statement targets). Upon construction, a new target is
|
// added; it is removed upon destruction.
|
|
class ParserTarget BASE_EMBEDDED {
|
public:
|
ParserTarget(ParserBase<Parser>* parser, BreakableStatement* statement)
|
: variable_(&parser->impl()->target_stack_),
|
statement_(statement),
|
previous_(parser->impl()->target_stack_) {
|
parser->impl()->target_stack_ = this;
|
}
|
|
~ParserTarget() { *variable_ = previous_; }
|
|
ParserTarget* previous() { return previous_; }
|
BreakableStatement* statement() { return statement_; }
|
|
private:
|
ParserTarget** variable_;
|
BreakableStatement* statement_;
|
ParserTarget* previous_;
|
};
|
|
class ParserTargetScope BASE_EMBEDDED {
|
public:
|
explicit ParserTargetScope(ParserBase<Parser>* parser)
|
: variable_(&parser->impl()->target_stack_),
|
previous_(parser->impl()->target_stack_) {
|
parser->impl()->target_stack_ = nullptr;
|
}
|
|
~ParserTargetScope() { *variable_ = previous_; }
|
|
private:
|
ParserTarget** variable_;
|
ParserTarget* previous_;
|
};
|
|
} // namespace internal
|
} // namespace v8
|
|
#endif // V8_PARSING_PARSER_H_
|