Commit 0d43421a authored by caitpotter88's avatar caitpotter88 Committed by Commit bot

[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}
parent 9c6ff183
......@@ -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")
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_;
};
......
This diff is collapsed.
This diff is collapsed.
......@@ -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
: 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) {
ParseFunctionFlags flags = ParseFunctionFlags::kIsNormal;
if (Check(Token::MUL)) {
flags |= ParseFunctionFlags::kIsGenerator;
if (allow_harmony_restrictive_declarations()) {
PreParserTraits::ReportMessageAt(
scanner()->location(),
MessageTemplate::kGeneratorInLegacyContext);
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] = {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment