[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:
caitpotter88 2016-05-16 16:17:13 -07:00 committed by Commit bot
parent 9c6ff18355
commit 0d43421a22
18 changed files with 977 additions and 170 deletions

View File

@ -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") \

View File

@ -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.

View File

@ -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++) {

View File

@ -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).

View File

@ -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));

View File

@ -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, \

View File

@ -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;

View File

@ -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> {};

View File

@ -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_;
};

View File

@ -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;

View File

@ -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();

View File

@ -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);

View File

@ -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);

View File

@ -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();

View File

@ -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) \

View File

@ -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_;

View File

@ -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:

View File

@ -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] = {