/**
* 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.internal;
import com.github.anba.es6draft.runtime.ExecutionContext;
/**
* Bytecode-based continuation implementation.
*/
public final class CodeContinuation<VALUE> implements Continuation<VALUE> {
private final Continuation.Handler<VALUE> handler;
private ResumptionPoint resumptionPoint;
public CodeContinuation(Continuation.Handler<VALUE> handler) {
this.handler = handler;
}
@Override
public VALUE start(ExecutionContext cx) {
assert resumptionPoint == null;
return execute(cx, null);
}
@Override
public VALUE resume(ExecutionContext cx, Object value) {
return execute(cx, prepareResume(value));
}
@Override
public VALUE _return(ExecutionContext cx, Object value) {
return execute(cx, prepareResume(new ReturnValue(value)));
}
@Override
public VALUE _throw(ExecutionContext cx, ScriptException exception) {
return execute(cx, prepareResume(exception));
}
private ResumptionPoint prepareResume(Object value) {
assert value != null;
ResumptionPoint rp = resumptionPoint;
resumptionPoint = null;
rp.setResumeValue(value);
return rp;
}
private VALUE execute(ExecutionContext cx, ResumptionPoint resumptionPoint) {
Object result;
try {
result = handler.evaluate(resumptionPoint);
} catch (ScriptException e) {
handler.close();
return handler.returnWith(cx, e);
} catch (Throwable e) {
handler.close();
throw CodeContinuation.<RuntimeException> rethrow(e);
}
if (result instanceof ResumptionPoint) {
ResumptionPoint rp = (ResumptionPoint) result;
this.resumptionPoint = rp;
return handler.suspendWith(cx, rp.getSuspendValue());
}
handler.close();
return handler.returnWith(cx, result);
}
@SuppressWarnings("unchecked")
private static <E extends Throwable> E rethrow(Throwable e) throws E {
throw (E) e;
}
}