[esnext] implement frontend changes for async/await proposal
BUG=v8:4483 LOG=Y R=littledan@chromium.org, adamk@chromium.org Review-Url: https://codereview.chromium.org/1841543003 Cr-Commit-Position: refs/heads/master@{#36261}
This commit is contained in:
parent
9c6ff18355
commit
0d43421a22
@ -242,6 +242,8 @@ class AstValue : public ZoneObject {
|
|||||||
#define STRING_CONSTANTS(F) \
|
#define STRING_CONSTANTS(F) \
|
||||||
F(anonymous_function, "(anonymous function)") \
|
F(anonymous_function, "(anonymous function)") \
|
||||||
F(arguments, "arguments") \
|
F(arguments, "arguments") \
|
||||||
|
F(async, "async") \
|
||||||
|
F(await, "await") \
|
||||||
F(constructor, "constructor") \
|
F(constructor, "constructor") \
|
||||||
F(default, "default") \
|
F(default, "default") \
|
||||||
F(done, "done") \
|
F(done, "done") \
|
||||||
|
@ -2587,12 +2587,12 @@ class FunctionLiteral final : public Expression {
|
|||||||
int start_position() const;
|
int start_position() const;
|
||||||
int end_position() const;
|
int end_position() const;
|
||||||
int SourceSize() const { return end_position() - start_position(); }
|
int SourceSize() const { return end_position() - start_position(); }
|
||||||
bool is_declaration() const { return IsDeclaration::decode(bitfield_); }
|
bool is_declaration() const { return function_type() == kDeclaration; }
|
||||||
bool is_named_expression() const {
|
bool is_named_expression() const {
|
||||||
return IsNamedExpression::decode(bitfield_);
|
return function_type() == kNamedExpression;
|
||||||
}
|
}
|
||||||
bool is_anonymous_expression() const {
|
bool is_anonymous_expression() const {
|
||||||
return IsAnonymousExpression::decode(bitfield_);
|
return function_type() == kAnonymousExpression;
|
||||||
}
|
}
|
||||||
LanguageMode language_mode() const;
|
LanguageMode language_mode() const;
|
||||||
|
|
||||||
@ -2669,6 +2669,9 @@ class FunctionLiteral final : public Expression {
|
|||||||
bitfield_ = ShouldBeUsedOnceHint::update(bitfield_, true);
|
bitfield_ = ShouldBeUsedOnceHint::update(bitfield_, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FunctionType function_type() const {
|
||||||
|
return FunctionTypeBits::decode(bitfield_);
|
||||||
|
}
|
||||||
FunctionKind kind() const { return FunctionKindBits::decode(bitfield_); }
|
FunctionKind kind() const { return FunctionKindBits::decode(bitfield_); }
|
||||||
|
|
||||||
int ast_node_count() { return ast_properties_.node_count(); }
|
int ast_node_count() { return ast_properties_.node_count(); }
|
||||||
@ -2714,10 +2717,7 @@ class FunctionLiteral final : public Expression {
|
|||||||
function_token_position_(RelocInfo::kNoPosition),
|
function_token_position_(RelocInfo::kNoPosition),
|
||||||
yield_count_(0) {
|
yield_count_(0) {
|
||||||
bitfield_ =
|
bitfield_ =
|
||||||
IsDeclaration::encode(function_type == kDeclaration) |
|
FunctionTypeBits::encode(function_type) | Pretenure::encode(false) |
|
||||||
IsNamedExpression::encode(function_type == kNamedExpression) |
|
|
||||||
IsAnonymousExpression::encode(function_type == kAnonymousExpression) |
|
|
||||||
Pretenure::encode(false) |
|
|
||||||
HasDuplicateParameters::encode(has_duplicate_parameters ==
|
HasDuplicateParameters::encode(has_duplicate_parameters ==
|
||||||
kHasDuplicateParameters) |
|
kHasDuplicateParameters) |
|
||||||
IsFunction::encode(is_function) |
|
IsFunction::encode(is_function) |
|
||||||
@ -2727,15 +2727,13 @@ class FunctionLiteral final : public Expression {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class IsDeclaration : public BitField16<bool, 0, 1> {};
|
class FunctionTypeBits : public BitField16<FunctionType, 0, 2> {};
|
||||||
class IsNamedExpression : public BitField16<bool, 1, 1> {};
|
class Pretenure : public BitField16<bool, 2, 1> {};
|
||||||
class IsAnonymousExpression : public BitField16<bool, 2, 1> {};
|
class HasDuplicateParameters : public BitField16<bool, 3, 1> {};
|
||||||
class Pretenure : public BitField16<bool, 3, 1> {};
|
class IsFunction : public BitField16<bool, 4, 1> {};
|
||||||
class HasDuplicateParameters : public BitField16<bool, 4, 1> {};
|
class ShouldEagerCompile : public BitField16<bool, 5, 1> {};
|
||||||
class IsFunction : public BitField16<bool, 5, 1> {};
|
class ShouldBeUsedOnceHint : public BitField16<bool, 6, 1> {};
|
||||||
class ShouldEagerCompile : public BitField16<bool, 6, 1> {};
|
class FunctionKindBits : public BitField16<FunctionKind, 7, 9> {};
|
||||||
class ShouldBeUsedOnceHint : public BitField16<bool, 7, 1> {};
|
|
||||||
class FunctionKindBits : public BitField16<FunctionKind, 8, 8> {};
|
|
||||||
|
|
||||||
// Start with 16-bit field, which should get packed together
|
// Start with 16-bit field, which should get packed together
|
||||||
// with Expression's trailing 16-bit field.
|
// with Expression's trailing 16-bit field.
|
||||||
|
@ -2457,6 +2457,7 @@ EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_string_padding)
|
|||||||
#ifdef V8_I18N_SUPPORT
|
#ifdef V8_I18N_SUPPORT
|
||||||
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(icu_case_mapping)
|
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(icu_case_mapping)
|
||||||
#endif
|
#endif
|
||||||
|
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_async_await)
|
||||||
|
|
||||||
void InstallPublicSymbol(Factory* factory, Handle<Context> native_context,
|
void InstallPublicSymbol(Factory* factory, Handle<Context> native_context,
|
||||||
const char* name, Handle<Symbol> value) {
|
const char* name, Handle<Symbol> value) {
|
||||||
@ -3030,6 +3031,7 @@ bool Genesis::InstallExperimentalNatives() {
|
|||||||
static const char* icu_case_mapping_natives[] = {"native icu-case-mapping.js",
|
static const char* icu_case_mapping_natives[] = {"native icu-case-mapping.js",
|
||||||
nullptr};
|
nullptr};
|
||||||
#endif
|
#endif
|
||||||
|
static const char* harmony_async_await_natives[] = {nullptr};
|
||||||
|
|
||||||
for (int i = ExperimentalNatives::GetDebuggerCount();
|
for (int i = ExperimentalNatives::GetDebuggerCount();
|
||||||
i < ExperimentalNatives::GetBuiltinsCount(); i++) {
|
i < ExperimentalNatives::GetBuiltinsCount(); i++) {
|
||||||
|
@ -204,14 +204,16 @@ DEFINE_IMPLICATION(es_staging, move_object_start)
|
|||||||
V(harmony_simd, "harmony simd") \
|
V(harmony_simd, "harmony simd") \
|
||||||
V(harmony_do_expressions, "harmony do-expressions") \
|
V(harmony_do_expressions, "harmony do-expressions") \
|
||||||
V(harmony_regexp_property, "harmony unicode regexp property classes") \
|
V(harmony_regexp_property, "harmony unicode regexp property classes") \
|
||||||
V(icu_case_mapping, "case mapping with ICU rather than Unibrow")
|
V(icu_case_mapping, "case mapping with ICU rather than Unibrow") \
|
||||||
|
V(harmony_async_await, "harmony async-await")
|
||||||
#else
|
#else
|
||||||
#define HARMONY_INPROGRESS(V) \
|
#define HARMONY_INPROGRESS(V) \
|
||||||
V(harmony_function_sent, "harmony function.sent") \
|
V(harmony_function_sent, "harmony function.sent") \
|
||||||
V(harmony_sharedarraybuffer, "harmony sharedarraybuffer") \
|
V(harmony_sharedarraybuffer, "harmony sharedarraybuffer") \
|
||||||
V(harmony_simd, "harmony simd") \
|
V(harmony_simd, "harmony simd") \
|
||||||
V(harmony_do_expressions, "harmony do-expressions") \
|
V(harmony_do_expressions, "harmony do-expressions") \
|
||||||
V(harmony_regexp_property, "harmony unicode regexp property classes")
|
V(harmony_regexp_property, "harmony unicode regexp property classes") \
|
||||||
|
V(harmony_async_await, "harmony async-await")
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Features that are complete (but still behind --harmony/es-staging flag).
|
// Features that are complete (but still behind --harmony/es-staging flag).
|
||||||
|
@ -963,11 +963,14 @@ enum FunctionKind {
|
|||||||
kBaseConstructor = 1 << 5,
|
kBaseConstructor = 1 << 5,
|
||||||
kGetterFunction = 1 << 6,
|
kGetterFunction = 1 << 6,
|
||||||
kSetterFunction = 1 << 7,
|
kSetterFunction = 1 << 7,
|
||||||
|
kAsyncFunction = 1 << 8,
|
||||||
kAccessorFunction = kGetterFunction | kSetterFunction,
|
kAccessorFunction = kGetterFunction | kSetterFunction,
|
||||||
kDefaultBaseConstructor = kDefaultConstructor | kBaseConstructor,
|
kDefaultBaseConstructor = kDefaultConstructor | kBaseConstructor,
|
||||||
kDefaultSubclassConstructor = kDefaultConstructor | kSubclassConstructor,
|
kDefaultSubclassConstructor = kDefaultConstructor | kSubclassConstructor,
|
||||||
kClassConstructor =
|
kClassConstructor =
|
||||||
kBaseConstructor | kSubclassConstructor | kDefaultConstructor,
|
kBaseConstructor | kSubclassConstructor | kDefaultConstructor,
|
||||||
|
kAsyncArrowFunction = kArrowFunction | kAsyncFunction,
|
||||||
|
kAsyncConciseMethod = kAsyncFunction | kConciseMethod
|
||||||
};
|
};
|
||||||
|
|
||||||
inline bool IsValidFunctionKind(FunctionKind kind) {
|
inline bool IsValidFunctionKind(FunctionKind kind) {
|
||||||
@ -982,7 +985,10 @@ inline bool IsValidFunctionKind(FunctionKind kind) {
|
|||||||
kind == FunctionKind::kDefaultBaseConstructor ||
|
kind == FunctionKind::kDefaultBaseConstructor ||
|
||||||
kind == FunctionKind::kDefaultSubclassConstructor ||
|
kind == FunctionKind::kDefaultSubclassConstructor ||
|
||||||
kind == FunctionKind::kBaseConstructor ||
|
kind == FunctionKind::kBaseConstructor ||
|
||||||
kind == FunctionKind::kSubclassConstructor;
|
kind == FunctionKind::kSubclassConstructor ||
|
||||||
|
kind == FunctionKind::kAsyncFunction ||
|
||||||
|
kind == FunctionKind::kAsyncArrowFunction ||
|
||||||
|
kind == FunctionKind::kAsyncConciseMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -997,6 +1003,10 @@ inline bool IsGeneratorFunction(FunctionKind kind) {
|
|||||||
return kind & FunctionKind::kGeneratorFunction;
|
return kind & FunctionKind::kGeneratorFunction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool IsAsyncFunction(FunctionKind kind) {
|
||||||
|
DCHECK(IsValidFunctionKind(kind));
|
||||||
|
return kind & FunctionKind::kAsyncFunction;
|
||||||
|
}
|
||||||
|
|
||||||
inline bool IsConciseMethod(FunctionKind kind) {
|
inline bool IsConciseMethod(FunctionKind kind) {
|
||||||
DCHECK(IsValidFunctionKind(kind));
|
DCHECK(IsValidFunctionKind(kind));
|
||||||
|
@ -358,6 +358,7 @@ class CallSite {
|
|||||||
T(BadSetterArity, "Setter must have exactly one formal parameter.") \
|
T(BadSetterArity, "Setter must have exactly one formal parameter.") \
|
||||||
T(ConstructorIsAccessor, "Class constructor may not be an accessor") \
|
T(ConstructorIsAccessor, "Class constructor may not be an accessor") \
|
||||||
T(ConstructorIsGenerator, "Class constructor may not be a generator") \
|
T(ConstructorIsGenerator, "Class constructor may not be a generator") \
|
||||||
|
T(ConstructorIsAsync, "Class constructor may not be an async method") \
|
||||||
T(DerivedConstructorReturn, \
|
T(DerivedConstructorReturn, \
|
||||||
"Derived constructors may only return object or undefined") \
|
"Derived constructors may only return object or undefined") \
|
||||||
T(DuplicateConstructor, "A class may only have one constructor") \
|
T(DuplicateConstructor, "A class may only have one constructor") \
|
||||||
@ -432,6 +433,10 @@ class CallSite {
|
|||||||
T(TemplateOctalLiteral, \
|
T(TemplateOctalLiteral, \
|
||||||
"Octal literals are not allowed in template strings.") \
|
"Octal literals are not allowed in template strings.") \
|
||||||
T(ThisFormalParameter, "'this' is not a valid formal parameter name") \
|
T(ThisFormalParameter, "'this' is not a valid formal parameter name") \
|
||||||
|
T(AwaitBindingIdentifier, \
|
||||||
|
"'await' is not a valid identifier name in an async function") \
|
||||||
|
T(AwaitExpressionFormalParameter, \
|
||||||
|
"Illegal await-expression in formal parameters of async function") \
|
||||||
T(TooManyArguments, \
|
T(TooManyArguments, \
|
||||||
"Too many arguments in function call (only 65535 allowed)") \
|
"Too many arguments in function call (only 65535 allowed)") \
|
||||||
T(TooManyParameters, \
|
T(TooManyParameters, \
|
||||||
|
@ -5786,6 +5786,7 @@ BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, dont_crankshaft,
|
|||||||
BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, dont_flush, kDontFlush)
|
BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, dont_flush, kDontFlush)
|
||||||
BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, is_arrow, kIsArrow)
|
BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, is_arrow, kIsArrow)
|
||||||
BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, is_generator, kIsGenerator)
|
BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, is_generator, kIsGenerator)
|
||||||
|
BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, is_async, kIsAsyncFunction)
|
||||||
BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, is_concise_method,
|
BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, is_concise_method,
|
||||||
kIsConciseMethod)
|
kIsConciseMethod)
|
||||||
BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, is_getter_function,
|
BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, is_getter_function,
|
||||||
@ -5795,6 +5796,10 @@ BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, is_setter_function,
|
|||||||
BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, is_default_constructor,
|
BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, is_default_constructor,
|
||||||
kIsDefaultConstructor)
|
kIsDefaultConstructor)
|
||||||
|
|
||||||
|
inline bool SharedFunctionInfo::is_resumable() const {
|
||||||
|
return is_generator() || is_async();
|
||||||
|
}
|
||||||
|
|
||||||
bool Script::HasValidSource() {
|
bool Script::HasValidSource() {
|
||||||
Object* src = this->source();
|
Object* src = this->source();
|
||||||
if (!src->IsString()) return true;
|
if (!src->IsString()) return true;
|
||||||
|
@ -4295,7 +4295,7 @@ class ScopeInfo : public FixedArray {
|
|||||||
class HasSimpleParametersField
|
class HasSimpleParametersField
|
||||||
: public BitField<bool, AsmFunctionField::kNext, 1> {};
|
: public BitField<bool, AsmFunctionField::kNext, 1> {};
|
||||||
class FunctionKindField
|
class FunctionKindField
|
||||||
: public BitField<FunctionKind, HasSimpleParametersField::kNext, 8> {};
|
: public BitField<FunctionKind, HasSimpleParametersField::kNext, 9> {};
|
||||||
|
|
||||||
// BitFields representing the encoded information for context locals in the
|
// BitFields representing the encoded information for context locals in the
|
||||||
// ContextLocalInfoEntries part.
|
// ContextLocalInfoEntries part.
|
||||||
@ -6853,6 +6853,13 @@ class SharedFunctionInfo: public HeapObject {
|
|||||||
// Indicates that this function is a generator.
|
// Indicates that this function is a generator.
|
||||||
DECL_BOOLEAN_ACCESSORS(is_generator)
|
DECL_BOOLEAN_ACCESSORS(is_generator)
|
||||||
|
|
||||||
|
// Indicates that this function is an async function.
|
||||||
|
DECL_BOOLEAN_ACCESSORS(is_async)
|
||||||
|
|
||||||
|
// Indicates that this function can be suspended, either via YieldExpressions
|
||||||
|
// or AwaitExpressions.
|
||||||
|
inline bool is_resumable() const;
|
||||||
|
|
||||||
// Indicates that this function is an arrow function.
|
// Indicates that this function is an arrow function.
|
||||||
DECL_BOOLEAN_ACCESSORS(is_arrow)
|
DECL_BOOLEAN_ACCESSORS(is_arrow)
|
||||||
|
|
||||||
@ -7149,6 +7156,7 @@ class SharedFunctionInfo: public HeapObject {
|
|||||||
kIsGetterFunction,
|
kIsGetterFunction,
|
||||||
kIsSetterFunction,
|
kIsSetterFunction,
|
||||||
// byte 3
|
// byte 3
|
||||||
|
kIsAsyncFunction,
|
||||||
kDeserialized,
|
kDeserialized,
|
||||||
kIsDeclaration,
|
kIsDeclaration,
|
||||||
kCompilerHintsCount, // Pseudo entry
|
kCompilerHintsCount, // Pseudo entry
|
||||||
@ -7171,7 +7179,7 @@ class SharedFunctionInfo: public HeapObject {
|
|||||||
ASSERT_FUNCTION_KIND_ORDER(kSetterFunction, kIsSetterFunction);
|
ASSERT_FUNCTION_KIND_ORDER(kSetterFunction, kIsSetterFunction);
|
||||||
#undef ASSERT_FUNCTION_KIND_ORDER
|
#undef ASSERT_FUNCTION_KIND_ORDER
|
||||||
|
|
||||||
class FunctionKindBits : public BitField<FunctionKind, kIsArrow, 8> {};
|
class FunctionKindBits : public BitField<FunctionKind, kIsArrow, 9> {};
|
||||||
|
|
||||||
class DeoptCountBits : public BitField<int, 0, 4> {};
|
class DeoptCountBits : public BitField<int, 0, 4> {};
|
||||||
class OptReenableTriesBits : public BitField<int, 4, 18> {};
|
class OptReenableTriesBits : public BitField<int, 4, 18> {};
|
||||||
|
@ -40,18 +40,22 @@ class ExpressionClassifier {
|
|||||||
LetPatternProduction = 1 << 7,
|
LetPatternProduction = 1 << 7,
|
||||||
CoverInitializedNameProduction = 1 << 8,
|
CoverInitializedNameProduction = 1 << 8,
|
||||||
TailCallExpressionProduction = 1 << 9,
|
TailCallExpressionProduction = 1 << 9,
|
||||||
|
AsyncArrowFormalParametersProduction = 1 << 10,
|
||||||
|
AsyncBindingPatternProduction = 1 << 11,
|
||||||
|
|
||||||
ExpressionProductions =
|
ExpressionProductions =
|
||||||
(ExpressionProduction | FormalParameterInitializerProduction |
|
(ExpressionProduction | FormalParameterInitializerProduction |
|
||||||
TailCallExpressionProduction),
|
TailCallExpressionProduction),
|
||||||
PatternProductions = (BindingPatternProduction |
|
PatternProductions =
|
||||||
AssignmentPatternProduction | LetPatternProduction),
|
(BindingPatternProduction | AssignmentPatternProduction |
|
||||||
|
LetPatternProduction | AsyncBindingPatternProduction),
|
||||||
FormalParametersProductions = (DistinctFormalParametersProduction |
|
FormalParametersProductions = (DistinctFormalParametersProduction |
|
||||||
StrictModeFormalParametersProduction),
|
StrictModeFormalParametersProduction),
|
||||||
StandardProductions = ExpressionProductions | PatternProductions,
|
StandardProductions = ExpressionProductions | PatternProductions,
|
||||||
AllProductions =
|
AllProductions =
|
||||||
(StandardProductions | FormalParametersProductions |
|
(StandardProductions | FormalParametersProductions |
|
||||||
ArrowFormalParametersProduction | CoverInitializedNameProduction)
|
ArrowFormalParametersProduction | CoverInitializedNameProduction |
|
||||||
|
AsyncArrowFormalParametersProduction | AsyncBindingPatternProduction)
|
||||||
};
|
};
|
||||||
|
|
||||||
enum FunctionProperties { NonSimpleParameter = 1 << 0 };
|
enum FunctionProperties { NonSimpleParameter = 1 << 0 };
|
||||||
@ -112,6 +116,14 @@ class ExpressionClassifier {
|
|||||||
|
|
||||||
bool is_valid_let_pattern() const { return is_valid(LetPatternProduction); }
|
bool is_valid_let_pattern() const { return is_valid(LetPatternProduction); }
|
||||||
|
|
||||||
|
bool is_valid_async_arrow_formal_parameters() const {
|
||||||
|
return is_valid(AsyncArrowFormalParametersProduction);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_valid_async_binding_pattern() const {
|
||||||
|
return is_valid(AsyncBindingPatternProduction);
|
||||||
|
}
|
||||||
|
|
||||||
const Error& expression_error() const { return expression_error_; }
|
const Error& expression_error() const { return expression_error_; }
|
||||||
|
|
||||||
const Error& formal_parameter_initializer_error() const {
|
const Error& formal_parameter_initializer_error() const {
|
||||||
@ -151,6 +163,13 @@ class ExpressionClassifier {
|
|||||||
const Error& tail_call_expression_error() const {
|
const Error& tail_call_expression_error() const {
|
||||||
return tail_call_expression_error_;
|
return tail_call_expression_error_;
|
||||||
}
|
}
|
||||||
|
const Error& async_arrow_formal_parameters_error() const {
|
||||||
|
return async_arrow_formal_parameters_error_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Error& async_binding_pattern_error() const {
|
||||||
|
return async_binding_pattern_error_;
|
||||||
|
}
|
||||||
|
|
||||||
bool is_simple_parameter_list() const {
|
bool is_simple_parameter_list() const {
|
||||||
return !(function_properties_ & NonSimpleParameter);
|
return !(function_properties_ & NonSimpleParameter);
|
||||||
@ -228,6 +247,26 @@ class ExpressionClassifier {
|
|||||||
arrow_formal_parameters_error_.arg = arg;
|
arrow_formal_parameters_error_.arg = arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RecordAsyncArrowFormalParametersError(const Scanner::Location& loc,
|
||||||
|
MessageTemplate::Template message,
|
||||||
|
const char* arg = nullptr) {
|
||||||
|
if (!is_valid_async_arrow_formal_parameters()) return;
|
||||||
|
invalid_productions_ |= AsyncArrowFormalParametersProduction;
|
||||||
|
async_arrow_formal_parameters_error_.location = loc;
|
||||||
|
async_arrow_formal_parameters_error_.message = message;
|
||||||
|
async_arrow_formal_parameters_error_.arg = arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RecordAsyncBindingPatternError(const Scanner::Location& loc,
|
||||||
|
MessageTemplate::Template message,
|
||||||
|
const char* arg = nullptr) {
|
||||||
|
if (!is_valid_async_binding_pattern()) return;
|
||||||
|
invalid_productions_ |= AsyncBindingPatternProduction;
|
||||||
|
async_binding_pattern_error_.location = loc;
|
||||||
|
async_binding_pattern_error_.message = message;
|
||||||
|
async_binding_pattern_error_.arg = arg;
|
||||||
|
}
|
||||||
|
|
||||||
void RecordDuplicateFormalParameterError(const Scanner::Location& loc) {
|
void RecordDuplicateFormalParameterError(const Scanner::Location& loc) {
|
||||||
if (!is_valid_formal_parameter_list_without_duplicates()) return;
|
if (!is_valid_formal_parameter_list_without_duplicates()) return;
|
||||||
invalid_productions_ |= DistinctFormalParametersProduction;
|
invalid_productions_ |= DistinctFormalParametersProduction;
|
||||||
@ -326,6 +365,11 @@ class ExpressionClassifier {
|
|||||||
cover_initialized_name_error_ = inner->cover_initialized_name_error_;
|
cover_initialized_name_error_ = inner->cover_initialized_name_error_;
|
||||||
if (errors & TailCallExpressionProduction)
|
if (errors & TailCallExpressionProduction)
|
||||||
tail_call_expression_error_ = inner->tail_call_expression_error_;
|
tail_call_expression_error_ = inner->tail_call_expression_error_;
|
||||||
|
if (errors & AsyncArrowFormalParametersProduction)
|
||||||
|
async_arrow_formal_parameters_error_ =
|
||||||
|
inner->async_arrow_formal_parameters_error_;
|
||||||
|
if (errors & AsyncBindingPatternProduction)
|
||||||
|
async_binding_pattern_error_ = inner->async_binding_pattern_error_;
|
||||||
}
|
}
|
||||||
|
|
||||||
// As an exception to the above, the result continues to be a valid arrow
|
// As an exception to the above, the result continues to be a valid arrow
|
||||||
@ -373,6 +417,8 @@ class ExpressionClassifier {
|
|||||||
Error let_pattern_error_;
|
Error let_pattern_error_;
|
||||||
Error cover_initialized_name_error_;
|
Error cover_initialized_name_error_;
|
||||||
Error tail_call_expression_error_;
|
Error tail_call_expression_error_;
|
||||||
|
Error async_arrow_formal_parameters_error_;
|
||||||
|
Error async_binding_pattern_error_;
|
||||||
DuplicateFinder* duplicate_finder_;
|
DuplicateFinder* duplicate_finder_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -29,6 +29,86 @@ enum AllowLabelledFunctionStatement {
|
|||||||
kDisallowLabelledFunctionStatement,
|
kDisallowLabelledFunctionStatement,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class FunctionBody { Normal, SingleExpression };
|
||||||
|
|
||||||
|
enum class ParseFunctionFlags {
|
||||||
|
kIsNormal = 0,
|
||||||
|
kIsGenerator = 1,
|
||||||
|
kIsAsync = 2,
|
||||||
|
kIsDefault = 4
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline ParseFunctionFlags operator|(ParseFunctionFlags lhs,
|
||||||
|
ParseFunctionFlags rhs) {
|
||||||
|
typedef unsigned char T;
|
||||||
|
return static_cast<ParseFunctionFlags>(static_cast<T>(lhs) |
|
||||||
|
static_cast<T>(rhs));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline ParseFunctionFlags& operator|=(ParseFunctionFlags& lhs,
|
||||||
|
const ParseFunctionFlags& rhs) {
|
||||||
|
lhs = lhs | rhs;
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool operator&(ParseFunctionFlags bitfield,
|
||||||
|
ParseFunctionFlags mask) {
|
||||||
|
typedef unsigned char T;
|
||||||
|
return static_cast<T>(bitfield) & static_cast<T>(mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class MethodKind {
|
||||||
|
Normal = 0,
|
||||||
|
Static = 1 << 0,
|
||||||
|
Generator = 1 << 1,
|
||||||
|
StaticGenerator = Static | Generator,
|
||||||
|
Async = 1 << 2,
|
||||||
|
StaticAsync = Static | Async,
|
||||||
|
|
||||||
|
/* Any non-ordinary method kinds */
|
||||||
|
SpecialMask = Generator | Async
|
||||||
|
};
|
||||||
|
|
||||||
|
inline bool IsValidMethodKind(MethodKind kind) {
|
||||||
|
return kind == MethodKind::Normal || kind == MethodKind::Static ||
|
||||||
|
kind == MethodKind::Generator || kind == MethodKind::StaticGenerator ||
|
||||||
|
kind == MethodKind::Async || kind == MethodKind::StaticAsync;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline MethodKind operator|(MethodKind lhs, MethodKind rhs) {
|
||||||
|
typedef unsigned char T;
|
||||||
|
return static_cast<MethodKind>(static_cast<T>(lhs) | static_cast<T>(rhs));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline MethodKind& operator|=(MethodKind& lhs, const MethodKind& rhs) {
|
||||||
|
lhs = lhs | rhs;
|
||||||
|
DCHECK(IsValidMethodKind(lhs));
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool operator&(MethodKind bitfield, MethodKind mask) {
|
||||||
|
typedef unsigned char T;
|
||||||
|
return static_cast<T>(bitfield) & static_cast<T>(mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool IsNormalMethod(MethodKind kind) {
|
||||||
|
return kind == MethodKind::Normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool IsSpecialMethod(MethodKind kind) {
|
||||||
|
return kind & MethodKind::SpecialMask;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool IsStaticMethod(MethodKind kind) {
|
||||||
|
return kind & MethodKind::Static;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool IsGeneratorMethod(MethodKind kind) {
|
||||||
|
return kind & MethodKind::Generator;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool IsAsyncMethod(MethodKind kind) { return kind & MethodKind::Async; }
|
||||||
|
|
||||||
struct FormalParametersBase {
|
struct FormalParametersBase {
|
||||||
explicit FormalParametersBase(Scope* scope) : scope(scope) {}
|
explicit FormalParametersBase(Scope* scope) : scope(scope) {}
|
||||||
Scope* scope;
|
Scope* scope;
|
||||||
@ -117,7 +197,8 @@ class ParserBase : public Traits {
|
|||||||
allow_harmony_do_expressions_(false),
|
allow_harmony_do_expressions_(false),
|
||||||
allow_harmony_for_in_(false),
|
allow_harmony_for_in_(false),
|
||||||
allow_harmony_function_name_(false),
|
allow_harmony_function_name_(false),
|
||||||
allow_harmony_function_sent_(false) {}
|
allow_harmony_function_sent_(false),
|
||||||
|
allow_harmony_async_await_(false) {}
|
||||||
|
|
||||||
#define ALLOW_ACCESSORS(name) \
|
#define ALLOW_ACCESSORS(name) \
|
||||||
bool allow_##name() const { return allow_##name##_; } \
|
bool allow_##name() const { return allow_##name##_; } \
|
||||||
@ -137,6 +218,7 @@ class ParserBase : public Traits {
|
|||||||
ALLOW_ACCESSORS(harmony_for_in);
|
ALLOW_ACCESSORS(harmony_for_in);
|
||||||
ALLOW_ACCESSORS(harmony_function_name);
|
ALLOW_ACCESSORS(harmony_function_name);
|
||||||
ALLOW_ACCESSORS(harmony_function_sent);
|
ALLOW_ACCESSORS(harmony_function_sent);
|
||||||
|
ALLOW_ACCESSORS(harmony_async_await);
|
||||||
SCANNER_ACCESSORS(harmony_exponentiation_operator);
|
SCANNER_ACCESSORS(harmony_exponentiation_operator);
|
||||||
|
|
||||||
#undef SCANNER_ACCESSORS
|
#undef SCANNER_ACCESSORS
|
||||||
@ -284,6 +366,8 @@ class ParserBase : public Traits {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool is_generator() const { return IsGeneratorFunction(kind_); }
|
bool is_generator() const { return IsGeneratorFunction(kind_); }
|
||||||
|
bool is_async_function() const { return IsAsyncFunction(kind_); }
|
||||||
|
bool is_resumable() const { return is_generator() || is_async_function(); }
|
||||||
|
|
||||||
FunctionKind kind() const { return kind_; }
|
FunctionKind kind() const { return kind_; }
|
||||||
FunctionState* outer() const { return outer_function_state_; }
|
FunctionState* outer() const { return outer_function_state_; }
|
||||||
@ -291,7 +375,7 @@ class ParserBase : public Traits {
|
|||||||
void set_generator_object_variable(
|
void set_generator_object_variable(
|
||||||
typename Traits::Type::GeneratorVariable* variable) {
|
typename Traits::Type::GeneratorVariable* variable) {
|
||||||
DCHECK(variable != NULL);
|
DCHECK(variable != NULL);
|
||||||
DCHECK(is_generator());
|
DCHECK(is_resumable());
|
||||||
generator_object_variable_ = variable;
|
generator_object_variable_ = variable;
|
||||||
}
|
}
|
||||||
typename Traits::Type::GeneratorVariable* generator_object_variable()
|
typename Traits::Type::GeneratorVariable* generator_object_variable()
|
||||||
@ -576,9 +660,10 @@ class ParserBase : public Traits {
|
|||||||
|
|
||||||
bool peek_any_identifier() {
|
bool peek_any_identifier() {
|
||||||
Token::Value next = peek();
|
Token::Value next = peek();
|
||||||
return next == Token::IDENTIFIER || next == Token::AWAIT ||
|
return next == Token::IDENTIFIER || next == Token::ENUM ||
|
||||||
next == Token::ENUM || next == Token::FUTURE_STRICT_RESERVED_WORD ||
|
next == Token::AWAIT || next == Token::ASYNC ||
|
||||||
next == Token::LET || next == Token::STATIC || next == Token::YIELD;
|
next == Token::FUTURE_STRICT_RESERVED_WORD || next == Token::LET ||
|
||||||
|
next == Token::STATIC || next == Token::YIELD;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CheckContextualKeyword(Vector<const char> keyword) {
|
bool CheckContextualKeyword(Vector<const char> keyword) {
|
||||||
@ -684,6 +769,10 @@ class ParserBase : public Traits {
|
|||||||
|
|
||||||
LanguageMode language_mode() { return scope_->language_mode(); }
|
LanguageMode language_mode() { return scope_->language_mode(); }
|
||||||
bool is_generator() const { return function_state_->is_generator(); }
|
bool is_generator() const { return function_state_->is_generator(); }
|
||||||
|
bool is_async_function() const {
|
||||||
|
return function_state_->is_async_function();
|
||||||
|
}
|
||||||
|
bool is_resumable() const { return function_state_->is_resumable(); }
|
||||||
|
|
||||||
// Report syntax errors.
|
// Report syntax errors.
|
||||||
void ReportMessage(MessageTemplate::Template message, const char* arg = NULL,
|
void ReportMessage(MessageTemplate::Template message, const char* arg = NULL,
|
||||||
@ -740,8 +829,16 @@ class ParserBase : public Traits {
|
|||||||
|
|
||||||
void ValidateBindingPattern(const ExpressionClassifier* classifier,
|
void ValidateBindingPattern(const ExpressionClassifier* classifier,
|
||||||
bool* ok) {
|
bool* ok) {
|
||||||
if (!classifier->is_valid_binding_pattern()) {
|
if (!classifier->is_valid_binding_pattern() ||
|
||||||
ReportClassifierError(classifier->binding_pattern_error());
|
!classifier->is_valid_async_binding_pattern()) {
|
||||||
|
const Scanner::Location& a = classifier->binding_pattern_error().location;
|
||||||
|
const Scanner::Location& b =
|
||||||
|
classifier->async_binding_pattern_error().location;
|
||||||
|
if (a.beg_pos < 0 || (b.beg_pos >= 0 && a.beg_pos > b.beg_pos)) {
|
||||||
|
ReportClassifierError(classifier->async_binding_pattern_error());
|
||||||
|
} else {
|
||||||
|
ReportClassifierError(classifier->binding_pattern_error());
|
||||||
|
}
|
||||||
*ok = false;
|
*ok = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -770,7 +867,8 @@ class ParserBase : public Traits {
|
|||||||
|
|
||||||
void ValidateArrowFormalParameters(const ExpressionClassifier* classifier,
|
void ValidateArrowFormalParameters(const ExpressionClassifier* classifier,
|
||||||
ExpressionT expr,
|
ExpressionT expr,
|
||||||
bool parenthesized_formals, bool* ok) {
|
bool parenthesized_formals, bool is_async,
|
||||||
|
bool* ok) {
|
||||||
if (classifier->is_valid_binding_pattern()) {
|
if (classifier->is_valid_binding_pattern()) {
|
||||||
// A simple arrow formal parameter: IDENTIFIER => BODY.
|
// A simple arrow formal parameter: IDENTIFIER => BODY.
|
||||||
if (!this->IsIdentifier(expr)) {
|
if (!this->IsIdentifier(expr)) {
|
||||||
@ -790,6 +888,12 @@ class ParserBase : public Traits {
|
|||||||
ReportClassifierError(error);
|
ReportClassifierError(error);
|
||||||
*ok = false;
|
*ok = false;
|
||||||
}
|
}
|
||||||
|
if (is_async && !classifier->is_valid_async_arrow_formal_parameters()) {
|
||||||
|
const typename ExpressionClassifier::Error& error =
|
||||||
|
classifier->async_arrow_formal_parameters_error();
|
||||||
|
ReportClassifierError(error);
|
||||||
|
*ok = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ValidateLetPattern(const ExpressionClassifier* classifier, bool* ok) {
|
void ValidateLetPattern(const ExpressionClassifier* classifier, bool* ok) {
|
||||||
@ -863,22 +967,32 @@ class ParserBase : public Traits {
|
|||||||
ExpressionClassifier* classifier, bool* ok);
|
ExpressionClassifier* classifier, bool* ok);
|
||||||
|
|
||||||
ExpressionT ParsePrimaryExpression(ExpressionClassifier* classifier,
|
ExpressionT ParsePrimaryExpression(ExpressionClassifier* classifier,
|
||||||
bool* ok);
|
bool* is_async, bool* ok);
|
||||||
|
ExpressionT ParsePrimaryExpression(ExpressionClassifier* classifier,
|
||||||
|
bool* ok) {
|
||||||
|
bool is_async;
|
||||||
|
return ParsePrimaryExpression(classifier, &is_async, ok);
|
||||||
|
}
|
||||||
ExpressionT ParseExpression(bool accept_IN, bool* ok);
|
ExpressionT ParseExpression(bool accept_IN, bool* ok);
|
||||||
ExpressionT ParseExpression(bool accept_IN, ExpressionClassifier* classifier,
|
ExpressionT ParseExpression(bool accept_IN, ExpressionClassifier* classifier,
|
||||||
bool* ok);
|
bool* ok);
|
||||||
ExpressionT ParseArrayLiteral(ExpressionClassifier* classifier, bool* ok);
|
ExpressionT ParseArrayLiteral(ExpressionClassifier* classifier, bool* ok);
|
||||||
ExpressionT ParsePropertyName(IdentifierT* name, bool* is_get, bool* is_set,
|
ExpressionT ParsePropertyName(IdentifierT* name, bool* is_get, bool* is_set,
|
||||||
bool* is_computed_name,
|
bool* is_await, bool* is_computed_name,
|
||||||
ExpressionClassifier* classifier, bool* ok);
|
ExpressionClassifier* classifier, bool* ok);
|
||||||
ExpressionT ParseObjectLiteral(ExpressionClassifier* classifier, bool* ok);
|
ExpressionT ParseObjectLiteral(ExpressionClassifier* classifier, bool* ok);
|
||||||
ObjectLiteralPropertyT ParsePropertyDefinition(
|
ObjectLiteralPropertyT ParsePropertyDefinition(
|
||||||
ObjectLiteralCheckerBase* checker, bool in_class, bool has_extends,
|
ObjectLiteralCheckerBase* checker, bool in_class, bool has_extends,
|
||||||
bool is_static, bool* is_computed_name, bool* has_seen_constructor,
|
MethodKind kind, bool* is_computed_name, bool* has_seen_constructor,
|
||||||
ExpressionClassifier* classifier, IdentifierT* name, bool* ok);
|
ExpressionClassifier* classifier, IdentifierT* name, bool* ok);
|
||||||
|
typename Traits::Type::ExpressionList ParseArguments(
|
||||||
|
Scanner::Location* first_spread_pos, bool maybe_arrow,
|
||||||
|
ExpressionClassifier* classifier, bool* ok);
|
||||||
typename Traits::Type::ExpressionList ParseArguments(
|
typename Traits::Type::ExpressionList ParseArguments(
|
||||||
Scanner::Location* first_spread_pos, ExpressionClassifier* classifier,
|
Scanner::Location* first_spread_pos, ExpressionClassifier* classifier,
|
||||||
bool* ok);
|
bool* ok) {
|
||||||
|
return ParseArguments(first_spread_pos, false, classifier, ok);
|
||||||
|
}
|
||||||
|
|
||||||
ExpressionT ParseAssignmentExpression(bool accept_IN,
|
ExpressionT ParseAssignmentExpression(bool accept_IN,
|
||||||
ExpressionClassifier* classifier,
|
ExpressionClassifier* classifier,
|
||||||
@ -898,12 +1012,15 @@ class ParserBase : public Traits {
|
|||||||
ExpressionT ParseLeftHandSideExpression(ExpressionClassifier* classifier,
|
ExpressionT ParseLeftHandSideExpression(ExpressionClassifier* classifier,
|
||||||
bool* ok);
|
bool* ok);
|
||||||
ExpressionT ParseMemberWithNewPrefixesExpression(
|
ExpressionT ParseMemberWithNewPrefixesExpression(
|
||||||
ExpressionClassifier* classifier, bool* ok);
|
ExpressionClassifier* classifier, bool* is_async, bool* ok);
|
||||||
ExpressionT ParseMemberExpression(ExpressionClassifier* classifier, bool* ok);
|
ExpressionT ParseMemberExpression(ExpressionClassifier* classifier,
|
||||||
|
bool* is_async, bool* ok);
|
||||||
ExpressionT ParseMemberExpressionContinuation(
|
ExpressionT ParseMemberExpressionContinuation(
|
||||||
ExpressionT expression, ExpressionClassifier* classifier, bool* ok);
|
ExpressionT expression, bool* is_async, ExpressionClassifier* classifier,
|
||||||
|
bool* ok);
|
||||||
ExpressionT ParseArrowFunctionLiteral(bool accept_IN,
|
ExpressionT ParseArrowFunctionLiteral(bool accept_IN,
|
||||||
const FormalParametersT& parameters,
|
const FormalParametersT& parameters,
|
||||||
|
bool is_async,
|
||||||
const ExpressionClassifier& classifier,
|
const ExpressionClassifier& classifier,
|
||||||
bool* ok);
|
bool* ok);
|
||||||
ExpressionT ParseTemplateLiteral(ExpressionT tag, int start,
|
ExpressionT ParseTemplateLiteral(ExpressionT tag, int start,
|
||||||
@ -975,7 +1092,7 @@ class ParserBase : public Traits {
|
|||||||
explicit ObjectLiteralCheckerBase(ParserBase* parser) : parser_(parser) {}
|
explicit ObjectLiteralCheckerBase(ParserBase* parser) : parser_(parser) {}
|
||||||
|
|
||||||
virtual void CheckProperty(Token::Value property, PropertyKind type,
|
virtual void CheckProperty(Token::Value property, PropertyKind type,
|
||||||
bool is_static, bool is_generator, bool* ok) = 0;
|
MethodKind method_type, bool* ok) = 0;
|
||||||
|
|
||||||
virtual ~ObjectLiteralCheckerBase() {}
|
virtual ~ObjectLiteralCheckerBase() {}
|
||||||
|
|
||||||
@ -993,8 +1110,8 @@ class ParserBase : public Traits {
|
|||||||
explicit ObjectLiteralChecker(ParserBase* parser)
|
explicit ObjectLiteralChecker(ParserBase* parser)
|
||||||
: ObjectLiteralCheckerBase(parser), has_seen_proto_(false) {}
|
: ObjectLiteralCheckerBase(parser), has_seen_proto_(false) {}
|
||||||
|
|
||||||
void CheckProperty(Token::Value property, PropertyKind type, bool is_static,
|
void CheckProperty(Token::Value property, PropertyKind type,
|
||||||
bool is_generator, bool* ok) override;
|
MethodKind method_type, bool* ok) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool IsProto() { return this->scanner()->LiteralMatches("__proto__", 9); }
|
bool IsProto() { return this->scanner()->LiteralMatches("__proto__", 9); }
|
||||||
@ -1008,8 +1125,8 @@ class ParserBase : public Traits {
|
|||||||
explicit ClassLiteralChecker(ParserBase* parser)
|
explicit ClassLiteralChecker(ParserBase* parser)
|
||||||
: ObjectLiteralCheckerBase(parser), has_seen_constructor_(false) {}
|
: ObjectLiteralCheckerBase(parser), has_seen_constructor_(false) {}
|
||||||
|
|
||||||
void CheckProperty(Token::Value property, PropertyKind type, bool is_static,
|
void CheckProperty(Token::Value property, PropertyKind type,
|
||||||
bool is_generator, bool* ok) override;
|
MethodKind method_type, bool* ok) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool IsConstructor() {
|
bool IsConstructor() {
|
||||||
@ -1046,6 +1163,7 @@ class ParserBase : public Traits {
|
|||||||
bool allow_harmony_for_in_;
|
bool allow_harmony_for_in_;
|
||||||
bool allow_harmony_function_name_;
|
bool allow_harmony_function_name_;
|
||||||
bool allow_harmony_function_sent_;
|
bool allow_harmony_function_sent_;
|
||||||
|
bool allow_harmony_async_await_;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class Traits>
|
template <class Traits>
|
||||||
@ -1181,7 +1299,8 @@ typename ParserBase<Traits>::IdentifierT
|
|||||||
ParserBase<Traits>::ParseAndClassifyIdentifier(ExpressionClassifier* classifier,
|
ParserBase<Traits>::ParseAndClassifyIdentifier(ExpressionClassifier* classifier,
|
||||||
bool* ok) {
|
bool* ok) {
|
||||||
Token::Value next = Next();
|
Token::Value next = Next();
|
||||||
if (next == Token::IDENTIFIER || (next == Token::AWAIT && !parsing_module_)) {
|
if (next == Token::IDENTIFIER || next == Token::ASYNC ||
|
||||||
|
(next == Token::AWAIT && !parsing_module_)) {
|
||||||
IdentifierT name = this->GetSymbol(scanner());
|
IdentifierT name = this->GetSymbol(scanner());
|
||||||
// When this function is used to read a formal parameter, we don't always
|
// When this function is used to read a formal parameter, we don't always
|
||||||
// know whether the function is going to be strict or sloppy. Indeed for
|
// know whether the function is going to be strict or sloppy. Indeed for
|
||||||
@ -1206,6 +1325,14 @@ ParserBase<Traits>::ParseAndClassifyIdentifier(ExpressionClassifier* classifier,
|
|||||||
scanner()->location(), MessageTemplate::kStrictEvalArguments);
|
scanner()->location(), MessageTemplate::kStrictEvalArguments);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (this->IsAwait(name)) {
|
||||||
|
if (is_async_function()) {
|
||||||
|
classifier->RecordPatternError(
|
||||||
|
scanner()->location(), MessageTemplate::kAwaitBindingIdentifier);
|
||||||
|
}
|
||||||
|
classifier->RecordAsyncArrowFormalParametersError(
|
||||||
|
scanner()->location(), MessageTemplate::kAwaitBindingIdentifier);
|
||||||
|
}
|
||||||
|
|
||||||
if (classifier->duplicate_finder() != nullptr &&
|
if (classifier->duplicate_finder() != nullptr &&
|
||||||
scanner()->FindSymbol(classifier->duplicate_finder(), 1) != 0) {
|
scanner()->FindSymbol(classifier->duplicate_finder(), 1) != 0) {
|
||||||
@ -1245,7 +1372,8 @@ typename ParserBase<Traits>::IdentifierT
|
|||||||
ParserBase<Traits>::ParseIdentifierOrStrictReservedWord(
|
ParserBase<Traits>::ParseIdentifierOrStrictReservedWord(
|
||||||
bool is_generator, bool* is_strict_reserved, bool* ok) {
|
bool is_generator, bool* is_strict_reserved, bool* ok) {
|
||||||
Token::Value next = Next();
|
Token::Value next = Next();
|
||||||
if (next == Token::IDENTIFIER || (next == Token::AWAIT && !parsing_module_)) {
|
if (next == Token::IDENTIFIER || (next == Token::AWAIT && !parsing_module_) ||
|
||||||
|
next == Token::ASYNC) {
|
||||||
*is_strict_reserved = false;
|
*is_strict_reserved = false;
|
||||||
} else if (next == Token::FUTURE_STRICT_RESERVED_WORD || next == Token::LET ||
|
} else if (next == Token::FUTURE_STRICT_RESERVED_WORD || next == Token::LET ||
|
||||||
next == Token::STATIC || (next == Token::YIELD && !is_generator)) {
|
next == Token::STATIC || (next == Token::YIELD && !is_generator)) {
|
||||||
@ -1265,9 +1393,10 @@ template <class Traits>
|
|||||||
typename ParserBase<Traits>::IdentifierT
|
typename ParserBase<Traits>::IdentifierT
|
||||||
ParserBase<Traits>::ParseIdentifierName(bool* ok) {
|
ParserBase<Traits>::ParseIdentifierName(bool* ok) {
|
||||||
Token::Value next = Next();
|
Token::Value next = Next();
|
||||||
if (next != Token::IDENTIFIER && next != Token::ENUM &&
|
if (next != Token::IDENTIFIER && next != Token::ASYNC &&
|
||||||
next != Token::AWAIT && next != Token::LET && next != Token::STATIC &&
|
next != Token::ENUM && next != Token::AWAIT && next != Token::LET &&
|
||||||
next != Token::YIELD && next != Token::FUTURE_STRICT_RESERVED_WORD &&
|
next != Token::STATIC && next != Token::YIELD &&
|
||||||
|
next != Token::FUTURE_STRICT_RESERVED_WORD &&
|
||||||
next != Token::ESCAPED_KEYWORD &&
|
next != Token::ESCAPED_KEYWORD &&
|
||||||
next != Token::ESCAPED_STRICT_RESERVED_WORD && !Token::IsKeyword(next)) {
|
next != Token::ESCAPED_STRICT_RESERVED_WORD && !Token::IsKeyword(next)) {
|
||||||
this->ReportUnexpectedToken(next);
|
this->ReportUnexpectedToken(next);
|
||||||
@ -1321,11 +1450,10 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseRegExpLiteral(
|
|||||||
#define DUMMY ) // to make indentation work
|
#define DUMMY ) // to make indentation work
|
||||||
#undef DUMMY
|
#undef DUMMY
|
||||||
|
|
||||||
|
|
||||||
template <class Traits>
|
template <class Traits>
|
||||||
typename ParserBase<Traits>::ExpressionT
|
typename ParserBase<Traits>::ExpressionT
|
||||||
ParserBase<Traits>::ParsePrimaryExpression(ExpressionClassifier* classifier,
|
ParserBase<Traits>::ParsePrimaryExpression(ExpressionClassifier* classifier,
|
||||||
bool* ok) {
|
bool* is_async, bool* ok) {
|
||||||
// PrimaryExpression ::
|
// PrimaryExpression ::
|
||||||
// 'this'
|
// 'this'
|
||||||
// 'null'
|
// 'null'
|
||||||
@ -1341,6 +1469,7 @@ ParserBase<Traits>::ParsePrimaryExpression(ExpressionClassifier* classifier,
|
|||||||
// '(' Expression ')'
|
// '(' Expression ')'
|
||||||
// TemplateLiteral
|
// TemplateLiteral
|
||||||
// do Block
|
// do Block
|
||||||
|
// AsyncFunctionExpression
|
||||||
|
|
||||||
int beg_pos = peek_position();
|
int beg_pos = peek_position();
|
||||||
switch (peek()) {
|
switch (peek()) {
|
||||||
@ -1360,6 +1489,16 @@ ParserBase<Traits>::ParsePrimaryExpression(ExpressionClassifier* classifier,
|
|||||||
BindingPatternUnexpectedToken(classifier);
|
BindingPatternUnexpectedToken(classifier);
|
||||||
return this->ExpressionFromLiteral(Next(), beg_pos, scanner(), factory());
|
return this->ExpressionFromLiteral(Next(), beg_pos, scanner(), factory());
|
||||||
|
|
||||||
|
case Token::ASYNC:
|
||||||
|
if (allow_harmony_async_await() &&
|
||||||
|
!scanner()->HasAnyLineTerminatorAfterNext() &&
|
||||||
|
PeekAhead() == Token::FUNCTION) {
|
||||||
|
Consume(Token::ASYNC);
|
||||||
|
return this->ParseAsyncFunctionExpression(CHECK_OK);
|
||||||
|
}
|
||||||
|
// CoverCallExpressionAndAsyncArrowHead
|
||||||
|
*is_async = true;
|
||||||
|
/* falls through */
|
||||||
case Token::IDENTIFIER:
|
case Token::IDENTIFIER:
|
||||||
case Token::LET:
|
case Token::LET:
|
||||||
case Token::STATIC:
|
case Token::STATIC:
|
||||||
@ -1631,11 +1770,10 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseArrayLiteral(
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <class Traits>
|
template <class Traits>
|
||||||
typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParsePropertyName(
|
typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParsePropertyName(
|
||||||
IdentifierT* name, bool* is_get, bool* is_set, bool* is_computed_name,
|
IdentifierT* name, bool* is_get, bool* is_set, bool* is_await,
|
||||||
ExpressionClassifier* classifier, bool* ok) {
|
bool* is_computed_name, ExpressionClassifier* classifier, bool* ok) {
|
||||||
Token::Value token = peek();
|
Token::Value token = peek();
|
||||||
int pos = peek_position();
|
int pos = peek_position();
|
||||||
|
|
||||||
@ -1680,6 +1818,9 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParsePropertyName(
|
|||||||
default:
|
default:
|
||||||
*name = ParseIdentifierName(CHECK_OK);
|
*name = ParseIdentifierName(CHECK_OK);
|
||||||
scanner()->IsGetOrSet(is_get, is_set);
|
scanner()->IsGetOrSet(is_get, is_set);
|
||||||
|
if (this->IsAwait(*name)) {
|
||||||
|
*is_await = true;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1689,38 +1830,50 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParsePropertyName(
|
|||||||
: factory()->NewStringLiteral(*name, pos);
|
: factory()->NewStringLiteral(*name, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <class Traits>
|
template <class Traits>
|
||||||
typename ParserBase<Traits>::ObjectLiteralPropertyT
|
typename ParserBase<Traits>::ObjectLiteralPropertyT
|
||||||
ParserBase<Traits>::ParsePropertyDefinition(
|
ParserBase<Traits>::ParsePropertyDefinition(
|
||||||
ObjectLiteralCheckerBase* checker, bool in_class, bool has_extends,
|
ObjectLiteralCheckerBase* checker, bool in_class, bool has_extends,
|
||||||
bool is_static, bool* is_computed_name, bool* has_seen_constructor,
|
MethodKind method_kind, bool* is_computed_name, bool* has_seen_constructor,
|
||||||
ExpressionClassifier* classifier, IdentifierT* name, bool* ok) {
|
ExpressionClassifier* classifier, IdentifierT* name, bool* ok) {
|
||||||
DCHECK(!in_class || is_static || has_seen_constructor != nullptr);
|
DCHECK(!in_class || IsStaticMethod(method_kind) ||
|
||||||
|
has_seen_constructor != nullptr);
|
||||||
ExpressionT value = this->EmptyExpression();
|
ExpressionT value = this->EmptyExpression();
|
||||||
bool is_get = false;
|
bool is_get = false;
|
||||||
bool is_set = false;
|
bool is_set = false;
|
||||||
|
bool is_await = false;
|
||||||
bool is_generator = Check(Token::MUL);
|
bool is_generator = Check(Token::MUL);
|
||||||
|
bool is_async = false;
|
||||||
|
const bool is_static = IsStaticMethod(method_kind);
|
||||||
|
|
||||||
Token::Value name_token = peek();
|
Token::Value name_token = peek();
|
||||||
|
|
||||||
|
if (is_generator) {
|
||||||
|
method_kind |= MethodKind::Generator;
|
||||||
|
} else if (allow_harmony_async_await() && name_token == Token::ASYNC &&
|
||||||
|
!scanner()->HasAnyLineTerminatorAfterNext() &&
|
||||||
|
PeekAhead() != Token::LPAREN && PeekAhead()) {
|
||||||
|
is_async = true;
|
||||||
|
}
|
||||||
|
|
||||||
int next_beg_pos = scanner()->peek_location().beg_pos;
|
int next_beg_pos = scanner()->peek_location().beg_pos;
|
||||||
int next_end_pos = scanner()->peek_location().end_pos;
|
int next_end_pos = scanner()->peek_location().end_pos;
|
||||||
ExpressionT name_expression =
|
ExpressionT name_expression = ParsePropertyName(
|
||||||
ParsePropertyName(name, &is_get, &is_set, is_computed_name, classifier,
|
name, &is_get, &is_set, &is_await, is_computed_name, classifier,
|
||||||
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
|
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
|
||||||
|
|
||||||
if (fni_ != nullptr && !*is_computed_name) {
|
if (fni_ != nullptr && !*is_computed_name) {
|
||||||
this->PushLiteralName(fni_, *name);
|
this->PushLiteralName(fni_, *name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!in_class && !is_generator) {
|
if (!in_class && !is_generator) {
|
||||||
DCHECK(!is_static);
|
DCHECK(!IsStaticMethod(method_kind));
|
||||||
|
|
||||||
if (peek() == Token::COLON) {
|
if (peek() == Token::COLON) {
|
||||||
// PropertyDefinition
|
// PropertyDefinition
|
||||||
// PropertyName ':' AssignmentExpression
|
// PropertyName ':' AssignmentExpression
|
||||||
if (!*is_computed_name) {
|
if (!*is_computed_name) {
|
||||||
checker->CheckProperty(name_token, kValueProperty, false, false,
|
checker->CheckProperty(name_token, kValueProperty, MethodKind::Normal,
|
||||||
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
|
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
|
||||||
}
|
}
|
||||||
Consume(Token::COLON);
|
Consume(Token::COLON);
|
||||||
@ -1730,8 +1883,8 @@ ParserBase<Traits>::ParsePropertyDefinition(
|
|||||||
CheckDestructuringElement(value, classifier, beg_pos,
|
CheckDestructuringElement(value, classifier, beg_pos,
|
||||||
scanner()->location().end_pos);
|
scanner()->location().end_pos);
|
||||||
|
|
||||||
return factory()->NewObjectLiteralProperty(name_expression, value, false,
|
return factory()->NewObjectLiteralProperty(name_expression, value,
|
||||||
*is_computed_name);
|
is_static, *is_computed_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Token::IsIdentifier(name_token, language_mode(), this->is_generator(),
|
if (Token::IsIdentifier(name_token, language_mode(), this->is_generator(),
|
||||||
@ -1752,7 +1905,11 @@ ParserBase<Traits>::ParsePropertyDefinition(
|
|||||||
classifier->RecordLetPatternError(
|
classifier->RecordLetPatternError(
|
||||||
scanner()->location(), MessageTemplate::kLetInLexicalBinding);
|
scanner()->location(), MessageTemplate::kLetInLexicalBinding);
|
||||||
}
|
}
|
||||||
|
if (is_await && is_async_function()) {
|
||||||
|
classifier->RecordPatternError(
|
||||||
|
Scanner::Location(next_beg_pos, next_end_pos),
|
||||||
|
MessageTemplate::kAwaitBindingIdentifier);
|
||||||
|
}
|
||||||
ExpressionT lhs = this->ExpressionFromIdentifier(
|
ExpressionT lhs = this->ExpressionFromIdentifier(
|
||||||
*name, next_beg_pos, next_end_pos, scope_, factory());
|
*name, next_beg_pos, next_end_pos, scope_, factory());
|
||||||
CheckDestructuringElement(lhs, classifier, next_beg_pos, next_end_pos);
|
CheckDestructuringElement(lhs, classifier, next_beg_pos, next_end_pos);
|
||||||
@ -1780,7 +1937,7 @@ ParserBase<Traits>::ParsePropertyDefinition(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return factory()->NewObjectLiteralProperty(
|
return factory()->NewObjectLiteralProperty(
|
||||||
name_expression, value, ObjectLiteralProperty::COMPUTED, false,
|
name_expression, value, ObjectLiteralProperty::COMPUTED, is_static,
|
||||||
false);
|
false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1790,20 +1947,32 @@ ParserBase<Traits>::ParsePropertyDefinition(
|
|||||||
Scanner::Location(next_beg_pos, scanner()->location().end_pos),
|
Scanner::Location(next_beg_pos, scanner()->location().end_pos),
|
||||||
MessageTemplate::kInvalidDestructuringTarget);
|
MessageTemplate::kInvalidDestructuringTarget);
|
||||||
|
|
||||||
|
if (is_async && !IsSpecialMethod(method_kind)) {
|
||||||
|
DCHECK(!is_get);
|
||||||
|
DCHECK(!is_set);
|
||||||
|
bool dont_care;
|
||||||
|
name_expression = ParsePropertyName(
|
||||||
|
name, &dont_care, &dont_care, &dont_care, is_computed_name, classifier,
|
||||||
|
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
|
||||||
|
method_kind |= MethodKind::Async;
|
||||||
|
}
|
||||||
|
|
||||||
if (is_generator || peek() == Token::LPAREN) {
|
if (is_generator || peek() == Token::LPAREN) {
|
||||||
// MethodDefinition
|
// MethodDefinition
|
||||||
// PropertyName '(' StrictFormalParameters ')' '{' FunctionBody '}'
|
// PropertyName '(' StrictFormalParameters ')' '{' FunctionBody '}'
|
||||||
// '*' PropertyName '(' StrictFormalParameters ')' '{' FunctionBody '}'
|
// '*' PropertyName '(' StrictFormalParameters ')' '{' FunctionBody '}'
|
||||||
if (!*is_computed_name) {
|
if (!*is_computed_name) {
|
||||||
checker->CheckProperty(name_token, kMethodProperty, is_static,
|
checker->CheckProperty(name_token, kMethodProperty, method_kind,
|
||||||
is_generator,
|
|
||||||
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
|
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
|
||||||
}
|
}
|
||||||
|
|
||||||
FunctionKind kind = is_generator ? FunctionKind::kConciseGeneratorMethod
|
FunctionKind kind = is_generator
|
||||||
: FunctionKind::kConciseMethod;
|
? FunctionKind::kConciseGeneratorMethod
|
||||||
|
: is_async ? FunctionKind::kAsyncConciseMethod
|
||||||
|
: FunctionKind::kConciseMethod;
|
||||||
|
|
||||||
if (in_class && !is_static && this->IsConstructor(*name)) {
|
if (in_class && !IsStaticMethod(method_kind) &&
|
||||||
|
this->IsConstructor(*name)) {
|
||||||
*has_seen_constructor = true;
|
*has_seen_constructor = true;
|
||||||
kind = has_extends ? FunctionKind::kSubclassConstructor
|
kind = has_extends ? FunctionKind::kSubclassConstructor
|
||||||
: FunctionKind::kBaseConstructor;
|
: FunctionKind::kBaseConstructor;
|
||||||
@ -1819,13 +1988,13 @@ ParserBase<Traits>::ParsePropertyDefinition(
|
|||||||
is_static, *is_computed_name);
|
is_static, *is_computed_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (in_class && name_token == Token::STATIC && !is_static) {
|
if (in_class && name_token == Token::STATIC && IsNormalMethod(method_kind)) {
|
||||||
// ClassElement (static)
|
// ClassElement (static)
|
||||||
// 'static' MethodDefinition
|
// 'static' MethodDefinition
|
||||||
*name = this->EmptyIdentifier();
|
*name = this->EmptyIdentifier();
|
||||||
ObjectLiteralPropertyT property = ParsePropertyDefinition(
|
ObjectLiteralPropertyT property = ParsePropertyDefinition(
|
||||||
checker, true, has_extends, true, is_computed_name, nullptr, classifier,
|
checker, true, has_extends, MethodKind::Static, is_computed_name,
|
||||||
name, ok);
|
nullptr, classifier, name, ok);
|
||||||
Traits::RewriteNonPattern(classifier, ok);
|
Traits::RewriteNonPattern(classifier, ok);
|
||||||
return property;
|
return property;
|
||||||
}
|
}
|
||||||
@ -1839,12 +2008,11 @@ ParserBase<Traits>::ParsePropertyDefinition(
|
|||||||
name_token = peek();
|
name_token = peek();
|
||||||
|
|
||||||
name_expression = ParsePropertyName(
|
name_expression = ParsePropertyName(
|
||||||
name, &dont_care, &dont_care, is_computed_name, classifier,
|
name, &dont_care, &dont_care, &dont_care, is_computed_name, classifier,
|
||||||
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
|
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
|
||||||
|
|
||||||
if (!*is_computed_name) {
|
if (!*is_computed_name) {
|
||||||
checker->CheckProperty(name_token, kAccessorProperty, is_static,
|
checker->CheckProperty(name_token, kAccessorProperty, method_kind,
|
||||||
is_generator,
|
|
||||||
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
|
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1894,13 +2062,12 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseObjectLiteral(
|
|||||||
FuncNameInferrer::State fni_state(fni_);
|
FuncNameInferrer::State fni_state(fni_);
|
||||||
|
|
||||||
const bool in_class = false;
|
const bool in_class = false;
|
||||||
const bool is_static = false;
|
|
||||||
const bool has_extends = false;
|
const bool has_extends = false;
|
||||||
bool is_computed_name = false;
|
bool is_computed_name = false;
|
||||||
IdentifierT name = this->EmptyIdentifier();
|
IdentifierT name = this->EmptyIdentifier();
|
||||||
ObjectLiteralPropertyT property = this->ParsePropertyDefinition(
|
ObjectLiteralPropertyT property = this->ParsePropertyDefinition(
|
||||||
&checker, in_class, has_extends, is_static, &is_computed_name, NULL,
|
&checker, in_class, has_extends, MethodKind::Normal, &is_computed_name,
|
||||||
classifier, &name, CHECK_OK);
|
NULL, classifier, &name, CHECK_OK);
|
||||||
|
|
||||||
if (is_computed_name) {
|
if (is_computed_name) {
|
||||||
has_computed_names = true;
|
has_computed_names = true;
|
||||||
@ -1934,11 +2101,10 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseObjectLiteral(
|
|||||||
pos);
|
pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <class Traits>
|
template <class Traits>
|
||||||
typename Traits::Type::ExpressionList ParserBase<Traits>::ParseArguments(
|
typename Traits::Type::ExpressionList ParserBase<Traits>::ParseArguments(
|
||||||
Scanner::Location* first_spread_arg_loc, ExpressionClassifier* classifier,
|
Scanner::Location* first_spread_arg_loc, bool maybe_arrow,
|
||||||
bool* ok) {
|
ExpressionClassifier* classifier, bool* ok) {
|
||||||
// Arguments ::
|
// Arguments ::
|
||||||
// '(' (AssignmentExpression)*[','] ')'
|
// '(' (AssignmentExpression)*[','] ')'
|
||||||
|
|
||||||
@ -1994,7 +2160,7 @@ typename Traits::Type::ExpressionList ParserBase<Traits>::ParseArguments(
|
|||||||
}
|
}
|
||||||
*first_spread_arg_loc = spread_arg;
|
*first_spread_arg_loc = spread_arg;
|
||||||
|
|
||||||
if (spread_arg.IsValid()) {
|
if ((!maybe_arrow || peek() != Token::ARROW) && spread_arg.IsValid()) {
|
||||||
// Unspread parameter sequences are translated into array literals in the
|
// Unspread parameter sequences are translated into array literals in the
|
||||||
// parser. Ensure that the number of materialized literals matches between
|
// parser. Ensure that the number of materialized literals matches between
|
||||||
// the parser and preparser
|
// the parser and preparser
|
||||||
@ -2026,18 +2192,31 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN,
|
|||||||
ParserBase<Traits>::Checkpoint checkpoint(this);
|
ParserBase<Traits>::Checkpoint checkpoint(this);
|
||||||
ExpressionClassifier arrow_formals_classifier(this,
|
ExpressionClassifier arrow_formals_classifier(this,
|
||||||
classifier->duplicate_finder());
|
classifier->duplicate_finder());
|
||||||
|
|
||||||
|
bool is_async = allow_harmony_async_await() && peek() == Token::ASYNC &&
|
||||||
|
!scanner()->HasAnyLineTerminatorAfterNext();
|
||||||
|
|
||||||
bool parenthesized_formals = peek() == Token::LPAREN;
|
bool parenthesized_formals = peek() == Token::LPAREN;
|
||||||
if (!parenthesized_formals) {
|
if (!is_async && !parenthesized_formals) {
|
||||||
ArrowFormalParametersUnexpectedToken(&arrow_formals_classifier);
|
ArrowFormalParametersUnexpectedToken(&arrow_formals_classifier);
|
||||||
}
|
}
|
||||||
ExpressionT expression = this->ParseConditionalExpression(
|
ExpressionT expression = this->ParseConditionalExpression(
|
||||||
accept_IN, &arrow_formals_classifier, CHECK_OK);
|
accept_IN, &arrow_formals_classifier, CHECK_OK);
|
||||||
|
|
||||||
|
if (is_async && peek_any_identifier() && PeekAhead() == Token::ARROW) {
|
||||||
|
// async Identifier => AsyncConciseBody
|
||||||
|
IdentifierT name =
|
||||||
|
ParseAndClassifyIdentifier(&arrow_formals_classifier, CHECK_OK);
|
||||||
|
expression = this->ExpressionFromIdentifier(
|
||||||
|
name, position(), scanner()->location().end_pos, scope_, factory());
|
||||||
|
}
|
||||||
|
|
||||||
if (peek() == Token::ARROW) {
|
if (peek() == Token::ARROW) {
|
||||||
classifier->RecordPatternError(scanner()->peek_location(),
|
classifier->RecordPatternError(scanner()->peek_location(),
|
||||||
MessageTemplate::kUnexpectedToken,
|
MessageTemplate::kUnexpectedToken,
|
||||||
Token::String(Token::ARROW));
|
Token::String(Token::ARROW));
|
||||||
ValidateArrowFormalParameters(&arrow_formals_classifier, expression,
|
ValidateArrowFormalParameters(&arrow_formals_classifier, expression,
|
||||||
parenthesized_formals, CHECK_OK);
|
parenthesized_formals, is_async, CHECK_OK);
|
||||||
// This reads strangely, but is correct: it checks whether any
|
// This reads strangely, but is correct: it checks whether any
|
||||||
// sub-expression of the parameter list failed to be a valid formal
|
// sub-expression of the parameter list failed to be a valid formal
|
||||||
// parameter initializer. Since YieldExpressions are banned anywhere
|
// parameter initializer. Since YieldExpressions are banned anywhere
|
||||||
@ -2045,9 +2224,11 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN,
|
|||||||
// TODO(adamk): Rename "FormalParameterInitializerError" to refer to
|
// TODO(adamk): Rename "FormalParameterInitializerError" to refer to
|
||||||
// "YieldExpression", which is its only use.
|
// "YieldExpression", which is its only use.
|
||||||
ValidateFormalParameterInitializer(&arrow_formals_classifier, ok);
|
ValidateFormalParameterInitializer(&arrow_formals_classifier, ok);
|
||||||
|
|
||||||
Scanner::Location loc(lhs_beg_pos, scanner()->location().end_pos);
|
Scanner::Location loc(lhs_beg_pos, scanner()->location().end_pos);
|
||||||
Scope* scope =
|
Scope* scope = this->NewScope(scope_, FUNCTION_SCOPE,
|
||||||
this->NewScope(scope_, FUNCTION_SCOPE, FunctionKind::kArrowFunction);
|
is_async ? FunctionKind::kAsyncArrowFunction
|
||||||
|
: FunctionKind::kArrowFunction);
|
||||||
// Because the arrow's parameters were parsed in the outer scope, any
|
// Because the arrow's parameters were parsed in the outer scope, any
|
||||||
// usage flags that might have been triggered there need to be copied
|
// usage flags that might have been triggered there need to be copied
|
||||||
// to the arrow scope.
|
// to the arrow scope.
|
||||||
@ -2069,7 +2250,7 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN,
|
|||||||
duplicate_loc);
|
duplicate_loc);
|
||||||
}
|
}
|
||||||
expression = this->ParseArrowFunctionLiteral(
|
expression = this->ParseArrowFunctionLiteral(
|
||||||
accept_IN, parameters, arrow_formals_classifier, CHECK_OK);
|
accept_IN, parameters, is_async, arrow_formals_classifier, CHECK_OK);
|
||||||
|
|
||||||
if (fni_ != nullptr) fni_->Infer();
|
if (fni_ != nullptr) fni_->Infer();
|
||||||
|
|
||||||
@ -2086,8 +2267,10 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN,
|
|||||||
classifier->Accumulate(
|
classifier->Accumulate(
|
||||||
&arrow_formals_classifier,
|
&arrow_formals_classifier,
|
||||||
ExpressionClassifier::StandardProductions |
|
ExpressionClassifier::StandardProductions |
|
||||||
ExpressionClassifier::FormalParametersProductions |
|
ExpressionClassifier::FormalParametersProductions |
|
||||||
ExpressionClassifier::CoverInitializedNameProduction,
|
ExpressionClassifier::CoverInitializedNameProduction |
|
||||||
|
ExpressionClassifier::AsyncArrowFormalParametersProduction |
|
||||||
|
ExpressionClassifier::AsyncBindingPatternProduction,
|
||||||
false);
|
false);
|
||||||
|
|
||||||
if (!Token::IsAssignmentOp(peek())) {
|
if (!Token::IsAssignmentOp(peek())) {
|
||||||
@ -2129,8 +2312,10 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN,
|
|||||||
CheckNoTailCallExpressions(&rhs_classifier, CHECK_OK);
|
CheckNoTailCallExpressions(&rhs_classifier, CHECK_OK);
|
||||||
Traits::RewriteNonPattern(&rhs_classifier, CHECK_OK);
|
Traits::RewriteNonPattern(&rhs_classifier, CHECK_OK);
|
||||||
classifier->Accumulate(
|
classifier->Accumulate(
|
||||||
&rhs_classifier, ExpressionClassifier::ExpressionProductions |
|
&rhs_classifier,
|
||||||
ExpressionClassifier::CoverInitializedNameProduction);
|
ExpressionClassifier::ExpressionProductions |
|
||||||
|
ExpressionClassifier::CoverInitializedNameProduction |
|
||||||
|
ExpressionClassifier::AsyncArrowFormalParametersProduction);
|
||||||
|
|
||||||
// TODO(1231235): We try to estimate the set of properties set by
|
// TODO(1231235): We try to estimate the set of properties set by
|
||||||
// constructors. We define a new property whenever there is an
|
// constructors. We define a new property whenever there is an
|
||||||
@ -2401,6 +2586,7 @@ ParserBase<Traits>::ParseUnaryExpression(ExpressionClassifier* classifier,
|
|||||||
// '-' UnaryExpression
|
// '-' UnaryExpression
|
||||||
// '~' UnaryExpression
|
// '~' UnaryExpression
|
||||||
// '!' UnaryExpression
|
// '!' UnaryExpression
|
||||||
|
// [+Await] AwaitExpression[?Yield]
|
||||||
|
|
||||||
Token::Value op = peek();
|
Token::Value op = peek();
|
||||||
if (Token::IsUnaryOp(op)) {
|
if (Token::IsUnaryOp(op)) {
|
||||||
@ -2448,6 +2634,40 @@ ParserBase<Traits>::ParseUnaryExpression(ExpressionClassifier* classifier,
|
|||||||
expression,
|
expression,
|
||||||
position());
|
position());
|
||||||
|
|
||||||
|
} else if (is_async_function() && peek() == Token::AWAIT) {
|
||||||
|
int beg_pos = peek_position();
|
||||||
|
switch (PeekAhead()) {
|
||||||
|
case Token::RPAREN:
|
||||||
|
case Token::RBRACK:
|
||||||
|
case Token::RBRACE:
|
||||||
|
case Token::ASSIGN:
|
||||||
|
case Token::COMMA: {
|
||||||
|
Next();
|
||||||
|
IdentifierT name = this->GetSymbol(scanner());
|
||||||
|
|
||||||
|
// Possibly async arrow formals --- record ExpressionError just in case.
|
||||||
|
ExpressionUnexpectedToken(classifier);
|
||||||
|
classifier->RecordAsyncBindingPatternError(
|
||||||
|
Scanner::Location(beg_pos, scanner()->location().end_pos),
|
||||||
|
MessageTemplate::kAwaitBindingIdentifier);
|
||||||
|
classifier->RecordAsyncArrowFormalParametersError(
|
||||||
|
Scanner::Location(beg_pos, scanner()->location().end_pos),
|
||||||
|
MessageTemplate::kAwaitBindingIdentifier);
|
||||||
|
|
||||||
|
return this->ExpressionFromIdentifier(
|
||||||
|
name, beg_pos, scanner()->location().end_pos, scope_, factory());
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Consume(Token::AWAIT);
|
||||||
|
|
||||||
|
ExpressionT value = ParseUnaryExpression(classifier, CHECK_OK);
|
||||||
|
|
||||||
|
classifier->RecordFormalParameterInitializerError(
|
||||||
|
Scanner::Location(beg_pos, scanner()->location().end_pos),
|
||||||
|
MessageTemplate::kAwaitExpressionFormalParameter);
|
||||||
|
return Traits::RewriteAwaitExpression(value, beg_pos);
|
||||||
} else {
|
} else {
|
||||||
return this->ParsePostfixExpression(classifier, ok);
|
return this->ParsePostfixExpression(classifier, ok);
|
||||||
}
|
}
|
||||||
@ -2497,8 +2717,9 @@ ParserBase<Traits>::ParseLeftHandSideExpression(
|
|||||||
return this->ParseTailCallExpression(classifier, ok);
|
return this->ParseTailCallExpression(classifier, ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
ExpressionT result =
|
bool is_async = false;
|
||||||
this->ParseMemberWithNewPrefixesExpression(classifier, CHECK_OK);
|
ExpressionT result = this->ParseMemberWithNewPrefixesExpression(
|
||||||
|
classifier, &is_async, CHECK_OK);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
switch (peek()) {
|
switch (peek()) {
|
||||||
@ -2518,13 +2739,12 @@ ParserBase<Traits>::ParseLeftHandSideExpression(
|
|||||||
|
|
||||||
case Token::LPAREN: {
|
case Token::LPAREN: {
|
||||||
CheckNoTailCallExpressions(classifier, CHECK_OK);
|
CheckNoTailCallExpressions(classifier, CHECK_OK);
|
||||||
|
int pos;
|
||||||
Traits::RewriteNonPattern(classifier, CHECK_OK);
|
Traits::RewriteNonPattern(classifier, CHECK_OK);
|
||||||
BindingPatternUnexpectedToken(classifier);
|
BindingPatternUnexpectedToken(classifier);
|
||||||
ArrowFormalParametersUnexpectedToken(classifier);
|
|
||||||
|
|
||||||
int pos;
|
|
||||||
if (scanner()->current_token() == Token::IDENTIFIER ||
|
if (scanner()->current_token() == Token::IDENTIFIER ||
|
||||||
scanner()->current_token() == Token::SUPER) {
|
scanner()->current_token() == Token::SUPER ||
|
||||||
|
scanner()->current_token() == Token::ASYNC) {
|
||||||
// For call of an identifier we want to report position of
|
// For call of an identifier we want to report position of
|
||||||
// the identifier as position of the call in the stack trace.
|
// the identifier as position of the call in the stack trace.
|
||||||
pos = position();
|
pos = position();
|
||||||
@ -2544,7 +2764,18 @@ ParserBase<Traits>::ParseLeftHandSideExpression(
|
|||||||
}
|
}
|
||||||
Scanner::Location spread_pos;
|
Scanner::Location spread_pos;
|
||||||
typename Traits::Type::ExpressionList args =
|
typename Traits::Type::ExpressionList args =
|
||||||
ParseArguments(&spread_pos, classifier, CHECK_OK);
|
ParseArguments(&spread_pos, is_async, classifier, CHECK_OK);
|
||||||
|
|
||||||
|
if (V8_UNLIKELY(is_async && peek() == Token::ARROW)) {
|
||||||
|
if (args->length()) {
|
||||||
|
// async ( Arguments ) => ...
|
||||||
|
return Traits::ExpressionListToExpression(args);
|
||||||
|
}
|
||||||
|
// async () => ...
|
||||||
|
return factory()->NewEmptyParentheses(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrowFormalParametersUnexpectedToken(classifier);
|
||||||
|
|
||||||
// Keep track of eval() calls since they disable all local variable
|
// Keep track of eval() calls since they disable all local variable
|
||||||
// optimizations.
|
// optimizations.
|
||||||
@ -2605,11 +2836,10 @@ ParserBase<Traits>::ParseLeftHandSideExpression(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <class Traits>
|
template <class Traits>
|
||||||
typename ParserBase<Traits>::ExpressionT
|
typename ParserBase<Traits>::ExpressionT
|
||||||
ParserBase<Traits>::ParseMemberWithNewPrefixesExpression(
|
ParserBase<Traits>::ParseMemberWithNewPrefixesExpression(
|
||||||
ExpressionClassifier* classifier, bool* ok) {
|
ExpressionClassifier* classifier, bool* is_async, bool* ok) {
|
||||||
// NewExpression ::
|
// NewExpression ::
|
||||||
// ('new')+ MemberExpression
|
// ('new')+ MemberExpression
|
||||||
//
|
//
|
||||||
@ -2642,7 +2872,8 @@ ParserBase<Traits>::ParseMemberWithNewPrefixesExpression(
|
|||||||
} else if (peek() == Token::PERIOD) {
|
} else if (peek() == Token::PERIOD) {
|
||||||
return ParseNewTargetExpression(CHECK_OK);
|
return ParseNewTargetExpression(CHECK_OK);
|
||||||
} else {
|
} else {
|
||||||
result = this->ParseMemberWithNewPrefixesExpression(classifier, CHECK_OK);
|
result = this->ParseMemberWithNewPrefixesExpression(classifier, is_async,
|
||||||
|
CHECK_OK);
|
||||||
}
|
}
|
||||||
Traits::RewriteNonPattern(classifier, CHECK_OK);
|
Traits::RewriteNonPattern(classifier, CHECK_OK);
|
||||||
if (peek() == Token::LPAREN) {
|
if (peek() == Token::LPAREN) {
|
||||||
@ -2658,8 +2889,8 @@ ParserBase<Traits>::ParseMemberWithNewPrefixesExpression(
|
|||||||
result = factory()->NewCallNew(result, args, new_pos);
|
result = factory()->NewCallNew(result, args, new_pos);
|
||||||
}
|
}
|
||||||
// The expression can still continue with . or [ after the arguments.
|
// The expression can still continue with . or [ after the arguments.
|
||||||
result =
|
result = this->ParseMemberExpressionContinuation(result, is_async,
|
||||||
this->ParseMemberExpressionContinuation(result, classifier, CHECK_OK);
|
classifier, CHECK_OK);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
// NewExpression without arguments.
|
// NewExpression without arguments.
|
||||||
@ -2667,14 +2898,13 @@ ParserBase<Traits>::ParseMemberWithNewPrefixesExpression(
|
|||||||
new_pos);
|
new_pos);
|
||||||
}
|
}
|
||||||
// No 'new' or 'super' keyword.
|
// No 'new' or 'super' keyword.
|
||||||
return this->ParseMemberExpression(classifier, ok);
|
return this->ParseMemberExpression(classifier, is_async, ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <class Traits>
|
template <class Traits>
|
||||||
typename ParserBase<Traits>::ExpressionT
|
typename ParserBase<Traits>::ExpressionT
|
||||||
ParserBase<Traits>::ParseMemberExpression(ExpressionClassifier* classifier,
|
ParserBase<Traits>::ParseMemberExpression(ExpressionClassifier* classifier,
|
||||||
bool* ok) {
|
bool* is_async, bool* ok) {
|
||||||
// MemberExpression ::
|
// MemberExpression ::
|
||||||
// (PrimaryExpression | FunctionLiteral | ClassLiteral)
|
// (PrimaryExpression | FunctionLiteral | ClassLiteral)
|
||||||
// ('[' Expression ']' | '.' Identifier | Arguments | TemplateLiteral)*
|
// ('[' Expression ']' | '.' Identifier | Arguments | TemplateLiteral)*
|
||||||
@ -2731,10 +2961,11 @@ ParserBase<Traits>::ParseMemberExpression(ExpressionClassifier* classifier,
|
|||||||
const bool is_new = false;
|
const bool is_new = false;
|
||||||
result = ParseSuperExpression(is_new, classifier, CHECK_OK);
|
result = ParseSuperExpression(is_new, classifier, CHECK_OK);
|
||||||
} else {
|
} else {
|
||||||
result = ParsePrimaryExpression(classifier, CHECK_OK);
|
result = ParsePrimaryExpression(classifier, is_async, CHECK_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
result = ParseMemberExpressionContinuation(result, classifier, CHECK_OK);
|
result =
|
||||||
|
ParseMemberExpressionContinuation(result, is_async, classifier, CHECK_OK);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2801,16 +3032,17 @@ ParserBase<Traits>::ParseNewTargetExpression(bool* ok) {
|
|||||||
return this->NewTargetExpression(scope_, factory(), pos);
|
return this->NewTargetExpression(scope_, factory(), pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <class Traits>
|
template <class Traits>
|
||||||
typename ParserBase<Traits>::ExpressionT
|
typename ParserBase<Traits>::ExpressionT
|
||||||
ParserBase<Traits>::ParseMemberExpressionContinuation(
|
ParserBase<Traits>::ParseMemberExpressionContinuation(
|
||||||
ExpressionT expression, ExpressionClassifier* classifier, bool* ok) {
|
ExpressionT expression, bool* is_async, ExpressionClassifier* classifier,
|
||||||
|
bool* ok) {
|
||||||
// Parses this part of MemberExpression:
|
// Parses this part of MemberExpression:
|
||||||
// ('[' Expression ']' | '.' Identifier | TemplateLiteral)*
|
// ('[' Expression ']' | '.' Identifier | TemplateLiteral)*
|
||||||
while (true) {
|
while (true) {
|
||||||
switch (peek()) {
|
switch (peek()) {
|
||||||
case Token::LBRACK: {
|
case Token::LBRACK: {
|
||||||
|
*is_async = false;
|
||||||
Traits::RewriteNonPattern(classifier, CHECK_OK);
|
Traits::RewriteNonPattern(classifier, CHECK_OK);
|
||||||
BindingPatternUnexpectedToken(classifier);
|
BindingPatternUnexpectedToken(classifier);
|
||||||
ArrowFormalParametersUnexpectedToken(classifier);
|
ArrowFormalParametersUnexpectedToken(classifier);
|
||||||
@ -2827,6 +3059,7 @@ ParserBase<Traits>::ParseMemberExpressionContinuation(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Token::PERIOD: {
|
case Token::PERIOD: {
|
||||||
|
*is_async = false;
|
||||||
Traits::RewriteNonPattern(classifier, CHECK_OK);
|
Traits::RewriteNonPattern(classifier, CHECK_OK);
|
||||||
BindingPatternUnexpectedToken(classifier);
|
BindingPatternUnexpectedToken(classifier);
|
||||||
ArrowFormalParametersUnexpectedToken(classifier);
|
ArrowFormalParametersUnexpectedToken(classifier);
|
||||||
@ -2843,6 +3076,7 @@ ParserBase<Traits>::ParseMemberExpressionContinuation(
|
|||||||
}
|
}
|
||||||
case Token::TEMPLATE_SPAN:
|
case Token::TEMPLATE_SPAN:
|
||||||
case Token::TEMPLATE_TAIL: {
|
case Token::TEMPLATE_TAIL: {
|
||||||
|
*is_async = false;
|
||||||
Traits::RewriteNonPattern(classifier, CHECK_OK);
|
Traits::RewriteNonPattern(classifier, CHECK_OK);
|
||||||
BindingPatternUnexpectedToken(classifier);
|
BindingPatternUnexpectedToken(classifier);
|
||||||
ArrowFormalParametersUnexpectedToken(classifier);
|
ArrowFormalParametersUnexpectedToken(classifier);
|
||||||
@ -3005,17 +3239,17 @@ bool ParserBase<Traits>::IsNextLetKeyword() {
|
|||||||
case Token::LET: // Yes, you can do let let = ... in sloppy mode
|
case Token::LET: // Yes, you can do let let = ... in sloppy mode
|
||||||
case Token::YIELD:
|
case Token::YIELD:
|
||||||
case Token::AWAIT:
|
case Token::AWAIT:
|
||||||
|
case Token::ASYNC:
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <class Traits>
|
template <class Traits>
|
||||||
typename ParserBase<Traits>::ExpressionT
|
typename ParserBase<Traits>::ExpressionT
|
||||||
ParserBase<Traits>::ParseArrowFunctionLiteral(
|
ParserBase<Traits>::ParseArrowFunctionLiteral(
|
||||||
bool accept_IN, const FormalParametersT& formal_parameters,
|
bool accept_IN, const FormalParametersT& formal_parameters, bool is_async,
|
||||||
const ExpressionClassifier& formals_classifier, bool* ok) {
|
const ExpressionClassifier& formals_classifier, bool* ok) {
|
||||||
if (peek() == Token::ARROW && scanner_->HasAnyLineTerminatorBeforeNext()) {
|
if (peek() == Token::ARROW && scanner_->HasAnyLineTerminatorBeforeNext()) {
|
||||||
// ASI inserts `;` after arrow parameters if a line terminator is found.
|
// ASI inserts `;` after arrow parameters if a line terminator is found.
|
||||||
@ -3032,10 +3266,11 @@ ParserBase<Traits>::ParseArrowFunctionLiteral(
|
|||||||
int expected_property_count = -1;
|
int expected_property_count = -1;
|
||||||
Scanner::Location super_loc;
|
Scanner::Location super_loc;
|
||||||
|
|
||||||
|
FunctionKind arrow_kind = is_async ? kAsyncArrowFunction : kArrowFunction;
|
||||||
{
|
{
|
||||||
typename Traits::Type::Factory function_factory(ast_value_factory());
|
typename Traits::Type::Factory function_factory(ast_value_factory());
|
||||||
FunctionState function_state(&function_state_, &scope_,
|
FunctionState function_state(&function_state_, &scope_,
|
||||||
formal_parameters.scope, kArrowFunction,
|
formal_parameters.scope, arrow_kind,
|
||||||
&function_factory);
|
&function_factory);
|
||||||
|
|
||||||
function_state.SkipMaterializedLiterals(
|
function_state.SkipMaterializedLiterals(
|
||||||
@ -3061,7 +3296,7 @@ ParserBase<Traits>::ParseArrowFunctionLiteral(
|
|||||||
} else {
|
} else {
|
||||||
body = this->ParseEagerFunctionBody(
|
body = this->ParseEagerFunctionBody(
|
||||||
this->EmptyIdentifier(), RelocInfo::kNoPosition, formal_parameters,
|
this->EmptyIdentifier(), RelocInfo::kNoPosition, formal_parameters,
|
||||||
kArrowFunction, FunctionLiteral::kAnonymousExpression, CHECK_OK);
|
arrow_kind, FunctionLiteral::kAnonymousExpression, CHECK_OK);
|
||||||
materialized_literal_count =
|
materialized_literal_count =
|
||||||
function_state.materialized_literal_count();
|
function_state.materialized_literal_count();
|
||||||
expected_property_count = function_state.expected_property_count();
|
expected_property_count = function_state.expected_property_count();
|
||||||
@ -3115,7 +3350,7 @@ ParserBase<Traits>::ParseArrowFunctionLiteral(
|
|||||||
materialized_literal_count, expected_property_count, num_parameters,
|
materialized_literal_count, expected_property_count, num_parameters,
|
||||||
FunctionLiteral::kNoDuplicateParameters,
|
FunctionLiteral::kNoDuplicateParameters,
|
||||||
FunctionLiteral::kAnonymousExpression,
|
FunctionLiteral::kAnonymousExpression,
|
||||||
FunctionLiteral::kShouldLazyCompile, FunctionKind::kArrowFunction,
|
FunctionLiteral::kShouldLazyCompile, arrow_kind,
|
||||||
formal_parameters.scope->start_position());
|
formal_parameters.scope->start_position());
|
||||||
|
|
||||||
function_literal->set_function_token_position(
|
function_literal->set_function_token_position(
|
||||||
@ -3284,13 +3519,12 @@ void ParserBase<Traits>::CheckDestructuringElement(
|
|||||||
#undef CHECK_OK
|
#undef CHECK_OK
|
||||||
#undef CHECK_OK_CUSTOM
|
#undef CHECK_OK_CUSTOM
|
||||||
|
|
||||||
|
|
||||||
template <typename Traits>
|
template <typename Traits>
|
||||||
void ParserBase<Traits>::ObjectLiteralChecker::CheckProperty(
|
void ParserBase<Traits>::ObjectLiteralChecker::CheckProperty(
|
||||||
Token::Value property, PropertyKind type, bool is_static, bool is_generator,
|
Token::Value property, PropertyKind type, MethodKind method_type,
|
||||||
bool* ok) {
|
bool* ok) {
|
||||||
DCHECK(!is_static);
|
DCHECK(!IsStaticMethod(method_type));
|
||||||
DCHECK(!is_generator || type == kMethodProperty);
|
DCHECK(!IsSpecialMethod(method_type) || type == kMethodProperty);
|
||||||
|
|
||||||
if (property == Token::SMI || property == Token::NUMBER) return;
|
if (property == Token::SMI || property == Token::NUMBER) return;
|
||||||
|
|
||||||
@ -3305,26 +3539,28 @@ void ParserBase<Traits>::ObjectLiteralChecker::CheckProperty(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <typename Traits>
|
template <typename Traits>
|
||||||
void ParserBase<Traits>::ClassLiteralChecker::CheckProperty(
|
void ParserBase<Traits>::ClassLiteralChecker::CheckProperty(
|
||||||
Token::Value property, PropertyKind type, bool is_static, bool is_generator,
|
Token::Value property, PropertyKind type, MethodKind method_type,
|
||||||
bool* ok) {
|
bool* ok) {
|
||||||
DCHECK(type == kMethodProperty || type == kAccessorProperty);
|
DCHECK(type == kMethodProperty || type == kAccessorProperty);
|
||||||
|
|
||||||
if (property == Token::SMI || property == Token::NUMBER) return;
|
if (property == Token::SMI || property == Token::NUMBER) return;
|
||||||
|
|
||||||
if (is_static) {
|
if (IsStaticMethod(method_type)) {
|
||||||
if (IsPrototype()) {
|
if (IsPrototype()) {
|
||||||
this->parser()->ReportMessage(MessageTemplate::kStaticPrototype);
|
this->parser()->ReportMessage(MessageTemplate::kStaticPrototype);
|
||||||
*ok = false;
|
*ok = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if (IsConstructor()) {
|
} else if (IsConstructor()) {
|
||||||
if (is_generator || type == kAccessorProperty) {
|
const bool is_generator = IsGeneratorMethod(method_type);
|
||||||
|
const bool is_async = IsAsyncMethod(method_type);
|
||||||
|
if (is_generator || is_async || type == kAccessorProperty) {
|
||||||
MessageTemplate::Template msg =
|
MessageTemplate::Template msg =
|
||||||
is_generator ? MessageTemplate::kConstructorIsGenerator
|
is_generator ? MessageTemplate::kConstructorIsGenerator
|
||||||
: MessageTemplate::kConstructorIsAccessor;
|
: is_async ? MessageTemplate::kConstructorIsAsync
|
||||||
|
: MessageTemplate::kConstructorIsAccessor;
|
||||||
this->parser()->ReportMessage(msg);
|
this->parser()->ReportMessage(msg);
|
||||||
*ok = false;
|
*ok = false;
|
||||||
return;
|
return;
|
||||||
|
@ -330,6 +330,10 @@ bool ParserTraits::IsUndefined(const AstRawString* identifier) const {
|
|||||||
return identifier == parser_->ast_value_factory()->undefined_string();
|
return identifier == parser_->ast_value_factory()->undefined_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ParserTraits::IsAwait(const AstRawString* identifier) const {
|
||||||
|
return identifier == parser_->ast_value_factory()->await_string();
|
||||||
|
}
|
||||||
|
|
||||||
bool ParserTraits::IsPrototype(const AstRawString* identifier) const {
|
bool ParserTraits::IsPrototype(const AstRawString* identifier) const {
|
||||||
return identifier == parser_->ast_value_factory()->prototype_string();
|
return identifier == parser_->ast_value_factory()->prototype_string();
|
||||||
}
|
}
|
||||||
@ -798,6 +802,7 @@ Parser::Parser(ParseInfo* info)
|
|||||||
FLAG_harmony_restrictive_declarations);
|
FLAG_harmony_restrictive_declarations);
|
||||||
set_allow_harmony_exponentiation_operator(
|
set_allow_harmony_exponentiation_operator(
|
||||||
FLAG_harmony_exponentiation_operator);
|
FLAG_harmony_exponentiation_operator);
|
||||||
|
set_allow_harmony_async_await(FLAG_harmony_async_await);
|
||||||
for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount;
|
for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount;
|
||||||
++feature) {
|
++feature) {
|
||||||
use_counts_[feature] = 0;
|
use_counts_[feature] = 0;
|
||||||
@ -1075,6 +1080,13 @@ FunctionLiteral* Parser::ParseLazy(Isolate* isolate, ParseInfo* info,
|
|||||||
bool ok = true;
|
bool ok = true;
|
||||||
|
|
||||||
if (shared_info->is_arrow()) {
|
if (shared_info->is_arrow()) {
|
||||||
|
bool is_async = allow_harmony_async_await() && shared_info->is_async();
|
||||||
|
if (is_async) {
|
||||||
|
DCHECK(!scanner()->HasAnyLineTerminatorAfterNext());
|
||||||
|
Consume(Token::ASYNC);
|
||||||
|
DCHECK(peek_any_identifier() || peek() == Token::LPAREN);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO(adamk): We should construct this scope from the ScopeInfo.
|
// TODO(adamk): We should construct this scope from the ScopeInfo.
|
||||||
Scope* scope =
|
Scope* scope =
|
||||||
NewScope(scope_, FUNCTION_SCOPE, FunctionKind::kArrowFunction);
|
NewScope(scope_, FUNCTION_SCOPE, FunctionKind::kArrowFunction);
|
||||||
@ -1115,8 +1127,8 @@ FunctionLiteral* Parser::ParseLazy(Isolate* isolate, ParseInfo* info,
|
|||||||
checkpoint.Restore(&formals.materialized_literals_count);
|
checkpoint.Restore(&formals.materialized_literals_count);
|
||||||
// Pass `accept_IN=true` to ParseArrowFunctionLiteral --- This should
|
// Pass `accept_IN=true` to ParseArrowFunctionLiteral --- This should
|
||||||
// not be observable, or else the preparser would have failed.
|
// not be observable, or else the preparser would have failed.
|
||||||
Expression* expression =
|
Expression* expression = ParseArrowFunctionLiteral(
|
||||||
ParseArrowFunctionLiteral(true, formals, formals_classifier, &ok);
|
true, formals, is_async, formals_classifier, &ok);
|
||||||
if (ok) {
|
if (ok) {
|
||||||
// Scanning must end at the same position that was recorded
|
// Scanning must end at the same position that was recorded
|
||||||
// previously. If not, parsing has been interrupted due to a stack
|
// previously. If not, parsing has been interrupted due to a stack
|
||||||
@ -1255,8 +1267,8 @@ Statement* Parser::ParseStatementListItem(bool* ok) {
|
|||||||
// StatementListItem:
|
// StatementListItem:
|
||||||
// Statement
|
// Statement
|
||||||
// Declaration
|
// Declaration
|
||||||
|
const Token::Value peeked = peek();
|
||||||
switch (peek()) {
|
switch (peeked) {
|
||||||
case Token::FUNCTION:
|
case Token::FUNCTION:
|
||||||
return ParseHoistableDeclaration(NULL, ok);
|
return ParseHoistableDeclaration(NULL, ok);
|
||||||
case Token::CLASS:
|
case Token::CLASS:
|
||||||
@ -1271,6 +1283,13 @@ Statement* Parser::ParseStatementListItem(bool* ok) {
|
|||||||
return ParseVariableStatement(kStatementListItem, NULL, ok);
|
return ParseVariableStatement(kStatementListItem, NULL, ok);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case Token::ASYNC:
|
||||||
|
if (allow_harmony_async_await() && PeekAhead() == Token::FUNCTION &&
|
||||||
|
!scanner()->HasAnyLineTerminatorAfterNext()) {
|
||||||
|
Consume(Token::ASYNC);
|
||||||
|
return ParseAsyncFunctionDeclaration(NULL, ok);
|
||||||
|
}
|
||||||
|
/* falls through */
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1560,7 +1579,10 @@ Statement* Parser::ParseExportDefault(bool* ok) {
|
|||||||
pos, FunctionLiteral::kDeclaration, language_mode(), CHECK_OK);
|
pos, FunctionLiteral::kDeclaration, language_mode(), CHECK_OK);
|
||||||
result = factory()->NewEmptyStatement(RelocInfo::kNoPosition);
|
result = factory()->NewEmptyStatement(RelocInfo::kNoPosition);
|
||||||
} else {
|
} else {
|
||||||
result = ParseHoistableDeclaration(pos, is_generator, &names, CHECK_OK);
|
result = ParseHoistableDeclaration(
|
||||||
|
pos, is_generator ? ParseFunctionFlags::kIsGenerator
|
||||||
|
: ParseFunctionFlags::kIsNormal,
|
||||||
|
&names, CHECK_OK);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1579,6 +1601,30 @@ Statement* Parser::ParseExportDefault(bool* ok) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Token::ASYNC:
|
||||||
|
if (allow_harmony_async_await() && PeekAhead() == Token::FUNCTION &&
|
||||||
|
!scanner()->HasAnyLineTerminatorAfterNext()) {
|
||||||
|
Consume(Token::ASYNC);
|
||||||
|
Consume(Token::FUNCTION);
|
||||||
|
int pos = position();
|
||||||
|
if (peek() == Token::LPAREN) {
|
||||||
|
// AsyncFunctionDeclaration[+Default] ::
|
||||||
|
// async [no LineTerminator here] function ( FormalParameters ) {
|
||||||
|
// AsyncFunctionBody
|
||||||
|
// }
|
||||||
|
default_export = ParseFunctionLiteral(
|
||||||
|
default_string, Scanner::Location::invalid(),
|
||||||
|
kSkipFunctionNameCheck, FunctionKind::kAsyncFunction, pos,
|
||||||
|
FunctionLiteral::kDeclaration, language_mode(), CHECK_OK);
|
||||||
|
result = factory()->NewEmptyStatement(RelocInfo::kNoPosition);
|
||||||
|
} else {
|
||||||
|
result = ParseHoistableDeclaration(pos, ParseFunctionFlags::kIsAsync,
|
||||||
|
&names, CHECK_OK);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* falls through */
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
int pos = peek_position();
|
int pos = peek_position();
|
||||||
ExpressionClassifier classifier(this);
|
ExpressionClassifier classifier(this);
|
||||||
@ -1703,6 +1749,14 @@ Statement* Parser::ParseExportDeclaration(bool* ok) {
|
|||||||
result = ParseVariableStatement(kStatementListItem, &names, CHECK_OK);
|
result = ParseVariableStatement(kStatementListItem, &names, CHECK_OK);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Token::ASYNC:
|
||||||
|
if (allow_harmony_async_await()) {
|
||||||
|
Consume(Token::ASYNC);
|
||||||
|
result = ParseAsyncFunctionDeclaration(&names, CHECK_OK);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* falls through */
|
||||||
|
|
||||||
default:
|
default:
|
||||||
*ok = false;
|
*ok = false;
|
||||||
ReportUnexpectedToken(scanner()->current_token());
|
ReportUnexpectedToken(scanner()->current_token());
|
||||||
@ -2062,13 +2116,29 @@ Statement* Parser::ParseHoistableDeclaration(
|
|||||||
ZoneList<const AstRawString*>* names, bool* ok) {
|
ZoneList<const AstRawString*>* names, bool* ok) {
|
||||||
Expect(Token::FUNCTION, CHECK_OK);
|
Expect(Token::FUNCTION, CHECK_OK);
|
||||||
int pos = position();
|
int pos = position();
|
||||||
bool is_generator = Check(Token::MUL);
|
ParseFunctionFlags flags = ParseFunctionFlags::kIsNormal;
|
||||||
return ParseHoistableDeclaration(pos, is_generator, names, ok);
|
if (Check(Token::MUL)) {
|
||||||
|
flags |= ParseFunctionFlags::kIsGenerator;
|
||||||
|
}
|
||||||
|
return ParseHoistableDeclaration(pos, flags, names, ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Statement* Parser::ParseAsyncFunctionDeclaration(
|
||||||
|
ZoneList<const AstRawString*>* names, bool* ok) {
|
||||||
|
DCHECK_EQ(scanner()->current_token(), Token::ASYNC);
|
||||||
|
int pos = position();
|
||||||
|
if (scanner()->HasAnyLineTerminatorBeforeNext()) {
|
||||||
|
*ok = false;
|
||||||
|
ReportUnexpectedToken(scanner()->current_token());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
Expect(Token::FUNCTION, CHECK_OK);
|
||||||
|
ParseFunctionFlags flags = ParseFunctionFlags::kIsAsync;
|
||||||
|
return ParseHoistableDeclaration(pos, flags, names, ok);
|
||||||
|
}
|
||||||
|
|
||||||
Statement* Parser::ParseHoistableDeclaration(
|
Statement* Parser::ParseHoistableDeclaration(
|
||||||
int pos, bool is_generator, ZoneList<const AstRawString*>* names,
|
int pos, ParseFunctionFlags flags, ZoneList<const AstRawString*>* names,
|
||||||
bool* ok) {
|
bool* ok) {
|
||||||
// FunctionDeclaration ::
|
// FunctionDeclaration ::
|
||||||
// 'function' Identifier '(' FormalParameters ')' '{' FunctionBody '}'
|
// 'function' Identifier '(' FormalParameters ')' '{' FunctionBody '}'
|
||||||
@ -2076,10 +2146,21 @@ Statement* Parser::ParseHoistableDeclaration(
|
|||||||
// 'function' '*' Identifier '(' FormalParameters ')' '{' FunctionBody '}'
|
// 'function' '*' Identifier '(' FormalParameters ')' '{' FunctionBody '}'
|
||||||
//
|
//
|
||||||
// 'function' and '*' (if present) have been consumed by the caller.
|
// 'function' and '*' (if present) have been consumed by the caller.
|
||||||
|
const bool is_generator = flags & ParseFunctionFlags::kIsGenerator;
|
||||||
|
const bool is_async = flags & ParseFunctionFlags::kIsAsync;
|
||||||
|
DCHECK(!is_generator || !is_async);
|
||||||
|
|
||||||
bool is_strict_reserved = false;
|
bool is_strict_reserved = false;
|
||||||
const AstRawString* name = ParseIdentifierOrStrictReservedWord(
|
const AstRawString* name = ParseIdentifierOrStrictReservedWord(
|
||||||
&is_strict_reserved, CHECK_OK);
|
&is_strict_reserved, CHECK_OK);
|
||||||
|
|
||||||
|
if (V8_UNLIKELY(is_async_function() && this->IsAwait(name))) {
|
||||||
|
ReportMessageAt(scanner()->location(),
|
||||||
|
MessageTemplate::kAwaitBindingIdentifier);
|
||||||
|
*ok = false;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
FuncNameInferrer::State fni_state(fni_);
|
FuncNameInferrer::State fni_state(fni_);
|
||||||
if (fni_ != NULL) fni_->PushEnclosingName(name);
|
if (fni_ != NULL) fni_->PushEnclosingName(name);
|
||||||
FunctionLiteral* fun = ParseFunctionLiteral(
|
FunctionLiteral* fun = ParseFunctionLiteral(
|
||||||
@ -2087,7 +2168,8 @@ Statement* Parser::ParseHoistableDeclaration(
|
|||||||
is_strict_reserved ? kFunctionNameIsStrictReserved
|
is_strict_reserved ? kFunctionNameIsStrictReserved
|
||||||
: kFunctionNameValidityUnknown,
|
: kFunctionNameValidityUnknown,
|
||||||
is_generator ? FunctionKind::kGeneratorFunction
|
is_generator ? FunctionKind::kGeneratorFunction
|
||||||
: FunctionKind::kNormalFunction,
|
: is_async ? FunctionKind::kAsyncFunction
|
||||||
|
: FunctionKind::kNormalFunction,
|
||||||
pos, FunctionLiteral::kDeclaration, language_mode(), CHECK_OK);
|
pos, FunctionLiteral::kDeclaration, language_mode(), CHECK_OK);
|
||||||
|
|
||||||
// Even if we're not at the top-level of the global or a function
|
// Even if we're not at the top-level of the global or a function
|
||||||
@ -2400,15 +2482,18 @@ static bool ContainsLabel(ZoneList<const AstRawString*>* labels,
|
|||||||
Statement* Parser::ParseFunctionDeclaration(bool* ok) {
|
Statement* Parser::ParseFunctionDeclaration(bool* ok) {
|
||||||
Consume(Token::FUNCTION);
|
Consume(Token::FUNCTION);
|
||||||
int pos = position();
|
int pos = position();
|
||||||
bool is_generator = Check(Token::MUL);
|
ParseFunctionFlags flags = ParseFunctionFlags::kIsNormal;
|
||||||
if (allow_harmony_restrictive_declarations() && is_generator) {
|
if (Check(Token::MUL)) {
|
||||||
ParserTraits::ReportMessageAt(
|
flags |= ParseFunctionFlags::kIsGenerator;
|
||||||
scanner()->location(),
|
if (allow_harmony_restrictive_declarations()) {
|
||||||
MessageTemplate::kGeneratorInLegacyContext);
|
ParserTraits::ReportMessageAt(scanner()->location(),
|
||||||
*ok = false;
|
MessageTemplate::kGeneratorInLegacyContext);
|
||||||
return nullptr;
|
*ok = false;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return ParseHoistableDeclaration(pos, is_generator, nullptr, CHECK_OK);
|
|
||||||
|
return ParseHoistableDeclaration(pos, flags, nullptr, CHECK_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
Statement* Parser::ParseExpressionOrLabelledStatement(
|
Statement* Parser::ParseExpressionOrLabelledStatement(
|
||||||
@ -4051,7 +4136,6 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
|||||||
CheckArityRestrictions(arity, kind, formals.has_rest, start_position,
|
CheckArityRestrictions(arity, kind, formals.has_rest, start_position,
|
||||||
formals_end_position, CHECK_OK);
|
formals_end_position, CHECK_OK);
|
||||||
Expect(Token::LBRACE, CHECK_OK);
|
Expect(Token::LBRACE, CHECK_OK);
|
||||||
|
|
||||||
// Don't include the rest parameter into the function's formal parameter
|
// Don't include the rest parameter into the function's formal parameter
|
||||||
// count (esp. the SharedFunctionInfo::internal_formal_parameter_count,
|
// count (esp. the SharedFunctionInfo::internal_formal_parameter_count,
|
||||||
// which says whether we need to create an arguments adaptor frame).
|
// which says whether we need to create an arguments adaptor frame).
|
||||||
@ -4207,6 +4291,36 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
|||||||
return function_literal;
|
return function_literal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Expression* Parser::ParseAsyncFunctionExpression(bool* ok) {
|
||||||
|
// AsyncFunctionDeclaration ::
|
||||||
|
// async [no LineTerminator here] function ( FormalParameters[Await] )
|
||||||
|
// { AsyncFunctionBody }
|
||||||
|
//
|
||||||
|
// async [no LineTerminator here] function BindingIdentifier[Await]
|
||||||
|
// ( FormalParameters[Await] ) { AsyncFunctionBody }
|
||||||
|
DCHECK_EQ(scanner()->current_token(), Token::ASYNC);
|
||||||
|
int pos = position();
|
||||||
|
Expect(Token::FUNCTION, CHECK_OK);
|
||||||
|
bool is_strict_reserved = false;
|
||||||
|
const AstRawString* name = nullptr;
|
||||||
|
FunctionLiteral::FunctionType type = FunctionLiteral::kAnonymousExpression;
|
||||||
|
|
||||||
|
if (peek_any_identifier()) {
|
||||||
|
type = FunctionLiteral::kNamedExpression;
|
||||||
|
name = ParseIdentifierOrStrictReservedWord(&is_strict_reserved, CHECK_OK);
|
||||||
|
if (this->IsAwait(name)) {
|
||||||
|
ReportMessageAt(scanner()->location(),
|
||||||
|
MessageTemplate::kAwaitBindingIdentifier);
|
||||||
|
*ok = false;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ParseFunctionLiteral(name, scanner()->location(),
|
||||||
|
is_strict_reserved ? kFunctionNameIsStrictReserved
|
||||||
|
: kFunctionNameValidityUnknown,
|
||||||
|
FunctionKind::kAsyncFunction, pos, type,
|
||||||
|
language_mode(), CHECK_OK);
|
||||||
|
}
|
||||||
|
|
||||||
void Parser::SkipLazyFunctionBody(int* materialized_literal_count,
|
void Parser::SkipLazyFunctionBody(int* materialized_literal_count,
|
||||||
int* expected_property_count, bool* ok,
|
int* expected_property_count, bool* ok,
|
||||||
@ -4606,6 +4720,7 @@ PreParser::PreParseResult Parser::ParseLazyFunctionBodyWithPreParser(
|
|||||||
SET_ALLOW(harmony_function_sent);
|
SET_ALLOW(harmony_function_sent);
|
||||||
SET_ALLOW(harmony_exponentiation_operator);
|
SET_ALLOW(harmony_exponentiation_operator);
|
||||||
SET_ALLOW(harmony_restrictive_declarations);
|
SET_ALLOW(harmony_restrictive_declarations);
|
||||||
|
SET_ALLOW(harmony_async_await);
|
||||||
#undef SET_ALLOW
|
#undef SET_ALLOW
|
||||||
}
|
}
|
||||||
PreParser::PreParseResult result = reusable_preparser_->PreParseLazyFunction(
|
PreParser::PreParseResult result = reusable_preparser_->PreParseLazyFunction(
|
||||||
@ -4676,13 +4791,12 @@ ClassLiteral* Parser::ParseClassLiteral(ExpressionClassifier* classifier,
|
|||||||
if (Check(Token::SEMICOLON)) continue;
|
if (Check(Token::SEMICOLON)) continue;
|
||||||
FuncNameInferrer::State fni_state(fni_);
|
FuncNameInferrer::State fni_state(fni_);
|
||||||
const bool in_class = true;
|
const bool in_class = true;
|
||||||
const bool is_static = false;
|
|
||||||
bool is_computed_name = false; // Classes do not care about computed
|
bool is_computed_name = false; // Classes do not care about computed
|
||||||
// property names here.
|
// property names here.
|
||||||
ExpressionClassifier property_classifier(this);
|
ExpressionClassifier property_classifier(this);
|
||||||
const AstRawString* property_name = nullptr;
|
const AstRawString* property_name = nullptr;
|
||||||
ObjectLiteral::Property* property = ParsePropertyDefinition(
|
ObjectLiteral::Property* property = ParsePropertyDefinition(
|
||||||
&checker, in_class, has_extends, is_static, &is_computed_name,
|
&checker, in_class, has_extends, MethodKind::Normal, &is_computed_name,
|
||||||
&has_seen_constructor, &property_classifier, &property_name, CHECK_OK);
|
&has_seen_constructor, &property_classifier, &property_name, CHECK_OK);
|
||||||
RewriteNonPattern(&property_classifier, CHECK_OK);
|
RewriteNonPattern(&property_classifier, CHECK_OK);
|
||||||
if (classifier != nullptr) {
|
if (classifier != nullptr) {
|
||||||
@ -5313,6 +5427,17 @@ void Parser::MarkCollectedTailCallExpressions() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Expression* ParserTraits::ExpressionListToExpression(
|
||||||
|
ZoneList<Expression*>* args) {
|
||||||
|
AstNodeFactory* factory = parser_->factory();
|
||||||
|
Expression* expr = args->at(0);
|
||||||
|
for (int i = 1; i < args->length(); ++i) {
|
||||||
|
expr = factory->NewBinaryOperation(Token::COMMA, expr, args->at(i),
|
||||||
|
expr->position());
|
||||||
|
}
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
|
||||||
void ParserTraits::RewriteDestructuringAssignments() {
|
void ParserTraits::RewriteDestructuringAssignments() {
|
||||||
parser_->RewriteDestructuringAssignments();
|
parser_->RewriteDestructuringAssignments();
|
||||||
}
|
}
|
||||||
@ -5333,6 +5458,11 @@ void ParserTraits::RewriteNonPattern(Type::ExpressionClassifier* classifier,
|
|||||||
parser_->RewriteNonPattern(classifier, ok);
|
parser_->RewriteNonPattern(classifier, ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Expression* ParserTraits::RewriteAwaitExpression(Expression* value, int pos) {
|
||||||
|
// TODO(caitp): Implement AsyncFunctionAwait()
|
||||||
|
// per tc39.github.io/ecmascript-asyncawait/#abstract-ops-async-function-await
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
Zone* ParserTraits::zone() const {
|
Zone* ParserTraits::zone() const {
|
||||||
return parser_->function_state_->scope()->zone();
|
return parser_->function_state_->scope()->zone();
|
||||||
|
@ -355,6 +355,7 @@ class ParserTraits {
|
|||||||
bool IsArguments(const AstRawString* identifier) const;
|
bool IsArguments(const AstRawString* identifier) const;
|
||||||
bool IsEvalOrArguments(const AstRawString* identifier) const;
|
bool IsEvalOrArguments(const AstRawString* identifier) const;
|
||||||
bool IsUndefined(const AstRawString* identifier) const;
|
bool IsUndefined(const AstRawString* identifier) const;
|
||||||
|
bool IsAwait(const AstRawString* identifier) const;
|
||||||
V8_INLINE bool IsFutureStrictReserved(const AstRawString* identifier) const;
|
V8_INLINE bool IsFutureStrictReserved(const AstRawString* identifier) const;
|
||||||
|
|
||||||
// Returns true if the expression is of type "this.foo".
|
// Returns true if the expression is of type "this.foo".
|
||||||
@ -554,6 +555,8 @@ class ParserTraits {
|
|||||||
const Scanner::Location& params_loc,
|
const Scanner::Location& params_loc,
|
||||||
Scanner::Location* duplicate_loc, bool* ok);
|
Scanner::Location* duplicate_loc, bool* ok);
|
||||||
|
|
||||||
|
V8_INLINE Expression* ParseAsyncFunctionExpression(bool* ok);
|
||||||
|
|
||||||
V8_INLINE DoExpression* ParseDoExpression(bool* ok);
|
V8_INLINE DoExpression* ParseDoExpression(bool* ok);
|
||||||
|
|
||||||
void ReindexLiterals(const ParserFormalParameters& parameters);
|
void ReindexLiterals(const ParserFormalParameters& parameters);
|
||||||
@ -637,6 +640,8 @@ class ParserTraits {
|
|||||||
ZoneList<v8::internal::Expression*>* args,
|
ZoneList<v8::internal::Expression*>* args,
|
||||||
int pos);
|
int pos);
|
||||||
|
|
||||||
|
Expression* ExpressionListToExpression(ZoneList<Expression*>* args);
|
||||||
|
|
||||||
// Rewrite all DestructuringAssignments in the current FunctionState.
|
// Rewrite all DestructuringAssignments in the current FunctionState.
|
||||||
V8_INLINE void RewriteDestructuringAssignments();
|
V8_INLINE void RewriteDestructuringAssignments();
|
||||||
|
|
||||||
@ -645,6 +650,8 @@ class ParserTraits {
|
|||||||
V8_INLINE Expression* RewriteAssignExponentiation(Expression* left,
|
V8_INLINE Expression* RewriteAssignExponentiation(Expression* left,
|
||||||
Expression* right, int pos);
|
Expression* right, int pos);
|
||||||
|
|
||||||
|
V8_INLINE Expression* RewriteAwaitExpression(Expression* value, int pos);
|
||||||
|
|
||||||
V8_INLINE void QueueDestructuringAssignmentForRewriting(
|
V8_INLINE void QueueDestructuringAssignmentForRewriting(
|
||||||
Expression* assignment);
|
Expression* assignment);
|
||||||
V8_INLINE void QueueNonPatternForRewriting(Expression* expr);
|
V8_INLINE void QueueNonPatternForRewriting(Expression* expr);
|
||||||
@ -772,7 +779,13 @@ class Parser : public ParserBase<ParserTraits> {
|
|||||||
Statement* ParseFunctionDeclaration(bool* ok);
|
Statement* ParseFunctionDeclaration(bool* ok);
|
||||||
Statement* ParseHoistableDeclaration(ZoneList<const AstRawString*>* names,
|
Statement* ParseHoistableDeclaration(ZoneList<const AstRawString*>* names,
|
||||||
bool* ok);
|
bool* ok);
|
||||||
Statement* ParseHoistableDeclaration(int pos, bool is_generator,
|
Statement* ParseHoistableDeclaration(int pos, ParseFunctionFlags flags,
|
||||||
|
ZoneList<const AstRawString*>* names,
|
||||||
|
bool* ok);
|
||||||
|
Statement* ParseAsyncFunctionDeclaration(ZoneList<const AstRawString*>* names,
|
||||||
|
bool* ok);
|
||||||
|
Expression* ParseAsyncFunctionExpression(bool* ok);
|
||||||
|
Statement* ParseFunctionDeclaration(int pos, bool is_generator,
|
||||||
ZoneList<const AstRawString*>* names,
|
ZoneList<const AstRawString*>* names,
|
||||||
bool* ok);
|
bool* ok);
|
||||||
Statement* ParseClassDeclaration(ZoneList<const AstRawString*>* names,
|
Statement* ParseClassDeclaration(ZoneList<const AstRawString*>* names,
|
||||||
@ -1255,6 +1268,9 @@ void ParserTraits::AddParameterInitializationBlock(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Expression* ParserTraits::ParseAsyncFunctionExpression(bool* ok) {
|
||||||
|
return parser_->ParseAsyncFunctionExpression(ok);
|
||||||
|
}
|
||||||
|
|
||||||
DoExpression* ParserTraits::ParseDoExpression(bool* ok) {
|
DoExpression* ParserTraits::ParseDoExpression(bool* ok) {
|
||||||
return parser_->ParseDoExpression(ok);
|
return parser_->ParseDoExpression(ok);
|
||||||
|
@ -51,6 +51,8 @@ PreParserIdentifier PreParserTraits::GetSymbol(Scanner* scanner) {
|
|||||||
return PreParserIdentifier::Static();
|
return PreParserIdentifier::Static();
|
||||||
} else if (scanner->current_token() == Token::YIELD) {
|
} else if (scanner->current_token() == Token::YIELD) {
|
||||||
return PreParserIdentifier::Yield();
|
return PreParserIdentifier::Yield();
|
||||||
|
} else if (scanner->current_token() == Token::ASYNC) {
|
||||||
|
return PreParserIdentifier::Async();
|
||||||
}
|
}
|
||||||
if (scanner->UnescapedLiteralMatches("eval", 4)) {
|
if (scanner->UnescapedLiteralMatches("eval", 4)) {
|
||||||
return PreParserIdentifier::Eval();
|
return PreParserIdentifier::Eval();
|
||||||
@ -193,6 +195,13 @@ PreParser::Statement PreParser::ParseStatementListItem(bool* ok) {
|
|||||||
return ParseVariableStatement(kStatementListItem, ok);
|
return ParseVariableStatement(kStatementListItem, ok);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case Token::ASYNC:
|
||||||
|
if (allow_harmony_async_await() && PeekAhead() == Token::FUNCTION &&
|
||||||
|
!scanner()->HasAnyLineTerminatorAfterNext()) {
|
||||||
|
Consume(Token::ASYNC);
|
||||||
|
return ParseAsyncFunctionDeclaration(ok);
|
||||||
|
}
|
||||||
|
/* falls through */
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -381,22 +390,44 @@ PreParser::Statement PreParser::ParseSubStatement(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PreParser::Statement PreParser::ParseHoistableDeclaration(
|
PreParser::Statement PreParser::ParseHoistableDeclaration(
|
||||||
int pos, bool is_generator, bool* ok) {
|
int pos, ParseFunctionFlags flags, bool* ok) {
|
||||||
|
const bool is_generator = flags & ParseFunctionFlags::kIsGenerator;
|
||||||
|
const bool is_async = flags & ParseFunctionFlags::kIsAsync;
|
||||||
|
DCHECK(!is_generator || !is_async);
|
||||||
|
|
||||||
bool is_strict_reserved = false;
|
bool is_strict_reserved = false;
|
||||||
Identifier name = ParseIdentifierOrStrictReservedWord(
|
Identifier name = ParseIdentifierOrStrictReservedWord(
|
||||||
&is_strict_reserved, CHECK_OK);
|
&is_strict_reserved, CHECK_OK);
|
||||||
|
|
||||||
|
if (V8_UNLIKELY(is_async_function() && this->IsAwait(name))) {
|
||||||
|
ReportMessageAt(scanner()->location(),
|
||||||
|
MessageTemplate::kAwaitBindingIdentifier);
|
||||||
|
*ok = false;
|
||||||
|
return Statement::Default();
|
||||||
|
}
|
||||||
|
|
||||||
ParseFunctionLiteral(name, scanner()->location(),
|
ParseFunctionLiteral(name, scanner()->location(),
|
||||||
is_strict_reserved ? kFunctionNameIsStrictReserved
|
is_strict_reserved ? kFunctionNameIsStrictReserved
|
||||||
: kFunctionNameValidityUnknown,
|
: kFunctionNameValidityUnknown,
|
||||||
is_generator ? FunctionKind::kGeneratorFunction
|
is_generator ? FunctionKind::kGeneratorFunction
|
||||||
: FunctionKind::kNormalFunction,
|
: is_async ? FunctionKind::kAsyncFunction
|
||||||
|
: FunctionKind::kNormalFunction,
|
||||||
pos, FunctionLiteral::kDeclaration, language_mode(),
|
pos, FunctionLiteral::kDeclaration, language_mode(),
|
||||||
CHECK_OK);
|
CHECK_OK);
|
||||||
return Statement::FunctionDeclaration();
|
return Statement::FunctionDeclaration();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PreParser::Statement PreParser::ParseAsyncFunctionDeclaration(bool* ok) {
|
||||||
|
// AsyncFunctionDeclaration ::
|
||||||
|
// async [no LineTerminator here] function BindingIdentifier[Await]
|
||||||
|
// ( FormalParameters[Await] ) { AsyncFunctionBody }
|
||||||
|
DCHECK_EQ(scanner()->current_token(), Token::ASYNC);
|
||||||
|
int pos = position();
|
||||||
|
Expect(Token::FUNCTION, CHECK_OK);
|
||||||
|
ParseFunctionFlags flags = ParseFunctionFlags::kIsAsync;
|
||||||
|
return ParseHoistableDeclaration(pos, flags, ok);
|
||||||
|
}
|
||||||
|
|
||||||
PreParser::Statement PreParser::ParseHoistableDeclaration(bool* ok) {
|
PreParser::Statement PreParser::ParseHoistableDeclaration(bool* ok) {
|
||||||
// FunctionDeclaration ::
|
// FunctionDeclaration ::
|
||||||
@ -404,10 +435,14 @@ PreParser::Statement PreParser::ParseHoistableDeclaration(bool* ok) {
|
|||||||
// GeneratorDeclaration ::
|
// GeneratorDeclaration ::
|
||||||
// 'function' '*' Identifier '(' FormalParameterListopt ')'
|
// 'function' '*' Identifier '(' FormalParameterListopt ')'
|
||||||
// '{' FunctionBody '}'
|
// '{' FunctionBody '}'
|
||||||
|
|
||||||
Expect(Token::FUNCTION, CHECK_OK);
|
Expect(Token::FUNCTION, CHECK_OK);
|
||||||
int pos = position();
|
int pos = position();
|
||||||
bool is_generator = Check(Token::MUL);
|
ParseFunctionFlags flags = ParseFunctionFlags::kIsNormal;
|
||||||
return ParseHoistableDeclaration(pos, is_generator, CHECK_OK);
|
if (Check(Token::MUL)) {
|
||||||
|
flags |= ParseFunctionFlags::kIsGenerator;
|
||||||
|
}
|
||||||
|
return ParseHoistableDeclaration(pos, flags, ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -566,15 +601,17 @@ PreParser::Statement PreParser::ParseVariableDeclarations(
|
|||||||
PreParser::Statement PreParser::ParseFunctionDeclaration(bool* ok) {
|
PreParser::Statement PreParser::ParseFunctionDeclaration(bool* ok) {
|
||||||
Consume(Token::FUNCTION);
|
Consume(Token::FUNCTION);
|
||||||
int pos = position();
|
int pos = position();
|
||||||
bool is_generator = Check(Token::MUL);
|
ParseFunctionFlags flags = ParseFunctionFlags::kIsNormal;
|
||||||
if (allow_harmony_restrictive_declarations() && is_generator) {
|
if (Check(Token::MUL)) {
|
||||||
PreParserTraits::ReportMessageAt(
|
flags |= ParseFunctionFlags::kIsGenerator;
|
||||||
scanner()->location(),
|
if (allow_harmony_restrictive_declarations()) {
|
||||||
MessageTemplate::kGeneratorInLegacyContext);
|
PreParserTraits::ReportMessageAt(
|
||||||
*ok = false;
|
scanner()->location(), MessageTemplate::kGeneratorInLegacyContext);
|
||||||
return Statement::Default();
|
*ok = false;
|
||||||
|
return Statement::Default();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return ParseHoistableDeclaration(pos, is_generator, ok);
|
return ParseHoistableDeclaration(pos, flags, ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
PreParser::Statement PreParser::ParseExpressionOrLabelledStatement(
|
PreParser::Statement PreParser::ParseExpressionOrLabelledStatement(
|
||||||
@ -1111,6 +1148,37 @@ PreParser::Expression PreParser::ParseFunctionLiteral(
|
|||||||
return Expression::Default();
|
return Expression::Default();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PreParser::Expression PreParser::ParseAsyncFunctionExpression(bool* ok) {
|
||||||
|
// AsyncFunctionDeclaration ::
|
||||||
|
// async [no LineTerminator here] function ( FormalParameters[Await] )
|
||||||
|
// { AsyncFunctionBody }
|
||||||
|
//
|
||||||
|
// async [no LineTerminator here] function BindingIdentifier[Await]
|
||||||
|
// ( FormalParameters[Await] ) { AsyncFunctionBody }
|
||||||
|
int pos = position();
|
||||||
|
Expect(Token::FUNCTION, CHECK_OK);
|
||||||
|
bool is_strict_reserved = false;
|
||||||
|
Identifier name;
|
||||||
|
FunctionLiteral::FunctionType type = FunctionLiteral::kAnonymousExpression;
|
||||||
|
|
||||||
|
if (peek_any_identifier()) {
|
||||||
|
type = FunctionLiteral::kNamedExpression;
|
||||||
|
name = ParseIdentifierOrStrictReservedWord(&is_strict_reserved, CHECK_OK);
|
||||||
|
if (this->IsAwait(name)) {
|
||||||
|
ReportMessageAt(scanner()->location(),
|
||||||
|
MessageTemplate::kAwaitBindingIdentifier);
|
||||||
|
*ok = false;
|
||||||
|
return Expression::Default();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ParseFunctionLiteral(name, scanner()->location(),
|
||||||
|
is_strict_reserved ? kFunctionNameIsStrictReserved
|
||||||
|
: kFunctionNameValidityUnknown,
|
||||||
|
FunctionKind::kAsyncFunction, pos, type, language_mode(),
|
||||||
|
CHECK_OK);
|
||||||
|
return Expression::Default();
|
||||||
|
}
|
||||||
|
|
||||||
void PreParser::ParseLazyFunctionLiteralBody(bool* ok,
|
void PreParser::ParseLazyFunctionLiteralBody(bool* ok,
|
||||||
Scanner::BookmarkScope* bookmark) {
|
Scanner::BookmarkScope* bookmark) {
|
||||||
@ -1172,12 +1240,11 @@ PreParserExpression PreParser::ParseClassLiteral(
|
|||||||
while (peek() != Token::RBRACE) {
|
while (peek() != Token::RBRACE) {
|
||||||
if (Check(Token::SEMICOLON)) continue;
|
if (Check(Token::SEMICOLON)) continue;
|
||||||
const bool in_class = true;
|
const bool in_class = true;
|
||||||
const bool is_static = false;
|
|
||||||
bool is_computed_name = false; // Classes do not care about computed
|
bool is_computed_name = false; // Classes do not care about computed
|
||||||
// property names here.
|
// property names here.
|
||||||
Identifier name;
|
Identifier name;
|
||||||
ExpressionClassifier property_classifier(this);
|
ExpressionClassifier property_classifier(this);
|
||||||
ParsePropertyDefinition(&checker, in_class, has_extends, is_static,
|
ParsePropertyDefinition(&checker, in_class, has_extends, MethodKind::Normal,
|
||||||
&is_computed_name, &has_seen_constructor,
|
&is_computed_name, &has_seen_constructor,
|
||||||
&property_classifier, &name, CHECK_OK);
|
&property_classifier, &name, CHECK_OK);
|
||||||
ValidateExpression(&property_classifier, CHECK_OK);
|
ValidateExpression(&property_classifier, CHECK_OK);
|
||||||
|
@ -61,6 +61,9 @@ class PreParserIdentifier {
|
|||||||
static PreParserIdentifier Await() {
|
static PreParserIdentifier Await() {
|
||||||
return PreParserIdentifier(kAwaitIdentifier);
|
return PreParserIdentifier(kAwaitIdentifier);
|
||||||
}
|
}
|
||||||
|
static PreParserIdentifier Async() {
|
||||||
|
return PreParserIdentifier(kAsyncIdentifier);
|
||||||
|
}
|
||||||
bool IsEval() const { return type_ == kEvalIdentifier; }
|
bool IsEval() const { return type_ == kEvalIdentifier; }
|
||||||
bool IsArguments() const { return type_ == kArgumentsIdentifier; }
|
bool IsArguments() const { return type_ == kArgumentsIdentifier; }
|
||||||
bool IsEvalOrArguments() const { return IsEval() || IsArguments(); }
|
bool IsEvalOrArguments() const { return IsEval() || IsArguments(); }
|
||||||
@ -72,6 +75,7 @@ class PreParserIdentifier {
|
|||||||
bool IsConstructor() const { return type_ == kConstructorIdentifier; }
|
bool IsConstructor() const { return type_ == kConstructorIdentifier; }
|
||||||
bool IsEnum() const { return type_ == kEnumIdentifier; }
|
bool IsEnum() const { return type_ == kEnumIdentifier; }
|
||||||
bool IsAwait() const { return type_ == kAwaitIdentifier; }
|
bool IsAwait() const { return type_ == kAwaitIdentifier; }
|
||||||
|
bool IsAsync() const { return type_ == kAsyncIdentifier; }
|
||||||
bool IsFutureStrictReserved() const {
|
bool IsFutureStrictReserved() const {
|
||||||
return type_ == kFutureStrictReservedIdentifier ||
|
return type_ == kFutureStrictReservedIdentifier ||
|
||||||
type_ == kLetIdentifier || type_ == kStaticIdentifier ||
|
type_ == kLetIdentifier || type_ == kStaticIdentifier ||
|
||||||
@ -100,7 +104,8 @@ class PreParserIdentifier {
|
|||||||
kPrototypeIdentifier,
|
kPrototypeIdentifier,
|
||||||
kConstructorIdentifier,
|
kConstructorIdentifier,
|
||||||
kEnumIdentifier,
|
kEnumIdentifier,
|
||||||
kAwaitIdentifier
|
kAwaitIdentifier,
|
||||||
|
kAsyncIdentifier
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit PreParserIdentifier(Type type) : type_(type) {}
|
explicit PreParserIdentifier(Type type) : type_(type) {}
|
||||||
@ -622,6 +627,14 @@ class PreParserTraits {
|
|||||||
return identifier.IsArguments();
|
return identifier.IsArguments();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool IsAwait(PreParserIdentifier identifier) {
|
||||||
|
return identifier.IsAwait();
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool IsAsync(PreParserIdentifier identifier) {
|
||||||
|
return identifier.IsAsync();
|
||||||
|
}
|
||||||
|
|
||||||
static bool IsEvalOrArguments(PreParserIdentifier identifier) {
|
static bool IsEvalOrArguments(PreParserIdentifier identifier) {
|
||||||
return identifier.IsEvalOrArguments();
|
return identifier.IsEvalOrArguments();
|
||||||
}
|
}
|
||||||
@ -865,6 +878,8 @@ class PreParserTraits {
|
|||||||
PreParserExpression expression, const Scanner::Location& params_loc,
|
PreParserExpression expression, const Scanner::Location& params_loc,
|
||||||
Scanner::Location* duplicate_loc, bool* ok);
|
Scanner::Location* duplicate_loc, bool* ok);
|
||||||
|
|
||||||
|
V8_INLINE PreParserExpression ParseAsyncFunctionExpression(bool* ok);
|
||||||
|
|
||||||
void ReindexLiterals(const PreParserFormalParameters& paramaters) {}
|
void ReindexLiterals(const PreParserFormalParameters& paramaters) {}
|
||||||
|
|
||||||
struct TemplateLiteralState {};
|
struct TemplateLiteralState {};
|
||||||
@ -937,6 +952,11 @@ class PreParserTraits {
|
|||||||
PreParserExpressionList args,
|
PreParserExpressionList args,
|
||||||
int pos);
|
int pos);
|
||||||
|
|
||||||
|
inline PreParserExpression ExpressionListToExpression(
|
||||||
|
PreParserExpressionList args) {
|
||||||
|
return PreParserExpression::Default();
|
||||||
|
}
|
||||||
|
|
||||||
inline void RewriteDestructuringAssignments() {}
|
inline void RewriteDestructuringAssignments() {}
|
||||||
|
|
||||||
inline PreParserExpression RewriteExponentiation(PreParserExpression left,
|
inline PreParserExpression RewriteExponentiation(PreParserExpression left,
|
||||||
@ -960,6 +980,9 @@ class PreParserTraits {
|
|||||||
inline void RewriteNonPattern(Type::ExpressionClassifier* classifier,
|
inline void RewriteNonPattern(Type::ExpressionClassifier* classifier,
|
||||||
bool* ok);
|
bool* ok);
|
||||||
|
|
||||||
|
inline PreParserExpression RewriteAwaitExpression(PreParserExpression value,
|
||||||
|
int pos);
|
||||||
|
|
||||||
V8_INLINE Zone* zone() const;
|
V8_INLINE Zone* zone() const;
|
||||||
V8_INLINE ZoneList<PreParserExpression>* GetNonPatternList() const;
|
V8_INLINE ZoneList<PreParserExpression>* GetNonPatternList() const;
|
||||||
|
|
||||||
@ -1076,8 +1099,11 @@ class PreParser : public ParserBase<PreParserTraits> {
|
|||||||
bool* ok);
|
bool* ok);
|
||||||
Statement ParseScopedStatement(bool legacy, bool* ok);
|
Statement ParseScopedStatement(bool legacy, bool* ok);
|
||||||
Statement ParseHoistableDeclaration(bool* ok);
|
Statement ParseHoistableDeclaration(bool* ok);
|
||||||
Statement ParseHoistableDeclaration(int pos, bool is_generator, bool* ok);
|
Statement ParseHoistableDeclaration(int pos, ParseFunctionFlags flags,
|
||||||
|
bool* ok);
|
||||||
Statement ParseFunctionDeclaration(bool* ok);
|
Statement ParseFunctionDeclaration(bool* ok);
|
||||||
|
Statement ParseAsyncFunctionDeclaration(bool* ok);
|
||||||
|
Expression ParseAsyncFunctionExpression(bool* ok);
|
||||||
Statement ParseClassDeclaration(bool* ok);
|
Statement ParseClassDeclaration(bool* ok);
|
||||||
Statement ParseBlock(bool* ok);
|
Statement ParseBlock(bool* ok);
|
||||||
Statement ParseVariableStatement(VariableDeclarationContext var_context,
|
Statement ParseVariableStatement(VariableDeclarationContext var_context,
|
||||||
@ -1166,6 +1192,9 @@ void PreParserTraits::ParseArrowFunctionFormalParameterList(
|
|||||||
// lists that are too long.
|
// lists that are too long.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PreParserExpression PreParserTraits::ParseAsyncFunctionExpression(bool* ok) {
|
||||||
|
return pre_parser_->ParseAsyncFunctionExpression(ok);
|
||||||
|
}
|
||||||
|
|
||||||
PreParserExpression PreParserTraits::ParseDoExpression(bool* ok) {
|
PreParserExpression PreParserTraits::ParseDoExpression(bool* ok) {
|
||||||
return pre_parser_->ParseDoExpression(ok);
|
return pre_parser_->ParseDoExpression(ok);
|
||||||
@ -1177,6 +1206,10 @@ void PreParserTraits::RewriteNonPattern(Type::ExpressionClassifier* classifier,
|
|||||||
pre_parser_->ValidateExpression(classifier, ok);
|
pre_parser_->ValidateExpression(classifier, ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PreParserExpression PreParserTraits::RewriteAwaitExpression(
|
||||||
|
PreParserExpression value, int pos) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
Zone* PreParserTraits::zone() const {
|
Zone* PreParserTraits::zone() const {
|
||||||
return pre_parser_->function_state_->scope()->zone();
|
return pre_parser_->function_state_->scope()->zone();
|
||||||
|
@ -249,6 +249,7 @@ Token::Value Scanner::Next() {
|
|||||||
if (V8_UNLIKELY(next_next_.token != Token::UNINITIALIZED)) {
|
if (V8_UNLIKELY(next_next_.token != Token::UNINITIALIZED)) {
|
||||||
next_ = next_next_;
|
next_ = next_next_;
|
||||||
next_next_.token = Token::UNINITIALIZED;
|
next_next_.token = Token::UNINITIALIZED;
|
||||||
|
has_line_terminator_before_next_ = has_line_terminator_after_next_;
|
||||||
return current_.token;
|
return current_.token;
|
||||||
}
|
}
|
||||||
has_line_terminator_before_next_ = false;
|
has_line_terminator_before_next_ = false;
|
||||||
@ -274,7 +275,12 @@ Token::Value Scanner::PeekAhead() {
|
|||||||
return next_next_.token;
|
return next_next_.token;
|
||||||
}
|
}
|
||||||
TokenDesc prev = current_;
|
TokenDesc prev = current_;
|
||||||
|
bool has_line_terminator_before_next =
|
||||||
|
has_line_terminator_before_next_ || has_multiline_comment_before_next_;
|
||||||
Next();
|
Next();
|
||||||
|
has_line_terminator_after_next_ =
|
||||||
|
has_line_terminator_before_next_ || has_multiline_comment_before_next_;
|
||||||
|
has_line_terminator_before_next_ = has_line_terminator_before_next;
|
||||||
Token::Value ret = next_.token;
|
Token::Value ret = next_.token;
|
||||||
next_next_ = next_;
|
next_next_ = next_;
|
||||||
next_ = current_;
|
next_ = current_;
|
||||||
@ -1136,6 +1142,7 @@ uc32 Scanner::ScanUnicodeEscape() {
|
|||||||
|
|
||||||
#define KEYWORDS(KEYWORD_GROUP, KEYWORD) \
|
#define KEYWORDS(KEYWORD_GROUP, KEYWORD) \
|
||||||
KEYWORD_GROUP('a') \
|
KEYWORD_GROUP('a') \
|
||||||
|
KEYWORD("async", Token::ASYNC) \
|
||||||
KEYWORD("await", Token::AWAIT) \
|
KEYWORD("await", Token::AWAIT) \
|
||||||
KEYWORD_GROUP('b') \
|
KEYWORD_GROUP('b') \
|
||||||
KEYWORD("break", Token::BREAK) \
|
KEYWORD("break", Token::BREAK) \
|
||||||
|
@ -442,6 +442,12 @@ class Scanner {
|
|||||||
has_multiline_comment_before_next_;
|
has_multiline_comment_before_next_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool HasAnyLineTerminatorAfterNext() {
|
||||||
|
Token::Value ensure_next_next = PeekAhead();
|
||||||
|
USE(ensure_next_next);
|
||||||
|
return has_line_terminator_after_next_;
|
||||||
|
}
|
||||||
|
|
||||||
// Scans the input as a regular expression pattern, previous
|
// Scans the input as a regular expression pattern, previous
|
||||||
// character(s) must be /(=). Returns true if a pattern is scanned.
|
// character(s) must be /(=). Returns true if a pattern is scanned.
|
||||||
bool ScanRegExpPattern(bool seen_equal);
|
bool ScanRegExpPattern(bool seen_equal);
|
||||||
@ -786,6 +792,7 @@ class Scanner {
|
|||||||
// Whether there is a multi-line comment that contains a
|
// Whether there is a multi-line comment that contains a
|
||||||
// line-terminator after the current token, and before the next.
|
// line-terminator after the current token, and before the next.
|
||||||
bool has_multiline_comment_before_next_;
|
bool has_multiline_comment_before_next_;
|
||||||
|
bool has_line_terminator_after_next_;
|
||||||
|
|
||||||
// Whether this scanner encountered an HTML comment.
|
// Whether this scanner encountered an HTML comment.
|
||||||
bool found_html_comment_;
|
bool found_html_comment_;
|
||||||
|
@ -149,6 +149,7 @@ namespace internal {
|
|||||||
\
|
\
|
||||||
/* Future reserved words (ECMA-262, section 7.6.1.2). */ \
|
/* Future reserved words (ECMA-262, section 7.6.1.2). */ \
|
||||||
T(FUTURE_STRICT_RESERVED_WORD, NULL, 0) \
|
T(FUTURE_STRICT_RESERVED_WORD, NULL, 0) \
|
||||||
|
K(ASYNC, "async", 0) \
|
||||||
/* `await` is a reserved word in module code only */ \
|
/* `await` is a reserved word in module code only */ \
|
||||||
K(AWAIT, "await", 0) \
|
K(AWAIT, "await", 0) \
|
||||||
K(CLASS, "class", 0) \
|
K(CLASS, "class", 0) \
|
||||||
@ -201,6 +202,7 @@ class Token {
|
|||||||
bool is_generator, bool is_module) {
|
bool is_generator, bool is_module) {
|
||||||
switch (tok) {
|
switch (tok) {
|
||||||
case IDENTIFIER:
|
case IDENTIFIER:
|
||||||
|
case ASYNC:
|
||||||
return true;
|
return true;
|
||||||
case ESCAPED_STRICT_RESERVED_WORD:
|
case ESCAPED_STRICT_RESERVED_WORD:
|
||||||
case FUTURE_STRICT_RESERVED_WORD:
|
case FUTURE_STRICT_RESERVED_WORD:
|
||||||
|
@ -1508,7 +1508,8 @@ enum ParserFlag {
|
|||||||
kAllowHarmonyFunctionSent,
|
kAllowHarmonyFunctionSent,
|
||||||
kAllowHarmonyRestrictiveDeclarations,
|
kAllowHarmonyRestrictiveDeclarations,
|
||||||
kAllowHarmonyExponentiationOperator,
|
kAllowHarmonyExponentiationOperator,
|
||||||
kAllowHarmonyForIn
|
kAllowHarmonyForIn,
|
||||||
|
kAllowHarmonyAsyncAwait
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ParserSyncTestResult {
|
enum ParserSyncTestResult {
|
||||||
@ -1529,6 +1530,8 @@ void SetParserFlags(i::ParserBase<Traits>* parser,
|
|||||||
parser->set_allow_harmony_exponentiation_operator(
|
parser->set_allow_harmony_exponentiation_operator(
|
||||||
flags.Contains(kAllowHarmonyExponentiationOperator));
|
flags.Contains(kAllowHarmonyExponentiationOperator));
|
||||||
parser->set_allow_harmony_for_in(flags.Contains(kAllowHarmonyForIn));
|
parser->set_allow_harmony_for_in(flags.Contains(kAllowHarmonyForIn));
|
||||||
|
parser->set_allow_harmony_async_await(
|
||||||
|
flags.Contains(kAllowHarmonyAsyncAwait));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -7448,6 +7451,234 @@ TEST(ExponentiationOperatorErrors) {
|
|||||||
arraysize(always_flags));
|
arraysize(always_flags));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(AsyncAwait) {
|
||||||
|
// clang-format off
|
||||||
|
const char* context_data[][2] = {
|
||||||
|
{ "'use strict';", "" },
|
||||||
|
{ "", "" },
|
||||||
|
{ NULL, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* data[] = {
|
||||||
|
"var asyncFn = async function() { await 1; };",
|
||||||
|
"var asyncFn = async function withName() { await 1; };",
|
||||||
|
"var asyncFn = async () => await 'test';",
|
||||||
|
"var asyncFn = async x => await x + 'test';",
|
||||||
|
"async function asyncFn() { await 1; }",
|
||||||
|
"var O = { async method() { await 1; } }",
|
||||||
|
"var O = { async ['meth' + 'od']() { await 1; } }",
|
||||||
|
"var O = { async 'method'() { await 1; } }",
|
||||||
|
"var O = { async 0() { await 1; } }",
|
||||||
|
"async function await() {}",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
static const ParserFlag always_flags[] = {kAllowHarmonyAsyncAwait};
|
||||||
|
RunParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags,
|
||||||
|
arraysize(always_flags));
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
const char* async_body_context_data[][2] = {
|
||||||
|
{ "async function f() {", "}" },
|
||||||
|
{ "var f = async function() {", "}" },
|
||||||
|
{ "var f = async() => {", "}" },
|
||||||
|
{ "var O = { async method() {", "} }" },
|
||||||
|
{ "'use strict'; async function f() {", "}" },
|
||||||
|
{ "'use strict'; var f = async function() {", "}" },
|
||||||
|
{ "'use strict'; var f = async() => {", "}" },
|
||||||
|
{ "'use strict'; var O = { async method() {", "} }" },
|
||||||
|
{ NULL, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* body_context_data[][2] = {
|
||||||
|
{ "function f() {", "}" },
|
||||||
|
{ "function* g() {", "}" },
|
||||||
|
{ "var f = function() {", "}" },
|
||||||
|
{ "var g = function*() {", "}" },
|
||||||
|
{ "var O = { method() {", "} }" },
|
||||||
|
{ "var O = { *method() {", "} }" },
|
||||||
|
{ "var f = () => {", "}" },
|
||||||
|
{ "'use strict'; function f() {", "}" },
|
||||||
|
{ "'use strict'; function* g() {", "}" },
|
||||||
|
{ "'use strict'; var f = function() {", "}" },
|
||||||
|
{ "'use strict'; var g = function*() {", "}" },
|
||||||
|
{ "'use strict'; var O = { method() {", "} }" },
|
||||||
|
{ "'use strict'; var O = { *method() {", "} }" },
|
||||||
|
{ "'use strict'; var f = () => {", "}" },
|
||||||
|
{ NULL, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* body_data[] = {
|
||||||
|
"var async = 1; return async;",
|
||||||
|
"let async = 1; return async;",
|
||||||
|
"const async = 1; return async;",
|
||||||
|
"function async() {} return async();",
|
||||||
|
"var async = async => async; return async();",
|
||||||
|
"function foo() { var await = 1; return await; }",
|
||||||
|
"function foo(await) { return await; }",
|
||||||
|
"function* foo() { var await = 1; return await; }",
|
||||||
|
"function* foo(await) { return await; }",
|
||||||
|
"var f = (await) => await;",
|
||||||
|
"var f = () => { var await = 1; return await; }",
|
||||||
|
"var O = { method() { var await = 1; return await; } };",
|
||||||
|
"var O = { method(await) { return await; } };",
|
||||||
|
"var O = { *method() { var await = 1; return await; } };",
|
||||||
|
"var O = { *method(await) { return await; } };",
|
||||||
|
|
||||||
|
"(function await() {})",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
RunParserSyncTest(async_body_context_data, body_data, kSuccess, NULL, 0,
|
||||||
|
always_flags, arraysize(always_flags));
|
||||||
|
RunParserSyncTest(body_context_data, body_data, kSuccess, NULL, 0,
|
||||||
|
always_flags, arraysize(always_flags));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(AsyncAwaitErrors) {
|
||||||
|
// clang-format off
|
||||||
|
const char* context_data[][2] = {
|
||||||
|
{ "'use strict';", "" },
|
||||||
|
{ "", "" },
|
||||||
|
{ NULL, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* strict_context_data[][2] = {
|
||||||
|
{ "'use strict';", "" },
|
||||||
|
{ NULL, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* error_data[] = {
|
||||||
|
"var asyncFn = async function() { var await = 1; };",
|
||||||
|
"var asyncFn = async function() { var { await } = 1; };",
|
||||||
|
"var asyncFn = async function() { var [ await ] = 1; };",
|
||||||
|
"var asyncFn = async function await() {};",
|
||||||
|
"var asyncFn = async () => var await = 'test';",
|
||||||
|
"var asyncFn = async await => await + 'test';",
|
||||||
|
"var asyncFn = async function(await) {};",
|
||||||
|
"var asyncFn = async function() { return async (await) => {}; }",
|
||||||
|
"var asyncFn = async (await) => 'test';",
|
||||||
|
"var asyncFn = async x => { var await = 1; }",
|
||||||
|
"var asyncFn = async x => { var { await } = 1; }",
|
||||||
|
"var asyncFn = async x => { var [ await ] = 1; }",
|
||||||
|
"async function f(await) {}",
|
||||||
|
"async function f() { var await = 1; }",
|
||||||
|
"async function f() { var { await } = 1; }",
|
||||||
|
"async function f() { var [ await ] = 1; }",
|
||||||
|
|
||||||
|
"var O = { async method(a, a) {} }",
|
||||||
|
"var O = { async ['meth' + 'od'](a, a) {} }",
|
||||||
|
"var O = { async 'method'(a, a) {} }",
|
||||||
|
"var O = { async 0(a, a) {} }",
|
||||||
|
|
||||||
|
"async function f() { var O = { async [await](a, a) {} } }",
|
||||||
|
|
||||||
|
"var asyncFn = async function() { await; }",
|
||||||
|
"async function f() { await; }",
|
||||||
|
"var O = { async method() { await; } };",
|
||||||
|
"var f = async() => await;",
|
||||||
|
"var f = async() => { await; };",
|
||||||
|
|
||||||
|
"var asyncFn = async function*() {}",
|
||||||
|
"async function* f() {}",
|
||||||
|
"var O = { *async method() {} };",
|
||||||
|
"var O = { async *method() {} };",
|
||||||
|
"var O = { async method*() {} };",
|
||||||
|
|
||||||
|
"var asyncFn = async function(x = await 1) { return x; }",
|
||||||
|
"async function f(x = await 1) { return x; }",
|
||||||
|
"var f = async(x = await 1) => x;",
|
||||||
|
"var O = { async method(x = await 1) { return x; } };",
|
||||||
|
|
||||||
|
"var f = async(x = await) => 1;",
|
||||||
|
|
||||||
|
"class C { async constructor() {} }",
|
||||||
|
"class C {}; class C2 extends C { async constructor() {} }",
|
||||||
|
"class C { static async prototype() {} }",
|
||||||
|
"class C {}; class C2 extends C { static async prototype() {} }",
|
||||||
|
|
||||||
|
"var f = async() => ((async(x = await 1) => x)();",
|
||||||
|
|
||||||
|
"var asyncFn = async function() { function await() {} }",
|
||||||
|
"var asyncFn = async() => { function await() {} }",
|
||||||
|
"var O = { async method() { function await() {} } }",
|
||||||
|
"async function foo() { function await() {} }",
|
||||||
|
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* strict_error_data[] = {
|
||||||
|
"var O = { async method(eval) {} }",
|
||||||
|
"var O = { async ['meth' + 'od'](eval) {} }",
|
||||||
|
"var O = { async 'method'(eval) {} }",
|
||||||
|
"var O = { async 0(eval) {} }",
|
||||||
|
|
||||||
|
"var O = { async method(arguments) {} }",
|
||||||
|
"var O = { async ['meth' + 'od'](arguments) {} }",
|
||||||
|
"var O = { async 'method'(arguments) {} }",
|
||||||
|
"var O = { async 0(arguments) {} }",
|
||||||
|
|
||||||
|
"var O = { async method(dupe, dupe) {} }",
|
||||||
|
|
||||||
|
// TODO(caitp): preparser needs to report duplicate parameter errors, too.
|
||||||
|
// "var f = async(dupe, dupe) => {}",
|
||||||
|
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
static const ParserFlag always_flags[] = {kAllowHarmonyAsyncAwait};
|
||||||
|
RunParserSyncTest(context_data, error_data, kError, NULL, 0, always_flags,
|
||||||
|
arraysize(always_flags));
|
||||||
|
RunParserSyncTest(strict_context_data, strict_error_data, kError, NULL, 0,
|
||||||
|
always_flags, arraysize(always_flags));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(AsyncAwaitModule) {
|
||||||
|
// clang-format off
|
||||||
|
const char* context_data[][2] = {
|
||||||
|
{ "", "" },
|
||||||
|
{ NULL, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* data[] = {
|
||||||
|
"export default async function() { await 1; }",
|
||||||
|
"export default async function async() { await 1; }",
|
||||||
|
"export async function async() { await 1; }",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
static const ParserFlag always_flags[] = {kAllowHarmonyAsyncAwait};
|
||||||
|
RunModuleParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags,
|
||||||
|
arraysize(always_flags), NULL, 0, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(AsyncAwaitModuleErrors) {
|
||||||
|
// clang-format off
|
||||||
|
const char* context_data[][2] = {
|
||||||
|
{ "", "" },
|
||||||
|
{ NULL, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* error_data[] = {
|
||||||
|
"export default (async function await() {})",
|
||||||
|
"export default async function await() {}",
|
||||||
|
"export async function await() {}",
|
||||||
|
"export async function() {}",
|
||||||
|
"export async",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
static const ParserFlag always_flags[] = {kAllowHarmonyAsyncAwait};
|
||||||
|
RunModuleParserSyncTest(context_data, error_data, kError, NULL, 0,
|
||||||
|
always_flags, arraysize(always_flags), NULL, 0,
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
|
||||||
TEST(RestrictiveForInErrors) {
|
TEST(RestrictiveForInErrors) {
|
||||||
// clang-format off
|
// clang-format off
|
||||||
const char* context_data[][2] = {
|
const char* context_data[][2] = {
|
||||||
|
Loading…
Reference in New Issue
Block a user