/**
* 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.observable;
import static com.github.anba.es6draft.runtime.AbstractOperations.GetMethod;
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.observable.SubscriptionAbstractOperations.CleanupSubscription;
import static com.github.anba.es6draft.runtime.objects.observable.SubscriptionAbstractOperations.CloseSubscription;
import static com.github.anba.es6draft.runtime.objects.observable.SubscriptionAbstractOperations.SubscriptionClosed;
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.Function;
import com.github.anba.es6draft.runtime.internal.Properties.Prototype;
import com.github.anba.es6draft.runtime.internal.ScriptException;
import com.github.anba.es6draft.runtime.types.Callable;
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>Observable</h1>
* <ul>
* <li>The %SubscriptionObserverPrototype% Object
* </ul>
*/
public final class SubscriptionObserverPrototype extends OrdinaryObject implements Initializable {
/**
* Constructs a new %SubscriptionObserverPrototype% object.
*
* @param realm
* the realm object
*/
public SubscriptionObserverPrototype(Realm realm) {
super(realm);
}
@Override
public void initialize(Realm realm) {
createProperties(realm, this, Properties.class);
}
/**
* Properties of the %SubscriptionObserverPrototype% Object
*/
public enum Properties {
;
@Prototype
public static final Intrinsics __proto__ = Intrinsics.ObjectPrototype;
private static SubscriptionObserverObject thisSubscriptionObserverObject(ExecutionContext cx, Object o) {
if (!(o instanceof SubscriptionObserverObject)) {
throw newTypeError(cx, Messages.Key.IncompatibleObject);
}
return (SubscriptionObserverObject) o;
}
/**
* %SubscriptionObserverPrototype%.next ( value )
*
* @param cx
* the execution context
* @param thisValue
* the function this-value
* @param value
* the next value
* @return the result {@code this.[[Observer]].next()} or {@code undefined} if this subscription is closed
*/
@Function(name = "next", arity = 1)
public static Object next(ExecutionContext cx, Object thisValue, Object value) {
/* steps 1-3 */
SubscriptionObserverObject o = thisSubscriptionObserverObject(cx, thisValue);
/* step 4 */
SubscriptionObject subscription = o.getSubscription();
/* step 5 */
if (SubscriptionClosed(subscription)) {
return UNDEFINED;
}
/* step 6 */
ScriptObject observer = subscription.getObserver();
/* step 7 (implicit) */
/* steps 8-11 */
try {
/* steps 8, 9.a */
Callable nextMethod = GetMethod(cx, observer, "next");
/* steps 9.b-c */
Object result;
if (nextMethod == null) {
result = UNDEFINED;
} else {
result = nextMethod.call(cx, observer, value);
}
/* step 11 */
return result;
} catch (ScriptException e) {
/* step 10 */
// FIXME: spec bug - CloseSubscription is not defined
// FIXME: spec bug - incorrect ReturnIfAbrupt does not match tests
try {
CloseSubscription(cx, subscription);
} catch (ScriptException ignore) {
}
/* step 11 */
throw e;
}
}
/**
* %SubscriptionObserverPrototype%.error ( exception )
*
* @param cx
* the execution context
* @param thisValue
* the function this-value
* @param exception
* the exception value
* @return the result {@code this.[[Observer]].error()}
*/
@Function(name = "error", arity = 1)
public static Object error(ExecutionContext cx, Object thisValue, Object exception) {
/* steps 1-3 */
SubscriptionObserverObject o = thisSubscriptionObserverObject(cx, thisValue);
/* step 4 */
SubscriptionObject subscription = o.getSubscription();
/* step 5 */
if (SubscriptionClosed(subscription)) {
throw ScriptException.create(exception);
}
/* step 6 */
ScriptObject observer = subscription.getObserver();
/* step 7 (implicit) */
/* step 8 */
subscription.clearObserver();
/* steps 9-13 */
Object result;
try {
/* steps 9, 10.a */
Callable errorMethod = GetMethod(cx, observer, "error");
/* steps 10.b-c */
if (errorMethod == null) {
/* step 10.b */
result = null;
} else {
/* step 10.c */
result = errorMethod.call(cx, observer, exception);
}
} catch (ScriptException e) {
/* steps 11-12 */
// FIXME: spec bug - incorrect ReturnIfAbrupt does not match tests
try {
CleanupSubscription(cx, subscription);
} catch (ScriptException ignore) {
}
/* step 13 */
throw e;
}
/* step 10.b */
if (result == null) {
// FIXME: spec bug - tests expect CleanupSubscription is called if no error method found
CleanupSubscription(cx, subscription);
throw ScriptException.create(exception);
}
/* steps 11-12 */
CleanupSubscription(cx, subscription);
/* step 13 */
return result;
}
/**
* %SubscriptionObserverPrototype%.complete ( value )
*
* @param cx
* the execution context
* @param thisValue
* the function this-value
* @param value
* the value
* @return the result {@code this.[[Observer]].complete()}
*/
@Function(name = "complete", arity = 1)
public static Object complete(ExecutionContext cx, Object thisValue, Object value) {
/* steps 1-3 */
SubscriptionObserverObject o = thisSubscriptionObserverObject(cx, thisValue);
/* step 4 */
SubscriptionObject subscription = o.getSubscription();
/* step 5 */
if (SubscriptionClosed(subscription)) {
return UNDEFINED;
}
/* step 6 */
ScriptObject observer = subscription.getObserver();
/* step 7 (implicit) */
/* step 8 */
subscription.clearObserver();
/* steps 9-13 */
Object result;
try {
/* steps 9, 10.a */
Callable completeMethod = GetMethod(cx, observer, "complete");
/* steps 10.b-c */
if (completeMethod == null) {
/* step 10.b */
result = UNDEFINED;
} else {
/* step 10.c */
result = completeMethod.call(cx, observer, value);
}
} catch (ScriptException e) {
/* steps 11-12 */
// FIXME: spec bug - incorrect ReturnIfAbrupt does not match tests
try {
CleanupSubscription(cx, subscription);
} catch (ScriptException ignore) {
}
/* step 13 */
throw e;
}
/* steps 11-12 */
CleanupSubscription(cx, subscription);
/* step 13 */
return result;
}
}
}