Files
ask262/engine262/src/abstract-ops/import-calls.mts
T

113 lines
5.3 KiB
TypeScript

// This file covers abstract operations defined in
// https://tc39.es/ecma262/#sec-import-calls
import {
AbstractModuleRecord,
Assert,
Call, CreateBuiltinFunction, CreateListIteratorRecord, GatherAsynchronousTransitiveDependencies, GetModuleNamespace, NewPromiseCapability, PerformPromiseThen, PromiseCapabilityRecord, surroundingAgent, Value,
type Arguments,
type PromiseObject,
} from '../index.mts';
import {
AbruptCompletion, ValueOfNormalCompletion, X, type PlainCompletion,
} from '../completion.mts';
import { PerformPromiseAll } from '../intrinsics/Promise.mts';
/** https://tc39.es/ecma262/#sec-ContinueDynamicImport */
export function ContinueDynamicImport(
promiseCapability: PromiseCapabilityRecord,
moduleCompletion: PlainCompletion<AbstractModuleRecord>,
phase: 'defer' | 'evaluation',
) {
// 1. If moduleCompletion is an abrupt completion, then
if (moduleCompletion instanceof AbruptCompletion) {
// a. Perform ! Call(promiseCapability.[[Reject]], undefined, « moduleCompletion.[[Value]] »).
X(Call(promiseCapability.Reject, Value.undefined, [moduleCompletion.Value]));
// b. Return unused.
return;
}
// 2. Let module be moduleCompletion.[[Value]].
const module = ValueOfNormalCompletion(moduleCompletion);
// 3. Let loadPromise be module.LoadRequestedModules().
const loadPromise = module.LoadRequestedModules();
// 4. Let rejectedClosure be a new Abstract Closure with parameters (reason) that captures promiseCapability and performs the following steps when called:
const rejectedClosure = ([reason = Value.undefined]: Arguments): void => {
// a. Perform ! Call(promiseCapability.[[Reject]], undefined, « reason »).
X(Call(promiseCapability.Reject, Value.undefined, [reason]));
// b. Return unused.
};
// 5. Let onRejected be CreateBuiltinFunction(rejectedClosure, 1, "", « »).
const onRejected = CreateBuiltinFunction(rejectedClosure, 1, Value(''), []);
// 6. Let linkAndEvaluateClosure be a new Abstract Closure with no parameters that captures module, promiseCapability, and onRejected and performs the following steps when called:
function* linkAndEvaluateClosure() {
// a. Let link be Completion(module.Link()).
const link = module.Link();
// b. If link is an abrupt completion, then
if (link instanceof AbruptCompletion) {
// i. Perform ! Call(promiseCapability.[[Reject]], undefined, « link.[[Value]] »).
X(Call(promiseCapability.Reject, Value.undefined, [link.Value]));
// ii. Return unused.
return;
}
let evaluatePromise: PromiseObject;
// c. Let evaluatePromise be module.Evaluate().
evaluatePromise = yield* module.Evaluate();
// d. Let fulfilledClosure be a new Abstract Closure with no parameters that captures module and promiseCapability and performs the following steps when called:
const fulfilledClosure = () => {
// i. Let namespace be GetModuleNamespace(module).
const namespace = GetModuleNamespace(module, phase);
// ii. Perform ! Call(promiseCapability.[[Resolve]], undefined, « namespace »).
X(Call(promiseCapability.Resolve, Value.undefined, [namespace]));
// iii. Return unused.
};
// e. If phase is "defer", then
if (phase === 'defer') {
// i. Let evaluationList be module.GatherAsynchronousTransitiveDependencies().
const evaluationList = GatherAsynchronousTransitiveDependencies(module);
// ii. If evaluationList is empty, then
if (evaluationList.length === 0) {
// 1. Perform fulfilledClosure().
fulfilledClosure();
// 2. Return unused.
return;
}
// iii. Let asyncDepsEvaluationPromises be a new empty List.
const asyncDepsEvaluationPromises = [];
// iv. For each dep in evaluationList, append dep.Evaluate() to asyncDepsEvaluationPromises.
for (const dep of evaluationList) {
asyncDepsEvaluationPromises.push(yield* dep.Evaluate());
}
// v. Let iterator be CreateListIteratorRecord(asyncDepsEvaluationPromises).
const iterator = CreateListIteratorRecord(asyncDepsEvaluationPromises);
// vi. Let pc be ! NewPromiseCapability(%Promise%).
const pc = X(NewPromiseCapability(surroundingAgent.intrinsic('%Promise%')));
// vii. Let evaluatePromise be ! PerformPromiseAll(iterator, %Promise%, pc, %Promise.resolve%).
evaluatePromise = X(PerformPromiseAll(iterator, surroundingAgent.intrinsic('%Promise%'), pc, surroundingAgent.intrinsic('%Promise.resolve%'))) as PromiseObject;
} else { // f. Else,
// i. Assert: phase is EVALUATION.
Assert(phase === 'evaluation');
// ii. Let evaluatePromise be module.Evaluate().
evaluatePromise = yield* module.Evaluate();
}
// e. Let onFulfilled be CreateBuiltinFunction(fulfilledClosure, 0, "", « »).
const onFulfilled = CreateBuiltinFunction(fulfilledClosure, 0, Value(''), []);
// f. Perform PerformPromiseThen(evaluatePromise, onFulfilled, onRejected).
PerformPromiseThen(evaluatePromise!, onFulfilled, onRejected);
// g. Return unused.
}
// 7. Let linkAndEvaluate be CreateBuiltinFunction(linkAndEvaluateClosure, 0, "", « »).
const linkAndEvaluate = CreateBuiltinFunction(linkAndEvaluateClosure, 0, Value(''), []);
// 8. Perform PerformPromiseThen(loadPromise, linkAndEvaluate, onRejected).
PerformPromiseThen(loadPromise, linkAndEvaluate, onRejected);
// 9. Return unused.
}