mirror of
https://github.com/bendtherules/ask262.git
synced 2026-08-18 21:31:46 +00:00
Squashed 'engine262/' content from commit ae71998
git-subtree-dir: engine262 git-subtree-split: ae71998cc5a8315700555135b1ac202a0d6d0b31
This commit is contained in:
@@ -0,0 +1,216 @@
|
||||
import { captureStack, isArray, callSiteToErrorStack } from '../helpers.mts';
|
||||
import type { ErrorObject } from '../intrinsics/Error.mts';
|
||||
import {
|
||||
Assert, Call, Construct, CopyNameAndLength, CreateBuiltinFunction, DeclarativeEnvironmentRecord, EnvironmentRecord, EvalDeclarationInstantiation, Evaluate, ExecutionContext, Get, GetFunctionRealm, HasOwnProperty, HostEnsureCanCompileStrings, HostLoadImportedModule, IsCallable, isErrorObject, isModuleNamespaceObject, JSStringValue, MakeBasicObject, NewPromiseCapability, NormalCompletion, ObjectValue, Parser, PerformPromiseThen, Q, RequireInternalSlot, surroundingAgent, ThrowCompletion, Value, wrappedParse, X, type Arguments, type BuiltinFunctionObject, type ExoticObject, type FunctionObject, type Mutable, type PlainCompletion, type Realm, type ValueEvaluator,
|
||||
} from '#self';
|
||||
|
||||
/** https://tc39.es/proposal-shadowrealm/#table-internal-slots-of-wrapped-function-exotic-objects */
|
||||
export interface WrappedFunctionExoticObject extends BuiltinFunctionObject, ExoticObject {
|
||||
readonly WrappedTargetFunction: FunctionObject;
|
||||
readonly Realm: Realm;
|
||||
}
|
||||
|
||||
export function isWrappedFunctionExoticObject(value: Value): value is WrappedFunctionExoticObject {
|
||||
return 'WrappedTargetFunction' in value;
|
||||
}
|
||||
|
||||
/** https://tc39.es/proposal-shadowrealm/#sec-wrapped-function-exotic-objects-call-thisargument-argumentslist */
|
||||
function* WrappedFunction_Call(this: WrappedFunctionExoticObject, thisArgument: Value, argumentList: Arguments): ValueEvaluator {
|
||||
const F = this;
|
||||
const callerContext = surroundingAgent.runningExecutionContext;
|
||||
const calleeContext = PrepareForWrappedFunctionCall(F);
|
||||
Assert(surroundingAgent.runningExecutionContext === calleeContext);
|
||||
const result = yield* OrdinaryWrappedFunctionCall(F, thisArgument, argumentList);
|
||||
surroundingAgent.executionContextStack.pop(calleeContext);
|
||||
Assert(surroundingAgent.runningExecutionContext === callerContext);
|
||||
return Q(result);
|
||||
}
|
||||
|
||||
/** https://tc39.es/proposal-shadowrealm/#sec-create-type-error-copy */
|
||||
export function CreateTypeErrorCopy(realmRecord: Realm, non_spec_evalRealm: Realm, originalError: Value): ObjectValue {
|
||||
realmRecord.HostDefined.attachingInspectorReportError?.(non_spec_evalRealm, originalError);
|
||||
let message = 'An error occurred in a ShadowRealm.';
|
||||
let errorData: string | undefined;
|
||||
let hostStack: ErrorObject['HostDefinedErrorStack'];
|
||||
let stack = '';
|
||||
if (originalError instanceof ObjectValue) {
|
||||
if (isErrorObject(originalError)) {
|
||||
errorData = originalError.ErrorData.stringValue();
|
||||
hostStack = originalError.HostDefinedErrorStack;
|
||||
} else {
|
||||
const S = captureStack();
|
||||
stack = callSiteToErrorStack(S.stack, S.nativeStack);
|
||||
}
|
||||
if (originalError.properties.has('message')) {
|
||||
const messageProp = originalError.properties.get('message');
|
||||
if (messageProp && messageProp.Value && messageProp.Value instanceof JSStringValue) {
|
||||
message = messageProp.Value.stringValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
const newError = X(Construct(realmRecord.Intrinsics['%TypeError%'], [Value(message)])) as ErrorObject;
|
||||
newError.ErrorData = errorData ? Value(errorData) : Value(message + stack);
|
||||
newError.HostDefinedErrorStack ??= hostStack;
|
||||
return newError;
|
||||
}
|
||||
|
||||
/** https://tc39.es/proposal-shadowrealm/#sec-ordinary-wrapped-function-call */
|
||||
export function* OrdinaryWrappedFunctionCall(F: WrappedFunctionExoticObject, thisArgument: Value, argumentList: Arguments) {
|
||||
const target = F.WrappedTargetFunction;
|
||||
Assert(IsCallable(target));
|
||||
const callerRealm = F.Realm;
|
||||
|
||||
// Note: Any exception objects produced after this point are associated with callerRealm.
|
||||
const targetRealm = Q(GetFunctionRealm(target));
|
||||
const wrappedArgs: Value[] = [];
|
||||
for (const arg of argumentList.values()) {
|
||||
const wrappedValue = Q(yield* GetWrappedValue(targetRealm, arg));
|
||||
wrappedArgs.push(wrappedValue);
|
||||
}
|
||||
const wrappedThisArgument = Q(yield* GetWrappedValue(targetRealm, thisArgument));
|
||||
const result = yield* Call(target, wrappedThisArgument, wrappedArgs);
|
||||
if (result instanceof Value || result instanceof NormalCompletion) {
|
||||
return Q(yield* GetWrappedValue(callerRealm, result instanceof Value ? result : result.Value));
|
||||
} else {
|
||||
const copiedError = CreateTypeErrorCopy(callerRealm, targetRealm, result.Value);
|
||||
return ThrowCompletion(copiedError);
|
||||
}
|
||||
}
|
||||
|
||||
/** https://tc39.es/proposal-shadowrealm/#sec-prepare-for-wrapped-function-call */
|
||||
export function PrepareForWrappedFunctionCall(F: WrappedFunctionExoticObject) {
|
||||
const calleeContext = new ExecutionContext();
|
||||
calleeContext.Function = F;
|
||||
const calleeRealm = F.Realm;
|
||||
calleeContext.Realm = calleeRealm;
|
||||
calleeContext.ScriptOrModule = Value.null;
|
||||
surroundingAgent.executionContextStack.push(calleeContext);
|
||||
// 9. NOTE: Any exception objects produced after this point are associated with calleeRealm.
|
||||
return calleeContext;
|
||||
}
|
||||
|
||||
/** https://tc39.es/proposal-shadowrealm/#sec-wrappedfunctioncreate */
|
||||
export function* WrappedFunctionCreate(callerRealm: Realm, Target: FunctionObject) {
|
||||
const internalSlotsList = ['WrappedTargetFunction', 'Call', 'Realm', 'Prototype', 'Extensible'];
|
||||
const wrapped = MakeBasicObject(internalSlotsList) as Mutable<WrappedFunctionExoticObject>;
|
||||
wrapped.Prototype = callerRealm.Intrinsics['%Function.prototype%'];
|
||||
wrapped.Call = WrappedFunction_Call;
|
||||
wrapped.WrappedTargetFunction = Target;
|
||||
wrapped.Realm = callerRealm;
|
||||
const result = yield* CopyNameAndLength(wrapped, Target);
|
||||
if (result instanceof ThrowCompletion) {
|
||||
return surroundingAgent.Throw('TypeError', 'Raw', 'Cannot create wrapped function');
|
||||
}
|
||||
return wrapped;
|
||||
}
|
||||
|
||||
/** https://tc39.es/proposal-shadowrealm/#sec-performshadowrealmeval */
|
||||
export function* PerformShadowRealmEval(sourceText: string, callerRealm: Realm, evalRealm: Realm): ValueEvaluator {
|
||||
Q(yield* HostEnsureCanCompileStrings(evalRealm, [], sourceText, false));
|
||||
const script = wrappedParse({ source: sourceText }, (p) => p.scope.with({
|
||||
newTarget: false,
|
||||
superProperty: false,
|
||||
superCall: false,
|
||||
}, () => p.parseScript()));
|
||||
const scriptId = surroundingAgent.addDynamicParsedSource(surroundingAgent.currentRealmRecord, sourceText, script);
|
||||
if (isArray(script)) {
|
||||
Parser.decorateSyntaxErrorWithScriptId(script[0], scriptId);
|
||||
return ThrowCompletion(script[0]);
|
||||
}
|
||||
if (!script.ScriptBody) {
|
||||
return Value.undefined;
|
||||
}
|
||||
|
||||
const body = script.ScriptBody;
|
||||
const strictEval = script.strict;
|
||||
const evalContext = GetShadowRealmContext(evalRealm, strictEval);
|
||||
evalContext.HostDefined ??= {};
|
||||
evalContext.HostDefined.scriptId = scriptId;
|
||||
// TODO: spec bug? dynamic import leak
|
||||
// evalContext.ScriptOrModule = scriptRec;
|
||||
const lexEnv = evalContext.LexicalEnvironment;
|
||||
// TODO: spec bug?
|
||||
Assert(lexEnv instanceof DeclarativeEnvironmentRecord);
|
||||
const varEnv = evalContext.VariableEnvironment;
|
||||
surroundingAgent.executionContextStack.push(evalContext);
|
||||
let result: PlainCompletion<Value | void> = yield* EvalDeclarationInstantiation(body, varEnv, lexEnv, Value.null, strictEval);
|
||||
if (result instanceof NormalCompletion) {
|
||||
result = yield* Evaluate(body);
|
||||
}
|
||||
if (result === undefined || (result instanceof NormalCompletion && result.Value === undefined)) {
|
||||
result = NormalCompletion(Value.undefined);
|
||||
}
|
||||
surroundingAgent.executionContextStack.pop(evalContext);
|
||||
if (result instanceof ThrowCompletion) {
|
||||
const copiedError = CreateTypeErrorCopy(callerRealm, evalRealm, result.Value);
|
||||
return ThrowCompletion(copiedError);
|
||||
}
|
||||
return Q(yield* GetWrappedValue(callerRealm, X(result) || Value.undefined));
|
||||
}
|
||||
|
||||
/** https://tc39.es/proposal-shadowrealm/#sec-shadowrealmimportvalue */
|
||||
export function ShadowRealmImportValue(specifierString: JSStringValue, exportNameString: JSStringValue, callerRealm: Realm, evalRealm: Realm): Value {
|
||||
const evalContext = GetShadowRealmContext(evalRealm, true);
|
||||
const innerCapability = X(NewPromiseCapability(surroundingAgent.intrinsic('%Promise%')));
|
||||
surroundingAgent.executionContextStack.push(evalContext);
|
||||
const referrer = evalContext.Realm;
|
||||
HostLoadImportedModule(referrer, {
|
||||
Specifier: specifierString,
|
||||
Phase: 'evaluation',
|
||||
Attributes: [],
|
||||
}, undefined, innerCapability);
|
||||
surroundingAgent.executionContextStack.pop(evalContext);
|
||||
const onFullfilled = CreateBuiltinFunction(function* onFullfilled([exports = Value.undefined]) {
|
||||
Assert(isModuleNamespaceObject(exports));
|
||||
const f = surroundingAgent.activeFunctionObject as FunctionObject;
|
||||
const string = exportNameString;
|
||||
const hasOwn = Q(yield* HasOwnProperty(exports, string));
|
||||
if (hasOwn === Value.false) {
|
||||
return surroundingAgent.Throw('TypeError', 'Raw', `The module does not define an export named ${string.stringValue()}.`);
|
||||
}
|
||||
const value = Q(yield* Get(exports, string));
|
||||
const realm = f.Realm;
|
||||
return Q(yield* GetWrappedValue(realm, value));
|
||||
}, 1, Value(''), [], callerRealm);
|
||||
const onRejected = CreateBuiltinFunction((([error = Value.undefined]) => {
|
||||
// 1. Let realmRecord be the function's associated Realm Record.
|
||||
const realmRecord = callerRealm;
|
||||
const copiedError = CreateTypeErrorCopy(realmRecord, evalRealm, error);
|
||||
return ThrowCompletion(copiedError);
|
||||
}), 1, Value(''), [], callerRealm);
|
||||
const promiseCapability = X(NewPromiseCapability(surroundingAgent.intrinsic('%Promise%')));
|
||||
return PerformPromiseThen(innerCapability.Promise, onFullfilled, onRejected, promiseCapability);
|
||||
}
|
||||
|
||||
/** https://tc39.es/proposal-shadowrealm/#sec-getwrappedvalue */
|
||||
export function* GetWrappedValue(callerRealm: Realm, value: Value): ValueEvaluator {
|
||||
if (value instanceof ObjectValue) {
|
||||
if (!IsCallable(value)) {
|
||||
return surroundingAgent.Throw('TypeError', 'NotAFunction', value);
|
||||
}
|
||||
return Q(yield* WrappedFunctionCreate(callerRealm, value));
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/** https://tc39.es/proposal-shadowrealm/#sec-validateshadowrealmobject */
|
||||
export function ValidateShadowRealmObject(O: Value): PlainCompletion<void> {
|
||||
Q(RequireInternalSlot(O, 'ShadowRealm'));
|
||||
}
|
||||
|
||||
/** https://tc39.es/proposal-shadowrealm/#sec-getshadowrealmcontext */
|
||||
export function GetShadowRealmContext(shadowRealmRecord: Realm, strictEval: boolean): ExecutionContext {
|
||||
const lexEnv = new DeclarativeEnvironmentRecord(shadowRealmRecord.GlobalEnv);
|
||||
let varEnv: EnvironmentRecord = shadowRealmRecord.GlobalEnv;
|
||||
if (strictEval) {
|
||||
varEnv = lexEnv;
|
||||
}
|
||||
const context = new ExecutionContext();
|
||||
context.Function = Value.null;
|
||||
context.Realm = shadowRealmRecord;
|
||||
context.ScriptOrModule = Value.null;
|
||||
context.VariableEnvironment = varEnv;
|
||||
context.LexicalEnvironment = lexEnv;
|
||||
context.PrivateEnvironment = Value.null;
|
||||
return context;
|
||||
}
|
||||
Reference in New Issue
Block a user