diff --git a/classpath/avian/Continuations.java b/classpath/avian/Continuations.java index 631bd48a72..476be807f7 100644 --- a/classpath/avian/Continuations.java +++ b/classpath/avian/Continuations.java @@ -120,6 +120,8 @@ import java.util.concurrent.Callable; public class Continuations { private Continuations() { } + private static final ThreadLocal latestReset = new ThreadLocal(); + /** * Captures the current continuation, passing a reference to the * specified receiver. @@ -181,6 +183,76 @@ public class Continuations { } } + public static T reset(final Callable thunk) throws Exception { + final Reset reset = new Reset(latestReset.get()); + latestReset.set(reset); + try { + T result = callWithCurrentContinuation + (new CallbackReceiver() { + public T receive(Callback continuation) throws Exception { + reset.continuation = continuation; + return thunk.call(); + } + }); + + if (reset.continuation != null) { + reset.continuation.handleResult(result); + } + + return result; + } finally { + latestReset.set(reset.next); + } + } + + public static Result shift + (final FunctionReceiver receiver) + throws Exception + { + return (Result) callWithCurrentContinuation(new CallbackReceiver() { + public Object receive(final Callback continuation) { + final Reset reset = latestReset.get(); + final Callback resetContinuation = reset.continuation; + reset.continuation = new Callback() { + public void handleResult(Object ignored) { + try { + resetContinuation.handleResult + (receiver.receive + (new Function() { + public Object call(final Object argument) + throws Exception { + Object result = callWithCurrentContinuation + (new CallbackReceiver() { + public Object receive + (Callback shiftContinuation) + throws Exception + { + reset.continuation = shiftContinuation; + continuation.handleResult(argument); + throw new AssertionError(); + } + }); + + reset.continuation = null; + return result; + } + })); + } catch (Exception e) { + resetContinuation.handleException(e); + } + } + + public void handleException(Throwable exception) { + throw new AssertionError(); + } + }; + + resetContinuation.handleResult(null); + throw new AssertionError(); + } + }); + } + private static native UnwindResult dynamicWind2(Runnable before, Callable thunk, Runnable after) @@ -235,4 +307,13 @@ public class Continuations { this.exception = exception; } } + + private static class Reset { + public Callback continuation; + public final Reset next; + + public Reset(Reset next) { + this.next = next; + } + } } diff --git a/classpath/avian/Function.java b/classpath/avian/Function.java new file mode 100644 index 0000000000..61e77fdcc5 --- /dev/null +++ b/classpath/avian/Function.java @@ -0,0 +1,15 @@ +/* Copyright (c) 2008-2013, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +package avian; + +public interface Function { + public Result call(Argument argument) throws Exception; +} diff --git a/classpath/avian/FunctionReceiver.java b/classpath/avian/FunctionReceiver.java new file mode 100644 index 0000000000..d58c36e7a4 --- /dev/null +++ b/classpath/avian/FunctionReceiver.java @@ -0,0 +1,15 @@ +/* Copyright (c) 2008-2013, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +package avian; + +public interface FunctionReceiver { + public Result receive(Function function) throws Exception; +} diff --git a/makefile b/makefile index fce13ac081..66f6baab72 100755 --- a/makefile +++ b/makefile @@ -1397,6 +1397,7 @@ unittest-depends = \ ifeq ($(continuations),true) continuation-tests = \ + extra.ComposableContinuations \ extra.Continuations \ extra.Coroutines \ extra.DynamicWind diff --git a/test/extra/ComposableContinuations.java b/test/extra/ComposableContinuations.java new file mode 100644 index 0000000000..ad964bcfdf --- /dev/null +++ b/test/extra/ComposableContinuations.java @@ -0,0 +1,43 @@ +package extra; + +import static avian.Continuations.shift; +import static avian.Continuations.reset; + +import avian.FunctionReceiver; +import avian.Function; + +import java.util.concurrent.Callable; + +public class ComposableContinuations { + private static void expect(boolean v) { + if (! v) throw new RuntimeException(); + } + + public static void main(String[] args) throws Exception { + expect(2 * reset(new Callable() { + public Integer call() throws Exception { + return 1 + shift(new FunctionReceiver() { + public Integer receive + (Function continuation) + throws Exception + { + return continuation.call(5); + } + }); + } + }) == 12); + + expect(1 + reset(new Callable() { + public Integer call() throws Exception { + return 2 * shift(new FunctionReceiver() { + public Integer receive + (Function continuation) + throws Exception + { + return continuation.call(continuation.call(4)); + } + }); + } + }) == 17); + } +}