diff options
author | Adriaan Moors <adriaan.moors@typesafe.com> | 2013-12-02 17:10:35 -0800 |
---|---|---|
committer | Adriaan Moors <adriaan.moors@typesafe.com> | 2013-12-13 17:36:16 -0800 |
commit | 858a5d513779f4af6f12c0a530bdeceb7a7fd4d9 (patch) | |
tree | becda6df1363a92c1fcdf39643433ba101de4c10 /src/continuations/library | |
parent | 7e74aa6b134bcaf158bd51aa7a63a4aaa8fee62e (diff) | |
download | scala-858a5d513779f4af6f12c0a530bdeceb7a7fd4d9.tar.gz scala-858a5d513779f4af6f12c0a530bdeceb7a7fd4d9.tar.bz2 scala-858a5d513779f4af6f12c0a530bdeceb7a7fd4d9.zip |
Modularize continuations plugin.
The continuations plugin and library will still ship with 2.11 (albeit unsupported).
They now reside at https://github.com/scala/scala-continuations.
Diffstat (limited to 'src/continuations/library')
-rw-r--r-- | src/continuations/library/scala/util/continuations/ControlContext.scala | 249 | ||||
-rw-r--r-- | src/continuations/library/scala/util/continuations/package.scala | 187 |
2 files changed, 0 insertions, 436 deletions
diff --git a/src/continuations/library/scala/util/continuations/ControlContext.scala b/src/continuations/library/scala/util/continuations/ControlContext.scala deleted file mode 100644 index c196809da9..0000000000 --- a/src/continuations/library/scala/util/continuations/ControlContext.scala +++ /dev/null @@ -1,249 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2010-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - -package scala.util.continuations - -import scala.annotation.{ Annotation, StaticAnnotation, TypeConstraint } - -/** This annotation is used to mark a parameter as part of a continuation - * context. - * - * The type `A @cpsParam[B,C]` is desugared to `ControlContext[A,B,C]` at compile - * time. - * - * @tparam B The type of computation state after computation has executed, and - * before control is returned to the shift. - * @tparam C The eventual return type of this delimited compuation. - * @see scala.util.continuations.ControlContext - */ -class cpsParam[-B,+C] extends StaticAnnotation with TypeConstraint - -private class cpsSym[B] extends Annotation // implementation detail - -private class cpsSynth extends Annotation // implementation detail - -private class cpsPlus extends StaticAnnotation with TypeConstraint // implementation detail -private class cpsMinus extends Annotation // implementation detail - - -/** - * This class represent a portion of computation that has a 'hole' in it. The - * class has the ability to compute state up until a certain point where the - * state has the `A` type. If this context is given a function of type - * `A => B` to move the state to the `B` type, then the entire computation can - * be completed resulting in a value of type `C`. - * - * An Example: {{{ - * val cc = new ControlContext[String, String, String]( - * fun = { (f: String=>String, err: Exception => String) => - * val updatedState = - * try f("State") - * catch { - * case e: Exception => err(e) - * } - * updatedState + "-Complete!" - * }, - * x = null.asIntanceOf[String] - * } - * cc.foreach(_ + "-Continued") // Results in "State-Continued-Complete!" - * }}} - * - * This class is used to transform calls to `shift` in the `continuations` - * package. Direct use and instantiation is possible, but usually reserved - * for advanced cases. - * - * - * A context may either be ''trivial'' or ''non-trivial''. A ''trivial'' - * context '''just''' has a state of type `A`. When completing the computation, - * it's only necessary to use the function of type `A => B` directly against - * the trivial value. A ''non-trivial'' value stores a computation '''around''' - * the state transformation of type `A => B` and cannot be short-circuited. - * - * @param fun The captured computation so far. The type - * `(A => B, Exception => B) => C` is a function where: - * - The first parameter `A=>B` represents the computation defined against - * the current state held in the ControlContext. - * - The second parameter `Exception => B` represents a computation to - * perform if an exception is thrown from the first parameter's computation. - * - The return value is the result of the entire computation contained in this - * `ControlContext`. - * @param x The current state stored in this context. Allowed to be null if - * the context is non-trivial. - * @tparam A The type of the state currently held in the context. - * @tparam B The type of the transformed state needed to complete this computation. - * @tparam C The return type of the entire computation stored in this context. - * @note `fun` and `x` are allowed to be `null`. - * @see scala.util.continutations.shiftR - */ -final class ControlContext[+A,-B,+C](val fun: (A => B, Exception => B) => C, val x: A) extends Serializable { - - /* - final def map[A1](f: A => A1): ControlContext[A1,B,C] = { - new ControlContext((k:(A1 => B)) => fun((x:A) => k(f(x))), null.asInstanceOf[A1]) - } - - final def flatMap[A1,B1<:B](f: (A => ControlContext[A1,B1,B])): ControlContext[A1,B1,C] = { - new ControlContext((k:(A1 => B1)) => fun((x:A) => f(x).fun(k))) - } - */ - - /** - * Modifies the currently captured state in this `ControlContext`. - * @tparam A1 The new type of state in this context. - * @param f A transformation function on the current state of the `ControlContext`. - * @return The new `ControlContext`. - */ - @noinline final def map[A1](f: A => A1): ControlContext[A1,B,C] = { - if (fun eq null) - try { - new ControlContext[A1,B,C](null, f(x)) // TODO: only alloc if f(x) != x - } catch { - case ex: Exception => - new ControlContext((k: A1 => B, thr: Exception => B) => thr(ex).asInstanceOf[C], null.asInstanceOf[A1]) - } - else - new ControlContext({ (k: A1 => B, thr: Exception => B) => - fun( { (x:A) => - var done = false - try { - val res = f(x) - done = true - k(res) - } catch { - case ex: Exception if !done => - thr(ex) - } - }, thr) - }, null.asInstanceOf[A1]) - } - - - // it would be nice if @inline would turn the trivial path into a tail call. - // unfortunately it doesn't, so we do it ourselves in SelectiveCPSTransform - - /** - * Maps and flattens this `ControlContext` with another `ControlContext` generated from the current state. - * @note The resulting comuptation is still the type `C`. - * @tparam A1 The new type of the contained state. - * @tparam B1 The new type of the state after the stored continuation has executed. - * @tparam C1 The result type of the nested `ControlContext`. Because the nested `ControlContext` is executed within - * the outer `ControlContext`, this type must `>: B` so that the resulting nested computation can be fed through - * the current continuation. - * @param f A transformation function from the current state to a nested `ControlContext`. - * @return The transformed `ControlContext`. - */ - @noinline final def flatMap[A1,B1,C1<:B](f: (A => ControlContext[A1,B1,C1])): ControlContext[A1,B1,C] = { - if (fun eq null) - try { - f(x).asInstanceOf[ControlContext[A1,B1,C]] - } catch { - case ex: Exception => - new ControlContext((k: A1 => B1, thr: Exception => B1) => thr(ex).asInstanceOf[C], null.asInstanceOf[A1]) - } - else - new ControlContext({ (k: A1 => B1, thr: Exception => B1) => - fun( { (x:A) => - var done = false - try { - val ctxR = f(x) - done = true - val res: C1 = ctxR.foreachFull(k, thr) // => B1 - res - } catch { - case ex: Exception if !done => - thr(ex).asInstanceOf[B] // => B NOTE: in general this is unsafe! - } // However, the plugin will not generate offending code - }, thr.asInstanceOf[Exception=>B]) // => B - }, null.asInstanceOf[A1]) - } - - /** - * Runs the computation against the state stored in this `ControlContext`. - * @param f the computation that modifies the current state of the context. - * @note This method could throw exceptions from the computations. - */ - final def foreach(f: A => B) = foreachFull(f, throw _) - - def foreachFull(f: A => B, g: Exception => B): C = { - if (fun eq null) - f(x).asInstanceOf[C] - else - fun(f, g) - } - - /** @return true if this context only stores a state value and not any deferred computation. */ - final def isTrivial = fun eq null - /** @return The current state value. */ - final def getTrivialValue = x.asInstanceOf[A] - - // need filter or other functions? - - final def flatMapCatch[A1>:A,B1<:B,C1>:C<:B1](pf: PartialFunction[Exception, ControlContext[A1,B1,C1]]): ControlContext[A1,B1,C1] = { // called by codegen from SelectiveCPSTransform - if (fun eq null) - this - else { - val fun1 = (ret1: A1 => B1, thr1: Exception => B1) => { - val thr: Exception => B1 = { t: Exception => - var captureExceptions = true - try { - if (pf.isDefinedAt(t)) { - val cc1 = pf(t) - captureExceptions = false - cc1.foreachFull(ret1, thr1) // Throw => B - } else { - captureExceptions = false - thr1(t) // Throw => B1 - } - } catch { - case t1: Exception if captureExceptions => thr1(t1) // => E2 - } - } - fun(ret1, thr)// fun(ret1, thr) // => B - } - new ControlContext(fun1, null.asInstanceOf[A1]) - } - } - - final def mapFinally(f: () => Unit): ControlContext[A,B,C] = { // called in code generated by SelectiveCPSTransform - if (fun eq null) { - try { - f() - this - } catch { - case ex: Exception => - new ControlContext((k: A => B, thr: Exception => B) => thr(ex).asInstanceOf[C], null.asInstanceOf[A]) - } - } else { - val fun1 = (ret1: A => B, thr1: Exception => B) => { - val ret: A => B = { x: A => - var captureExceptions = true - try { - f() - captureExceptions = false - ret1(x) - } catch { - case t1: Exception if captureExceptions => thr1(t1) - } - } - val thr: Exception => B = { t: Exception => - var captureExceptions = true - try { - f() - captureExceptions = false - thr1(t) - } catch { - case t1: Exception if captureExceptions => thr1(t1) - } - } - fun(ret, thr1) - } - new ControlContext(fun1, null.asInstanceOf[A]) - } - } - -} diff --git a/src/continuations/library/scala/util/continuations/package.scala b/src/continuations/library/scala/util/continuations/package.scala deleted file mode 100644 index 573fae85e7..0000000000 --- a/src/continuations/library/scala/util/continuations/package.scala +++ /dev/null @@ -1,187 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2010-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - -package scala.util - -/* TODO: better documentation of return-type modification. - * (Especially what means "Illegal answer type modification: ... andThen ...") - */ - -/** - * Delimited continuations are a feature for modifying the usual control flow - * of a program. To use continuations, provide the option `-P:continuations:enable` - * to the Scala compiler or REPL to activate the compiler plugin. - * - * Below is an example of using continuations to suspend execution while awaiting - * user input. Similar facilities are used in so-called continuation-based web frameworks. - * - * {{{ - * def go = - * reset { - * println("Welcome!") - * val first = ask("Please give me a number") - * val second = ask("Please enter another number") - * printf("The sum of your numbers is: %d\n", first + second) - * } - * }}} - * - * The `reset` is provided by this package and delimits the extent of the - * transformation. The `ask` is a function that will be defined below. Its - * effect is to issue a prompt and then suspend execution awaiting user input. - * Once the user provides an input value, execution of the suspended block - * resumes. - * - * {{{ - * val sessions = new HashMap[UUID, Int=>Unit] - * def ask(prompt: String): Int @cps[Unit] = - * shift { - * k: (Int => Unit) => { - * val id = uuidGen - * printf("%s\nrespond with: submit(0x%x, ...)\n", prompt, id) - * sessions += id -> k - * } - * } - * }}} - * - * The type of `ask` includes a `@cps` annotation which drives the transformation. - * The type signature `Int @cps[Unit]` means that `ask` should be used in a - * context requiring an `Int`, but actually it will suspend and return `Unit`. - * - * The computation leading up to the first `ask` is executed normally. The - * remainder of the reset block is wrapped into a closure that is passed as - * the parameter `k` to the `shift` function, which can then decide whether - * and how to execute the continuation. In this example, the continuation is - * stored in a sessions map for later execution. This continuation includes a - * second call to `ask`, which is treated likewise once the execution resumes. - * - * <h2>CPS Annotation</h2> - * - * The aforementioned `@cps[A]` annotation is an alias for the more general - * `@cpsParam[B,C]` where `B=C`. The type `A @cpsParam[B,C]` describes a term - * which yields a value of type `A` within an evaluation context producing a - * value of type `B`. After the CPS transformation, this return type is - * modified to `C`. - * - * The `@cpsParam` annotations are introduced by `shift` blocks, and propagate - * via the return types to the dynamically enclosing context. The propagation - * stops upon reaching a `reset` block. - */ - -package object continuations { - - /** An annotation that denotes a type is part of a continuation context. - * `@cps[A]` is shorthand for `cpsParam[A,A]`. - * @tparam A The return type of the continuation context. - */ - type cps[A] = cpsParam[A,A] - - /** An annotation that denotes a type is part of a side effecting continuation context. - * `@suspendable` is shorthand notation for `@cpsParam[Unit,Unit]` or `@cps[Unit]`. - */ - type suspendable = cps[Unit] - - /** - * The `shift` function captures the remaining computation in a `reset` block - * and passes it to a closure provided by the user. - * - * For example: - * {{{ - * reset { - * shift { (k: Int => Int) => k(5) } + 1 - * } - * }}} - * - * In this example, `shift` is used in the expression `shift ... + 1`. - * The compiler will alter this expression so that the call - * to `shift` becomes a parameter to a function, creating something like: - * {{{ - * { (k: Int => Int) => k(5) } apply { _ + 1 } - * }}} - * The result of this expression is 6. - * - * There can be more than one `shift` call in a `reset` block. Each call - * to `shift` can alter the return type of expression within the reset block, - * but will not change the return type of the entire `reset { block }` - * expression. - * - * @param fun A function where - * - The parameter is the remainder of computation within the current - * `reset` block. This is passed as a function `A => B`. - * - The return is the return value of the `ControlContext` which is - * generated from this inversion. - * @note Must be invoked in the context of a call to `reset` This context - * may not be far up the stack, but a call to reset is needed to - * eventually remove the `@cps` annotations from types. - */ - def shift[A,B,C](fun: (A => B) => C): A @cpsParam[B,C] = { - throw new NoSuchMethodException("this code has to be compiled with the Scala continuations plugin enabled") - } - /** Creates a context for continuations captured within the argument closure - * of this `reset` call and returns the result of the entire transformed - * computation. Within an expression of the form `reset { block }`, - * the closure expression (`block`) will be modified such that at each - * call to `shift` the remainder of the expression is transformed into a - * function to be passed into the shift. - * @return The result of a block of code that uses `shift` to capture continuations. - */ - def reset[A,C](ctx: =>(A @cpsParam[A,C])): C = { - val ctxR = reify[A,A,C](ctx) - if (ctxR.isTrivial) - ctxR.getTrivialValue.asInstanceOf[C] - else - ctxR.foreach((x:A) => x) - } - - def reset0[A](ctx: =>(A @cpsParam[A,A])): A = reset(ctx) - - def run[A](ctx: =>(Any @cpsParam[Unit,A])): A = { - val ctxR = reify[Any,Unit,A](ctx) - if (ctxR.isTrivial) - ctxR.getTrivialValue.asInstanceOf[A] - else - ctxR.foreach((x:Any) => ()) - } - - - // methods below are primarily implementation details and are not - // needed frequently in client code - - def shiftUnit0[A,B](x: A): A @cpsParam[B,B] = { - shiftUnit[A,B,B](x) - } - - def shiftUnit[A,B,C>:B](x: A): A @cpsParam[B,C] = { - throw new NoSuchMethodException("this code has to be compiled with the Scala continuations plugin enabled") - } - - /** This method converts from the sugared `A @cpsParam[B,C]` type to the desugared - * `ControlContext[A,B,C]` type. The underlying data is not changed. - */ - def reify[A,B,C](ctx: =>(A @cpsParam[B,C])): ControlContext[A,B,C] = { - throw new NoSuchMethodException("this code has to be compiled with the Scala continuations plugin enabled") - } - - def shiftUnitR[A,B](x: A): ControlContext[A,B,B] = { // called in code generated by SelectiveCPSTransform - new ControlContext[A, B, B](null, x) - } - - /** - * Captures a computation into a `ControlContext`. - * @param fun The function which accepts the inverted computation and returns - * a final result. - * @see shift - */ - def shiftR[A,B,C](fun: (A => B) => C): ControlContext[A,B,C] = { // called in code generated by SelectiveCPSTransform - new ControlContext((f:A=>B,g:Exception=>B) => fun(f), null.asInstanceOf[A]) - } - - def reifyR[A,B,C](ctx: => ControlContext[A,B,C]): ControlContext[A,B,C] = { // called in code generated by SelectiveCPSTransform - ctx - } - -} |