fa0066d170
e3246ad69c
removed some redundancies in yield and yield*.
In particular:
- AsyncGeneratorRawYield becomes unnecessary, and is deleted in this CL
- Parser::RewriteYieldStar() is updated to perform the IteratorValue() algorithm as appropriate
BUG=v8:6187, v8:5855
R=rmcilroy@chromium.org, adamk@chromium.org, littledan@chromium.org, vogelheim@chromium.org
Change-Id: I05e8429b9cbd4531c330ee53a05656b90162064c
Reviewed-on: https://chromium-review.googlesource.com/471806
Reviewed-by: Ross McIlroy <rmcilroy@chromium.org>
Reviewed-by: Georg Neis <neis@chromium.org>
Reviewed-by: Daniel Vogelheim <vogelheim@chromium.org>
Commit-Queue: Caitlin Potter <caitp@igalia.com>
Cr-Commit-Position: refs/heads/master@{#44649}
1731 lines
55 KiB
JavaScript
1731 lines
55 KiB
JavaScript
// Copyright 2017 the V8 project authors. All rights reserved.
|
||
// Use of this source code is governed by a BSD-style license that can be
|
||
// found in the LICENSE file.
|
||
|
||
// Flags: --harmony-async-iteration --allow-natives-syntax
|
||
|
||
function assertThrowsAsync(run, errorType, message) {
|
||
var actual;
|
||
var hadValue = false;
|
||
var hadError = false;
|
||
var promise = run();
|
||
|
||
if (typeof promise !== "object" || typeof promise.then !== "function") {
|
||
throw new MjsUnitAssertionError(
|
||
`Expected ${run.toString()} to return a Promise, but it returned ` +
|
||
PrettyPrint(promise));
|
||
}
|
||
|
||
promise.then(function(value) { hadValue = true; actual = value; },
|
||
function(error) { hadError = true; actual = error; });
|
||
|
||
assertFalse(hadValue || hadError);
|
||
|
||
%RunMicrotasks();
|
||
|
||
if (!hadError) {
|
||
throw new MjsUnitAssertionError(
|
||
"Expected " + run + "() to throw " + errorType.name +
|
||
", but did not throw.");
|
||
}
|
||
if (!(actual instanceof errorType))
|
||
throw new MjsUnitAssertionError(
|
||
"Expected " + run + "() to throw " + errorType.name +
|
||
", but threw '" + actual + "'");
|
||
if (message !== void 0 && actual.message !== message)
|
||
throw new MjsUnitAssertionError(
|
||
"Expected " + run + "() to throw '" + message + "', but threw '" +
|
||
actual.message + "'");
|
||
};
|
||
|
||
function assertEqualsAsync(expected, run, msg) {
|
||
var actual;
|
||
var hadValue = false;
|
||
var hadError = false;
|
||
var promise = run();
|
||
|
||
if (typeof promise !== "object" || typeof promise.then !== "function") {
|
||
throw new MjsUnitAssertionError(
|
||
`Expected ${run.toString()} to return a Promise, but it returned ` +
|
||
`${promise}`);
|
||
}
|
||
|
||
promise.then(function(value) { hadValue = true; actual = value; },
|
||
function(error) { hadError = true; actual = error; });
|
||
|
||
assertFalse(hadValue || hadError);
|
||
|
||
%RunMicrotasks();
|
||
|
||
if (hadError) throw actual;
|
||
|
||
assertTrue(
|
||
hadValue, "Expected '" + run.toString() + "' to produce a value");
|
||
|
||
assertEquals(expected, actual, msg);
|
||
};
|
||
|
||
class MyError extends Error {};
|
||
function Thrower(msg) { throw new MyError(msg); }
|
||
function Rejecter(msg) {
|
||
return new Promise(function(resolve, reject) {
|
||
Promise.resolve().then(function() {
|
||
reject(new MyError(msg));
|
||
});
|
||
});
|
||
}
|
||
function Resolver(msg) {
|
||
return new Promise(function(resolve, reject) {
|
||
Promise.resolve().then(function() {
|
||
resolve(msg);
|
||
});
|
||
});
|
||
}
|
||
|
||
async function ForAwaitOfValues(it) {
|
||
let array = [];
|
||
for await (let x of it) array.push(x);
|
||
return array;
|
||
}
|
||
|
||
let log = [];
|
||
function logIterResult(iter_result) {
|
||
log.push(iter_result);
|
||
}
|
||
function logError(error) {
|
||
log.push(error);
|
||
}
|
||
|
||
function AbortUnreachable() {
|
||
%AbortJS("This code should not be reachable.");
|
||
}
|
||
|
||
// ----------------------------------------------------------------------------
|
||
// Do not install `AsyncGeneratorFunction` constructor on global object
|
||
assertEquals(undefined, this.AsyncGeneratorFunction);
|
||
let AsyncGeneratorFunction = (async function*() {}).constructor;
|
||
|
||
// ----------------------------------------------------------------------------
|
||
// The AsyncGeneratorFunction Constructor is the %AsyncGeneratorFunction%
|
||
// intrinsic object and is a subclass of Function.
|
||
// (proposal-async-iteration/#sec-asyncgeneratorfunction-constructor)
|
||
assertEquals(Object.getPrototypeOf(AsyncGeneratorFunction), Function);
|
||
assertEquals(Object.getPrototypeOf(AsyncGeneratorFunction.prototype),
|
||
Function.prototype);
|
||
assertTrue(async function*() {} instanceof Function);
|
||
|
||
// ----------------------------------------------------------------------------
|
||
// Let functionPrototype be the intrinsic object %AsyncGeneratorPrototype%.
|
||
async function* asyncGeneratorForProto() {}
|
||
assertEquals(AsyncGeneratorFunction.prototype,
|
||
Object.getPrototypeOf(asyncGeneratorForProto));
|
||
assertEquals(AsyncGeneratorFunction.prototype,
|
||
Object.getPrototypeOf(async function*() {}));
|
||
assertEquals(AsyncGeneratorFunction.prototype,
|
||
Object.getPrototypeOf({ async* method() {} }.method));
|
||
assertEquals(AsyncGeneratorFunction.prototype,
|
||
Object.getPrototypeOf(AsyncGeneratorFunction()));
|
||
assertEquals(AsyncGeneratorFunction.prototype,
|
||
Object.getPrototypeOf(new AsyncGeneratorFunction()));
|
||
|
||
// ----------------------------------------------------------------------------
|
||
// AsyncGeneratorFunctionCreate produces a function whose prototype property is
|
||
// derived from %AsyncGeneratorPrototype%
|
||
assertEquals(AsyncGeneratorFunction.prototype.prototype,
|
||
Object.getPrototypeOf(asyncGeneratorForProto.prototype));
|
||
assertTrue(asyncGeneratorForProto.hasOwnProperty("prototype"));
|
||
assertEquals(AsyncGeneratorFunction.prototype.prototype,
|
||
Object.getPrototypeOf((async function*() {}).prototype));
|
||
assertTrue((async function*() {}).hasOwnProperty("prototype"));
|
||
assertEquals(AsyncGeneratorFunction.prototype.prototype,
|
||
Object.getPrototypeOf(({ async* method() {} }).method.prototype));
|
||
assertTrue(({ async* method() {} }).method.hasOwnProperty("prototype"));
|
||
assertEquals(AsyncGeneratorFunction.prototype.prototype,
|
||
Object.getPrototypeOf(AsyncGeneratorFunction().prototype));
|
||
assertTrue(AsyncGeneratorFunction().hasOwnProperty("prototype"));
|
||
assertEquals(AsyncGeneratorFunction.prototype.prototype,
|
||
Object.getPrototypeOf(new AsyncGeneratorFunction().prototype));
|
||
assertTrue(new AsyncGeneratorFunction().hasOwnProperty("prototype"));
|
||
|
||
// ----------------------------------------------------------------------------
|
||
// Basic Function.prototype.toString()
|
||
async function* asyncGeneratorForToString() {}
|
||
assertEquals("async function* asyncGeneratorForToString() {}",
|
||
asyncGeneratorForToString.toString());
|
||
|
||
assertEquals("async function* () {}", async function*() {}.toString());
|
||
assertEquals("async function* namedAsyncGeneratorForToString() {}",
|
||
async function* namedAsyncGeneratorForToString() {}.toString());
|
||
|
||
assertEquals("async *method() { }",
|
||
({ async *method() { } }).method.toString());
|
||
assertEquals("async *method() { }",
|
||
(class { static async *method() { } }).method.toString());
|
||
assertEquals("async *method() { }",
|
||
(new (class { async *method() { } })).method.toString());
|
||
|
||
assertEquals("async function* anonymous() {\n\n}",
|
||
AsyncGeneratorFunction().toString());
|
||
assertEquals("async function* anonymous() {\n\n}",
|
||
(new AsyncGeneratorFunction()).toString());
|
||
|
||
// ----------------------------------------------------------------------------
|
||
// AsyncGenerator functions syntactically allow AwaitExpressions
|
||
assertEquals(1, async function*(a) { await 1; }.length);
|
||
assertEquals(2, async function*(a, b) { await 1; }.length);
|
||
assertEquals(1, async function*(a, b = 2) { await 1; }.length);
|
||
assertEquals(2, async function*(a, b, ...c) { await 1; }.length);
|
||
|
||
assertEquals(1, ({ async* f(a) { await 1; } }).f.length);
|
||
assertEquals(2, ({ async* f(a, b) { await 1; } }).f.length);
|
||
assertEquals(1, ({ async* f(a, b = 2) { await 1; } }).f.length);
|
||
assertEquals(2, ({ async* f(a, b, ...c) { await 1; } }).f.length);
|
||
|
||
assertEquals(1, AsyncGeneratorFunction("a", "await 1").length);
|
||
assertEquals(2, AsyncGeneratorFunction("a", "b", "await 1").length);
|
||
assertEquals(1, AsyncGeneratorFunction("a", "b = 2", "await 1").length);
|
||
assertEquals(2, AsyncGeneratorFunction("a", "b", "...c", "await 1").length);
|
||
|
||
assertEquals(1, (new AsyncGeneratorFunction("a", "await 1")).length);
|
||
assertEquals(2, (new AsyncGeneratorFunction("a", "b", "await 1")).length);
|
||
assertEquals(1, (new AsyncGeneratorFunction("a", "b = 2", "await 1")).length);
|
||
assertEquals(2,
|
||
(new AsyncGeneratorFunction("a", "b", "...c", "await 1")).length);
|
||
|
||
// ----------------------------------------------------------------------------
|
||
// AsyncGenerator functions syntactically allow YieldExpressions
|
||
assertEquals(1, async function*(a) { yield 1; }.length);
|
||
assertEquals(2, async function*(a, b) { yield 1; }.length);
|
||
assertEquals(1, async function*(a, b = 2) { yield 1; }.length);
|
||
assertEquals(2, async function*(a, b, ...c) { yield 1; }.length);
|
||
|
||
assertEquals(1, ({ async* f(a) { yield 1; } }).f.length);
|
||
assertEquals(2, ({ async* f(a, b) { yield 1; } }).f.length);
|
||
assertEquals(1, ({ async* f(a, b = 2) { yield 1; } }).f.length);
|
||
assertEquals(2, ({ async* f(a, b, ...c) { yield 1; } }).f.length);
|
||
|
||
assertEquals(1, AsyncGeneratorFunction("a", "yield 1").length);
|
||
assertEquals(2, AsyncGeneratorFunction("a", "b", "yield 1").length);
|
||
assertEquals(1, AsyncGeneratorFunction("a", "b = 2", "yield 1").length);
|
||
assertEquals(2, AsyncGeneratorFunction("a", "b", "...c", "yield 1").length);
|
||
|
||
assertEquals(1, (new AsyncGeneratorFunction("a", "yield 1")).length);
|
||
assertEquals(2, (new AsyncGeneratorFunction("a", "b", "yield 1")).length);
|
||
assertEquals(1, (new AsyncGeneratorFunction("a", "b = 2", "yield 1")).length);
|
||
assertEquals(2,
|
||
(new AsyncGeneratorFunction("a", "b", "...c", "yield 1")).length);
|
||
|
||
// ----------------------------------------------------------------------------
|
||
// AsyncGeneratorFunction.prototype[ @@toStringTag ]
|
||
var descriptor =
|
||
Object.getOwnPropertyDescriptor(AsyncGeneratorFunction.prototype,
|
||
Symbol.toStringTag);
|
||
assertEquals("AsyncGeneratorFunction", descriptor.value);
|
||
assertEquals(false, descriptor.enumerable);
|
||
assertEquals(false, descriptor.writable);
|
||
assertEquals(true, descriptor.configurable);
|
||
|
||
assertEquals(1, AsyncGeneratorFunction.length);
|
||
|
||
// ----------------------------------------------------------------------------
|
||
// Let F be ! FunctionAllocate(functionPrototype, Strict, "non-constructor")
|
||
async function* asyncNonConstructorDecl() {}
|
||
assertThrows(() => new asyncNonConstructorDecl(), TypeError);
|
||
assertThrows(() => asyncNonConstructorDecl.caller, TypeError);
|
||
assertThrows(() => asyncNonConstructorDecl.arguments, TypeError);
|
||
|
||
assertThrows(() => new (async function*() {}), TypeError);
|
||
assertThrows(() => (async function*() {}).caller, TypeError);
|
||
assertThrows(() => (async function*() {}).arguments, TypeError);
|
||
|
||
assertThrows(
|
||
() => new ({ async* nonConstructor() {} }).nonConstructor(), TypeError);
|
||
assertThrows(
|
||
() => ({ async* nonConstructor() {} }).nonConstructor.caller, TypeError);
|
||
assertThrows(
|
||
() => ({ async* nonConstructor() {} }).nonConstructor.arguments, TypeError);
|
||
|
||
assertThrows(
|
||
() => new (AsyncGeneratorFunction("nonconstructor"))(), TypeError);
|
||
assertThrows(
|
||
() => AsyncGeneratorFunction("nonconstructor").caller, TypeError);
|
||
assertThrows(
|
||
() => AsyncGeneratorFunction("nonconstructor").arguments, TypeError);
|
||
|
||
assertThrows(
|
||
() => new (new AsyncGeneratorFunction("nonconstructor"))(), TypeError);
|
||
assertThrows(
|
||
() => (new AsyncGeneratorFunction("nonconstructor")).caller, TypeError);
|
||
assertThrows(
|
||
() => (new AsyncGeneratorFunction("nonconstructor")).arguments, TypeError);
|
||
|
||
// ----------------------------------------------------------------------------
|
||
// Empty functions
|
||
async function* emptyAsyncGenerator() {}
|
||
let it = emptyAsyncGenerator();
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = (async function* emptyAsyncGeneratorExpr() { })();
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = ({ async* method() { } }).method();
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = AsyncGeneratorFunction(``)();
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = (new AsyncGeneratorFunction(``))();
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
|
||
// ----------------------------------------------------------------------------
|
||
// Top-level ReturnStatement
|
||
async function* asyncGeneratorForReturn() {
|
||
return "boop1";
|
||
throw "(unreachble)";
|
||
}
|
||
it = asyncGeneratorForReturn();
|
||
assertEqualsAsync({ value: "boop1", done: true }, () => it.next());
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = (async function*() {
|
||
return "boop2";
|
||
throw "(unreachable)";
|
||
})();
|
||
assertEqualsAsync({ value: "boop2", done: true }, () => it.next());
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = ({ async* method() { return "boop3"; throw "(unreachable)"; } }).method();
|
||
assertEqualsAsync({ value: "boop3", done: true }, () => it.next());
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = AsyncGeneratorFunction(`
|
||
return "boop4";
|
||
throw "(unreachable)";`)();
|
||
assertEqualsAsync({ value: "boop4", done: true }, () => it.next());
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = (new AsyncGeneratorFunction(`
|
||
return "boop5";
|
||
throw "(unreachable)";`))();
|
||
assertEqualsAsync({ value: "boop5", done: true }, () => it.next());
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
// ----------------------------------------------------------------------------
|
||
// Top-level ReturnStatement after await
|
||
async function* asyncGeneratorForReturnAfterAwait() {
|
||
await 1;
|
||
return "boop6";
|
||
throw "(unreachable)";
|
||
}
|
||
it = asyncGeneratorForReturnAfterAwait();
|
||
assertEqualsAsync({ value: "boop6", done: true }, () => it.next());
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = (async function*() { await 1; return "boop7"; throw "(unreachable)"; })();
|
||
assertEqualsAsync({ value: "boop7", done: true }, () => it.next());
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = ({
|
||
async* method() {
|
||
await 1;
|
||
return "boop8";
|
||
throw "(unreachable)";
|
||
}
|
||
}).method();
|
||
assertEqualsAsync({ value: "boop8", done: true }, () => it.next());
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = AsyncGeneratorFunction(`
|
||
await 1;
|
||
return "boop9";
|
||
throw "(unreachable)"`)();
|
||
assertEqualsAsync({ value: "boop9", done: true }, () => it.next());
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = (new AsyncGeneratorFunction(`
|
||
await 1;
|
||
return "boop10";
|
||
throw "(unreachable)"`))();
|
||
assertEqualsAsync({ value: "boop10", done: true }, () => it.next());
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
// ----------------------------------------------------------------------------
|
||
// Top-level Yields
|
||
|
||
async function* asyncGeneratorForYields() {
|
||
yield 1;
|
||
yield await Resolver(2);
|
||
yield Resolver(3);
|
||
return 4;
|
||
throw "(unreachable)";
|
||
}
|
||
|
||
it = asyncGeneratorForYields();
|
||
assertEqualsAsync([1, 2, 3], () => ForAwaitOfValues(it));
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = (async function*() {
|
||
yield "cow";
|
||
yield await Resolver("bird");
|
||
yield await "dog";
|
||
yield Resolver("donkey");
|
||
return "badger";
|
||
throw "(unreachable)"; })();
|
||
assertEqualsAsync(["cow", "bird", "dog", "donkey"], () => ForAwaitOfValues(it));
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = ({
|
||
async* method() {
|
||
yield "A";
|
||
yield await Resolver("B");
|
||
yield await "C";
|
||
yield Resolver("CC");
|
||
return "D";
|
||
throw "(unreachable)";
|
||
}
|
||
}).method();
|
||
assertEqualsAsync(["A", "B", "C", "CC"], () => ForAwaitOfValues(it));
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = AsyncGeneratorFunction(`
|
||
yield "alpha";
|
||
yield await Resolver("beta");
|
||
yield await "gamma";
|
||
yield Resolver("delta");
|
||
return "epsilon";
|
||
throw "(unreachable)"`)();
|
||
assertEqualsAsync(["alpha", "beta", "gamma", "delta"],
|
||
() => ForAwaitOfValues(it));
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = (new AsyncGeneratorFunction(`
|
||
yield "α";
|
||
yield await Resolver("β");
|
||
yield await "γ";
|
||
yield Resolver("δ");
|
||
return "ε";
|
||
throw "(unreachable)"`))();
|
||
assertEqualsAsync(["α", "β", "γ", "δ"], () => ForAwaitOfValues(it));
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
// ----------------------------------------------------------------------------
|
||
// Nested Resume via [AsyncGenerator].next()
|
||
log = [];
|
||
async function* asyncGeneratorForNestedResumeNext() {
|
||
it.next().then(logIterResult, logError);
|
||
it.next().then(logIterResult, logError);
|
||
yield "rootbeer";
|
||
yield await Resolver("float");
|
||
}
|
||
it = asyncGeneratorForNestedResumeNext();
|
||
it.next().then(logIterResult, AbortUnreachable);
|
||
%RunMicrotasks();
|
||
assertEquals([
|
||
{ value: "rootbeer", done: false },
|
||
{ value: "float", done: false },
|
||
{ value: undefined, done: true }
|
||
], log);
|
||
|
||
log = [];
|
||
let asyncGeneratorExprForNestedResumeNext = async function*() {
|
||
it.next().then(logIterResult, logError);
|
||
it.next().then(logIterResult, logError);
|
||
yield "first";
|
||
yield await Resolver("second");
|
||
};
|
||
it = asyncGeneratorExprForNestedResumeNext();
|
||
it.next().then(logIterResult, AbortUnreachable);
|
||
%RunMicrotasks();
|
||
assertEquals([
|
||
{ value: "first", done: false },
|
||
{ value: "second", done: false },
|
||
{ value: undefined, done: true }
|
||
], log);
|
||
|
||
log = [];
|
||
let asyncGeneratorMethodForNestedResumeNext = ({
|
||
async* method() {
|
||
it.next().then(logIterResult, logError);
|
||
it.next().then(logIterResult, logError);
|
||
yield "remember";
|
||
yield await Resolver("the cant!");
|
||
}
|
||
}).method;
|
||
it = asyncGeneratorMethodForNestedResumeNext();
|
||
it.next().then(logIterResult, AbortUnreachable);
|
||
%RunMicrotasks();
|
||
assertEquals([
|
||
{ value: "remember", done: false },
|
||
{ value: "the cant!", done: false },
|
||
{ value: undefined, done: true }
|
||
], log);
|
||
|
||
log = [];
|
||
let asyncGeneratorCallEvalForNestedResumeNext =
|
||
AsyncGeneratorFunction(`
|
||
it.next().then(logIterResult, logError);
|
||
it.next().then(logIterResult, logError);
|
||
yield "reading";
|
||
yield await Resolver("rainbow!");`);
|
||
it = asyncGeneratorCallEvalForNestedResumeNext();
|
||
it.next().then(logIterResult, AbortUnreachable);
|
||
%RunMicrotasks();
|
||
assertEquals([
|
||
{ value: "reading", done: false },
|
||
{ value: "rainbow!", done: false },
|
||
{ value: undefined, done: true }
|
||
], log);
|
||
|
||
log = [];
|
||
let asyncGeneratorNewEvalForNestedResumeNext =
|
||
new AsyncGeneratorFunction(`
|
||
it.next().then(logIterResult, logError);
|
||
it.next().then(logIterResult, logError);
|
||
yield 731;
|
||
yield await Resolver("BB!");`);
|
||
it = asyncGeneratorNewEvalForNestedResumeNext();
|
||
it.next().then(logIterResult, AbortUnreachable);
|
||
%RunMicrotasks();
|
||
assertEquals([
|
||
{ value: 731, done: false },
|
||
{ value: "BB!", done: false },
|
||
{ value: undefined, done: true }
|
||
], log);
|
||
|
||
// ----------------------------------------------------------------------------
|
||
// Nested Resume via [AsyncGenerator].throw()
|
||
log = [];
|
||
async function* asyncGeneratorForNestedResumeThrow() {
|
||
try {
|
||
it.throw(await Rejecter("...")).then(logIterResult, logError);
|
||
} catch (e) {
|
||
it.throw("throw2").then(logIterResult, logError);
|
||
it.next().then(logIterResult, logError);
|
||
throw "throw1";
|
||
}
|
||
AbortUnreachable();
|
||
}
|
||
it = asyncGeneratorForNestedResumeThrow();
|
||
it.next().then(logIterResult, logError);
|
||
%RunMicrotasks();
|
||
assertEquals([
|
||
"throw1",
|
||
"throw2",
|
||
{ value: undefined, done: true }
|
||
], log);
|
||
|
||
log = [];
|
||
let asyncGeneratorExprForNestedResumeThrow = async function*() {
|
||
try {
|
||
it.throw(await Rejecter("...")).then(logIterResult, logError);
|
||
} catch (e) {
|
||
it.throw("throw4").then(logIterResult, logError);
|
||
it.next().then(logIterResult, logError);
|
||
throw "throw3";
|
||
}
|
||
AbortUnreachable();
|
||
};
|
||
it = asyncGeneratorExprForNestedResumeThrow();
|
||
it.next().then(logIterResult, logError);
|
||
%RunMicrotasks();
|
||
assertEquals([
|
||
"throw3",
|
||
"throw4",
|
||
{ value: undefined, done: true }
|
||
], log);
|
||
|
||
log = [];
|
||
let asyncGeneratorMethodForNestedResumeThrow = ({
|
||
async* method() {
|
||
try {
|
||
it.throw(await Rejecter("...")).then(logIterResult, logError);
|
||
} catch (e) {
|
||
it.throw("throw6").then(logIterResult, logError);
|
||
it.next().then(logIterResult, logError);
|
||
throw "throw5";
|
||
}
|
||
AbortUnreachable();
|
||
}
|
||
}).method;
|
||
it = asyncGeneratorMethodForNestedResumeThrow();
|
||
it.next().then(logIterResult, logError);
|
||
%RunMicrotasks();
|
||
assertEquals([
|
||
"throw5",
|
||
"throw6",
|
||
{ value: undefined, done: true }
|
||
], log);
|
||
|
||
log = [];
|
||
let asyncGeneratorCallEvalForNestedResumeThrow =
|
||
AsyncGeneratorFunction(`
|
||
try {
|
||
it.throw(await Rejecter("...")).then(logIterResult, logError);
|
||
} catch (e) {
|
||
it.throw("throw8").then(logIterResult, logError);
|
||
it.next().then(logIterResult, logError);
|
||
throw "throw7";
|
||
}
|
||
AbortUnreachable();`);
|
||
it = asyncGeneratorCallEvalForNestedResumeThrow();
|
||
it.next().then(logIterResult, logError);
|
||
%RunMicrotasks();
|
||
assertEquals([
|
||
"throw7",
|
||
"throw8",
|
||
{ value: undefined, done: true }
|
||
], log);
|
||
|
||
log = [];
|
||
let asyncGeneratorNewEvalForNestedResumeThrow =
|
||
new AsyncGeneratorFunction(`
|
||
try {
|
||
it.throw(await Rejecter("...")).then(logIterResult, logError);
|
||
} catch (e) {
|
||
it.throw("throw10").then(logIterResult, logError);
|
||
it.next().then(logIterResult, logError);
|
||
throw "throw9";
|
||
}
|
||
AbortUnreachable();`);
|
||
it = asyncGeneratorNewEvalForNestedResumeThrow();
|
||
it.next().then(logIterResult, logError);
|
||
%RunMicrotasks();
|
||
assertEquals([
|
||
"throw9",
|
||
"throw10",
|
||
{ value: undefined, done: true }
|
||
], log);
|
||
|
||
// ----------------------------------------------------------------------------
|
||
// Nested Resume via [AsyncGenerator].return()
|
||
log = [];
|
||
async function* asyncGeneratorForNestedResumeReturn() {
|
||
it.return("step2").then(logIterResult, logError);
|
||
it.next().then(logIterResult, logError);
|
||
yield "step1";
|
||
AbortUnreachable();
|
||
}
|
||
it = asyncGeneratorForNestedResumeReturn();
|
||
it.next().then(logIterResult, logError);
|
||
%RunMicrotasks();
|
||
assertEquals([
|
||
{ value: "step1", done: false },
|
||
{ value: "step2", done: true },
|
||
{ value: undefined, done: true },
|
||
], log);
|
||
|
||
log = [];
|
||
let asyncGeneratorExprForNestedResumeReturn = async function*() {
|
||
it.return("step4").then(logIterResult, logError);
|
||
it.next().then(logIterResult, logError);
|
||
yield "step3";
|
||
};
|
||
it = asyncGeneratorExprForNestedResumeReturn();
|
||
it.next().then(logIterResult, logError);
|
||
%RunMicrotasks();
|
||
assertEquals([
|
||
{ value: "step3", done: false },
|
||
{ value: "step4", done: true },
|
||
{ value: undefined, done: true },
|
||
], log);
|
||
|
||
log = [];
|
||
let asyncGeneratorMethodForNestedResumeReturn = ({
|
||
async* method() {
|
||
it.return("step6").then(logIterResult, logError);
|
||
it.next().then(logIterResult, logError);
|
||
yield "step5";
|
||
}
|
||
}).method;
|
||
it = asyncGeneratorMethodForNestedResumeReturn();
|
||
it.next().then(logIterResult, logError);
|
||
%RunMicrotasks();
|
||
assertEquals([
|
||
{ value: "step5", done: false },
|
||
{ value: "step6", done: true },
|
||
{ value: undefined, done: true },
|
||
], log);
|
||
|
||
log = [];
|
||
let asyncGeneratorCallEvalForNestedResumeReturn =
|
||
AsyncGeneratorFunction(`
|
||
it.return("step8").then(logIterResult, logError);
|
||
it.next().then(logIterResult, logError);
|
||
yield "step7";`);
|
||
it = asyncGeneratorCallEvalForNestedResumeReturn();
|
||
it.next().then(logIterResult, logError);
|
||
%RunMicrotasks();
|
||
assertEquals([
|
||
{ value: "step7", done: false },
|
||
{ value: "step8", done: true },
|
||
{ value: undefined, done: true },
|
||
], log);
|
||
|
||
log = [];
|
||
let asyncGeneratorNewEvalForNestedResumeReturn =
|
||
new AsyncGeneratorFunction(`
|
||
it.return("step10").then(logIterResult, logError);
|
||
it.next().then(logIterResult, logError);
|
||
yield "step9";`);
|
||
it = asyncGeneratorNewEvalForNestedResumeReturn();
|
||
it.next().then(logIterResult, logError);
|
||
%RunMicrotasks();
|
||
assertEquals([
|
||
{ value: "step9", done: false },
|
||
{ value: "step10", done: true },
|
||
{ value: undefined, done: true },
|
||
], log);
|
||
|
||
// ----------------------------------------------------------------------------
|
||
// Top-level Yield ThrowStatement
|
||
|
||
async function* asyncGeneratorForYieldThrow() {
|
||
yield await Thrower("OOPS1");
|
||
throw "(unreachable)";
|
||
}
|
||
it = asyncGeneratorForYieldThrow();
|
||
assertThrowsAsync(() => it.next(), MyError, "OOPS1");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = (async function*() { yield Thrower("OOPS2"); throw "(unreachable)"; })();
|
||
assertThrowsAsync(() => it.next(), MyError, "OOPS2");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = ({
|
||
async* method() {
|
||
yield Thrower("OOPS3");
|
||
throw "(unreachable)";
|
||
}
|
||
}).method();
|
||
assertThrowsAsync(() => it.next(), MyError, "OOPS3");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = AsyncGeneratorFunction(`
|
||
yield Thrower("OOPS4");
|
||
throw "(unreachable)"`)();
|
||
assertThrowsAsync(() => it.next(), MyError, "OOPS4");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = (new AsyncGeneratorFunction(`
|
||
yield Thrower("OOPS5");
|
||
throw "(unreachable)"`))();
|
||
assertThrowsAsync(() => it.next(), MyError, "OOPS5");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
// ----------------------------------------------------------------------------
|
||
// Top-level Yield Awaited Rejection
|
||
async function* asyncGeneratorForYieldAwaitedRejection() {
|
||
yield await Rejecter("OOPS1");
|
||
throw "(unreachable)";
|
||
}
|
||
it = asyncGeneratorForYieldAwaitedRejection();
|
||
assertThrowsAsync(() => it.next(), MyError, "OOPS1");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = (async function*() {
|
||
yield await Rejecter("OOPS2");
|
||
throw "(unreachable)";
|
||
})();
|
||
assertThrowsAsync(() => it.next(), MyError, "OOPS2");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = ({
|
||
async* method() {
|
||
yield await Rejecter("OOPS3");
|
||
throw "(unreachable)";
|
||
}
|
||
}).method();
|
||
assertThrowsAsync(() => it.next(), MyError, "OOPS3");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = AsyncGeneratorFunction(`
|
||
yield await Rejecter("OOPS4");
|
||
throw "(unreachable)"`)();
|
||
assertThrowsAsync(() => it.next(), MyError, "OOPS4");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = (new AsyncGeneratorFunction(`
|
||
yield await Rejecter("OOPS5");
|
||
throw "(unreachable)"`))();
|
||
assertThrowsAsync(() => it.next(), MyError, "OOPS5");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
|
||
// ----------------------------------------------------------------------------
|
||
// Top-level ThrowStatement
|
||
async function* asyncGeneratorForThrow() {
|
||
throw new MyError("BOOM1");
|
||
throw "(unreachable)";
|
||
}
|
||
it = asyncGeneratorForThrow();
|
||
assertThrowsAsync(() => it.next(), MyError, "BOOM1");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = (async function*() {
|
||
throw new MyError("BOOM2");
|
||
throw "(unreachable)";
|
||
})();
|
||
assertThrowsAsync(() => it.next(), MyError, "BOOM2");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = ({
|
||
async* method() {
|
||
throw new MyError("BOOM3");
|
||
throw "(unreachable)";
|
||
}
|
||
}).method();
|
||
assertThrowsAsync(() => it.next(), MyError, "BOOM3");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = (AsyncGeneratorFunction(`
|
||
throw new MyError("BOOM4");
|
||
throw "(unreachable)";`))()
|
||
assertThrowsAsync(() => it.next(), MyError, "BOOM4");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = (AsyncGeneratorFunction(`
|
||
throw new MyError("BOOM5");
|
||
throw "(unreachable)";`))()
|
||
assertThrowsAsync(() => it.next(), MyError, "BOOM5");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
// ----------------------------------------------------------------------------
|
||
// Top-level ThrowStatement after Await
|
||
async function* asyncGeneratorForThrowAfterAwait() {
|
||
await 1;
|
||
throw new MyError("BOOM6");
|
||
throw "(unreachable)";
|
||
}
|
||
it = asyncGeneratorForThrowAfterAwait();
|
||
assertThrowsAsync(() => it.next(), MyError, "BOOM6");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = (async function*() {
|
||
await 1;
|
||
throw new MyError("BOOM7");
|
||
throw "(unreachable)";
|
||
})();
|
||
assertThrowsAsync(() => it.next(), MyError, "BOOM7");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = ({
|
||
async* method() {
|
||
await 1;
|
||
throw new MyError("BOOM8");
|
||
throw "(unreachable)";
|
||
}
|
||
}).method();
|
||
assertThrowsAsync(() => it.next(), MyError, "BOOM8");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = (AsyncGeneratorFunction(`
|
||
await 1;
|
||
throw new MyError("BOOM9");
|
||
throw "(unreachable)";`))();
|
||
assertThrowsAsync(() => it.next(), MyError, "BOOM9");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = (new AsyncGeneratorFunction(`
|
||
await 1;
|
||
throw new MyError("BOOM10");
|
||
throw "(unreachable)";`))();
|
||
assertThrowsAsync(() => it.next(), MyError, "BOOM10");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
// ----------------------------------------------------------------------------
|
||
// Top-level Awaited rejection
|
||
async function* asyncGeneratorForAwaitedRejection() {
|
||
await Rejecter("BOOM11");
|
||
throw "(unreachable)";
|
||
}
|
||
it = asyncGeneratorForAwaitedRejection();
|
||
assertThrowsAsync(() => it.next(), MyError, "BOOM11");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = (async function*() {
|
||
await Rejecter("BOOM12");
|
||
throw "(unreachable)";
|
||
})();
|
||
assertThrowsAsync(() => it.next(), MyError, "BOOM12");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = ({
|
||
async* method() {
|
||
await Rejecter("BOOM13");
|
||
throw "(unreachable)";
|
||
}
|
||
}).method();
|
||
|
||
assertThrowsAsync(() => it.next(), MyError, "BOOM13");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = (AsyncGeneratorFunction(`
|
||
await Rejecter("BOOM14");
|
||
throw "(unreachable)";`))();
|
||
assertThrowsAsync(() => it.next(), MyError, "BOOM14");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = (new AsyncGeneratorFunction(`
|
||
await Rejecter("BOOM15");
|
||
throw "(unreachable)";`))();
|
||
assertThrowsAsync(() => it.next(), MyError, "BOOM15");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
// ----------------------------------------------------------------------------
|
||
// Caught ThrowStatement
|
||
async function* asyncGeneratorForCaughtThrow() {
|
||
try {
|
||
throw new MyError("BOOM1");
|
||
} catch (e) {
|
||
return "caught1";
|
||
}
|
||
throw "(unreachable)";
|
||
}
|
||
it = asyncGeneratorForCaughtThrow();
|
||
assertEqualsAsync({ value: "caught1", done: true }, () => it.next());
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = (async function*() {
|
||
try {
|
||
throw new MyError("BOOM2");
|
||
} catch (e) {
|
||
return "caught2";
|
||
}
|
||
throw "(unreachable)";
|
||
})();
|
||
assertEqualsAsync({ value: "caught2", done: true }, () => it.next());
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = ({
|
||
async* method() {
|
||
try {
|
||
throw new MyError("BOOM3");
|
||
} catch (e) {
|
||
return "caught3";
|
||
}
|
||
throw "(unreachable)";
|
||
}
|
||
}).method();
|
||
assertEqualsAsync({ value: "caught3", done: true }, () => it.next());
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = (AsyncGeneratorFunction(`
|
||
try {
|
||
throw new MyError("BOOM4");
|
||
} catch (e) {
|
||
return "caught4";
|
||
}
|
||
throw "(unreachable)";`))()
|
||
assertEqualsAsync({ value: "caught4", done: true }, () => it.next());
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = (AsyncGeneratorFunction(`
|
||
try {
|
||
throw new MyError("BOOM5");
|
||
} catch (e) {
|
||
return "caught5";
|
||
}
|
||
throw "(unreachable)";`))()
|
||
assertEqualsAsync({ value: "caught5", done: true }, () => it.next());
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
// ----------------------------------------------------------------------------
|
||
// Caught ThrowStatement and rethrow
|
||
async function* asyncGeneratorForCaughtRethrow() {
|
||
try {
|
||
throw new MyError("BOOM1");
|
||
} catch (e) {
|
||
throw new MyError("RETHROW1");
|
||
}
|
||
throw "(unreachable)";
|
||
}
|
||
it = asyncGeneratorForCaughtRethrow();
|
||
assertThrowsAsync(() => it.next(), MyError, "RETHROW1");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = (async function*() {
|
||
try {
|
||
throw new MyError("BOOM2");
|
||
} catch (e) {
|
||
throw new MyError("RETHROW2");
|
||
}
|
||
throw "(unreachable)";
|
||
})();
|
||
assertThrowsAsync(() => it.next(), MyError, "RETHROW2");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = ({
|
||
async* method() {
|
||
try {
|
||
throw new MyError("BOOM3");
|
||
} catch (e) {
|
||
throw new MyError("RETHROW3");
|
||
}
|
||
throw "(unreachable)";
|
||
}
|
||
}).method();
|
||
assertThrowsAsync(() => it.next(), MyError, "RETHROW3");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = (AsyncGeneratorFunction(`
|
||
try {
|
||
throw new MyError("BOOM4");
|
||
} catch (e) {
|
||
throw new MyError("RETHROW4");
|
||
}
|
||
throw "(unreachable)";`))()
|
||
assertThrowsAsync(() => it.next(), MyError, "RETHROW4");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = (AsyncGeneratorFunction(`
|
||
try {
|
||
throw new MyError("BOOM5");
|
||
} catch (e) {
|
||
throw new MyError("RETHROW5");
|
||
}
|
||
throw "(unreachable)";`))()
|
||
assertThrowsAsync(() => it.next(), MyError, "RETHROW5");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
// ----------------------------------------------------------------------------
|
||
// ReturnStatement in Try, ReturnStatement in Finally
|
||
async function* asyncGeneratorForReturnInTryReturnInFinally() {
|
||
try {
|
||
return "early1"
|
||
} finally {
|
||
return "later1";
|
||
}
|
||
throw "(unreachable)";
|
||
}
|
||
it = asyncGeneratorForReturnInTryReturnInFinally();
|
||
assertEqualsAsync({ value: "later1", done: true }, () => it.next());
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = (async function*() {
|
||
try {
|
||
return "early2";
|
||
} finally {
|
||
return "later2";
|
||
}
|
||
throw "(unreachable)";
|
||
})();
|
||
assertEqualsAsync({ value: "later2", done: true }, () => it.next());
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = ({
|
||
async* method() {
|
||
try {
|
||
return "early3";
|
||
} finally {
|
||
return "later3";
|
||
}
|
||
throw "(unreachable)";
|
||
}
|
||
}).method();
|
||
assertEqualsAsync({ value: "later3", done: true }, () => it.next());
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = (AsyncGeneratorFunction(`
|
||
try {
|
||
return "early4";
|
||
} finally {
|
||
return "later4";
|
||
}
|
||
throw "(unreachable)";`))()
|
||
assertEqualsAsync({ value: "later4", done: true }, () => it.next());
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = (AsyncGeneratorFunction(`
|
||
try {
|
||
return "early5";
|
||
} finally {
|
||
return "later5";
|
||
}
|
||
throw "(unreachable)";`))()
|
||
assertEqualsAsync({ value: "later5", done: true }, () => it.next());
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
// ----------------------------------------------------------------------------
|
||
// ThrowStatement in Try, ReturnStatement in Finally
|
||
async function* asyncGeneratorForThrowInTryReturnInFinally() {
|
||
try {
|
||
throw new MyError("BOOM1");
|
||
} finally {
|
||
return "later1";
|
||
}
|
||
throw "(unreachable)";
|
||
}
|
||
it = asyncGeneratorForThrowInTryReturnInFinally();
|
||
assertEqualsAsync({ value: "later1", done: true }, () => it.next());
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = (async function*() {
|
||
try {
|
||
throw new MyError("BOOM2");
|
||
} finally {
|
||
return "later2";
|
||
}
|
||
throw "(unreachable)";
|
||
})();
|
||
assertEqualsAsync({ value: "later2", done: true }, () => it.next());
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = ({
|
||
async* method() {
|
||
try {
|
||
throw new MyError("BOOM3");
|
||
} finally {
|
||
return "later3";
|
||
}
|
||
throw "(unreachable)";
|
||
}
|
||
}).method();
|
||
assertEqualsAsync({ value: "later3", done: true }, () => it.next());
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = (AsyncGeneratorFunction(`
|
||
try {
|
||
throw new MyError("BOOM4");
|
||
} finally {
|
||
return "later4";
|
||
}
|
||
throw "(unreachable)";`))()
|
||
assertEqualsAsync({ value: "later4", done: true }, () => it.next());
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = (AsyncGeneratorFunction(`
|
||
try {
|
||
throw new MyError("BOOM5");
|
||
} finally {
|
||
return "later5";
|
||
}
|
||
throw "(unreachable)";`))()
|
||
assertEqualsAsync({ value: "later5", done: true }, () => it.next());
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
// ----------------------------------------------------------------------------
|
||
// Awaited Rejection in Try, ReturnStatement in Finally
|
||
async function* asyncGeneratorForAwaitRejectionInTryReturnInFinally() {
|
||
try {
|
||
await Rejecter("BOOM1");
|
||
} finally {
|
||
return "later1";
|
||
}
|
||
throw "(unreachable)";
|
||
}
|
||
it = asyncGeneratorForThrowInTryReturnInFinally();
|
||
assertEqualsAsync({ value: "later1", done: true }, () => it.next());
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = (async function*() {
|
||
try {
|
||
await Rejecter("BOOM2");
|
||
} finally {
|
||
return "later2";
|
||
}
|
||
throw "(unreachable)";
|
||
})();
|
||
assertEqualsAsync({ value: "later2", done: true }, () => it.next());
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = ({
|
||
async* method() {
|
||
try {
|
||
await Rejecter("BOOM3");
|
||
} finally {
|
||
return "later3";
|
||
}
|
||
throw "(unreachable)";
|
||
}
|
||
}).method();
|
||
assertEqualsAsync({ value: "later3", done: true }, () => it.next());
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = (AsyncGeneratorFunction(`
|
||
try {
|
||
await Rejecter("BOOM4");
|
||
} finally {
|
||
return "later4";
|
||
}
|
||
throw "(unreachable)";`))()
|
||
assertEqualsAsync({ value: "later4", done: true }, () => it.next());
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = (AsyncGeneratorFunction(`
|
||
try {
|
||
await Rejecter("BOOM5");
|
||
} finally {
|
||
return "later5";
|
||
}
|
||
throw "(unreachable)";`))()
|
||
assertEqualsAsync({ value: "later5", done: true }, () => it.next());
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
// ----------------------------------------------------------------------------
|
||
// ReturnStatement in Try, ThrowStatement in Finally
|
||
async function* asyncGeneratorForReturnInTryThrowInFinally() {
|
||
try {
|
||
return "early1"
|
||
} finally {
|
||
throw new MyError("BOOM1");
|
||
}
|
||
throw "(unreachable)";
|
||
}
|
||
it = asyncGeneratorForReturnInTryThrowInFinally();
|
||
assertThrowsAsync(() => it.next(), MyError, "BOOM1");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = (async function*() {
|
||
try {
|
||
return "early2";
|
||
} finally {
|
||
throw new MyError("BOOM2");
|
||
}
|
||
throw "(unreachable)";
|
||
})();
|
||
assertThrowsAsync(() => it.next(), MyError, "BOOM2");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = ({
|
||
async* method() {
|
||
try {
|
||
return "early3";
|
||
} finally {
|
||
throw new MyError("BOOM3");
|
||
}
|
||
throw "(unreachable)";
|
||
}
|
||
}).method();
|
||
assertThrowsAsync(() => it.next(), MyError, "BOOM3");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = (AsyncGeneratorFunction(`
|
||
try {
|
||
return "early4";
|
||
} finally {
|
||
throw new MyError("BOOM4");
|
||
}
|
||
throw "(unreachable)";`))()
|
||
assertThrowsAsync(() => it.next(), MyError, "BOOM4");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = (AsyncGeneratorFunction(`
|
||
try {
|
||
return "early5";
|
||
} finally {
|
||
throw new MyError("BOOM5");
|
||
}
|
||
throw "(unreachable)";`))()
|
||
assertThrowsAsync(() => it.next(), MyError, "BOOM5");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
// ----------------------------------------------------------------------------
|
||
// ThrowStatement in Try, ThrowStatement in Finally
|
||
|
||
async function* asyncGeneratorForThrowInTryThrowInFinally() {
|
||
try {
|
||
throw new MyError("EARLY1");
|
||
} finally {
|
||
throw new MyError("BOOM1");
|
||
}
|
||
throw "(unreachable)";
|
||
}
|
||
it = asyncGeneratorForThrowInTryThrowInFinally();
|
||
assertThrowsAsync(() => it.next(), MyError, "BOOM1");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = (async function*() {
|
||
try {
|
||
throw new MyError("EARLY2");
|
||
} finally {
|
||
throw new MyError("BOOM2");
|
||
}
|
||
throw "(unreachable)";
|
||
})();
|
||
assertThrowsAsync(() => it.next(), MyError, "BOOM2");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = ({
|
||
async* method() {
|
||
try {
|
||
throw new MyError("EARLY3");
|
||
} finally {
|
||
throw new MyError("BOOM3");
|
||
}
|
||
throw "(unreachable)";
|
||
}
|
||
}).method();
|
||
assertThrowsAsync(() => it.next(), MyError, "BOOM3");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = (AsyncGeneratorFunction(`
|
||
try {
|
||
throw new MyError("EARLY4");
|
||
} finally {
|
||
throw new MyError("BOOM4");
|
||
}
|
||
throw "(unreachable)";`))()
|
||
assertThrowsAsync(() => it.next(), MyError, "BOOM4");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = (AsyncGeneratorFunction(`
|
||
try {
|
||
throw new MyError("EARLY5");
|
||
} finally {
|
||
throw new MyError("BOOM5");
|
||
}
|
||
throw "(unreachable)";`))()
|
||
assertThrowsAsync(() => it.next(), MyError, "BOOM5");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
// ----------------------------------------------------------------------------
|
||
// Awaited Rejection in Try, ThrowStatement in Finally
|
||
|
||
async function* asyncGeneratorForAwaitedRejectInTryThrowInFinally() {
|
||
try {
|
||
await Rejecter("EARLY1");
|
||
} finally {
|
||
throw new MyError("BOOM1");
|
||
}
|
||
throw "(unreachable)";
|
||
}
|
||
it = asyncGeneratorForAwaitedRejectInTryThrowInFinally();
|
||
assertThrowsAsync(() => it.next(), MyError, "BOOM1");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = (async function*() {
|
||
try {
|
||
await Rejecter("EARLY2");
|
||
} finally {
|
||
throw new MyError("BOOM2");
|
||
}
|
||
throw "(unreachable)";
|
||
})();
|
||
assertThrowsAsync(() => it.next(), MyError, "BOOM2");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = ({
|
||
async* method() {
|
||
try {
|
||
await Rejecter("EARLY3");
|
||
} finally {
|
||
throw new MyError("BOOM3");
|
||
}
|
||
throw "(unreachable)";
|
||
}
|
||
}).method();
|
||
assertThrowsAsync(() => it.next(), MyError, "BOOM3");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = (AsyncGeneratorFunction(`
|
||
try {
|
||
await Rejecter("EARLY4");
|
||
} finally {
|
||
throw new MyError("BOOM4");
|
||
}
|
||
throw "(unreachable)";`))()
|
||
assertThrowsAsync(() => it.next(), MyError, "BOOM4");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = (AsyncGeneratorFunction(`
|
||
try {
|
||
await Rejecter("EARLY5");
|
||
} finally {
|
||
throw new MyError("BOOM5");
|
||
}
|
||
throw "(unreachable)";`))()
|
||
assertThrowsAsync(() => it.next(), MyError, "BOOM5");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
// ----------------------------------------------------------------------------
|
||
// ReturnStatement in Try, Awaited Rejection in Finally
|
||
async function* asyncGeneratorForReturnInTryAwaitedRejectionInFinally() {
|
||
try {
|
||
return "early1"
|
||
} finally {
|
||
await Rejecter("BOOM1");
|
||
}
|
||
throw "(unreachable)";
|
||
}
|
||
it = asyncGeneratorForReturnInTryAwaitedRejectionInFinally();
|
||
assertThrowsAsync(() => it.next(), MyError, "BOOM1");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = (async function*() {
|
||
try {
|
||
return "early2";
|
||
} finally {
|
||
await Rejecter("BOOM2");
|
||
}
|
||
throw "(unreachable)";
|
||
})();
|
||
assertThrowsAsync(() => it.next(), MyError, "BOOM2");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = ({
|
||
async* method() {
|
||
try {
|
||
return "early3";
|
||
} finally {
|
||
await Rejecter("BOOM3");
|
||
}
|
||
throw "(unreachable)";
|
||
}
|
||
}).method();
|
||
assertThrowsAsync(() => it.next(), MyError, "BOOM3");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = (AsyncGeneratorFunction(`
|
||
try {
|
||
return "early4";
|
||
} finally {
|
||
await Rejecter("BOOM4");
|
||
}
|
||
throw "(unreachable)";`))()
|
||
assertThrowsAsync(() => it.next(), MyError, "BOOM4");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = (AsyncGeneratorFunction(`
|
||
try {
|
||
return "early5";
|
||
} finally {
|
||
await Rejecter("BOOM5");
|
||
}
|
||
throw "(unreachable)";`))()
|
||
assertThrowsAsync(() => it.next(), MyError, "BOOM5");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
// ----------------------------------------------------------------------------
|
||
// ThrowStatement in Try, Awaited Rejection in Finally
|
||
|
||
async function* asyncGeneratorForThrowInTryAwaitedRejectionInFinally() {
|
||
try {
|
||
throw new MyError("EARLY1");
|
||
} finally {
|
||
await Rejecter("BOOM1");
|
||
}
|
||
throw "(unreachable)";
|
||
}
|
||
it = asyncGeneratorForThrowInTryAwaitedRejectionInFinally();
|
||
assertThrowsAsync(() => it.next(), MyError, "BOOM1");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = (async function*() {
|
||
try {
|
||
throw new MyError("EARLY2");
|
||
} finally {
|
||
await Rejecter("BOOM2");
|
||
}
|
||
throw "(unreachable)";
|
||
})();
|
||
assertThrowsAsync(() => it.next(), MyError, "BOOM2");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = ({
|
||
async* method() {
|
||
try {
|
||
throw new MyError("EARLY3");
|
||
} finally {
|
||
await Rejecter("BOOM3");
|
||
}
|
||
throw "(unreachable)";
|
||
}
|
||
}).method();
|
||
assertThrowsAsync(() => it.next(), MyError, "BOOM3");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = (AsyncGeneratorFunction(`
|
||
try {
|
||
throw new MyError("EARLY4");
|
||
} finally {
|
||
await Rejecter("BOOM4");
|
||
}
|
||
throw "(unreachable)";`))()
|
||
assertThrowsAsync(() => it.next(), MyError, "BOOM4");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = (AsyncGeneratorFunction(`
|
||
try {
|
||
throw new MyError("EARLY5");
|
||
} finally {
|
||
await Rejecter("BOOM5");
|
||
}
|
||
throw "(unreachable)";`))()
|
||
assertThrowsAsync(() => it.next(), MyError, "BOOM5");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
// ----------------------------------------------------------------------------
|
||
// Awaited Rejection in Try, Awaited Rejection in Finally
|
||
|
||
async function* asyncGeneratorForAwaitedRejectInTryAwaitedRejectionInFinally() {
|
||
try {
|
||
await Rejecter("EARLY1");
|
||
} finally {
|
||
await Rejecter("BOOM1");
|
||
}
|
||
throw "(unreachable)";
|
||
}
|
||
it = asyncGeneratorForAwaitedRejectInTryAwaitedRejectionInFinally();
|
||
assertThrowsAsync(() => it.next(), MyError, "BOOM1");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = (async function*() {
|
||
try {
|
||
await Rejecter("EARLY2");
|
||
} finally {
|
||
await Rejecter("BOOM2");
|
||
}
|
||
throw "(unreachable)";
|
||
})();
|
||
assertThrowsAsync(() => it.next(), MyError, "BOOM2");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = ({
|
||
async* method() {
|
||
try {
|
||
await Rejecter("EARLY3");
|
||
} finally {
|
||
await Rejecter("BOOM3");
|
||
}
|
||
throw "(unreachable)";
|
||
}
|
||
}).method();
|
||
assertThrowsAsync(() => it.next(), MyError, "BOOM3");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = (AsyncGeneratorFunction(`
|
||
try {
|
||
await Rejecter("EARLY4");
|
||
} finally {
|
||
await Rejecter("BOOM4");
|
||
}
|
||
throw "(unreachable)";`))()
|
||
assertThrowsAsync(() => it.next(), MyError, "BOOM4");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
it = (AsyncGeneratorFunction(`
|
||
try {
|
||
await Rejecter("EARLY5");
|
||
} finally {
|
||
await Rejecter("BOOM5");
|
||
}
|
||
throw "(unreachable)";`))()
|
||
assertThrowsAsync(() => it.next(), MyError, "BOOM5");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||
|
||
// ----------------------------------------------------------------------------
|
||
// Early errors during parameter initialization
|
||
|
||
async function* asyncGeneratorForParameterInitializationErrors(
|
||
[...a], b = c, d) {
|
||
AbortUnreachable();
|
||
}
|
||
assertThrows(() => asyncGeneratorForParameterInitializationErrors(null),
|
||
TypeError);
|
||
assertThrows(() => asyncGeneratorForParameterInitializationErrors([]),
|
||
ReferenceError);
|
||
|
||
let asyncGeneratorExprForParameterInitializationErrors =
|
||
async function*([...a], b = c, d) {
|
||
AbortUnreachable();
|
||
};
|
||
assertThrows(() => asyncGeneratorExprForParameterInitializationErrors(null),
|
||
TypeError);
|
||
assertThrows(() => asyncGeneratorExprForParameterInitializationErrors([]),
|
||
ReferenceError);
|
||
|
||
let asyncGeneratorMethodForParameterInitializationErrors = ({
|
||
async* method([...a], b = c, d) {
|
||
AbortUnreachable();
|
||
}
|
||
}).method;
|
||
assertThrows(() => asyncGeneratorMethodForParameterInitializationErrors(null),
|
||
TypeError);
|
||
assertThrows(() => asyncGeneratorMethodForParameterInitializationErrors([]),
|
||
ReferenceError);
|
||
|
||
let asyncGeneratorCallEvalForParameterInitializationErrors =
|
||
AsyncGeneratorFunction("[...a], b = c, d", `AbortUnreachable();`);
|
||
assertThrows(() => asyncGeneratorCallEvalForParameterInitializationErrors(null),
|
||
TypeError);
|
||
assertThrows(() => asyncGeneratorCallEvalForParameterInitializationErrors([]),
|
||
ReferenceError);
|
||
|
||
let asyncGeneratorNewEvalForParameterInitializationErrors =
|
||
new AsyncGeneratorFunction("[...a], b = c, d",
|
||
`AbortUnreachable();`);
|
||
assertThrows(() => asyncGeneratorNewEvalForParameterInitializationErrors(null),
|
||
TypeError);
|
||
assertThrows(() => asyncGeneratorNewEvalForParameterInitializationErrors([]),
|
||
ReferenceError);
|
||
|
||
// ----------------------------------------------------------------------------
|
||
// Invoke [AsyncGenerator].return() when generator is in state suspendedStart
|
||
|
||
async function* asyncGeneratorForReturnSuspendedStart() {
|
||
AbortUnreachable();
|
||
}
|
||
it = asyncGeneratorForReturnSuspendedStart();
|
||
assertEqualsAsync({ value: "ret1", done: true }, () => it.return("ret1"));
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next("x"));
|
||
assertEqualsAsync({ value: "nores", done: true },
|
||
() => it.return("nores"));
|
||
assertThrowsAsync(() => it.throw(new MyError("nores")), MyError, "nores");
|
||
|
||
it = (async function*() {
|
||
AbortUnreachable();
|
||
})();
|
||
assertEqualsAsync({ value: "ret2", done: true }, () => it.return("ret2"));
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next("x"));
|
||
assertEqualsAsync({ value: "nores", done: true },
|
||
() => it.return("nores"));
|
||
assertThrowsAsync(() => it.throw(new MyError("nores")), MyError, "nores");
|
||
|
||
it = ({
|
||
async* method() {
|
||
AbortUnreachable();
|
||
}
|
||
}).method();
|
||
assertEqualsAsync({ value: "ret3", done: true }, () => it.return("ret3"));
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next("x"));
|
||
assertEqualsAsync({ value: "nores", done: true },
|
||
() => it.return("nores"));
|
||
assertThrowsAsync(() => it.throw(new MyError("nores")), MyError, "nores");
|
||
|
||
it = (AsyncGeneratorFunction(`AbortUnreachable();`))();
|
||
assertEqualsAsync({ value: "ret4", done: true }, () => it.return("ret4"));
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next("x"));
|
||
assertEqualsAsync({ value: "nores", done: true },
|
||
() => it.return("nores"));
|
||
assertThrowsAsync(() => it.throw(new MyError("nores")), MyError, "nores");
|
||
|
||
it = (AsyncGeneratorFunction(`AbortUnreachable();`))();
|
||
assertEqualsAsync({ value: "ret5", done: true }, () => it.return("ret5"));
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next("x"));
|
||
assertEqualsAsync({ value: "nores", done: true },
|
||
() => it.return("nores"));
|
||
assertThrowsAsync(() => it.throw(new MyError("nores")), MyError, "nores");
|
||
|
||
// ----------------------------------------------------------------------------
|
||
// Invoke [AsyncGenerator].throw() when generator is in state suspendedStart
|
||
|
||
async function* asyncGeneratorForThrowSuspendedStart() {
|
||
AbortUnreachable();
|
||
}
|
||
it = asyncGeneratorForReturnSuspendedStart();
|
||
assertThrowsAsync(() => it.throw(new MyError("throw1")), MyError, "throw1");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next("x"));
|
||
assertEqualsAsync({ value: "nores", done: true },
|
||
() => it.return("nores"));
|
||
assertThrowsAsync(() => it.throw(new MyError("nores")), MyError, "nores");
|
||
|
||
it = (async function*() {
|
||
AbortUnreachable();
|
||
})();
|
||
assertThrowsAsync(() => it.throw(new MyError("throw2")), MyError, "throw2");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next("x"));
|
||
assertEqualsAsync({ value: "nores", done: true },
|
||
() => it.return("nores"));
|
||
assertThrowsAsync(() => it.throw(new MyError("nores")), MyError, "nores");
|
||
|
||
it = ({
|
||
async* method() {
|
||
AbortUnreachable();
|
||
}
|
||
}).method();
|
||
assertThrowsAsync(() => it.throw(new MyError("throw3")), MyError, "throw3");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next("x"));
|
||
assertEqualsAsync({ value: "nores", done: true },
|
||
() => it.return("nores"));
|
||
assertThrowsAsync(() => it.throw(new MyError("nores")), MyError, "nores");
|
||
|
||
it = (AsyncGeneratorFunction(`AbortUnreachable()`))();
|
||
assertThrowsAsync(() => it.throw(new MyError("throw4")), MyError, "throw4");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next("x"));
|
||
assertEqualsAsync({ value: "nores", done: true },
|
||
() => it.return("nores"));
|
||
assertThrowsAsync(() => it.throw(new MyError("nores")), MyError, "nores");
|
||
|
||
it = (AsyncGeneratorFunction(`AbortUnreachable();`))();
|
||
assertThrowsAsync(() => it.throw(new MyError("throw5")), MyError, "throw5");
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next("x"));
|
||
assertEqualsAsync({ value: "nores", done: true },
|
||
() => it.return("nores"));
|
||
assertThrowsAsync(() => it.throw(new MyError("nores")), MyError, "nores");
|
||
|
||
// ----------------------------------------------------------------------------
|
||
// Simple yield*:
|
||
|
||
log = [];
|
||
async function* asyncGeneratorYieldStar1() {
|
||
yield* {
|
||
get [Symbol.asyncIterator]() {
|
||
log.push({ name: "get @@asyncIterator" });
|
||
return (...args) => {
|
||
log.push({ name: "call @@asyncIterator", args });
|
||
return this;
|
||
};
|
||
},
|
||
get [Symbol.iterator]() {
|
||
log.push({ name: "get @@iterator" });
|
||
return (...args) => {
|
||
log.push({ name: "call @@iterator", args });
|
||
return this;
|
||
}
|
||
},
|
||
get next() {
|
||
log.push({ name: "get next" });
|
||
return (...args) => {
|
||
log.push({ name: "call next", args });
|
||
return {
|
||
get then() {
|
||
log.push({ name: "get then" });
|
||
return null;
|
||
},
|
||
get value() {
|
||
log.push({ name: "get value" });
|
||
throw (exception = new MyError("AbruptValue!"));
|
||
},
|
||
get done() {
|
||
log.push({ name: "get done" });
|
||
return false;
|
||
}
|
||
};
|
||
}
|
||
},
|
||
get return() {
|
||
log.push({ name: "get return" });
|
||
return (...args) => {
|
||
log.push({ name: "call return", args });
|
||
return { value: args[0], done: true };
|
||
}
|
||
},
|
||
get throw() {
|
||
log.push({ name: "get throw" });
|
||
return (...args) => {
|
||
log.push({ name: "call throw", args });
|
||
throw args[0];
|
||
};
|
||
},
|
||
};
|
||
}
|
||
|
||
it = asyncGeneratorYieldStar1();
|
||
assertThrowsAsync(() => it.next(), MyError);
|
||
assertEquals([
|
||
{ name: "get @@asyncIterator" },
|
||
{ name: "call @@asyncIterator", args: [] },
|
||
{ name: "get next" },
|
||
{ name: "call next", args: [undefined] },
|
||
{ name: "get then" },
|
||
{ name: "get done" },
|
||
{ name: "get value" },
|
||
], log);
|
||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|