mirror of
https://github.com/bendtherules/completion-viz.git
synced 2026-08-18 13:42:51 +00:00
Clone engine262 in /engine262
This commit is contained in:
@@ -0,0 +1,211 @@
|
||||
import { surroundingAgent } from '../engine.mjs';
|
||||
import {
|
||||
Q, X,
|
||||
Await,
|
||||
Completion,
|
||||
EnsureCompletion,
|
||||
NormalCompletion,
|
||||
AbruptCompletion,
|
||||
} from '../completion.mjs';
|
||||
import { Evaluate } from '../evaluator.mjs';
|
||||
import { Value, Type } from '../value.mjs';
|
||||
import { resume, handleInResume } from '../helpers.mjs';
|
||||
import {
|
||||
Assert,
|
||||
Call,
|
||||
CreateBuiltinFunction,
|
||||
CreateIterResultObject,
|
||||
GetGeneratorKind,
|
||||
NewPromiseCapability,
|
||||
PerformPromiseThen,
|
||||
PromiseResolve,
|
||||
} from './all.mjs';
|
||||
|
||||
// This file covers abstract operations defined in
|
||||
// 25.5 #sec-asyncgenerator-objects
|
||||
|
||||
// 25.5.3.1 #sec-asyncgeneratorrequest-records
|
||||
class AsyncGeneratorRequestRecord {
|
||||
constructor(completion, promiseCapability) {
|
||||
this.Completion = completion;
|
||||
this.Capability = promiseCapability;
|
||||
}
|
||||
}
|
||||
|
||||
// 25.5.3.2 #sec-asyncgeneratorstart
|
||||
export function AsyncGeneratorStart(generator, generatorBody) {
|
||||
// Assert: generator is an AsyncGenerator instance.
|
||||
Assert(generator.AsyncGeneratorState === Value.undefined);
|
||||
const genContext = surroundingAgent.runningExecutionContext;
|
||||
genContext.Generator = generator;
|
||||
genContext.codeEvaluationState = (function* resumer() {
|
||||
const result = EnsureCompletion(yield* Evaluate(generatorBody));
|
||||
// Assert: If we return here, the async generator either threw an exception or performed either an implicit or explicit return.
|
||||
surroundingAgent.executionContextStack.pop(genContext);
|
||||
generator.AsyncGeneratorState = 'completed';
|
||||
let resultValue;
|
||||
if (result instanceof NormalCompletion) {
|
||||
resultValue = Value.undefined;
|
||||
} else {
|
||||
resultValue = result.Value;
|
||||
if (result.Type !== 'return') {
|
||||
return X(AsyncGeneratorReject(generator, resultValue));
|
||||
}
|
||||
}
|
||||
return X(AsyncGeneratorResolve(generator, resultValue, Value.true));
|
||||
}());
|
||||
generator.AsyncGeneratorContext = genContext;
|
||||
generator.AsyncGeneratorState = 'suspendedStart';
|
||||
generator.AsyncGeneratorQueue = [];
|
||||
return Value.undefined;
|
||||
}
|
||||
|
||||
// 25.5.3.3 #sec-asyncgeneratorresolve
|
||||
function AsyncGeneratorResolve(generator, value, done) {
|
||||
// Assert: generator is an AsyncGenerator instance.
|
||||
const queue = generator.AsyncGeneratorQueue;
|
||||
Assert(queue.length > 0);
|
||||
const next = queue.shift();
|
||||
const promiseCapability = next.Capability;
|
||||
const iteratorResult = X(CreateIterResultObject(value, done));
|
||||
X(Call(promiseCapability.Resolve, Value.undefined, [iteratorResult]));
|
||||
X(AsyncGeneratorResumeNext(generator));
|
||||
return Value.undefined;
|
||||
}
|
||||
|
||||
// 25.5.3.4 #sec-asyncgeneratorreject
|
||||
function AsyncGeneratorReject(generator, exception) {
|
||||
// Assert: generator is an AsyncGenerator instance.
|
||||
const queue = generator.AsyncGeneratorQueue;
|
||||
Assert(queue.length > 0);
|
||||
const next = queue.shift();
|
||||
const promiseCapability = next.Capability;
|
||||
X(Call(promiseCapability.Reject, Value.undefined, [exception]));
|
||||
X(AsyncGeneratorResumeNext(generator));
|
||||
return Value.undefined;
|
||||
}
|
||||
|
||||
// 25.5.3.5.1 #async-generator-resume-next-return-processor-fulfilled
|
||||
function AsyncGeneratorResumeNextReturnProcessorFulfilledFunctions([value = Value.undefined]) {
|
||||
const F = surroundingAgent.activeFunctionObject;
|
||||
F.Generator.AsyncGeneratorState = 'completed';
|
||||
return X(AsyncGeneratorResolve(F.Generator, value, Value.true));
|
||||
}
|
||||
|
||||
// 25.5.3.5.2 #async-generator-resume-next-return-processor-rejected
|
||||
function AsyncGeneratorResumeNextReturnProcessorRejectedFunctions([reason = Value.undefined]) {
|
||||
const F = surroundingAgent.activeFunctionObject;
|
||||
F.Generator.AsyncGeneratorState = 'completed';
|
||||
return X(AsyncGeneratorReject(F.Generator, reason));
|
||||
}
|
||||
|
||||
// 25.5.3.5 #sec-asyncgeneratorresumenext
|
||||
function AsyncGeneratorResumeNext(generator) {
|
||||
// Assert: generator is an AsyncGenerator instance.
|
||||
let state = generator.AsyncGeneratorState;
|
||||
Assert(state !== 'executing');
|
||||
if (state === 'awaiting-return') {
|
||||
return Value.undefined;
|
||||
}
|
||||
const queue = generator.AsyncGeneratorQueue;
|
||||
if (queue.length === 0) {
|
||||
return Value.undefined;
|
||||
}
|
||||
const next = queue[0];
|
||||
Assert(next instanceof AsyncGeneratorRequestRecord);
|
||||
const completion = next.Completion;
|
||||
if (completion instanceof AbruptCompletion) {
|
||||
if (state === 'suspendedStart') {
|
||||
generator.AsyncGeneratorState = 'completed';
|
||||
state = 'completed';
|
||||
}
|
||||
if (state === 'completed') {
|
||||
if (completion.Type === 'return') {
|
||||
generator.AsyncGeneratorState = 'awaiting-return';
|
||||
const promise = Q(PromiseResolve(surroundingAgent.intrinsic('%Promise%'), completion.Value));
|
||||
const stepsFulfilled = AsyncGeneratorResumeNextReturnProcessorFulfilledFunctions;
|
||||
const onFulfilled = X(CreateBuiltinFunction(stepsFulfilled, ['Generator']));
|
||||
onFulfilled.Generator = generator;
|
||||
const stepsRejected = AsyncGeneratorResumeNextReturnProcessorRejectedFunctions;
|
||||
const onRejected = X(CreateBuiltinFunction(stepsRejected, ['Generator']));
|
||||
onRejected.Generator = generator;
|
||||
X(PerformPromiseThen(promise, onFulfilled, onRejected));
|
||||
return Value.undefined;
|
||||
} else {
|
||||
Assert(completion.Type === 'throw');
|
||||
X(AsyncGeneratorReject(generator, completion.Value));
|
||||
return Value.undefined;
|
||||
}
|
||||
}
|
||||
} else if (state === 'completed') {
|
||||
return X(AsyncGeneratorResolve(generator, Value.undefined, Value.true));
|
||||
}
|
||||
Assert(state === 'suspendedStart' || state === 'suspendedYield');
|
||||
const genContext = generator.AsyncGeneratorContext;
|
||||
const callerContext = surroundingAgent.runningExecutionContext;
|
||||
// Suspend callerContext
|
||||
generator.AsyncGeneratorState = 'executing';
|
||||
surroundingAgent.executionContextStack.push(genContext);
|
||||
const result = resume(genContext, completion);
|
||||
Assert(!(result instanceof AbruptCompletion));
|
||||
Assert(surroundingAgent.runningExecutionContext === callerContext);
|
||||
return Value.undefined;
|
||||
}
|
||||
|
||||
// 25.5.3.6 #sec-asyncgeneratorenqueue
|
||||
export function AsyncGeneratorEnqueue(generator, completion) {
|
||||
Assert(completion instanceof Completion);
|
||||
const promiseCapability = X(NewPromiseCapability(surroundingAgent.intrinsic('%Promise%')));
|
||||
if (Type(generator) !== 'Object' || !('AsyncGeneratorState' in generator)) {
|
||||
const badGeneratorError = surroundingAgent.Throw('TypeError', 'NotATypeObject', 'AsyncGenerator', generator).Value;
|
||||
X(Call(promiseCapability.Reject, Value.undefined, [badGeneratorError]));
|
||||
return promiseCapability.Promise;
|
||||
}
|
||||
const queue = generator.AsyncGeneratorQueue;
|
||||
const request = new AsyncGeneratorRequestRecord(completion, promiseCapability);
|
||||
queue.push(request);
|
||||
const state = generator.AsyncGeneratorState;
|
||||
if (state !== 'executing') {
|
||||
X(AsyncGeneratorResumeNext(generator));
|
||||
}
|
||||
return promiseCapability.Promise;
|
||||
}
|
||||
|
||||
// #sec-asyncgeneratoryield
|
||||
export function* AsyncGeneratorYield(value) {
|
||||
// 1. Let genContext be the running execution context.
|
||||
const genContext = surroundingAgent.runningExecutionContext;
|
||||
// 2. Assert: genContext is the execution context of a generator.
|
||||
Assert(genContext.Generator !== Value.undefined);
|
||||
// 3. Let generator be the value of the Generator component of genContext.
|
||||
const generator = genContext.Generator;
|
||||
// 4. Assert: GetGeneratorKind() is async.
|
||||
Assert(GetGeneratorKind() === 'async');
|
||||
// 5. Set value to ? Await(value).
|
||||
value = Q(yield* Await(value));
|
||||
// 6. Set generator.[[AsyncGeneratorState]] to suspendedYield.
|
||||
generator.AsyncGeneratorState = 'suspendedYield';
|
||||
// 7. Remove genContext from the execution context stack and restore the execution context that is at the top of the execution context stack as the running execution context.
|
||||
surroundingAgent.executionContextStack.pop(genContext);
|
||||
// 8. Set the code evaluation state of genContext such that when evaluation is resumed with a Completion resumptionValue the following steps will be performed:
|
||||
const resumptionValue = EnsureCompletion(yield handleInResume(AsyncGeneratorResolve, generator, value, Value.false));
|
||||
|
||||
// a. If resumptionValue.[[Type]] is not return, return Completion(resumptionValue).
|
||||
if (resumptionValue.Type !== 'return') {
|
||||
return Completion(resumptionValue);
|
||||
}
|
||||
// b. Let awaited be Await(resumptionValue.[[Value]]).
|
||||
const awaited = EnsureCompletion(yield* Await(resumptionValue.Value));
|
||||
// c. If awaited.[[Type]] is throw, return Completion(awaited).
|
||||
if (awaited.Type === 'Throw') {
|
||||
return Completion(awaited);
|
||||
}
|
||||
// d. Assert: awaited.[[Type]] is normal.
|
||||
Assert(awaited.Type === 'normal');
|
||||
// e. Return Completion { [[Type]]: return, [[Value]]: awaited.[[Value]], [[Target]]: empty }.
|
||||
return new Completion({ Type: 'return', Value: awaited.Value, Target: undefined });
|
||||
// f. NOTE: When one of the above steps returns, it returns to the evaluation of the YieldExpression production that originally called this abstract operation.
|
||||
|
||||
// 9. Return ! AsyncGeneratorResolve(generator, value, false).
|
||||
// 10. NOTE: This returns to the evaluation of the operation that had most previously resumed evaluation of genContext.
|
||||
}
|
||||
Reference in New Issue
Block a user