/** * Copyright (c) 2012-2016 André Bargull * Alle Rechte vorbehalten / All Rights Reserved. Use is subject to license terms. * * <https://github.com/anba/es6draft> */ package com.github.anba.es6draft.runtime.objects.promise; import static com.github.anba.es6draft.runtime.AbstractOperations.Invoke; import static com.github.anba.es6draft.runtime.AbstractOperations.IsCallable; import static com.github.anba.es6draft.runtime.AbstractOperations.SpeciesConstructor; import static com.github.anba.es6draft.runtime.internal.Errors.newTypeError; import static com.github.anba.es6draft.runtime.internal.Properties.createProperties; import static com.github.anba.es6draft.runtime.objects.promise.PromiseAbstractOperations.IsPromise; import static com.github.anba.es6draft.runtime.objects.promise.PromiseAbstractOperations.NewPromiseCapability; import static com.github.anba.es6draft.runtime.types.Undefined.UNDEFINED; import com.github.anba.es6draft.runtime.ExecutionContext; import com.github.anba.es6draft.runtime.Realm; import com.github.anba.es6draft.runtime.internal.Initializable; import com.github.anba.es6draft.runtime.internal.Messages; import com.github.anba.es6draft.runtime.internal.Properties.Attributes; import com.github.anba.es6draft.runtime.internal.Properties.Function; import com.github.anba.es6draft.runtime.internal.Properties.Prototype; import com.github.anba.es6draft.runtime.internal.Properties.Value; import com.github.anba.es6draft.runtime.objects.promise.PromiseAbstractOperations.PromiseReactionTask; import com.github.anba.es6draft.runtime.types.BuiltinSymbol; import com.github.anba.es6draft.runtime.types.Callable; import com.github.anba.es6draft.runtime.types.Constructor; import com.github.anba.es6draft.runtime.types.Intrinsics; import com.github.anba.es6draft.runtime.types.ScriptObject; import com.github.anba.es6draft.runtime.types.builtins.OrdinaryObject; /** * <h1>25 Control Abstraction Objects</h1><br> * <h2>25.4 Promise Objects</h2> * <ul> * <li>25.4.5 Properties of the Promise Prototype Object * </ul> */ public final class PromisePrototype extends OrdinaryObject implements Initializable { /** * Constructs a new Promise prototype object. * * @param realm * the realm object */ public PromisePrototype(Realm realm) { super(realm); } @Override public void initialize(Realm realm) { createProperties(realm, this, Properties.class); } /** * 25.4.5 Properties of the Promise Prototype Object */ public enum Properties { ; @Prototype public static final Intrinsics __proto__ = Intrinsics.ObjectPrototype; /** * 25.4.5.2 Promise.prototype.constructor */ @Value(name = "constructor") public static final Intrinsics constructor = Intrinsics.Promise; /** * 25.4.5.1 Promise.prototype.catch ( onRejected ) * * @param cx * the execution context * @param thisValue * the function this-value * @param onRejected * the onRejected handler * @return the new promise object */ @Function(name = "catch", arity = 1) public static Object _catch(ExecutionContext cx, Object thisValue, Object onRejected) { /* step 1 */ Object promise = thisValue; /* step 2 */ return Invoke(cx, promise, "then", UNDEFINED, onRejected); } /** * 25.4.5.3 Promise.prototype.then ( onFulfilled , onRejected ) * * @param cx * the execution context * @param thisValue * the function this-value * @param onFulfilled * the onFulfilled handler * @param onRejected * the onRejected handler * @return the new promise object */ @Function(name = "then", arity = 2) public static Object then(ExecutionContext cx, Object thisValue, Object onFulfilled, Object onRejected) { /* step 2 */ if (!IsPromise(thisValue)) { throw newTypeError(cx, Messages.Key.IncompatibleObject); } /* step 1 */ PromiseObject promise = (PromiseObject) thisValue; /* steps 3-4 */ Constructor c = SpeciesConstructor(cx, promise, Intrinsics.Promise); /* steps 5-6 */ PromiseCapability<ScriptObject> resultCapability = NewPromiseCapability(cx, c); /* step 7 */ return PerformPromiseThen(cx, promise, onFulfilled, onRejected, resultCapability); } /** * 25.4.5.4 Promise.prototype [ @@toStringTag ] */ @Value(name = "[Symbol.toStringTag]", symbol = BuiltinSymbol.toStringTag, attributes = @Attributes(writable = false, enumerable = false, configurable = true)) public static final String toStringTag = "Promise"; } /** * 25.4.5.3.1 PerformPromiseThen ( promise, onFulfilled, onRejected, resultCapability ) * * @param <PROMISE> * the promise type * @param cx * the execution context * @param promise * the promise object * @param onFulfilled * the onFulfilled handler * @param onRejected * the onRejected handler * @param resultCapability * the new promise capability record * @return the new promise object */ public static <PROMISE extends ScriptObject> PROMISE PerformPromiseThen(ExecutionContext cx, PromiseObject promise, Object onFulfilled, Object onRejected, PromiseCapability<PROMISE> resultCapability) { /* steps 1-2 (not applicable) */ /* step 3 */ PromiseReaction.Type fulfillType = PromiseReaction.Type.Function; if (!IsCallable(onFulfilled)) { fulfillType = PromiseReaction.Type.Identity; onFulfilled = null; } /* step 4 */ PromiseReaction.Type rejectType = PromiseReaction.Type.Function; if (!IsCallable(onRejected)) { rejectType = PromiseReaction.Type.Thrower; onRejected = null; } /* step 5 */ PromiseReaction fulfillReaction = new PromiseReaction(resultCapability, (Callable) onFulfilled, fulfillType); /* step 6 */ PromiseReaction rejectReaction = new PromiseReaction(resultCapability, (Callable) onRejected, rejectType); /* step 7 */ if (promise.getState() == PromiseObject.State.Pending) { promise.addFulfillReaction(fulfillReaction); promise.addRejectReaction(rejectReaction); promise.notifyRejectReaction(rejectReaction); } /* step 8 */ else if (promise.getState() == PromiseObject.State.Fulfilled) { Object value = promise.getResult(); Realm realm = cx.getRealm(); realm.enqueuePromiseTask(new PromiseReactionTask(realm, fulfillReaction, value)); } /* step 9 */ else { assert promise.getState() == PromiseObject.State.Rejected; Object reason = promise.getResult(); Realm realm = cx.getRealm(); realm.enqueuePromiseTask(new PromiseReactionTask(realm, rejectReaction, reason)); promise.notifyRejectReaction(rejectReaction); } /* step 10 */ return resultCapability.getPromise(); } }