123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- using Jint.Native.Object;
- using Jint.Native.Symbol;
- using Jint.Runtime;
- using Jint.Runtime.Descriptors;
- using Jint.Runtime.Interop;
- namespace Jint.Native.Promise;
- internal sealed class PromisePrototype : Prototype
- {
- private readonly PromiseConstructor _constructor;
- internal PromisePrototype(
- Engine engine,
- Realm realm,
- PromiseConstructor constructor,
- ObjectPrototype objectPrototype) : base(engine, realm)
- {
- _prototype = objectPrototype;
- _constructor = constructor;
- }
- protected override void Initialize()
- {
- const PropertyFlag lengthFlags = PropertyFlag.Configurable;
- const PropertyFlag propertyFlags = PropertyFlag.Configurable | PropertyFlag.Writable;
- var properties = new PropertyDictionary(5, checkExistingKeys: false)
- {
- ["constructor"] = new(_constructor, PropertyFlag.NonEnumerable),
- ["then"] = new(new ClrFunction(Engine, "then", Then, 2, lengthFlags), propertyFlags),
- ["catch"] = new(new ClrFunction(Engine, "catch", Catch, 1, lengthFlags), propertyFlags),
- ["finally"] = new(new ClrFunction(Engine, "finally", Finally, 1, lengthFlags), propertyFlags)
- };
- SetProperties(properties);
- var symbols = new SymbolDictionary(1)
- {
- [GlobalSymbolRegistry.ToStringTag] = new(new JsString("Promise"), PropertyFlag.Configurable)
- };
- SetSymbols(symbols);
- }
- // https://tc39.es/ecma262/#sec-promise.prototype.then
- // When the then method is called with arguments onFulfilled and onRejected,
- // the following steps are taken:
- //
- // 1. Let promise be the this value.
- // 2. If IsPromise(promise) is false, throw a TypeError exception.
- // 3. Let C be ? SpeciesConstructor(promise, %Promise%).
- // 4. Let resultCapability be ? NewPromiseCapability(C).
- // 5. Return PerformPromiseThen(promise, onFulfilled, onRejected, resultCapability).
- private JsValue Then(JsValue thisValue, JsCallArguments arguments)
- {
- // 1. Let promise be the this value.
- // 2. If IsPromise(promise) is false, throw a TypeError exception.
- var promise = thisValue as JsPromise;
- if (promise is null)
- {
- Throw.TypeError(_realm, "Method Promise.prototype.then called on incompatible receiver");
- }
- // 3. Let C be ? SpeciesConstructor(promise, %Promise%).
- var ctor = SpeciesConstructor(promise, _realm.Intrinsics.Promise);
- // 4. Let resultCapability be ? NewPromiseCapability(C).
- var capability = PromiseConstructor.NewPromiseCapability(_engine, (JsValue) ctor);
- // 5. Return PerformPromiseThen(promise, onFulfilled, onRejected, resultCapability).
- return PromiseOperations.PerformPromiseThen(_engine, promise, arguments.At(0), arguments.At(1), capability);
- }
- // https://tc39.es/ecma262/#sec-promise.prototype.catch
- //
- // When the catch method is called with argument onRejected,
- // the following steps are taken:
- //
- // 1. Let promise be the this value.
- // 2. Return ? Invoke(promise, "then", « undefined, onRejected »).
- private JsValue Catch(JsValue thisValue, JsCallArguments arguments) =>
- _engine.Invoke(thisValue, "then", [Undefined, arguments.At(0)]);
- // https://tc39.es/ecma262/#sec-promise.prototype.finally
- private JsValue Finally(JsValue thisValue, JsCallArguments arguments)
- {
- // 1. Let promise be the this value.
- // 2. If Type(promise) is not Object, throw a TypeError exception.
- var promise = thisValue as ObjectInstance;
- if (promise is null)
- {
- Throw.TypeError(_realm, "this passed to Promise.prototype.finally is not an object");
- }
- // 3. Let C be ? SpeciesConstructor(promise, %Promise%).
- // 4. Assert: IsConstructor(C) is true.
- var ctor = SpeciesConstructor(promise, _realm.Intrinsics.Promise);
- JsValue thenFinally;
- JsValue catchFinally;
- var onFinally = arguments.At(0);
- // 5. If IsCallable(onFinally) is false, then
- if (onFinally is not ICallable onFinallyFunc)
- {
- // a. Let thenFinally be onFinally.
- // b. Let catchFinally be onFinally.
- thenFinally = onFinally;
- catchFinally = onFinally;
- }
- else
- {
- thenFinally = ThenFinallyFunctions(onFinallyFunc, ctor);
- catchFinally = CatchFinallyFunctions(onFinallyFunc, ctor);
- }
- // 7. Return ? Invoke(promise, "then", « thenFinally, catchFinally »).
- return _engine.Invoke(promise, "then", [thenFinally, catchFinally]);
- }
- // https://tc39.es/ecma262/#sec-thenfinallyfunctions
- private ClrFunction ThenFinallyFunctions(ICallable onFinally, IConstructor ctor) =>
- new ClrFunction(_engine, "", (_, args) =>
- {
- var value = args.At(0);
- //4. Let result be ? Call(onFinally, undefined).
- var result = onFinally.Call(Undefined, Arguments.Empty);
- // 7. Let promise be ? PromiseResolve(C, result).
- var promise = _realm.Intrinsics.Promise.Resolve((JsValue) ctor, [result]);
- // 8. Let valueThunk be equivalent to a function that returns value.
- var valueThunk = new ClrFunction(_engine, "", (_, _) => value);
- // 9. Return ? Invoke(promise, "then", « valueThunk »).
- return _engine.Invoke(promise, "then", [valueThunk]);
- }, 1, PropertyFlag.Configurable);
- // https://tc39.es/ecma262/#sec-catchfinallyfunctions
- private ClrFunction CatchFinallyFunctions(ICallable onFinally, IConstructor ctor) =>
- new ClrFunction(_engine, "", (_, args) =>
- {
- var reason = args.At(0);
- //4. Let result be ? Call(onFinally, undefined).
- var result = onFinally.Call(Undefined, Arguments.Empty);
- // 7. Let promise be ? PromiseResolve(C, result).
- var promise = _realm.Intrinsics.Promise.Resolve((JsValue) ctor, [result]);
- // 8. Let thrower be equivalent to a function that throws reason.
- var thrower = new ClrFunction(_engine, "", (_, _) => throw new JavaScriptException(reason));
- // 9. Return ? Invoke(promise, "then", « thrower »).
- return _engine.Invoke(promise, "then", [thrower]);
- }, 1, PropertyFlag.Configurable);
- }
|