+/*----- Control structures ------------------------------------------------*/
+
+private case class ExitBlock[T](brand: Brand, result: T)
+ extends ControlThrowable;
+
+def block[T](body: (T => Nothing) => T): T = {
+ /* block { exit[T] => ...; exit(x); ... }
+ *
+ * Execute the body until it calls the `exit' function or finishes.
+ * Annoyingly, Scala isn't clever enough to infer the return type, so
+ * you'll have to write it explicitly.
+ */
+
+ val mybrand = new Brand;
+ try { body { result => throw new ExitBlock(mybrand, result) } }
+ catch {
+ case ExitBlock(brand, result) if brand eq mybrand =>
+ result.asInstanceOf[T]
+ }
+}
+
+def blockUnit(body: (=> Nothing) => Unit) {
+ /* blockUnit { exit => ...; exit; ... }
+ *
+ * Like `block'; it just saves you having to write `exit[Unit] => ...;
+ * exit(ok); ...'.
+ */
+
+ val mybrand = new Brand;
+ try { body { throw new ExitBlock(mybrand, null) }; }
+ catch { case ExitBlock(brand, result) if brand eq mybrand => ok; }
+}
+
+def loop[T](body: (T => Nothing) => Unit): T = {
+ /* loop { exit[T] => ...; exit(x); ... }
+ *
+ * Repeatedly execute the body until it calls the `exit' function.
+ * Annoyingly, Scala isn't clever enough to infer the return type, so
+ * you'll have to write it explicitly.
+ */
+
+ block { exit => while (true) body(exit); unreachable }
+}
+
+def loopUnit(body: (=> Nothing) => Unit): Unit = {
+ /* loopUnit { exit => ...; exit; ... }
+ *
+ * Like `loop'; it just saves you having to write `exit[Unit] => ...;
+ * exit(()); ...'.
+ */
+
+ blockUnit { exit => while (true) body(exit); }
+}
+
+val BREAKS = new Breaks;
+import BREAKS.{breakable, break};
+
+/*----- Interruptably doing things ----------------------------------------*/
+
+private class InterruptCatcher[T](body: => T, onWakeup: => Unit)
+ extends AbstractSelector(null) {
+ /* Hook onto the VM's thread interruption machinery.
+ *
+ * The `run' method is the only really interesting one. It will run the
+ * BODY, returning its result; if the thread is interrupted during this
+ * time, ONWAKEUP is invoked for effect. The expectation is that ONWAKEUP
+ * will somehow cause BODY to stop early.
+ *
+ * Credit for this hack goes to Nicholas Wilson: see
+ * <https://github.com/NWilson/javaInterruptHook>.
+ */
+
+ private def nope: Nothing =
+ { throw new UnsupportedOperationException("can't do that"); }
+ protected def implCloseSelector() { }
+ protected def register(chan: AbstractSelectableChannel,
+ ops: Int, att: Any): SelectionKey = nope;
+ def keys(): JSet[SelectionKey] = nope;
+ def selectedKeys(): JSet[SelectionKey] = nope;
+ def select(): Int = nope;
+ def select(millis: Long): Int = nope;
+ def selectNow(): Int = nope;
+
+ def run(): T = try {
+ begin();
+ val ret = body;
+ if (Thread.interrupted()) throw new InterruptedException;
+ ret
+ } finally {
+ end();
+ }
+ def wakeup(): Selector = { onWakeup; this }
+}
+
+class PendingInterruptable[T] private[tripe](body: => T) {
+ /* This class exists to provide the `onInterrupt THUNK' syntax. */
+
+ def onInterrupt(thunk: => Unit): T =
+ new InterruptCatcher(body, thunk).run();
+}
+def interruptably[T](body: => T) = {
+ /* interruptably { BODY } onInterrupt { THUNK }
+ *
+ * Execute BODY and return its result. If the thread receives an
+ * interrupt -- or is already in an interrupted state -- execute THUNK for
+ * effect; it is expected to cause BODY to return expeditiously, and when
+ * the BODY completes, an `InterruptedException' is thrown.
+ */
+
+ new PendingInterruptable(body);
+}
+