Files
jsrt/lib/stdlib/coroutine.js
T
2026-10-16 08:00:06 +00:00

63 lines
2.0 KiB
JavaScript

// The drivers of async fns and generators
//
// The compiler lowers each async fn and generator to a coroutine (see
// compiler/src/transform/async.rs): a step closure, which runs the body until
// it suspends or returns, and an object `co`:
//
// { __proto__: <a proto below>, step, value, awaiting, result, done }
//
// A yield puts its value in `value`, an await puts its promise in `awaiting`,
// and a return puts its value in `result` and sets `done`. The fn returns
// `co.start()`. Only these drivers differ between the kinds
//
// Not supported yet: `throw()` on a generator, and `finally` blocks in
// `return()`, which need exceptions
// A generator's object is `co` itself
const __GeneratorProto = {
// The body runs up to its `initial_yield`, after its params
start() {
this.step(undefined);
return this;
},
next(input) {
if (this.done) return { value: undefined, done: true };
this.step(input);
if (this.done) return { value: this.result, done: true };
return { value: this.value, done: false };
},
return(value) {
this.done = true;
return { value: value, done: true };
},
};
// An async fn returns a promise, which its return fulfils. A rejected await
// rejects it, and the rest of the body does not run, as an uncaught throw at the
// await would
const __AsyncProto = {
// The body runs up to its first await, in the call
start() {
const promise = new Promise(undefined);
this.run(promise);
return promise;
},
run(promise) {
this.step(undefined);
if (this.done) __resolve(promise, this.result);
else this.awaiting.then(() => this.run(promise), (reason) => __reject(promise, reason));
},
// What an await waits on: a promise as it is, any other value as a fulfilled one.
// The step reads the value from it when it resumes
toPromise(x) {
return __is_promise(x) ? x : Promise.resolve(x);
},
};