Commit 9377fd1a authored by Caitlin Potter's avatar Caitlin Potter Committed by Commit Bot

[async-iteration] implement parsing for AsyncGenerators

Just the front-end side of
https://chromium-review.googlesource.com/c/446961/. Adds support for
parsing AsyncGeneratorExpression, AsyncGeneratorDeclaration, and
AsyncGeneratorMethod, as well as parser tests.

BUG=v8:5855
R=neis@chromium.org, marja@chromium.org, littledan@chromium.org

Change-Id: I70e1a9681f22573f29292eacb4b9f57f9a38e2b2
Reviewed-on: https://chromium-review.googlesource.com/447117Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Reviewed-by: 's avatarMarja Hölttä <marja@chromium.org>
Commit-Queue: Caitlin Potter <caitp@igalia.com>
Cr-Commit-Position: refs/heads/master@{#44040}
parent 5f8c0a13
......@@ -324,10 +324,17 @@ void AstNumberingVisitor::VisitCallRuntime(CallRuntime* node) {
// has to stash it somewhere. Changing the runtime function into another
// one in ast-numbering seemed like a simple and straightforward solution to
// that problem.
if (node->is_jsruntime() &&
node->context_index() == Context::ASYNC_FUNCTION_AWAIT_CAUGHT_INDEX &&
catch_prediction_ == HandlerTable::ASYNC_AWAIT) {
node->set_context_index(Context::ASYNC_FUNCTION_AWAIT_UNCAUGHT_INDEX);
if (node->is_jsruntime() && catch_prediction_ == HandlerTable::ASYNC_AWAIT) {
switch (node->context_index()) {
case Context::ASYNC_FUNCTION_AWAIT_CAUGHT_INDEX:
node->set_context_index(Context::ASYNC_FUNCTION_AWAIT_UNCAUGHT_INDEX);
break;
case Context::ASYNC_GENERATOR_AWAIT_CAUGHT:
node->set_context_index(Context::ASYNC_GENERATOR_AWAIT_UNCAUGHT);
break;
default:
break;
}
}
}
......
......@@ -2508,6 +2508,8 @@ class Suspend final : public Expression {
static constexpr Flags kYieldStar = Flags::kYieldStar;
static constexpr Flags kAwait = Flags::kAwait;
static constexpr Flags kAsyncGenerator = Flags::kAsyncGenerator;
Expression* generator_object() const { return generator_object_; }
Expression* expression() const { return expression_; }
OnException on_exception() const {
......@@ -2525,6 +2527,9 @@ class Suspend final : public Expression {
bool is_yield() const { return suspend_type() == Flags::kYield; }
bool is_yield_star() const { return suspend_type() == Flags::kYieldStar; }
bool is_await() const { return suspend_type() == Flags::kAwait; }
bool is_async_generator() const {
return (suspend_type() & Flags::kGeneratorTypeMask) == kAsyncGenerator;
}
void set_generator_object(Expression* e) { generator_object_ = e; }
void set_expression(Expression* e) { expression_ = e; }
......
......@@ -767,6 +767,16 @@ Variable* DeclarationScope::DeclarePromiseVar(const AstRawString* name) {
return result;
}
Variable* DeclarationScope::DeclareAsyncGeneratorAwaitVar(
const AstRawString* name) {
DCHECK(is_function_scope());
DCHECK_NULL(async_generator_await_var());
Variable* result = EnsureRareData()->promise = NewTemporary(name);
DCHECK_NULL(promise_var()); // promise is alias for generator await var
result->set_is_used();
return result;
}
bool Scope::HasBeenRemoved() const {
if (sibling() == this) {
DCHECK_NULL(inner_scope_);
......
......@@ -704,6 +704,7 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope {
// Ignition without ScopeInfo.
Variable* DeclareGeneratorObjectVar(const AstRawString* name);
Variable* DeclarePromiseVar(const AstRawString* name);
Variable* DeclareAsyncGeneratorAwaitVar(const AstRawString* name);
// Declare a parameter in this scope. When there are duplicated
// parameters the rightmost one 'wins'. However, the implementation
......@@ -756,9 +757,16 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope {
Variable* promise_var() const {
DCHECK(is_function_scope());
DCHECK(IsAsyncFunction(function_kind_));
if (IsAsyncGeneratorFunction(function_kind_)) return nullptr;
return GetRareVariable(RareVariable::kPromise);
}
Variable* async_generator_await_var() const {
DCHECK(is_function_scope());
DCHECK(IsAsyncGeneratorFunction(function_kind_));
return GetRareVariable(RareVariable::kAsyncGeneratorAwaitResult);
}
// Parameters. The left-most parameter has index 0.
// Only valid for function and module scopes.
Variable* parameter(int index) const {
......@@ -936,7 +944,8 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope {
enum class RareVariable {
kThisFunction = offsetof(RareData, this_function),
kGeneratorObject = offsetof(RareData, generator_object),
kPromise = offsetof(RareData, promise)
kPromise = offsetof(RareData, promise),
kAsyncGeneratorAwaitResult = kPromise
};
V8_INLINE RareData* EnsureRareData() {
......
......@@ -35,55 +35,60 @@ enum ContextLookupFlags {
// must always be allocated via Heap::AllocateContext() or
// Factory::NewContext.
#define NATIVE_CONTEXT_INTRINSIC_FUNCTIONS(V) \
V(ASYNC_FUNCTION_AWAIT_CAUGHT_INDEX, JSFunction, \
async_function_await_caught) \
V(ASYNC_FUNCTION_AWAIT_UNCAUGHT_INDEX, JSFunction, \
async_function_await_uncaught) \
V(ASYNC_FUNCTION_PROMISE_CREATE_INDEX, JSFunction, \
async_function_promise_create) \
V(ASYNC_FUNCTION_PROMISE_RELEASE_INDEX, JSFunction, \
async_function_promise_release) \
V(IS_ARRAYLIKE, JSFunction, is_arraylike) \
V(GENERATOR_NEXT_INTERNAL, JSFunction, generator_next_internal) \
V(GET_TEMPLATE_CALL_SITE_INDEX, JSFunction, get_template_call_site) \
V(MAKE_ERROR_INDEX, JSFunction, make_error) \
V(MAKE_RANGE_ERROR_INDEX, JSFunction, make_range_error) \
V(MAKE_SYNTAX_ERROR_INDEX, JSFunction, make_syntax_error) \
V(MAKE_TYPE_ERROR_INDEX, JSFunction, make_type_error) \
V(MAKE_URI_ERROR_INDEX, JSFunction, make_uri_error) \
V(OBJECT_CREATE, JSFunction, object_create) \
V(OBJECT_DEFINE_PROPERTIES, JSFunction, object_define_properties) \
V(OBJECT_DEFINE_PROPERTY, JSFunction, object_define_property) \
V(OBJECT_FREEZE, JSFunction, object_freeze) \
V(OBJECT_GET_PROTOTYPE_OF, JSFunction, object_get_prototype_of) \
V(OBJECT_IS_EXTENSIBLE, JSFunction, object_is_extensible) \
V(OBJECT_IS_FROZEN, JSFunction, object_is_frozen) \
V(OBJECT_IS_SEALED, JSFunction, object_is_sealed) \
V(OBJECT_KEYS, JSFunction, object_keys) \
V(REGEXP_INTERNAL_MATCH, JSFunction, regexp_internal_match) \
V(REFLECT_APPLY_INDEX, JSFunction, reflect_apply) \
V(REFLECT_CONSTRUCT_INDEX, JSFunction, reflect_construct) \
V(REFLECT_DEFINE_PROPERTY_INDEX, JSFunction, reflect_define_property) \
V(REFLECT_DELETE_PROPERTY_INDEX, JSFunction, reflect_delete_property) \
V(SPREAD_ARGUMENTS_INDEX, JSFunction, spread_arguments) \
V(SPREAD_ITERABLE_INDEX, JSFunction, spread_iterable) \
V(TYPED_ARRAY_CONSTRUCT_BY_ARRAY_BUFFER_INDEX, JSFunction, \
typed_array_construct_by_array_buffer) \
V(TYPED_ARRAY_CONSTRUCT_BY_LENGTH_INDEX, JSFunction, \
typed_array_construct_by_length) \
V(TYPED_ARRAY_INITIALIZE_INDEX, JSFunction, typed_array_initialize) \
V(MATH_FLOOR_INDEX, JSFunction, math_floor) \
V(MATH_POW_INDEX, JSFunction, math_pow) \
V(NEW_PROMISE_CAPABILITY_INDEX, JSFunction, new_promise_capability) \
V(PROMISE_INTERNAL_CONSTRUCTOR_INDEX, JSFunction, \
promise_internal_constructor) \
V(PROMISE_INTERNAL_REJECT_INDEX, JSFunction, promise_internal_reject) \
V(IS_PROMISE_INDEX, JSFunction, is_promise) \
V(PROMISE_RESOLVE_INDEX, JSFunction, promise_resolve) \
V(PROMISE_THEN_INDEX, JSFunction, promise_then) \
V(PROMISE_HANDLE_INDEX, JSFunction, promise_handle) \
V(PROMISE_HANDLE_REJECT_INDEX, JSFunction, promise_handle_reject)
#define NATIVE_CONTEXT_INTRINSIC_FUNCTIONS(V) \
V(ASYNC_FUNCTION_AWAIT_CAUGHT_INDEX, JSFunction, \
async_function_await_caught) \
V(ASYNC_FUNCTION_AWAIT_UNCAUGHT_INDEX, JSFunction, \
async_function_await_uncaught) \
V(ASYNC_FUNCTION_PROMISE_CREATE_INDEX, JSFunction, \
async_function_promise_create) \
V(ASYNC_FUNCTION_PROMISE_RELEASE_INDEX, JSFunction, \
async_function_promise_release) \
V(IS_ARRAYLIKE, JSFunction, is_arraylike) \
V(GENERATOR_NEXT_INTERNAL, JSFunction, generator_next_internal) \
V(GET_TEMPLATE_CALL_SITE_INDEX, JSFunction, get_template_call_site) \
V(MAKE_ERROR_INDEX, JSFunction, make_error) \
V(MAKE_RANGE_ERROR_INDEX, JSFunction, make_range_error) \
V(MAKE_SYNTAX_ERROR_INDEX, JSFunction, make_syntax_error) \
V(MAKE_TYPE_ERROR_INDEX, JSFunction, make_type_error) \
V(MAKE_URI_ERROR_INDEX, JSFunction, make_uri_error) \
V(OBJECT_CREATE, JSFunction, object_create) \
V(OBJECT_DEFINE_PROPERTIES, JSFunction, object_define_properties) \
V(OBJECT_DEFINE_PROPERTY, JSFunction, object_define_property) \
V(OBJECT_FREEZE, JSFunction, object_freeze) \
V(OBJECT_GET_PROTOTYPE_OF, JSFunction, object_get_prototype_of) \
V(OBJECT_IS_EXTENSIBLE, JSFunction, object_is_extensible) \
V(OBJECT_IS_FROZEN, JSFunction, object_is_frozen) \
V(OBJECT_IS_SEALED, JSFunction, object_is_sealed) \
V(OBJECT_KEYS, JSFunction, object_keys) \
V(REGEXP_INTERNAL_MATCH, JSFunction, regexp_internal_match) \
V(REFLECT_APPLY_INDEX, JSFunction, reflect_apply) \
V(REFLECT_CONSTRUCT_INDEX, JSFunction, reflect_construct) \
V(REFLECT_DEFINE_PROPERTY_INDEX, JSFunction, reflect_define_property) \
V(REFLECT_DELETE_PROPERTY_INDEX, JSFunction, reflect_delete_property) \
V(SPREAD_ARGUMENTS_INDEX, JSFunction, spread_arguments) \
V(SPREAD_ITERABLE_INDEX, JSFunction, spread_iterable) \
V(TYPED_ARRAY_CONSTRUCT_BY_ARRAY_BUFFER_INDEX, JSFunction, \
typed_array_construct_by_array_buffer) \
V(TYPED_ARRAY_CONSTRUCT_BY_LENGTH_INDEX, JSFunction, \
typed_array_construct_by_length) \
V(TYPED_ARRAY_INITIALIZE_INDEX, JSFunction, typed_array_initialize) \
V(MATH_FLOOR_INDEX, JSFunction, math_floor) \
V(MATH_POW_INDEX, JSFunction, math_pow) \
V(NEW_PROMISE_CAPABILITY_INDEX, JSFunction, new_promise_capability) \
V(PROMISE_INTERNAL_CONSTRUCTOR_INDEX, JSFunction, \
promise_internal_constructor) \
V(PROMISE_INTERNAL_REJECT_INDEX, JSFunction, promise_internal_reject) \
V(IS_PROMISE_INDEX, JSFunction, is_promise) \
V(PROMISE_RESOLVE_INDEX, JSFunction, promise_resolve) \
V(PROMISE_THEN_INDEX, JSFunction, promise_then) \
V(PROMISE_HANDLE_INDEX, JSFunction, promise_handle) \
V(PROMISE_HANDLE_REJECT_INDEX, JSFunction, promise_handle_reject) \
V(ASYNC_GENERATOR_AWAIT_CAUGHT, JSFunction, async_generator_await_caught) \
V(ASYNC_GENERATOR_AWAIT_UNCAUGHT, JSFunction, \
async_generator_await_uncaught) \
V(ASYNC_GENERATOR_YIELD, JSFunction, async_generator_yield) \
V(ASYNC_GENERATOR_RAW_YIELD, JSFunction, async_generator_raw_yield)
#define NATIVE_CONTEXT_IMPORTED_FIELDS(V) \
V(ARRAY_CONCAT_INDEX, JSFunction, array_concat) \
......
......@@ -1100,7 +1100,11 @@ enum FunctionKind : uint16_t {
kClassConstructor =
kBaseConstructor | kDerivedConstructor | kDefaultConstructor,
kAsyncArrowFunction = kArrowFunction | kAsyncFunction,
kAsyncConciseMethod = kAsyncFunction | kConciseMethod
kAsyncConciseMethod = kAsyncFunction | kConciseMethod,
// https://tc39.github.io/proposal-async-iteration/
kAsyncConciseGeneratorMethod = kAsyncFunction | kConciseGeneratorMethod,
kAsyncGeneratorFunction = kAsyncFunction | kGeneratorFunction
};
inline bool IsValidFunctionKind(FunctionKind kind) {
......@@ -1119,7 +1123,9 @@ inline bool IsValidFunctionKind(FunctionKind kind) {
kind == FunctionKind::kDerivedConstructor ||
kind == FunctionKind::kAsyncFunction ||
kind == FunctionKind::kAsyncArrowFunction ||
kind == FunctionKind::kAsyncConciseMethod;
kind == FunctionKind::kAsyncConciseMethod ||
kind == FunctionKind::kAsyncConciseGeneratorMethod ||
kind == FunctionKind::kAsyncGeneratorFunction;
}
......@@ -1144,6 +1150,12 @@ inline bool IsAsyncFunction(FunctionKind kind) {
return (kind & FunctionKind::kAsyncFunction) != 0;
}
inline bool IsAsyncGeneratorFunction(FunctionKind kind) {
DCHECK(IsValidFunctionKind(kind));
const FunctionKind kMask = FunctionKind::kAsyncGeneratorFunction;
return (kind & kMask) == kMask;
}
inline bool IsResumableFunction(FunctionKind kind) {
return IsGeneratorFunction(kind) || IsAsyncFunction(kind) || IsModule(kind);
}
......@@ -1340,7 +1352,11 @@ enum class SuspendGeneratorFlags {
kAwait = 2,
kSuspendTypeMask = 3,
kBitWidth = 2,
kGenerator = 0 << 2,
kAsyncGenerator = 1 << 2,
kGeneratorTypeMask = 1 << 2,
kBitWidth = 3,
};
inline constexpr SuspendGeneratorFlags operator&(SuspendGeneratorFlags lhs,
......
This diff is collapsed.
This diff is collapsed.
......@@ -179,6 +179,7 @@ struct ParserTypes<Parser> {
typedef v8::internal::FunctionLiteral* FunctionLiteral;
typedef ObjectLiteral::Property* ObjectLiteralProperty;
typedef ClassLiteral::Property* ClassLiteralProperty;
typedef v8::internal::Suspend* Suspend;
typedef ZoneList<v8::internal::Expression*>* ExpressionList;
typedef ZoneList<ObjectLiteral::Property*>* ObjectPropertyList;
typedef ZoneList<ClassLiteral::Property*>* ClassPropertyList;
......@@ -673,6 +674,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
Expression* BuildResolvePromise(Expression* value, int pos);
Expression* BuildRejectPromise(Expression* value, int pos);
Variable* PromiseVariable();
Variable* AsyncGeneratorAwaitVariable();
// Generic AST generator for throwing errors from compiled code.
Expression* NewThrowError(Runtime::FunctionId function_id,
......@@ -687,7 +689,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
Statement* FinalizeForOfStatement(ForOfStatement* loop, Variable* completion,
IteratorType type, int pos);
void BuildIteratorClose(ZoneList<Statement*>* statements, Variable* iterator,
Variable* input, Variable* output);
Variable* input, Variable* output, IteratorType type);
void BuildIteratorCloseForCompletion(Scope* scope,
ZoneList<Statement*>* statements,
Variable* iterator,
......
......@@ -834,6 +834,7 @@ struct ParserTypes<PreParser> {
typedef PreParserExpression FunctionLiteral;
typedef PreParserExpression ObjectLiteralProperty;
typedef PreParserExpression ClassLiteralProperty;
typedef PreParserExpression Suspend;
typedef PreParserExpressionList ExpressionList;
typedef PreParserExpressionList ObjectPropertyList;
typedef PreParserExpressionList ClassPropertyList;
......
......@@ -77,6 +77,36 @@ RUNTIME_FUNCTION(Runtime_GeneratorGetInputOrDebugPos) {
return generator->input_or_debug_pos();
}
RUNTIME_FUNCTION(Runtime_AsyncGeneratorGetAwaitInput) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
// To be implemented in a followup CL
UNREACHABLE();
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_AsyncGeneratorReturn) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
// To be implemented in a followup CL
UNREACHABLE();
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_AsyncGeneratorReject) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
// To be implemented in a followup CL
UNREACHABLE();
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_GeneratorGetResumeMode) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
......
......@@ -239,6 +239,9 @@ namespace internal {
F(GeneratorGetReceiver, 1, 1) \
F(GeneratorGetContext, 1, 1) \
F(GeneratorGetInputOrDebugPos, 1, 1) \
F(AsyncGeneratorGetAwaitInput, 1, 1) \
F(AsyncGeneratorReturn, 2, 1) \
F(AsyncGeneratorReject, 2, 1) \
F(GeneratorGetContinuation, 1, 1) \
F(GeneratorGetSourcePosition, 1, 1) \
F(GeneratorGetResumeMode, 1, 1)
......
......@@ -9637,34 +9637,44 @@ TEST(ForAwaitOf) {
const char* context_data[][2] = {
{ "async function f() { for await ", " ; }" },
{ "async function f() { for await ", " { } }" },
{ "async function * f() { for await ", " { } }" },
{ "async function f() { 'use strict'; for await ", " ; }" },
{ "async function f() { 'use strict'; for await ", " { } }" },
{ "async function * f() { 'use strict'; for await ", " { } }" },
{ "async function f() { for\nawait ", " ; }" },
{ "async function f() { for\nawait ", " { } }" },
{ "async function * f() { for\nawait ", " { } }" },
{ "async function f() { 'use strict'; for\nawait ", " ; }" },
{ "async function f() { 'use strict'; for\nawait ", " { } }" },
{ "async function f() { 'use strict'; for\nawait ", " { } }" },
{ "async function * f() { 'use strict'; for\nawait ", " { } }" },
{ "async function f() { for await\n", " ; }" },
{ "async function f() { for await\n", " { } }" },
{ "async function * f() { for await\n", " { } }" },
{ "async function f() { 'use strict'; for await\n", " ; }" },
{ "async function f() { 'use strict'; for await\n", " { } }" },
{ "async function * f() { 'use strict'; for await\n", " { } }" },
{ NULL, NULL }
};
const char* context_data2[][2] = {
{ "async function f() { let a; for await ", " ; }" },
{ "async function f() { let a; for await ", " { } }" },
{ "async function * f() { let a; for await ", " { } }" },
{ "async function f() { 'use strict'; let a; for await ", " ; }" },
{ "async function f() { 'use strict'; let a; for await ", " { } }" },
{ "async function * f() { 'use strict'; let a; for await ", " { } }" },
{ "async function f() { let a; for\nawait ", " ; }" },
{ "async function f() { let a; for\nawait ", " { } }" },
{ "async function * f() { let a; for\nawait ", " { } }" },
{ "async function f() { 'use strict'; let a; for\nawait ", " ; }" },
{ "async function f() { 'use strict'; let a; for\nawait ", " { } }" },
{ "async function f() { 'use strict'; let a; for\nawait ", " { } }" },
{ "async function * f() { 'use strict'; let a; for\nawait ", " { } }" },
{ "async function f() { let a; for await\n", " ; }" },
{ "async function f() { let a; for await\n", " { } }" },
{ "async function * f() { let a; for await\n", " { } }" },
{ "async function f() { 'use strict'; let a; for await\n", " ; }" },
{ "async function f() { 'use strict'; let a; for await\n", " { } }" },
{ "async function * f() { 'use strict'; let a; for await\n", " { } }" },
{ NULL, NULL }
};
......@@ -9775,6 +9785,10 @@ TEST(ForAwaitOfErrors) {
{ "async function f() { for await ", " { } }" },
{ "async function f() { 'use strict'; for await ", " ; }" },
{ "async function f() { 'use strict'; for await ", " { } }" },
{ "async function * f() { for await ", " ; }" },
{ "async function * f() { for await ", " { } }" },
{ "async function * f() { 'use strict'; for await ", " ; }" },
{ "async function * f() { 'use strict'; for await ", " { } }" },
{ NULL, NULL }
};
......@@ -9951,3 +9965,192 @@ TEST(ForAwaitOfFunctionDeclaration) {
RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags,
arraysize(always_flags));
}
TEST(AsyncGenerator) {
// clang-format off
const char* context_data[][2] = {
{ "async function * gen() {", "}" },
{ "(async function * gen() {", "})" },
{ "(async function * () {", "})" },
{ "({ async * gen () {", "} })" },
{ NULL, NULL }
};
const char* statement_data[] = {
// An async generator without a body is valid.
""
// Valid yield expressions inside generators.
"yield 2;",
"yield * 2;",
"yield * \n 2;",
"yield yield 1;",
"yield * yield * 1;",
"yield 3 + (yield 4);",
"yield * 3 + (yield * 4);",
"(yield * 3) + (yield * 4);",
"yield 3; yield 4;",
"yield * 3; yield * 4;",
"(function (yield) { })",
"(function yield() { })",
"(function (await) { })",
"(function await() { })",
"yield { yield: 12 }",
"yield /* comment */ { yield: 12 }",
"yield * \n { yield: 12 }",
"yield /* comment */ * \n { yield: 12 }",
// You can return in an async generator.
"yield 1; return",
"yield * 1; return",
"yield 1; return 37",
"yield * 1; return 37",
"yield 1; return 37; yield 'dead';",
"yield * 1; return 37; yield * 'dead';",
// Yield/Await are still a valid key in object literals.
"({ yield: 1 })",
"({ get yield() { } })",
"({ await: 1 })",
"({ get await() { } })",
// And in assignment pattern computed properties
"({ [yield]: x } = { })",
"({ [await 1]: x } = { })",
// Yield without RHS.
"yield;",
"yield",
"yield\n",
"yield /* comment */"
"yield // comment\n"
"(yield)",
"[yield]",
"{yield}",
"yield, yield",
"yield; yield",
"(yield) ? yield : yield",
"(yield) \n ? yield : yield",
// If there is a newline before the next token, we don't look for RHS.
"yield\nfor (;;) {}",
"x = class extends (yield) {}",
"x = class extends f(yield) {}",
"x = class extends (null, yield) { }",
"x = class extends (a ? null : yield) { }",
"x = class extends (await 10) {}",
"x = class extends f(await 10) {}",
"x = class extends (null, await 10) { }",
"x = class extends (a ? null : await 10) { }",
// More tests featuring AwaitExpressions
"await 10",
"await 10; return",
"await 10; return 20",
"await 10; return 20; yield 'dead'",
"await (yield 10)",
"await (yield 10); return",
"await (yield 10); return 20",
"await (yield 10); return 20; yield 'dead'",
"yield await 10",
"yield await 10; return",
"yield await 10; return 20",
"yield await 10; return 20; yield 'dead'",
"await /* comment */ 10",
"await // comment\n 10",
"yield await /* comment\n */ 10",
"yield await // comment\n 10",
"await (yield /* comment */)",
"await (yield // comment\n)",
NULL
};
// clang-format on
static const ParserFlag always_flags[] = {kAllowHarmonyAsyncIteration};
RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
always_flags, arraysize(always_flags));
}
TEST(AsyncGeneratorErrors) {
// clang-format off
const char* context_data[][2] = {
{ "async function * gen() {", "}" },
{ "\"use strict\"; async function * gen() {", "}" },
{ NULL, NULL }
};
const char* statement_data[] = {
// Invalid yield expressions inside generators.
"var yield;",
"var await;",
"var foo, yield;",
"var foo, await;",
"try { } catch (yield) { }",
"try { } catch (await) { }",
"function yield() { }",
"function await() { }",
// The name of the NFE is bound in the generator, which does not permit
// yield or await to be identifiers.
"(async function * yield() { })",
"(async function * await() { })",
// Yield and Await aren't valid as a formal parameter for generators.
"async function * foo(yield) { }",
"(async function * foo(yield) { })",
"async function * foo(await) { }",
"(async function * foo(await) { })",
"yield = 1;",
"await = 1;",
"var foo = yield = 1;",
"var foo = await = 1;",
"++yield;",
"++await;",
"yield++;",
"await++;",
"yield *",
"(yield *)",
// Yield binds very loosely, so this parses as "yield (3 + yield 4)", which
// is invalid.
"yield 3 + yield 4;",
"yield: 34",
"yield ? 1 : 2",
// Parses as yield (/ yield): invalid.
"yield / yield",
"+ yield",
"+ yield 3",
// Invalid (no newline allowed between yield and *).
"yield\n*3",
// Invalid (we see a newline, so we parse {yield:42} as a statement, not an
// object literal, and yield is not a valid label).
"yield\n{yield: 42}",
"yield /* comment */\n {yield: 42}",
"yield //comment\n {yield: 42}",
// Destructuring binding and assignment are both disallowed
"var [yield] = [42];",
"var [await] = [42];",
"var {foo: yield} = {a: 42};",
"var {foo: await} = {a: 42};",
"[yield] = [42];",
"[await] = [42];",
"({a: yield} = {a: 42});",
"({a: await} = {a: 42});",
// Also disallow full yield/await expressions on LHS
"var [yield 24] = [42];",
"var [await 24] = [42];",
"var {foo: yield 24} = {a: 42};",
"var {foo: await 24} = {a: 42};",
"[yield 24] = [42];",
"[await 24] = [42];",
"({a: yield 24} = {a: 42});",
"({a: await 24} = {a: 42});",
"for (yield 'x' in {});",
"for (await 'x' in {});",
"for (yield 'x' of {});",
"for (await 'x' of {});",
"for (yield 'x' in {} in {});",
"for (await 'x' in {} in {});",
"for (yield 'x' in {} of {});",
"for (await 'x' in {} of {});",
"class C extends yield { }",
"class C extends await { }",
NULL
};
// clang-format on
static const ParserFlag always_flags[] = {kAllowHarmonyAsyncIteration};
RunParserSyncTest(context_data, statement_data, kError, NULL, 0, always_flags,
arraysize(always_flags));
}
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