[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) \
|
||||
F(anonymous_function, "(anonymous function)") \
|
||||
F(arguments, "arguments") \
|
||||
F(async, "async") \
|
||||
F(await, "await") \
|
||||
F(constructor, "constructor") \
|
||||
F(default, "default") \
|
||||
F(done, "done") \
|
||||
|
@ -2587,12 +2587,12 @@ class FunctionLiteral final : public Expression {
|
||||
int start_position() const;
|
||||
int end_position() const;
|
||||
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 {
|
||||
return IsNamedExpression::decode(bitfield_);
|
||||
return function_type() == kNamedExpression;
|
||||
}
|
||||
bool is_anonymous_expression() const {
|
||||
return IsAnonymousExpression::decode(bitfield_);
|
||||
return function_type() == kAnonymousExpression;
|
||||
}
|
||||
LanguageMode language_mode() const;
|
||||
|
||||
@ -2669,6 +2669,9 @@ class FunctionLiteral final : public Expression {
|
||||
bitfield_ = ShouldBeUsedOnceHint::update(bitfield_, true);
|
||||
}
|
||||
|
||||
FunctionType function_type() const {
|
||||
return FunctionTypeBits::decode(bitfield_);
|
||||
}
|
||||
FunctionKind kind() const { return FunctionKindBits::decode(bitfield_); }
|
||||
|
||||
int ast_node_count() { return ast_properties_.node_count(); }
|
||||
@ -2714,10 +2717,7 @@ class FunctionLiteral final : public Expression {
|
||||
function_token_position_(RelocInfo::kNoPosition),
|
||||
yield_count_(0) {
|
||||
bitfield_ =
|
||||
IsDeclaration::encode(function_type == kDeclaration) |
|
||||
IsNamedExpression::encode(function_type == kNamedExpression) |
|
||||
IsAnonymousExpression::encode(function_type == kAnonymousExpression) |
|
||||
Pretenure::encode(false) |
|
||||
FunctionTypeBits::encode(function_type) | Pretenure::encode(false) |
|
||||
HasDuplicateParameters::encode(has_duplicate_parameters ==
|
||||
kHasDuplicateParameters) |
|
||||
IsFunction::encode(is_function) |
|
||||
@ -2727,15 +2727,13 @@ class FunctionLiteral final : public Expression {
|
||||
}
|
||||
|
||||
private:
|
||||
class IsDeclaration : public BitField16<bool, 0, 1> {};
|
||||
class IsNamedExpression : public BitField16<bool, 1, 1> {};
|
||||
class IsAnonymousExpression : public BitField16<bool, 2, 1> {};
|
||||
class Pretenure : public BitField16<bool, 3, 1> {};
|
||||
class HasDuplicateParameters : public BitField16<bool, 4, 1> {};
|
||||
class IsFunction : public BitField16<bool, 5, 1> {};
|
||||
class ShouldEagerCompile : public BitField16<bool, 6, 1> {};
|
||||
class ShouldBeUsedOnceHint : public BitField16<bool, 7, 1> {};
|
||||
class FunctionKindBits : public BitField16<FunctionKind, 8, 8> {};
|
||||
class FunctionTypeBits : public BitField16<FunctionType, 0, 2> {};
|
||||
class Pretenure : public BitField16<bool, 2, 1> {};
|
||||
class HasDuplicateParameters : public BitField16<bool, 3, 1> {};
|
||||
class IsFunction : public BitField16<bool, 4, 1> {};
|
||||
class ShouldEagerCompile : public BitField16<bool, 5, 1> {};
|
||||
class ShouldBeUsedOnceHint : public BitField16<bool, 6, 1> {};
|
||||
class FunctionKindBits : public BitField16<FunctionKind, 7, 9> {};
|
||||
|
||||
// Start with 16-bit field, which should get packed together
|
||||
// with Expression's trailing 16-bit field.
|
||||
|
@ -2457,6 +2457,7 @@ EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_string_padding)
|
||||
#ifdef V8_I18N_SUPPORT
|
||||
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(icu_case_mapping)
|
||||
#endif
|
||||
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_async_await)
|
||||
|
||||
void InstallPublicSymbol(Factory* factory, Handle<Context> native_context,
|
||||
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",
|
||||
nullptr};
|
||||
#endif
|
||||
static const char* harmony_async_await_natives[] = {nullptr};
|
||||
|
||||
for (int i = ExperimentalNatives::GetDebuggerCount();
|
||||
i < ExperimentalNatives::GetBuiltinsCount(); i++) {
|
||||
|
@ -204,14 +204,16 @@ DEFINE_IMPLICATION(es_staging, move_object_start)
|
||||
V(harmony_simd, "harmony simd") \
|
||||
V(harmony_do_expressions, "harmony do-expressions") \
|
||||
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
|
||||
#define HARMONY_INPROGRESS(V) \
|
||||
V(harmony_function_sent, "harmony function.sent") \
|
||||
V(harmony_sharedarraybuffer, "harmony sharedarraybuffer") \
|
||||
V(harmony_simd, "harmony simd") \
|
||||
V(harmony_do_expressions, "harmony do-expressions") \
|
||||
V(harmony_regexp_property, "harmony unicode regexp property classes")
|
||||
#define HARMONY_INPROGRESS(V) \
|
||||
V(harmony_function_sent, "harmony function.sent") \
|
||||
V(harmony_sharedarraybuffer, "harmony sharedarraybuffer") \
|
||||
V(harmony_simd, "harmony simd") \
|
||||
V(harmony_do_expressions, "harmony do-expressions") \
|
||||
V(harmony_regexp_property, "harmony unicode regexp property classes") \
|
||||
V(harmony_async_await, "harmony async-await")
|
||||
#endif
|
||||
|
||||
// Features that are complete (but still behind --harmony/es-staging flag).
|
||||
|
@ -963,11 +963,14 @@ enum FunctionKind {
|
||||
kBaseConstructor = 1 << 5,
|
||||
kGetterFunction = 1 << 6,
|
||||
kSetterFunction = 1 << 7,
|
||||
kAsyncFunction = 1 << 8,
|
||||
kAccessorFunction = kGetterFunction | kSetterFunction,
|
||||
kDefaultBaseConstructor = kDefaultConstructor | kBaseConstructor,
|
||||
kDefaultSubclassConstructor = kDefaultConstructor | kSubclassConstructor,
|
||||
kClassConstructor =
|
||||
kBaseConstructor | kSubclassConstructor | kDefaultConstructor,
|
||||
kAsyncArrowFunction = kArrowFunction | kAsyncFunction,
|
||||
kAsyncConciseMethod = kAsyncFunction | kConciseMethod
|
||||
};
|
||||
|
||||
inline bool IsValidFunctionKind(FunctionKind kind) {
|
||||
@ -982,7 +985,10 @@ inline bool IsValidFunctionKind(FunctionKind kind) {
|
||||
kind == FunctionKind::kDefaultBaseConstructor ||
|
||||
kind == FunctionKind::kDefaultSubclassConstructor ||
|
||||
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;
|
||||
}
|
||||
|
||||
inline bool IsAsyncFunction(FunctionKind kind) {
|
||||
DCHECK(IsValidFunctionKind(kind));
|
||||
return kind & FunctionKind::kAsyncFunction;
|
||||
}
|
||||
|
||||
inline bool IsConciseMethod(FunctionKind kind) {
|
||||
DCHECK(IsValidFunctionKind(kind));
|
||||
|
@ -358,6 +358,7 @@ class CallSite {
|
||||
T(BadSetterArity, "Setter must have exactly one formal parameter.") \
|
||||
T(ConstructorIsAccessor, "Class constructor may not be an accessor") \
|
||||
T(ConstructorIsGenerator, "Class constructor may not be a generator") \
|
||||
T(ConstructorIsAsync, "Class constructor may not be an async method") \
|
||||
T(DerivedConstructorReturn, \
|
||||
"Derived constructors may only return object or undefined") \
|
||||
T(DuplicateConstructor, "A class may only have one constructor") \
|
||||
@ -432,6 +433,10 @@ class CallSite {
|
||||
T(TemplateOctalLiteral, \
|
||||
"Octal literals are not allowed in template strings.") \
|
||||
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, \
|
||||
"Too many arguments in function call (only 65535 allowed)") \
|
||||
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, is_arrow, kIsArrow)
|
||||
BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, is_generator, kIsGenerator)
|
||||
BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, is_async, kIsAsyncFunction)
|
||||
BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, is_concise_method,
|
||||
kIsConciseMethod)
|
||||
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,
|
||||
kIsDefaultConstructor)
|
||||
|
||||
inline bool SharedFunctionInfo::is_resumable() const {
|
||||
return is_generator() || is_async();
|
||||
}
|
||||
|
||||
bool Script::HasValidSource() {
|
||||
Object* src = this->source();
|
||||
if (!src->IsString()) return true;
|
||||
|
@ -4295,7 +4295,7 @@ class ScopeInfo : public FixedArray {
|
||||
class HasSimpleParametersField
|
||||
: public BitField<bool, AsmFunctionField::kNext, 1> {};
|
||||
class FunctionKindField
|
||||
: public BitField<FunctionKind, HasSimpleParametersField::kNext, 8> {};
|
||||
: public BitField<FunctionKind, HasSimpleParametersField::kNext, 9> {};
|
||||
|
||||
// BitFields representing the encoded information for context locals in the
|
||||
// ContextLocalInfoEntries part.
|
||||
@ -6853,6 +6853,13 @@ class SharedFunctionInfo: public HeapObject {
|
||||
// Indicates that this function is a 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.
|
||||
DECL_BOOLEAN_ACCESSORS(is_arrow)
|
||||
|
||||
@ -7149,6 +7156,7 @@ class SharedFunctionInfo: public HeapObject {
|
||||
kIsGetterFunction,
|
||||
kIsSetterFunction,
|
||||
// byte 3
|
||||
kIsAsyncFunction,
|
||||
kDeserialized,
|
||||
kIsDeclaration,
|
||||
kCompilerHintsCount, // Pseudo entry
|
||||
@ -7171,7 +7179,7 @@ class SharedFunctionInfo: public HeapObject {
|
||||
ASSERT_FUNCTION_KIND_ORDER(kSetterFunction, kIsSetterFunction);
|
||||
#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 OptReenableTriesBits : public BitField<int, 4, 18> {};
|
||||
|
@ -40,18 +40,22 @@ class ExpressionClassifier {
|
||||
LetPatternProduction = 1 << 7,
|
||||
CoverInitializedNameProduction = 1 << 8,
|
||||
TailCallExpressionProduction = 1 << 9,
|
||||
AsyncArrowFormalParametersProduction = 1 << 10,
|
||||
AsyncBindingPatternProduction = 1 << 11,
|
||||
|
||||
ExpressionProductions =
|
||||
(ExpressionProduction | FormalParameterInitializerProduction |
|
||||
TailCallExpressionProduction),
|
||||
PatternProductions = (BindingPatternProduction |
|
||||
AssignmentPatternProduction | LetPatternProduction),
|
||||
PatternProductions =
|
||||
(BindingPatternProduction | AssignmentPatternProduction |
|
||||
LetPatternProduction | AsyncBindingPatternProduction),
|
||||
FormalParametersProductions = (DistinctFormalParametersProduction |
|
||||
StrictModeFormalParametersProduction),
|
||||
StandardProductions = ExpressionProductions | PatternProductions,
|
||||
AllProductions =
|
||||
(StandardProductions | FormalParametersProductions |
|
||||
ArrowFormalParametersProduction | CoverInitializedNameProduction)
|
||||
ArrowFormalParametersProduction | CoverInitializedNameProduction |
|
||||
AsyncArrowFormalParametersProduction | AsyncBindingPatternProduction)
|
||||
};
|
||||
|
||||
enum FunctionProperties { NonSimpleParameter = 1 << 0 };
|
||||
@ -112,6 +116,14 @@ class ExpressionClassifier {
|
||||
|
||||
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& formal_parameter_initializer_error() const {
|
||||
@ -151,6 +163,13 @@ class ExpressionClassifier {
|
||||
const Error& tail_call_expression_error() const {
|
||||
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 {
|
||||
return !(function_properties_ & NonSimpleParameter);
|
||||
@ -228,6 +247,26 @@ class ExpressionClassifier {
|
||||
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) {
|
||||
if (!is_valid_formal_parameter_list_without_duplicates()) return;
|
||||
invalid_productions_ |= DistinctFormalParametersProduction;
|
||||
@ -326,6 +365,11 @@ class ExpressionClassifier {
|
||||
cover_initialized_name_error_ = inner->cover_initialized_name_error_;
|
||||
if (errors & TailCallExpressionProduction)
|
||||
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
|
||||
@ -373,6 +417,8 @@ class ExpressionClassifier {
|
||||
Error let_pattern_error_;
|
||||
Error cover_initialized_name_error_;
|
||||
Error tail_call_expression_error_;
|
||||
Error async_arrow_formal_parameters_error_;
|
||||
Error async_binding_pattern_error_;
|
||||
DuplicateFinder* duplicate_finder_;
|
||||
};
|
||||
|
||||
|
@ -29,6 +29,86 @@ enum AllowLabelledFunctionStatement {
|
||||
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 {
|
||||
explicit FormalParametersBase(Scope* scope) : scope(scope) {}
|
||||
Scope* scope;
|
||||
@ -117,7 +197,8 @@ class ParserBase : public Traits {
|
||||
allow_harmony_do_expressions_(false),
|
||||
allow_harmony_for_in_(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) \
|
||||
bool allow_##name() const { return allow_##name##_; } \
|
||||
@ -137,6 +218,7 @@ class ParserBase : public Traits {
|
||||
ALLOW_ACCESSORS(harmony_for_in);
|
||||
ALLOW_ACCESSORS(harmony_function_name);
|
||||
ALLOW_ACCESSORS(harmony_function_sent);
|
||||
ALLOW_ACCESSORS(harmony_async_await);
|
||||
SCANNER_ACCESSORS(harmony_exponentiation_operator);
|
||||
|
||||
#undef SCANNER_ACCESSORS
|
||||
@ -284,6 +366,8 @@ class ParserBase : public Traits {
|
||||
}
|
||||
|
||||
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_; }
|
||||
FunctionState* outer() const { return outer_function_state_; }
|
||||
@ -291,7 +375,7 @@ class ParserBase : public Traits {
|
||||
void set_generator_object_variable(
|
||||
typename Traits::Type::GeneratorVariable* variable) {
|
||||
DCHECK(variable != NULL);
|
||||
DCHECK(is_generator());
|
||||
DCHECK(is_resumable());
|
||||
generator_object_variable_ = variable;
|
||||
}
|
||||
typename Traits::Type::GeneratorVariable* generator_object_variable()
|
||||
@ -576,9 +660,10 @@ class ParserBase : public Traits {
|
||||
|
||||
bool peek_any_identifier() {
|
||||
Token::Value next = peek();
|
||||
return next == Token::IDENTIFIER || next == Token::AWAIT ||
|
||||
next == Token::ENUM || next == Token::FUTURE_STRICT_RESERVED_WORD ||
|
||||
next == Token::LET || next == Token::STATIC || next == Token::YIELD;
|
||||
return next == Token::IDENTIFIER || next == Token::ENUM ||
|
||||
next == Token::AWAIT || next == Token::ASYNC ||
|
||||
next == Token::FUTURE_STRICT_RESERVED_WORD || next == Token::LET ||
|
||||
next == Token::STATIC || next == Token::YIELD;
|
||||
}
|
||||
|
||||
bool CheckContextualKeyword(Vector<const char> keyword) {
|
||||
@ -684,6 +769,10 @@ class ParserBase : public Traits {
|
||||
|
||||
LanguageMode language_mode() { return scope_->language_mode(); }
|
||||
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.
|
||||
void ReportMessage(MessageTemplate::Template message, const char* arg = NULL,
|
||||
@ -740,8 +829,16 @@ class ParserBase : public Traits {
|
||||
|
||||
void ValidateBindingPattern(const ExpressionClassifier* classifier,
|
||||
bool* ok) {
|
||||
if (!classifier->is_valid_binding_pattern()) {
|
||||
ReportClassifierError(classifier->binding_pattern_error());
|
||||
if (!classifier->is_valid_binding_pattern() ||
|
||||
!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;
|
||||
}
|
||||
}
|
||||
@ -770,7 +867,8 @@ class ParserBase : public Traits {
|
||||
|
||||
void ValidateArrowFormalParameters(const ExpressionClassifier* classifier,
|
||||
ExpressionT expr,
|
||||
bool parenthesized_formals, bool* ok) {
|
||||
bool parenthesized_formals, bool is_async,
|
||||
bool* ok) {
|
||||
if (classifier->is_valid_binding_pattern()) {
|
||||
// A simple arrow formal parameter: IDENTIFIER => BODY.
|
||||
if (!this->IsIdentifier(expr)) {
|
||||
@ -790,6 +888,12 @@ class ParserBase : public Traits {
|
||||
ReportClassifierError(error);
|
||||
*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) {
|
||||
@ -863,22 +967,32 @@ class ParserBase : public Traits {
|
||||
ExpressionClassifier* classifier, bool* ok);
|
||||
|
||||
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, ExpressionClassifier* classifier,
|
||||
bool* ok);
|
||||
ExpressionT ParseArrayLiteral(ExpressionClassifier* classifier, bool* ok);
|
||||
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);
|
||||
ExpressionT ParseObjectLiteral(ExpressionClassifier* classifier, bool* ok);
|
||||
ObjectLiteralPropertyT ParsePropertyDefinition(
|
||||
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);
|
||||
typename Traits::Type::ExpressionList ParseArguments(
|
||||
Scanner::Location* first_spread_pos, bool maybe_arrow,
|
||||
ExpressionClassifier* classifier, bool* ok);
|
||||
typename Traits::Type::ExpressionList ParseArguments(
|
||||
Scanner::Location* first_spread_pos, ExpressionClassifier* classifier,
|
||||
bool* ok);
|
||||
bool* ok) {
|
||||
return ParseArguments(first_spread_pos, false, classifier, ok);
|
||||
}
|
||||
|
||||
ExpressionT ParseAssignmentExpression(bool accept_IN,
|
||||
ExpressionClassifier* classifier,
|
||||
@ -898,12 +1012,15 @@ class ParserBase : public Traits {
|
||||
ExpressionT ParseLeftHandSideExpression(ExpressionClassifier* classifier,
|
||||
bool* ok);
|
||||
ExpressionT ParseMemberWithNewPrefixesExpression(
|
||||
ExpressionClassifier* classifier, bool* ok);
|
||||
ExpressionT ParseMemberExpression(ExpressionClassifier* classifier, bool* ok);
|
||||
ExpressionClassifier* classifier, bool* is_async, bool* ok);
|
||||
ExpressionT ParseMemberExpression(ExpressionClassifier* classifier,
|
||||
bool* is_async, bool* ok);
|
||||
ExpressionT ParseMemberExpressionContinuation(
|
||||
ExpressionT expression, ExpressionClassifier* classifier, bool* ok);
|
||||
ExpressionT expression, bool* is_async, ExpressionClassifier* classifier,
|
||||
bool* ok);
|
||||
ExpressionT ParseArrowFunctionLiteral(bool accept_IN,
|
||||
const FormalParametersT& parameters,
|
||||
bool is_async,
|
||||
const ExpressionClassifier& classifier,
|
||||
bool* ok);
|
||||
ExpressionT ParseTemplateLiteral(ExpressionT tag, int start,
|
||||
@ -975,7 +1092,7 @@ class ParserBase : public Traits {
|
||||
explicit ObjectLiteralCheckerBase(ParserBase* parser) : parser_(parser) {}
|
||||
|
||||
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() {}
|
||||
|
||||
@ -993,8 +1110,8 @@ class ParserBase : public Traits {
|
||||
explicit ObjectLiteralChecker(ParserBase* parser)
|
||||
: ObjectLiteralCheckerBase(parser), has_seen_proto_(false) {}
|
||||
|
||||
void CheckProperty(Token::Value property, PropertyKind type, bool is_static,
|
||||
bool is_generator, bool* ok) override;
|
||||
void CheckProperty(Token::Value property, PropertyKind type,
|
||||
MethodKind method_type, bool* ok) override;
|
||||
|
||||
private:
|
||||
bool IsProto() { return this->scanner()->LiteralMatches("__proto__", 9); }
|
||||
@ -1008,8 +1125,8 @@ class ParserBase : public Traits {
|
||||
explicit ClassLiteralChecker(ParserBase* parser)
|
||||
: ObjectLiteralCheckerBase(parser), has_seen_constructor_(false) {}
|
||||
|
||||
void CheckProperty(Token::Value property, PropertyKind type, bool is_static,
|
||||
bool is_generator, bool* ok) override;
|
||||
void CheckProperty(Token::Value property, PropertyKind type,
|
||||
MethodKind method_type, bool* ok) override;
|
||||
|
||||
private:
|
||||
bool IsConstructor() {
|
||||
@ -1046,6 +1163,7 @@ class ParserBase : public Traits {
|
||||
bool allow_harmony_for_in_;
|
||||
bool allow_harmony_function_name_;
|
||||
bool allow_harmony_function_sent_;
|
||||
bool allow_harmony_async_await_;
|
||||
};
|
||||
|
||||
template <class Traits>
|
||||
@ -1181,7 +1299,8 @@ typename ParserBase<Traits>::IdentifierT
|
||||
ParserBase<Traits>::ParseAndClassifyIdentifier(ExpressionClassifier* classifier,
|
||||
bool* ok) {
|
||||
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());
|
||||
// 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
|
||||
@ -1206,6 +1325,14 @@ ParserBase<Traits>::ParseAndClassifyIdentifier(ExpressionClassifier* classifier,
|
||||
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 &&
|
||||
scanner()->FindSymbol(classifier->duplicate_finder(), 1) != 0) {
|
||||
@ -1245,7 +1372,8 @@ typename ParserBase<Traits>::IdentifierT
|
||||
ParserBase<Traits>::ParseIdentifierOrStrictReservedWord(
|
||||
bool is_generator, bool* is_strict_reserved, bool* ok) {
|
||||
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;
|
||||
} else if (next == Token::FUTURE_STRICT_RESERVED_WORD || next == Token::LET ||
|
||||
next == Token::STATIC || (next == Token::YIELD && !is_generator)) {
|
||||
@ -1265,9 +1393,10 @@ template <class Traits>
|
||||
typename ParserBase<Traits>::IdentifierT
|
||||
ParserBase<Traits>::ParseIdentifierName(bool* ok) {
|
||||
Token::Value next = Next();
|
||||
if (next != Token::IDENTIFIER && next != Token::ENUM &&
|
||||
next != Token::AWAIT && next != Token::LET && next != Token::STATIC &&
|
||||
next != Token::YIELD && next != Token::FUTURE_STRICT_RESERVED_WORD &&
|
||||
if (next != Token::IDENTIFIER && next != Token::ASYNC &&
|
||||
next != Token::ENUM && next != Token::AWAIT && next != Token::LET &&
|
||||
next != Token::STATIC && next != Token::YIELD &&
|
||||
next != Token::FUTURE_STRICT_RESERVED_WORD &&
|
||||
next != Token::ESCAPED_KEYWORD &&
|
||||
next != Token::ESCAPED_STRICT_RESERVED_WORD && !Token::IsKeyword(next)) {
|
||||
this->ReportUnexpectedToken(next);
|
||||
@ -1321,11 +1450,10 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseRegExpLiteral(
|
||||
#define DUMMY ) // to make indentation work
|
||||
#undef DUMMY
|
||||
|
||||
|
||||
template <class Traits>
|
||||
typename ParserBase<Traits>::ExpressionT
|
||||
ParserBase<Traits>::ParsePrimaryExpression(ExpressionClassifier* classifier,
|
||||
bool* ok) {
|
||||
bool* is_async, bool* ok) {
|
||||
// PrimaryExpression ::
|
||||
// 'this'
|
||||
// 'null'
|
||||
@ -1341,6 +1469,7 @@ ParserBase<Traits>::ParsePrimaryExpression(ExpressionClassifier* classifier,
|
||||
// '(' Expression ')'
|
||||
// TemplateLiteral
|
||||
// do Block
|
||||
// AsyncFunctionExpression
|
||||
|
||||
int beg_pos = peek_position();
|
||||
switch (peek()) {
|
||||
@ -1360,6 +1489,16 @@ ParserBase<Traits>::ParsePrimaryExpression(ExpressionClassifier* classifier,
|
||||
BindingPatternUnexpectedToken(classifier);
|
||||
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::LET:
|
||||
case Token::STATIC:
|
||||
@ -1631,11 +1770,10 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseArrayLiteral(
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
template <class Traits>
|
||||
typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParsePropertyName(
|
||||
IdentifierT* name, bool* is_get, bool* is_set, bool* is_computed_name,
|
||||
ExpressionClassifier* classifier, bool* ok) {
|
||||
IdentifierT* name, bool* is_get, bool* is_set, bool* is_await,
|
||||
bool* is_computed_name, ExpressionClassifier* classifier, bool* ok) {
|
||||
Token::Value token = peek();
|
||||
int pos = peek_position();
|
||||
|
||||
@ -1680,6 +1818,9 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParsePropertyName(
|
||||
default:
|
||||
*name = ParseIdentifierName(CHECK_OK);
|
||||
scanner()->IsGetOrSet(is_get, is_set);
|
||||
if (this->IsAwait(*name)) {
|
||||
*is_await = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1689,38 +1830,50 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParsePropertyName(
|
||||
: factory()->NewStringLiteral(*name, pos);
|
||||
}
|
||||
|
||||
|
||||
template <class Traits>
|
||||
typename ParserBase<Traits>::ObjectLiteralPropertyT
|
||||
ParserBase<Traits>::ParsePropertyDefinition(
|
||||
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) {
|
||||
DCHECK(!in_class || is_static || has_seen_constructor != nullptr);
|
||||
DCHECK(!in_class || IsStaticMethod(method_kind) ||
|
||||
has_seen_constructor != nullptr);
|
||||
ExpressionT value = this->EmptyExpression();
|
||||
bool is_get = false;
|
||||
bool is_set = false;
|
||||
bool is_await = false;
|
||||
bool is_generator = Check(Token::MUL);
|
||||
bool is_async = false;
|
||||
const bool is_static = IsStaticMethod(method_kind);
|
||||
|
||||
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_end_pos = scanner()->peek_location().end_pos;
|
||||
ExpressionT name_expression =
|
||||
ParsePropertyName(name, &is_get, &is_set, is_computed_name, classifier,
|
||||
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
|
||||
ExpressionT name_expression = ParsePropertyName(
|
||||
name, &is_get, &is_set, &is_await, is_computed_name, classifier,
|
||||
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
|
||||
|
||||
if (fni_ != nullptr && !*is_computed_name) {
|
||||
this->PushLiteralName(fni_, *name);
|
||||
}
|
||||
|
||||
if (!in_class && !is_generator) {
|
||||
DCHECK(!is_static);
|
||||
DCHECK(!IsStaticMethod(method_kind));
|
||||
|
||||
if (peek() == Token::COLON) {
|
||||
// PropertyDefinition
|
||||
// PropertyName ':' AssignmentExpression
|
||||
if (!*is_computed_name) {
|
||||
checker->CheckProperty(name_token, kValueProperty, false, false,
|
||||
checker->CheckProperty(name_token, kValueProperty, MethodKind::Normal,
|
||||
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
|
||||
}
|
||||
Consume(Token::COLON);
|
||||
@ -1730,8 +1883,8 @@ ParserBase<Traits>::ParsePropertyDefinition(
|
||||
CheckDestructuringElement(value, classifier, beg_pos,
|
||||
scanner()->location().end_pos);
|
||||
|
||||
return factory()->NewObjectLiteralProperty(name_expression, value, false,
|
||||
*is_computed_name);
|
||||
return factory()->NewObjectLiteralProperty(name_expression, value,
|
||||
is_static, *is_computed_name);
|
||||
}
|
||||
|
||||
if (Token::IsIdentifier(name_token, language_mode(), this->is_generator(),
|
||||
@ -1752,7 +1905,11 @@ ParserBase<Traits>::ParsePropertyDefinition(
|
||||
classifier->RecordLetPatternError(
|
||||
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(
|
||||
*name, next_beg_pos, next_end_pos, scope_, factory());
|
||||
CheckDestructuringElement(lhs, classifier, next_beg_pos, next_end_pos);
|
||||
@ -1780,7 +1937,7 @@ ParserBase<Traits>::ParsePropertyDefinition(
|
||||
}
|
||||
|
||||
return factory()->NewObjectLiteralProperty(
|
||||
name_expression, value, ObjectLiteralProperty::COMPUTED, false,
|
||||
name_expression, value, ObjectLiteralProperty::COMPUTED, is_static,
|
||||
false);
|
||||
}
|
||||
}
|
||||
@ -1790,20 +1947,32 @@ ParserBase<Traits>::ParsePropertyDefinition(
|
||||
Scanner::Location(next_beg_pos, scanner()->location().end_pos),
|
||||
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) {
|
||||
// MethodDefinition
|
||||
// PropertyName '(' StrictFormalParameters ')' '{' FunctionBody '}'
|
||||
// '*' PropertyName '(' StrictFormalParameters ')' '{' FunctionBody '}'
|
||||
if (!*is_computed_name) {
|
||||
checker->CheckProperty(name_token, kMethodProperty, is_static,
|
||||
is_generator,
|
||||
checker->CheckProperty(name_token, kMethodProperty, method_kind,
|
||||
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
|
||||
}
|
||||
|
||||
FunctionKind kind = is_generator ? FunctionKind::kConciseGeneratorMethod
|
||||
: FunctionKind::kConciseMethod;
|
||||
FunctionKind kind = is_generator
|
||||
? 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;
|
||||
kind = has_extends ? FunctionKind::kSubclassConstructor
|
||||
: FunctionKind::kBaseConstructor;
|
||||
@ -1819,13 +1988,13 @@ ParserBase<Traits>::ParsePropertyDefinition(
|
||||
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)
|
||||
// 'static' MethodDefinition
|
||||
*name = this->EmptyIdentifier();
|
||||
ObjectLiteralPropertyT property = ParsePropertyDefinition(
|
||||
checker, true, has_extends, true, is_computed_name, nullptr, classifier,
|
||||
name, ok);
|
||||
checker, true, has_extends, MethodKind::Static, is_computed_name,
|
||||
nullptr, classifier, name, ok);
|
||||
Traits::RewriteNonPattern(classifier, ok);
|
||||
return property;
|
||||
}
|
||||
@ -1839,12 +2008,11 @@ ParserBase<Traits>::ParsePropertyDefinition(
|
||||
name_token = peek();
|
||||
|
||||
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));
|
||||
|
||||
if (!*is_computed_name) {
|
||||
checker->CheckProperty(name_token, kAccessorProperty, is_static,
|
||||
is_generator,
|
||||
checker->CheckProperty(name_token, kAccessorProperty, method_kind,
|
||||
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
|
||||
}
|
||||
|
||||
@ -1894,13 +2062,12 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseObjectLiteral(
|
||||
FuncNameInferrer::State fni_state(fni_);
|
||||
|
||||
const bool in_class = false;
|
||||
const bool is_static = false;
|
||||
const bool has_extends = false;
|
||||
bool is_computed_name = false;
|
||||
IdentifierT name = this->EmptyIdentifier();
|
||||
ObjectLiteralPropertyT property = this->ParsePropertyDefinition(
|
||||
&checker, in_class, has_extends, is_static, &is_computed_name, NULL,
|
||||
classifier, &name, CHECK_OK);
|
||||
&checker, in_class, has_extends, MethodKind::Normal, &is_computed_name,
|
||||
NULL, classifier, &name, CHECK_OK);
|
||||
|
||||
if (is_computed_name) {
|
||||
has_computed_names = true;
|
||||
@ -1934,11 +2101,10 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseObjectLiteral(
|
||||
pos);
|
||||
}
|
||||
|
||||
|
||||
template <class Traits>
|
||||
typename Traits::Type::ExpressionList ParserBase<Traits>::ParseArguments(
|
||||
Scanner::Location* first_spread_arg_loc, ExpressionClassifier* classifier,
|
||||
bool* ok) {
|
||||
Scanner::Location* first_spread_arg_loc, bool maybe_arrow,
|
||||
ExpressionClassifier* classifier, bool* ok) {
|
||||
// Arguments ::
|
||||
// '(' (AssignmentExpression)*[','] ')'
|
||||
|
||||
@ -1994,7 +2160,7 @@ typename Traits::Type::ExpressionList ParserBase<Traits>::ParseArguments(
|
||||
}
|
||||
*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
|
||||
// parser. Ensure that the number of materialized literals matches between
|
||||
// the parser and preparser
|
||||
@ -2026,18 +2192,31 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN,
|
||||
ParserBase<Traits>::Checkpoint checkpoint(this);
|
||||
ExpressionClassifier arrow_formals_classifier(this,
|
||||
classifier->duplicate_finder());
|
||||
|
||||
bool is_async = allow_harmony_async_await() && peek() == Token::ASYNC &&
|
||||
!scanner()->HasAnyLineTerminatorAfterNext();
|
||||
|
||||
bool parenthesized_formals = peek() == Token::LPAREN;
|
||||
if (!parenthesized_formals) {
|
||||
if (!is_async && !parenthesized_formals) {
|
||||
ArrowFormalParametersUnexpectedToken(&arrow_formals_classifier);
|
||||
}
|
||||
ExpressionT expression = this->ParseConditionalExpression(
|
||||
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) {
|
||||
classifier->RecordPatternError(scanner()->peek_location(),
|
||||
MessageTemplate::kUnexpectedToken,
|
||||
Token::String(Token::ARROW));
|
||||
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
|
||||
// sub-expression of the parameter list failed to be a valid formal
|
||||
// parameter initializer. Since YieldExpressions are banned anywhere
|
||||
@ -2045,9 +2224,11 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN,
|
||||
// TODO(adamk): Rename "FormalParameterInitializerError" to refer to
|
||||
// "YieldExpression", which is its only use.
|
||||
ValidateFormalParameterInitializer(&arrow_formals_classifier, ok);
|
||||
|
||||
Scanner::Location loc(lhs_beg_pos, scanner()->location().end_pos);
|
||||
Scope* scope =
|
||||
this->NewScope(scope_, FUNCTION_SCOPE, FunctionKind::kArrowFunction);
|
||||
Scope* scope = this->NewScope(scope_, FUNCTION_SCOPE,
|
||||
is_async ? FunctionKind::kAsyncArrowFunction
|
||||
: FunctionKind::kArrowFunction);
|
||||
// Because the arrow's parameters were parsed in the outer scope, any
|
||||
// usage flags that might have been triggered there need to be copied
|
||||
// to the arrow scope.
|
||||
@ -2069,7 +2250,7 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN,
|
||||
duplicate_loc);
|
||||
}
|
||||
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();
|
||||
|
||||
@ -2086,8 +2267,10 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN,
|
||||
classifier->Accumulate(
|
||||
&arrow_formals_classifier,
|
||||
ExpressionClassifier::StandardProductions |
|
||||
ExpressionClassifier::FormalParametersProductions |
|
||||
ExpressionClassifier::CoverInitializedNameProduction,
|
||||
ExpressionClassifier::FormalParametersProductions |
|
||||
ExpressionClassifier::CoverInitializedNameProduction |
|
||||
ExpressionClassifier::AsyncArrowFormalParametersProduction |
|
||||
ExpressionClassifier::AsyncBindingPatternProduction,
|
||||
false);
|
||||
|
||||
if (!Token::IsAssignmentOp(peek())) {
|
||||
@ -2129,8 +2312,10 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN,
|
||||
CheckNoTailCallExpressions(&rhs_classifier, CHECK_OK);
|
||||
Traits::RewriteNonPattern(&rhs_classifier, CHECK_OK);
|
||||
classifier->Accumulate(
|
||||
&rhs_classifier, ExpressionClassifier::ExpressionProductions |
|
||||
ExpressionClassifier::CoverInitializedNameProduction);
|
||||
&rhs_classifier,
|
||||
ExpressionClassifier::ExpressionProductions |
|
||||
ExpressionClassifier::CoverInitializedNameProduction |
|
||||
ExpressionClassifier::AsyncArrowFormalParametersProduction);
|
||||
|
||||
// TODO(1231235): We try to estimate the set of properties set by
|
||||
// constructors. We define a new property whenever there is an
|
||||
@ -2401,6 +2586,7 @@ ParserBase<Traits>::ParseUnaryExpression(ExpressionClassifier* classifier,
|
||||
// '-' UnaryExpression
|
||||
// '~' UnaryExpression
|
||||
// '!' UnaryExpression
|
||||
// [+Await] AwaitExpression[?Yield]
|
||||
|
||||
Token::Value op = peek();
|
||||
if (Token::IsUnaryOp(op)) {
|
||||
@ -2448,6 +2634,40 @@ ParserBase<Traits>::ParseUnaryExpression(ExpressionClassifier* classifier,
|
||||
expression,
|
||||
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 {
|
||||
return this->ParsePostfixExpression(classifier, ok);
|
||||
}
|
||||
@ -2497,8 +2717,9 @@ ParserBase<Traits>::ParseLeftHandSideExpression(
|
||||
return this->ParseTailCallExpression(classifier, ok);
|
||||
}
|
||||
|
||||
ExpressionT result =
|
||||
this->ParseMemberWithNewPrefixesExpression(classifier, CHECK_OK);
|
||||
bool is_async = false;
|
||||
ExpressionT result = this->ParseMemberWithNewPrefixesExpression(
|
||||
classifier, &is_async, CHECK_OK);
|
||||
|
||||
while (true) {
|
||||
switch (peek()) {
|
||||
@ -2518,13 +2739,12 @@ ParserBase<Traits>::ParseLeftHandSideExpression(
|
||||
|
||||
case Token::LPAREN: {
|
||||
CheckNoTailCallExpressions(classifier, CHECK_OK);
|
||||
int pos;
|
||||
Traits::RewriteNonPattern(classifier, CHECK_OK);
|
||||
BindingPatternUnexpectedToken(classifier);
|
||||
ArrowFormalParametersUnexpectedToken(classifier);
|
||||
|
||||
int pos;
|
||||
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
|
||||
// the identifier as position of the call in the stack trace.
|
||||
pos = position();
|
||||
@ -2544,7 +2764,18 @@ ParserBase<Traits>::ParseLeftHandSideExpression(
|
||||
}
|
||||
Scanner::Location spread_pos;
|
||||
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
|
||||
// optimizations.
|
||||
@ -2605,11 +2836,10 @@ ParserBase<Traits>::ParseLeftHandSideExpression(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class Traits>
|
||||
typename ParserBase<Traits>::ExpressionT
|
||||
ParserBase<Traits>::ParseMemberWithNewPrefixesExpression(
|
||||
ExpressionClassifier* classifier, bool* ok) {
|
||||
ExpressionClassifier* classifier, bool* is_async, bool* ok) {
|
||||
// NewExpression ::
|
||||
// ('new')+ MemberExpression
|
||||
//
|
||||
@ -2642,7 +2872,8 @@ ParserBase<Traits>::ParseMemberWithNewPrefixesExpression(
|
||||
} else if (peek() == Token::PERIOD) {
|
||||
return ParseNewTargetExpression(CHECK_OK);
|
||||
} else {
|
||||
result = this->ParseMemberWithNewPrefixesExpression(classifier, CHECK_OK);
|
||||
result = this->ParseMemberWithNewPrefixesExpression(classifier, is_async,
|
||||
CHECK_OK);
|
||||
}
|
||||
Traits::RewriteNonPattern(classifier, CHECK_OK);
|
||||
if (peek() == Token::LPAREN) {
|
||||
@ -2658,8 +2889,8 @@ ParserBase<Traits>::ParseMemberWithNewPrefixesExpression(
|
||||
result = factory()->NewCallNew(result, args, new_pos);
|
||||
}
|
||||
// The expression can still continue with . or [ after the arguments.
|
||||
result =
|
||||
this->ParseMemberExpressionContinuation(result, classifier, CHECK_OK);
|
||||
result = this->ParseMemberExpressionContinuation(result, is_async,
|
||||
classifier, CHECK_OK);
|
||||
return result;
|
||||
}
|
||||
// NewExpression without arguments.
|
||||
@ -2667,14 +2898,13 @@ ParserBase<Traits>::ParseMemberWithNewPrefixesExpression(
|
||||
new_pos);
|
||||
}
|
||||
// No 'new' or 'super' keyword.
|
||||
return this->ParseMemberExpression(classifier, ok);
|
||||
return this->ParseMemberExpression(classifier, is_async, ok);
|
||||
}
|
||||
|
||||
|
||||
template <class Traits>
|
||||
typename ParserBase<Traits>::ExpressionT
|
||||
ParserBase<Traits>::ParseMemberExpression(ExpressionClassifier* classifier,
|
||||
bool* ok) {
|
||||
bool* is_async, bool* ok) {
|
||||
// MemberExpression ::
|
||||
// (PrimaryExpression | FunctionLiteral | ClassLiteral)
|
||||
// ('[' Expression ']' | '.' Identifier | Arguments | TemplateLiteral)*
|
||||
@ -2731,10 +2961,11 @@ ParserBase<Traits>::ParseMemberExpression(ExpressionClassifier* classifier,
|
||||
const bool is_new = false;
|
||||
result = ParseSuperExpression(is_new, classifier, CHECK_OK);
|
||||
} 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;
|
||||
}
|
||||
|
||||
@ -2801,16 +3032,17 @@ ParserBase<Traits>::ParseNewTargetExpression(bool* ok) {
|
||||
return this->NewTargetExpression(scope_, factory(), pos);
|
||||
}
|
||||
|
||||
|
||||
template <class Traits>
|
||||
typename ParserBase<Traits>::ExpressionT
|
||||
ParserBase<Traits>::ParseMemberExpressionContinuation(
|
||||
ExpressionT expression, ExpressionClassifier* classifier, bool* ok) {
|
||||
ExpressionT expression, bool* is_async, ExpressionClassifier* classifier,
|
||||
bool* ok) {
|
||||
// Parses this part of MemberExpression:
|
||||
// ('[' Expression ']' | '.' Identifier | TemplateLiteral)*
|
||||
while (true) {
|
||||
switch (peek()) {
|
||||
case Token::LBRACK: {
|
||||
*is_async = false;
|
||||
Traits::RewriteNonPattern(classifier, CHECK_OK);
|
||||
BindingPatternUnexpectedToken(classifier);
|
||||
ArrowFormalParametersUnexpectedToken(classifier);
|
||||
@ -2827,6 +3059,7 @@ ParserBase<Traits>::ParseMemberExpressionContinuation(
|
||||
break;
|
||||
}
|
||||
case Token::PERIOD: {
|
||||
*is_async = false;
|
||||
Traits::RewriteNonPattern(classifier, CHECK_OK);
|
||||
BindingPatternUnexpectedToken(classifier);
|
||||
ArrowFormalParametersUnexpectedToken(classifier);
|
||||
@ -2843,6 +3076,7 @@ ParserBase<Traits>::ParseMemberExpressionContinuation(
|
||||
}
|
||||
case Token::TEMPLATE_SPAN:
|
||||
case Token::TEMPLATE_TAIL: {
|
||||
*is_async = false;
|
||||
Traits::RewriteNonPattern(classifier, CHECK_OK);
|
||||
BindingPatternUnexpectedToken(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::YIELD:
|
||||
case Token::AWAIT:
|
||||
case Token::ASYNC:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class Traits>
|
||||
typename ParserBase<Traits>::ExpressionT
|
||||
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) {
|
||||
if (peek() == Token::ARROW && scanner_->HasAnyLineTerminatorBeforeNext()) {
|
||||
// ASI inserts `;` after arrow parameters if a line terminator is found.
|
||||
@ -3032,10 +3266,11 @@ ParserBase<Traits>::ParseArrowFunctionLiteral(
|
||||
int expected_property_count = -1;
|
||||
Scanner::Location super_loc;
|
||||
|
||||
FunctionKind arrow_kind = is_async ? kAsyncArrowFunction : kArrowFunction;
|
||||
{
|
||||
typename Traits::Type::Factory function_factory(ast_value_factory());
|
||||
FunctionState function_state(&function_state_, &scope_,
|
||||
formal_parameters.scope, kArrowFunction,
|
||||
formal_parameters.scope, arrow_kind,
|
||||
&function_factory);
|
||||
|
||||
function_state.SkipMaterializedLiterals(
|
||||
@ -3061,7 +3296,7 @@ ParserBase<Traits>::ParseArrowFunctionLiteral(
|
||||
} else {
|
||||
body = this->ParseEagerFunctionBody(
|
||||
this->EmptyIdentifier(), RelocInfo::kNoPosition, formal_parameters,
|
||||
kArrowFunction, FunctionLiteral::kAnonymousExpression, CHECK_OK);
|
||||
arrow_kind, FunctionLiteral::kAnonymousExpression, CHECK_OK);
|
||||
materialized_literal_count =
|
||||
function_state.materialized_literal_count();
|
||||
expected_property_count = function_state.expected_property_count();
|
||||
@ -3115,7 +3350,7 @@ ParserBase<Traits>::ParseArrowFunctionLiteral(
|
||||
materialized_literal_count, expected_property_count, num_parameters,
|
||||
FunctionLiteral::kNoDuplicateParameters,
|
||||
FunctionLiteral::kAnonymousExpression,
|
||||
FunctionLiteral::kShouldLazyCompile, FunctionKind::kArrowFunction,
|
||||
FunctionLiteral::kShouldLazyCompile, arrow_kind,
|
||||
formal_parameters.scope->start_position());
|
||||
|
||||
function_literal->set_function_token_position(
|
||||
@ -3284,13 +3519,12 @@ void ParserBase<Traits>::CheckDestructuringElement(
|
||||
#undef CHECK_OK
|
||||
#undef CHECK_OK_CUSTOM
|
||||
|
||||
|
||||
template <typename Traits>
|
||||
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) {
|
||||
DCHECK(!is_static);
|
||||
DCHECK(!is_generator || type == kMethodProperty);
|
||||
DCHECK(!IsStaticMethod(method_type));
|
||||
DCHECK(!IsSpecialMethod(method_type) || type == kMethodProperty);
|
||||
|
||||
if (property == Token::SMI || property == Token::NUMBER) return;
|
||||
|
||||
@ -3305,26 +3539,28 @@ void ParserBase<Traits>::ObjectLiteralChecker::CheckProperty(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <typename Traits>
|
||||
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) {
|
||||
DCHECK(type == kMethodProperty || type == kAccessorProperty);
|
||||
|
||||
if (property == Token::SMI || property == Token::NUMBER) return;
|
||||
|
||||
if (is_static) {
|
||||
if (IsStaticMethod(method_type)) {
|
||||
if (IsPrototype()) {
|
||||
this->parser()->ReportMessage(MessageTemplate::kStaticPrototype);
|
||||
*ok = false;
|
||||
return;
|
||||
}
|
||||
} 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 =
|
||||
is_generator ? MessageTemplate::kConstructorIsGenerator
|
||||
: MessageTemplate::kConstructorIsAccessor;
|
||||
: is_async ? MessageTemplate::kConstructorIsAsync
|
||||
: MessageTemplate::kConstructorIsAccessor;
|
||||
this->parser()->ReportMessage(msg);
|
||||
*ok = false;
|
||||
return;
|
||||
|
@ -330,6 +330,10 @@ bool ParserTraits::IsUndefined(const AstRawString* identifier) const {
|
||||
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 {
|
||||
return identifier == parser_->ast_value_factory()->prototype_string();
|
||||
}
|
||||
@ -798,6 +802,7 @@ Parser::Parser(ParseInfo* info)
|
||||
FLAG_harmony_restrictive_declarations);
|
||||
set_allow_harmony_exponentiation_operator(
|
||||
FLAG_harmony_exponentiation_operator);
|
||||
set_allow_harmony_async_await(FLAG_harmony_async_await);
|
||||
for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount;
|
||||
++feature) {
|
||||
use_counts_[feature] = 0;
|
||||
@ -1075,6 +1080,13 @@ FunctionLiteral* Parser::ParseLazy(Isolate* isolate, ParseInfo* info,
|
||||
bool ok = true;
|
||||
|
||||
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.
|
||||
Scope* scope =
|
||||
NewScope(scope_, FUNCTION_SCOPE, FunctionKind::kArrowFunction);
|
||||
@ -1115,8 +1127,8 @@ FunctionLiteral* Parser::ParseLazy(Isolate* isolate, ParseInfo* info,
|
||||
checkpoint.Restore(&formals.materialized_literals_count);
|
||||
// Pass `accept_IN=true` to ParseArrowFunctionLiteral --- This should
|
||||
// not be observable, or else the preparser would have failed.
|
||||
Expression* expression =
|
||||
ParseArrowFunctionLiteral(true, formals, formals_classifier, &ok);
|
||||
Expression* expression = ParseArrowFunctionLiteral(
|
||||
true, formals, is_async, formals_classifier, &ok);
|
||||
if (ok) {
|
||||
// Scanning must end at the same position that was recorded
|
||||
// previously. If not, parsing has been interrupted due to a stack
|
||||
@ -1255,8 +1267,8 @@ Statement* Parser::ParseStatementListItem(bool* ok) {
|
||||
// StatementListItem:
|
||||
// Statement
|
||||
// Declaration
|
||||
|
||||
switch (peek()) {
|
||||
const Token::Value peeked = peek();
|
||||
switch (peeked) {
|
||||
case Token::FUNCTION:
|
||||
return ParseHoistableDeclaration(NULL, ok);
|
||||
case Token::CLASS:
|
||||
@ -1271,6 +1283,13 @@ Statement* Parser::ParseStatementListItem(bool* ok) {
|
||||
return ParseVariableStatement(kStatementListItem, NULL, ok);
|
||||
}
|
||||
break;
|
||||
case Token::ASYNC:
|
||||
if (allow_harmony_async_await() && PeekAhead() == Token::FUNCTION &&
|
||||
!scanner()->HasAnyLineTerminatorAfterNext()) {
|
||||
Consume(Token::ASYNC);
|
||||
return ParseAsyncFunctionDeclaration(NULL, ok);
|
||||
}
|
||||
/* falls through */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -1560,7 +1579,10 @@ Statement* Parser::ParseExportDefault(bool* ok) {
|
||||
pos, FunctionLiteral::kDeclaration, language_mode(), CHECK_OK);
|
||||
result = factory()->NewEmptyStatement(RelocInfo::kNoPosition);
|
||||
} else {
|
||||
result = ParseHoistableDeclaration(pos, is_generator, &names, CHECK_OK);
|
||||
result = ParseHoistableDeclaration(
|
||||
pos, is_generator ? ParseFunctionFlags::kIsGenerator
|
||||
: ParseFunctionFlags::kIsNormal,
|
||||
&names, CHECK_OK);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1579,6 +1601,30 @@ Statement* Parser::ParseExportDefault(bool* ok) {
|
||||
}
|
||||
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: {
|
||||
int pos = peek_position();
|
||||
ExpressionClassifier classifier(this);
|
||||
@ -1703,6 +1749,14 @@ Statement* Parser::ParseExportDeclaration(bool* ok) {
|
||||
result = ParseVariableStatement(kStatementListItem, &names, CHECK_OK);
|
||||
break;
|
||||
|
||||
case Token::ASYNC:
|
||||
if (allow_harmony_async_await()) {
|
||||
Consume(Token::ASYNC);
|
||||
result = ParseAsyncFunctionDeclaration(&names, CHECK_OK);
|
||||
break;
|
||||
}
|
||||
/* falls through */
|
||||
|
||||
default:
|
||||
*ok = false;
|
||||
ReportUnexpectedToken(scanner()->current_token());
|
||||
@ -2062,13 +2116,29 @@ Statement* Parser::ParseHoistableDeclaration(
|
||||
ZoneList<const AstRawString*>* names, bool* ok) {
|
||||
Expect(Token::FUNCTION, CHECK_OK);
|
||||
int pos = position();
|
||||
bool is_generator = Check(Token::MUL);
|
||||
return ParseHoistableDeclaration(pos, is_generator, names, ok);
|
||||
ParseFunctionFlags flags = ParseFunctionFlags::kIsNormal;
|
||||
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(
|
||||
int pos, bool is_generator, ZoneList<const AstRawString*>* names,
|
||||
int pos, ParseFunctionFlags flags, ZoneList<const AstRawString*>* names,
|
||||
bool* ok) {
|
||||
// FunctionDeclaration ::
|
||||
// 'function' Identifier '(' FormalParameters ')' '{' FunctionBody '}'
|
||||
@ -2076,10 +2146,21 @@ Statement* Parser::ParseHoistableDeclaration(
|
||||
// 'function' '*' Identifier '(' FormalParameters ')' '{' FunctionBody '}'
|
||||
//
|
||||
// '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;
|
||||
const AstRawString* name = ParseIdentifierOrStrictReservedWord(
|
||||
&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_);
|
||||
if (fni_ != NULL) fni_->PushEnclosingName(name);
|
||||
FunctionLiteral* fun = ParseFunctionLiteral(
|
||||
@ -2087,7 +2168,8 @@ Statement* Parser::ParseHoistableDeclaration(
|
||||
is_strict_reserved ? kFunctionNameIsStrictReserved
|
||||
: kFunctionNameValidityUnknown,
|
||||
is_generator ? FunctionKind::kGeneratorFunction
|
||||
: FunctionKind::kNormalFunction,
|
||||
: is_async ? FunctionKind::kAsyncFunction
|
||||
: FunctionKind::kNormalFunction,
|
||||
pos, FunctionLiteral::kDeclaration, language_mode(), CHECK_OK);
|
||||
|
||||
// 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) {
|
||||
Consume(Token::FUNCTION);
|
||||
int pos = position();
|
||||
bool is_generator = Check(Token::MUL);
|
||||
if (allow_harmony_restrictive_declarations() && is_generator) {
|
||||
ParserTraits::ReportMessageAt(
|
||||
scanner()->location(),
|
||||
MessageTemplate::kGeneratorInLegacyContext);
|
||||
*ok = false;
|
||||
return nullptr;
|
||||
ParseFunctionFlags flags = ParseFunctionFlags::kIsNormal;
|
||||
if (Check(Token::MUL)) {
|
||||
flags |= ParseFunctionFlags::kIsGenerator;
|
||||
if (allow_harmony_restrictive_declarations()) {
|
||||
ParserTraits::ReportMessageAt(scanner()->location(),
|
||||
MessageTemplate::kGeneratorInLegacyContext);
|
||||
*ok = false;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
return ParseHoistableDeclaration(pos, is_generator, nullptr, CHECK_OK);
|
||||
|
||||
return ParseHoistableDeclaration(pos, flags, nullptr, CHECK_OK);
|
||||
}
|
||||
|
||||
Statement* Parser::ParseExpressionOrLabelledStatement(
|
||||
@ -4051,7 +4136,6 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
||||
CheckArityRestrictions(arity, kind, formals.has_rest, start_position,
|
||||
formals_end_position, CHECK_OK);
|
||||
Expect(Token::LBRACE, CHECK_OK);
|
||||
|
||||
// Don't include the rest parameter into the function's formal parameter
|
||||
// count (esp. the SharedFunctionInfo::internal_formal_parameter_count,
|
||||
// which says whether we need to create an arguments adaptor frame).
|
||||
@ -4207,6 +4291,36 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
||||
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,
|
||||
int* expected_property_count, bool* ok,
|
||||
@ -4606,6 +4720,7 @@ PreParser::PreParseResult Parser::ParseLazyFunctionBodyWithPreParser(
|
||||
SET_ALLOW(harmony_function_sent);
|
||||
SET_ALLOW(harmony_exponentiation_operator);
|
||||
SET_ALLOW(harmony_restrictive_declarations);
|
||||
SET_ALLOW(harmony_async_await);
|
||||
#undef SET_ALLOW
|
||||
}
|
||||
PreParser::PreParseResult result = reusable_preparser_->PreParseLazyFunction(
|
||||
@ -4676,13 +4791,12 @@ ClassLiteral* Parser::ParseClassLiteral(ExpressionClassifier* classifier,
|
||||
if (Check(Token::SEMICOLON)) continue;
|
||||
FuncNameInferrer::State fni_state(fni_);
|
||||
const bool in_class = true;
|
||||
const bool is_static = false;
|
||||
bool is_computed_name = false; // Classes do not care about computed
|
||||
// property names here.
|
||||
ExpressionClassifier property_classifier(this);
|
||||
const AstRawString* property_name = nullptr;
|
||||
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);
|
||||
RewriteNonPattern(&property_classifier, CHECK_OK);
|
||||
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() {
|
||||
parser_->RewriteDestructuringAssignments();
|
||||
}
|
||||
@ -5333,6 +5458,11 @@ void ParserTraits::RewriteNonPattern(Type::ExpressionClassifier* classifier,
|
||||
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 {
|
||||
return parser_->function_state_->scope()->zone();
|
||||
|
@ -355,6 +355,7 @@ class ParserTraits {
|
||||
bool IsArguments(const AstRawString* identifier) const;
|
||||
bool IsEvalOrArguments(const AstRawString* identifier) const;
|
||||
bool IsUndefined(const AstRawString* identifier) const;
|
||||
bool IsAwait(const AstRawString* identifier) const;
|
||||
V8_INLINE bool IsFutureStrictReserved(const AstRawString* identifier) const;
|
||||
|
||||
// Returns true if the expression is of type "this.foo".
|
||||
@ -554,6 +555,8 @@ class ParserTraits {
|
||||
const Scanner::Location& params_loc,
|
||||
Scanner::Location* duplicate_loc, bool* ok);
|
||||
|
||||
V8_INLINE Expression* ParseAsyncFunctionExpression(bool* ok);
|
||||
|
||||
V8_INLINE DoExpression* ParseDoExpression(bool* ok);
|
||||
|
||||
void ReindexLiterals(const ParserFormalParameters& parameters);
|
||||
@ -637,6 +640,8 @@ class ParserTraits {
|
||||
ZoneList<v8::internal::Expression*>* args,
|
||||
int pos);
|
||||
|
||||
Expression* ExpressionListToExpression(ZoneList<Expression*>* args);
|
||||
|
||||
// Rewrite all DestructuringAssignments in the current FunctionState.
|
||||
V8_INLINE void RewriteDestructuringAssignments();
|
||||
|
||||
@ -645,6 +650,8 @@ class ParserTraits {
|
||||
V8_INLINE Expression* RewriteAssignExponentiation(Expression* left,
|
||||
Expression* right, int pos);
|
||||
|
||||
V8_INLINE Expression* RewriteAwaitExpression(Expression* value, int pos);
|
||||
|
||||
V8_INLINE void QueueDestructuringAssignmentForRewriting(
|
||||
Expression* assignment);
|
||||
V8_INLINE void QueueNonPatternForRewriting(Expression* expr);
|
||||
@ -772,7 +779,13 @@ class Parser : public ParserBase<ParserTraits> {
|
||||
Statement* ParseFunctionDeclaration(bool* ok);
|
||||
Statement* ParseHoistableDeclaration(ZoneList<const AstRawString*>* names,
|
||||
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,
|
||||
bool* ok);
|
||||
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) {
|
||||
return parser_->ParseDoExpression(ok);
|
||||
|
@ -51,6 +51,8 @@ PreParserIdentifier PreParserTraits::GetSymbol(Scanner* scanner) {
|
||||
return PreParserIdentifier::Static();
|
||||
} else if (scanner->current_token() == Token::YIELD) {
|
||||
return PreParserIdentifier::Yield();
|
||||
} else if (scanner->current_token() == Token::ASYNC) {
|
||||
return PreParserIdentifier::Async();
|
||||
}
|
||||
if (scanner->UnescapedLiteralMatches("eval", 4)) {
|
||||
return PreParserIdentifier::Eval();
|
||||
@ -193,6 +195,13 @@ PreParser::Statement PreParser::ParseStatementListItem(bool* ok) {
|
||||
return ParseVariableStatement(kStatementListItem, ok);
|
||||
}
|
||||
break;
|
||||
case Token::ASYNC:
|
||||
if (allow_harmony_async_await() && PeekAhead() == Token::FUNCTION &&
|
||||
!scanner()->HasAnyLineTerminatorAfterNext()) {
|
||||
Consume(Token::ASYNC);
|
||||
return ParseAsyncFunctionDeclaration(ok);
|
||||
}
|
||||
/* falls through */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -381,22 +390,44 @@ PreParser::Statement PreParser::ParseSubStatement(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
Identifier name = ParseIdentifierOrStrictReservedWord(
|
||||
&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(),
|
||||
is_strict_reserved ? kFunctionNameIsStrictReserved
|
||||
: kFunctionNameValidityUnknown,
|
||||
is_generator ? FunctionKind::kGeneratorFunction
|
||||
: FunctionKind::kNormalFunction,
|
||||
: is_async ? FunctionKind::kAsyncFunction
|
||||
: FunctionKind::kNormalFunction,
|
||||
pos, FunctionLiteral::kDeclaration, language_mode(),
|
||||
CHECK_OK);
|
||||
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) {
|
||||
// FunctionDeclaration ::
|
||||
@ -404,10 +435,14 @@ PreParser::Statement PreParser::ParseHoistableDeclaration(bool* ok) {
|
||||
// GeneratorDeclaration ::
|
||||
// 'function' '*' Identifier '(' FormalParameterListopt ')'
|
||||
// '{' FunctionBody '}'
|
||||
|
||||
Expect(Token::FUNCTION, CHECK_OK);
|
||||
int pos = position();
|
||||
bool is_generator = Check(Token::MUL);
|
||||
return ParseHoistableDeclaration(pos, is_generator, CHECK_OK);
|
||||
ParseFunctionFlags flags = ParseFunctionFlags::kIsNormal;
|
||||
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) {
|
||||
Consume(Token::FUNCTION);
|
||||
int pos = position();
|
||||
bool is_generator = Check(Token::MUL);
|
||||
if (allow_harmony_restrictive_declarations() && is_generator) {
|
||||
PreParserTraits::ReportMessageAt(
|
||||
scanner()->location(),
|
||||
MessageTemplate::kGeneratorInLegacyContext);
|
||||
*ok = false;
|
||||
return Statement::Default();
|
||||
ParseFunctionFlags flags = ParseFunctionFlags::kIsNormal;
|
||||
if (Check(Token::MUL)) {
|
||||
flags |= ParseFunctionFlags::kIsGenerator;
|
||||
if (allow_harmony_restrictive_declarations()) {
|
||||
PreParserTraits::ReportMessageAt(
|
||||
scanner()->location(), MessageTemplate::kGeneratorInLegacyContext);
|
||||
*ok = false;
|
||||
return Statement::Default();
|
||||
}
|
||||
}
|
||||
return ParseHoistableDeclaration(pos, is_generator, ok);
|
||||
return ParseHoistableDeclaration(pos, flags, ok);
|
||||
}
|
||||
|
||||
PreParser::Statement PreParser::ParseExpressionOrLabelledStatement(
|
||||
@ -1111,6 +1148,37 @@ PreParser::Expression PreParser::ParseFunctionLiteral(
|
||||
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,
|
||||
Scanner::BookmarkScope* bookmark) {
|
||||
@ -1172,12 +1240,11 @@ PreParserExpression PreParser::ParseClassLiteral(
|
||||
while (peek() != Token::RBRACE) {
|
||||
if (Check(Token::SEMICOLON)) continue;
|
||||
const bool in_class = true;
|
||||
const bool is_static = false;
|
||||
bool is_computed_name = false; // Classes do not care about computed
|
||||
// property names here.
|
||||
Identifier name;
|
||||
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,
|
||||
&property_classifier, &name, CHECK_OK);
|
||||
ValidateExpression(&property_classifier, CHECK_OK);
|
||||
|
@ -61,6 +61,9 @@ class PreParserIdentifier {
|
||||
static PreParserIdentifier Await() {
|
||||
return PreParserIdentifier(kAwaitIdentifier);
|
||||
}
|
||||
static PreParserIdentifier Async() {
|
||||
return PreParserIdentifier(kAsyncIdentifier);
|
||||
}
|
||||
bool IsEval() const { return type_ == kEvalIdentifier; }
|
||||
bool IsArguments() const { return type_ == kArgumentsIdentifier; }
|
||||
bool IsEvalOrArguments() const { return IsEval() || IsArguments(); }
|
||||
@ -72,6 +75,7 @@ class PreParserIdentifier {
|
||||
bool IsConstructor() const { return type_ == kConstructorIdentifier; }
|
||||
bool IsEnum() const { return type_ == kEnumIdentifier; }
|
||||
bool IsAwait() const { return type_ == kAwaitIdentifier; }
|
||||
bool IsAsync() const { return type_ == kAsyncIdentifier; }
|
||||
bool IsFutureStrictReserved() const {
|
||||
return type_ == kFutureStrictReservedIdentifier ||
|
||||
type_ == kLetIdentifier || type_ == kStaticIdentifier ||
|
||||
@ -100,7 +104,8 @@ class PreParserIdentifier {
|
||||
kPrototypeIdentifier,
|
||||
kConstructorIdentifier,
|
||||
kEnumIdentifier,
|
||||
kAwaitIdentifier
|
||||
kAwaitIdentifier,
|
||||
kAsyncIdentifier
|
||||
};
|
||||
|
||||
explicit PreParserIdentifier(Type type) : type_(type) {}
|
||||
@ -622,6 +627,14 @@ class PreParserTraits {
|
||||
return identifier.IsArguments();
|
||||
}
|
||||
|
||||
static bool IsAwait(PreParserIdentifier identifier) {
|
||||
return identifier.IsAwait();
|
||||
}
|
||||
|
||||
static bool IsAsync(PreParserIdentifier identifier) {
|
||||
return identifier.IsAsync();
|
||||
}
|
||||
|
||||
static bool IsEvalOrArguments(PreParserIdentifier identifier) {
|
||||
return identifier.IsEvalOrArguments();
|
||||
}
|
||||
@ -865,6 +878,8 @@ class PreParserTraits {
|
||||
PreParserExpression expression, const Scanner::Location& params_loc,
|
||||
Scanner::Location* duplicate_loc, bool* ok);
|
||||
|
||||
V8_INLINE PreParserExpression ParseAsyncFunctionExpression(bool* ok);
|
||||
|
||||
void ReindexLiterals(const PreParserFormalParameters& paramaters) {}
|
||||
|
||||
struct TemplateLiteralState {};
|
||||
@ -937,6 +952,11 @@ class PreParserTraits {
|
||||
PreParserExpressionList args,
|
||||
int pos);
|
||||
|
||||
inline PreParserExpression ExpressionListToExpression(
|
||||
PreParserExpressionList args) {
|
||||
return PreParserExpression::Default();
|
||||
}
|
||||
|
||||
inline void RewriteDestructuringAssignments() {}
|
||||
|
||||
inline PreParserExpression RewriteExponentiation(PreParserExpression left,
|
||||
@ -960,6 +980,9 @@ class PreParserTraits {
|
||||
inline void RewriteNonPattern(Type::ExpressionClassifier* classifier,
|
||||
bool* ok);
|
||||
|
||||
inline PreParserExpression RewriteAwaitExpression(PreParserExpression value,
|
||||
int pos);
|
||||
|
||||
V8_INLINE Zone* zone() const;
|
||||
V8_INLINE ZoneList<PreParserExpression>* GetNonPatternList() const;
|
||||
|
||||
@ -1076,8 +1099,11 @@ class PreParser : public ParserBase<PreParserTraits> {
|
||||
bool* ok);
|
||||
Statement ParseScopedStatement(bool legacy, 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 ParseAsyncFunctionDeclaration(bool* ok);
|
||||
Expression ParseAsyncFunctionExpression(bool* ok);
|
||||
Statement ParseClassDeclaration(bool* ok);
|
||||
Statement ParseBlock(bool* ok);
|
||||
Statement ParseVariableStatement(VariableDeclarationContext var_context,
|
||||
@ -1166,6 +1192,9 @@ void PreParserTraits::ParseArrowFunctionFormalParameterList(
|
||||
// lists that are too long.
|
||||
}
|
||||
|
||||
PreParserExpression PreParserTraits::ParseAsyncFunctionExpression(bool* ok) {
|
||||
return pre_parser_->ParseAsyncFunctionExpression(ok);
|
||||
}
|
||||
|
||||
PreParserExpression PreParserTraits::ParseDoExpression(bool* ok) {
|
||||
return pre_parser_->ParseDoExpression(ok);
|
||||
@ -1177,6 +1206,10 @@ void PreParserTraits::RewriteNonPattern(Type::ExpressionClassifier* classifier,
|
||||
pre_parser_->ValidateExpression(classifier, ok);
|
||||
}
|
||||
|
||||
PreParserExpression PreParserTraits::RewriteAwaitExpression(
|
||||
PreParserExpression value, int pos) {
|
||||
return value;
|
||||
}
|
||||
|
||||
Zone* PreParserTraits::zone() const {
|
||||
return pre_parser_->function_state_->scope()->zone();
|
||||
|
@ -249,6 +249,7 @@ Token::Value Scanner::Next() {
|
||||
if (V8_UNLIKELY(next_next_.token != Token::UNINITIALIZED)) {
|
||||
next_ = next_next_;
|
||||
next_next_.token = Token::UNINITIALIZED;
|
||||
has_line_terminator_before_next_ = has_line_terminator_after_next_;
|
||||
return current_.token;
|
||||
}
|
||||
has_line_terminator_before_next_ = false;
|
||||
@ -274,7 +275,12 @@ Token::Value Scanner::PeekAhead() {
|
||||
return next_next_.token;
|
||||
}
|
||||
TokenDesc prev = current_;
|
||||
bool has_line_terminator_before_next =
|
||||
has_line_terminator_before_next_ || has_multiline_comment_before_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;
|
||||
next_next_ = next_;
|
||||
next_ = current_;
|
||||
@ -1136,6 +1142,7 @@ uc32 Scanner::ScanUnicodeEscape() {
|
||||
|
||||
#define KEYWORDS(KEYWORD_GROUP, KEYWORD) \
|
||||
KEYWORD_GROUP('a') \
|
||||
KEYWORD("async", Token::ASYNC) \
|
||||
KEYWORD("await", Token::AWAIT) \
|
||||
KEYWORD_GROUP('b') \
|
||||
KEYWORD("break", Token::BREAK) \
|
||||
|
@ -442,6 +442,12 @@ class Scanner {
|
||||
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
|
||||
// character(s) must be /(=). Returns true if a pattern is scanned.
|
||||
bool ScanRegExpPattern(bool seen_equal);
|
||||
@ -786,6 +792,7 @@ class Scanner {
|
||||
// Whether there is a multi-line comment that contains a
|
||||
// line-terminator after the current token, and before the next.
|
||||
bool has_multiline_comment_before_next_;
|
||||
bool has_line_terminator_after_next_;
|
||||
|
||||
// Whether this scanner encountered an HTML comment.
|
||||
bool found_html_comment_;
|
||||
|
@ -149,6 +149,7 @@ namespace internal {
|
||||
\
|
||||
/* Future reserved words (ECMA-262, section 7.6.1.2). */ \
|
||||
T(FUTURE_STRICT_RESERVED_WORD, NULL, 0) \
|
||||
K(ASYNC, "async", 0) \
|
||||
/* `await` is a reserved word in module code only */ \
|
||||
K(AWAIT, "await", 0) \
|
||||
K(CLASS, "class", 0) \
|
||||
@ -201,6 +202,7 @@ class Token {
|
||||
bool is_generator, bool is_module) {
|
||||
switch (tok) {
|
||||
case IDENTIFIER:
|
||||
case ASYNC:
|
||||
return true;
|
||||
case ESCAPED_STRICT_RESERVED_WORD:
|
||||
case FUTURE_STRICT_RESERVED_WORD:
|
||||
|
@ -1508,7 +1508,8 @@ enum ParserFlag {
|
||||
kAllowHarmonyFunctionSent,
|
||||
kAllowHarmonyRestrictiveDeclarations,
|
||||
kAllowHarmonyExponentiationOperator,
|
||||
kAllowHarmonyForIn
|
||||
kAllowHarmonyForIn,
|
||||
kAllowHarmonyAsyncAwait
|
||||
};
|
||||
|
||||
enum ParserSyncTestResult {
|
||||
@ -1529,6 +1530,8 @@ void SetParserFlags(i::ParserBase<Traits>* parser,
|
||||
parser->set_allow_harmony_exponentiation_operator(
|
||||
flags.Contains(kAllowHarmonyExponentiationOperator));
|
||||
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));
|
||||
}
|
||||
|
||||
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) {
|
||||
// clang-format off
|
||||
const char* context_data[][2] = {
|
||||
|
Loading…
Reference in New Issue
Block a user