diff --git a/Dsl/.js/build.sbt b/Dsl/.js/build.sbt
deleted file mode 120000
index 0569694f..00000000
--- a/Dsl/.js/build.sbt
+++ /dev/null
@@ -1 +0,0 @@
-../build.sbt
\ No newline at end of file
diff --git a/Dsl/.jvm/build.sbt b/Dsl/.jvm/build.sbt
deleted file mode 120000
index 0569694f..00000000
--- a/Dsl/.jvm/build.sbt
+++ /dev/null
@@ -1 +0,0 @@
-../build.sbt
\ No newline at end of file
diff --git a/Dsl/build.sbt b/Dsl/build.sbt
deleted file mode 100644
index e2a23844..00000000
--- a/Dsl/build.sbt
+++ /dev/null
@@ -1,32 +0,0 @@
-scalacOptions ++= {
- scalaBinaryVersion.value match {
- case "2.11" =>
- Some("-Xexperimental")
- case _ =>
- None
- }
-}
-
-
-scalacOptions ++= {
- import Ordering.Implicits._
- if (VersionNumber(scalaVersion.value).numbers >= Seq(2L, 13L)) {
- Seq("-Ymacro-annotations")
- } else {
- Nil
- }
-}
-
-libraryDependencies ++= {
- import Ordering.Implicits._
- if (VersionNumber(scalaVersion.value).numbers >= Seq(2L, 13L)) {
- Nil
- } else {
- Seq(compilerPlugin("org.scalamacros" % "paradise" % "2.1.1" cross CrossVersion.full))
- }
-}
-
-libraryDependencies += "com.thoughtworks.enableIf" %% "enableif" % "1.1.6"
-
-// Improve backward compatibility for Scala 2.11
-scalacOptions += "-Ydelambdafy:method"
diff --git a/Dsl/src/main/scala/com/thoughtworks/dsl/Dsl.scala b/Dsl/src/main/scala/com/thoughtworks/dsl/Dsl.scala
deleted file mode 100644
index 39ed2c1c..00000000
--- a/Dsl/src/main/scala/com/thoughtworks/dsl/Dsl.scala
+++ /dev/null
@@ -1,265 +0,0 @@
-package com.thoughtworks.dsl
-
-import com.thoughtworks.dsl.Dsl.!!
-import com.thoughtworks.enableMembersIf
-
-import scala.annotation._
-import scala.collection._
-import scala.collection.mutable.Builder
-import scala.concurrent.Future
-import scala.language.higherKinds
-import scala.util.{Failure, Success, Try}
-import scala.util.control.{NonFatal, TailCalls}
-import scala.util.control.TailCalls.TailRec
-
-/** The domain-specific interpreter for `Keyword` in `Domain`,
- * which is a dependent type type class that registers an asynchronous callback function,
- * to handle the `Value` inside `Keyword`.
- *
- * @tparam Value The value held inside `Keyword`.
- * @author 杨博 (Yang Bo)
- * @example Creating a collaborative DSL in [[https://github.com/ThoughtWorksInc/Dsl.scala Dsl.scala]] is easy.
- * Only two steps are required:
- *
- * - Defining their domain-specific [[com.thoughtworks.dsl.Dsl.Keyword Keyword]].
- * - Implementing this [[Dsl]] type class, which is an interpreter for an [[com.thoughtworks.dsl.Dsl.Keyword Keyword]].
- *
- */
-@implicitNotFound("The keyword ${Keyword} is not supported inside a function that returns ${Domain}.")
-trait Dsl[-Keyword, Domain, +Value] {
-
- /** Registers an asynchronous callback `handler` on `keyword`, to handle the `Value`. */
- def cpsApply(keyword: Keyword, handler: Value => Domain): Domain
-
-}
-
-private[dsl] trait LowPriorityDsl2 {
-
- import Dsl._
- import Scala211Or212._
- import Scala213._
-
- implicit def nothingCollectionDsl[Keyword, Element, Collection[_]](
- implicit factory: Factory[Element, Collection[Element]],
- restDsl: Dsl[Keyword, Element, Nothing]
- ): Dsl[Keyword, Collection[Element], Nothing] = { (keyword, handler) =>
- singleton(resetDomain(keyword))
- }
-}
-
-private[dsl] trait LowPriorityDsl1 extends LowPriorityDsl2 {
-
- implicit def derivedFunction1Dsl[Keyword, State, Domain, Value](
- implicit restDsl: Dsl[Keyword, Domain, Value]
- ): Dsl[Keyword, State => Domain, Value] = { (keyword, handler) =>
- val restDsl1 = restDsl
- locally { state: State =>
- val handler1 = handler
- restDsl1.cpsApply(keyword, handler1(_)(state))
- }
-
- }
-
-}
-
-private[dsl] trait LowPriorityDsl0 extends LowPriorityDsl1 {
-
-// // FIXME: Shift
-// implicit def continuationDsl[Keyword, LeftDomain, RightDomain, Value](
-// implicit restDsl: Dsl[Keyword, LeftDomain, Value],
-// shiftDsl2: Dsl[Shift[LeftDomain, RightDomain], LeftDomain, RightDomain]
-// ): Dsl[Keyword, LeftDomain !! RightDomain, Value] = {
-// new Dsl[Keyword, LeftDomain !! RightDomain, Value] {
-// def cpsApply(keyword: Keyword, handler: Value => LeftDomain !! RightDomain): LeftDomain !! RightDomain = {
-// (continue: RightDomain => LeftDomain) =>
-// restDsl.cpsApply(keyword, { a =>
-// restDsl2.cpsApply(handler(a), continue)
-// })
-// }
-// }
-// }
-
- implicit def throwableContinuationDsl[Keyword, LeftDomain, Value](
- implicit restDsl: Dsl[Keyword, LeftDomain, Value]
- ): Dsl[Keyword, LeftDomain !! Throwable, Value] = { (keyword, handler) => continue =>
- restDsl.cpsApply(
- keyword,
- new (Value => LeftDomain) {
- def apply(value: Value): LeftDomain = {
- val protectedContinuation = try {
- handler(value)
- } catch {
- case NonFatal(e) =>
- return continue(e)
- }
- // FIXME: Shift[Domain, Throwable]
- protectedContinuation(continue)
- }
- }
- )
- }
-
-}
-
-object Dsl extends LowPriorityDsl0 {
-
- @enableMembersIf(scala.util.Properties.versionNumberString.matches("""^2\.1(1|2)\..*$"""))
- private[dsl] object Scala211Or212 {
- type Factory[-A, +C] = scala.collection.generic.CanBuildFrom[Nothing, A, C]
-
- @inline
- def singleton[A, C](a: A)(implicit factory: Factory[A, C]): C = {
- val builder = factory()
- builder.sizeHint(1)
- builder += a
- builder.result()
- }
-
- }
-
- @enableMembersIf(scala.util.Properties.versionNumberString.matches("""^2\.13\..*$"""))
- private[dsl] object Scala213 {
-
- @inline
- def singleton[A, C](a: A)(implicit factory: Factory[A, C]): C = {
- factory.fromSpecific(a :: Nil)
- }
-
- }
-
- @inline
- private[dsl] def resetDomain[Keyword, Domain](keyword: Keyword)(
- implicit dsl: Dsl[Keyword, Domain, Domain]): Domain = {
- dsl.cpsApply(keyword, implicitly)
- }
-
- implicit def nothingContinuationDsl[Keyword, LeftDomain, RightDomain](
- implicit restDsl: Dsl[Keyword, RightDomain, Nothing]): Dsl[Keyword, LeftDomain !! RightDomain, Nothing] = {
- (keyword, handler) =>
- _(resetDomain(keyword))
- }
-
- implicit def nothingFutureDsl[Keyword, Domain](
- implicit restDsl: Dsl[Keyword, Domain, Nothing]): Dsl[Keyword, Future[Domain], Nothing] = { (keyword, handler) =>
- Future.successful(resetDomain(keyword))
- }
-
- implicit def derivedTailRecDsl[Keyword, Domain, Value](
- implicit restDsl: Dsl[Keyword, Domain, Value]): Dsl[Keyword, TailRec[Domain], Value] = { (keyword, handler) =>
- TailCalls.done {
- restDsl.cpsApply(keyword, { value =>
- handler(value).result
- })
- }
- }
-
- implicit def derivedThrowableTailRecDsl[Keyword, LeftDomain, Value](
- implicit restDsl: Dsl[Keyword, LeftDomain !! Throwable, Value])
- : Dsl[Keyword, TailRec[LeftDomain] !! Throwable, Value] = { (keyword, handler) => tailRecFailureHandler =>
- TailCalls.done(restDsl.cpsApply(keyword, { value => failureHandler =>
- handler(value) { e =>
- TailCalls.done(failureHandler(e))
- }.result
- }) { e =>
- tailRecFailureHandler(e).result
- })
- }
-
- type Continuation[R, +A] = (A => R @reset) => R
-
- object Continuation {
- @inline
- def now[R, A](a: A): R !! A = _(a)
-
- @inline
- def empty[R, A](r: R): R !! A = Function.const(r)
-
- @inline
- def delay[R, A](a: () => A): R !! A = _(a())
-
- @inline
- def apply[R, A](a: => A): (R !! A) @reset = delay(a _)
-
- def toTryContinuation[LeftDomain, Value](task: LeftDomain !! Throwable !! Value)(
- handler: Try[Value] => LeftDomain): LeftDomain = {
- task { a => failureHandler =>
- handler(Success(a))
- } { e =>
- handler(Failure(e))
- }
- }
-
- def fromTryContinuation[LeftDomain, Value](continuation: LeftDomain !! Try[Value])(
- successHandler: Value => LeftDomain !! Throwable)(failureHandler: Throwable => LeftDomain): LeftDomain = {
- continuation(
- new (Try[Value] => LeftDomain) {
- def apply(result: Try[Value]): LeftDomain = {
- result match {
- case Success(a) =>
- val protectedContinuation = try {
- successHandler(a)
- } catch {
- case NonFatal(e) =>
- return failureHandler(e)
- }
- protectedContinuation(failureHandler)
- case Failure(e) =>
- failureHandler(e)
- }
- }
- }
- )
- }
-
- }
-
- type !![R, +A] = Continuation[R, A]
- val !! = Continuation
-
- private[dsl] /* sealed */ trait ResetAnnotation extends Annotation with StaticAnnotation
- private[dsl] final class nonTypeConstraintReset extends ResetAnnotation with StaticAnnotation
-
- /** An annotation to explicitly perform reset control operator on a code block.
- *
- * @note This annotation can be automatically added
- * if [[compilerplugins.ResetEverywhere ResetEverywhere]] compiler plug-in is enabled.
- */
- final class reset extends ResetAnnotation with StaticAnnotation with TypeConstraint
-
- /** An annotation to mark a method is a shift control operator. */
- final class shift extends StaticAnnotation
-
- def apply[Keyword, Domain, Value](implicit typeClass: Dsl[Keyword, Domain, Value]): Dsl[Keyword, Domain, Value] =
- typeClass
-
- /**
- *
- * @tparam Self the self type
- * @see [[https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern Curiously recurring template pattern]]
- * for the reason why we need the `Self` type parameter
- */
- trait Keyword[Self, Value] extends Any { this: Self =>
-
- @shift
- @compileTimeOnly(
- """This method requires the compiler plugin: `addCompilerPlugin("com.thoughtworks.dsl" %% "compilerplugins-bangnotation" % "latest.release")` and must only be called inside a code block annotated as `@reset`.""")
- final def unary_! : Value = {
- throw new IllegalAccessException(
- """This method requires the compiler plugin: `addCompilerPlugin("com.thoughtworks.dsl" %% "compilerplugins-bangnotation" % "latest.release")` and must only be called inside a code block annotated as `@reset`."""
- )
- }
-
- @inline
- final def cpsApply[Domain](handler: Value => Domain)(implicit dsl: Dsl[Self, Domain, Value]): Domain = {
- dsl.cpsApply(this, handler)
- }
-
- /** An alias to [[cpsApply]]. */
- @inline
- final def apply[Domain](handler: Value => Domain)(implicit dsl: Dsl[Self, Domain, Value]): Domain = {
- cpsApply(handler)
- }
-
- }
-
-}
diff --git a/build.sbt b/build.sbt
index 595f4864..29d77d9b 100644
--- a/build.sbt
+++ b/build.sbt
@@ -1,333 +1,13 @@
// shadow sbt-scalajs' crossProject(JSPlatform, JVMPlatform) and CrossType from Scala.js 0.6.x
import sbtcrossproject.CrossPlugin.autoImport.{crossProject, CrossType}
-lazy val `compilerplugins-BangNotation` = project
- .dependsOn(DslJVM % Test, DslJVM % Provided)
- .settings(
- scalacOptions in Test += raw"""-Xplugin:${(packageBin in Compile).value}""",
- scalacOptions in Test += raw"""-Xplugin:${(packageBin in `compilerplugins-ResetEverywhere` in Compile).value}"""
- )
-
-lazy val `compilerplugins-ResetEverywhere` = project.dependsOn(DslJVM % Test, DslJVM % Provided)
-
-lazy val Dsl =
- crossProject(JSPlatform, JVMPlatform).crossType(CrossType.Pure).build()
-lazy val DslJS = Dsl.js
-lazy val DslJVM = Dsl.jvm
-
-lazy val `domains-task` =
- crossProject(JSPlatform, JVMPlatform)
- .crossType(CrossType.Pure)
- .settings(
- scalacOptions += raw"""-Xplugin:${(packageBin in `compilerplugins-BangNotation` in Compile).value}""",
- scalacOptions += raw"""-Xplugin:${(packageBin in `compilerplugins-ResetEverywhere` in Compile).value}"""
- )
- .dependsOn(`keywords-Shift`,
- `keywords-Each` % Test,
- `keywords-Fork` % Test,
- `keywords-Using` % Test,
- `keywords-Yield` % Test,
- `comprehension` % Test)
-lazy val `domains-taskJS` = `domains-task`.js
-lazy val `domains-taskJVM` = `domains-task`.jvm
-
-lazy val `keywords-Fork` =
- crossProject(JSPlatform, JVMPlatform)
- .crossType(CrossType.Pure)
- .settings(
- scalacOptions += raw"""-Xplugin:${(packageBin in `compilerplugins-BangNotation` in Compile).value}""",
- scalacOptions += raw"""-Xplugin:${(packageBin in `compilerplugins-ResetEverywhere` in Compile).value}"""
- )
- .dependsOn(Dsl, `keywords-Shift`, `keywords-Catch`, `keywords-Continue`, `keywords-ForEach`)
-lazy val `keywords-ForkJS` = `keywords-Fork`.js
-lazy val `keywords-ForkJVM` = `keywords-Fork`.jvm
-
-lazy val `keywords-Return` =
- crossProject(JSPlatform, JVMPlatform)
- .crossType(CrossType.Pure)
- .settings(
- scalacOptions += raw"""-Xplugin:${(packageBin in `compilerplugins-BangNotation` in Compile).value}""",
- scalacOptions += raw"""-Xplugin:${(packageBin in `compilerplugins-ResetEverywhere` in Compile).value}"""
- )
- .dependsOn(Dsl)
-
-lazy val `keywords-ReturnJS` = `keywords-Return`.js
-lazy val `keywords-ReturnJVM` = `keywords-Return`.jvm
-
-lazy val `keywords-Continue` =
- crossProject(JSPlatform, JVMPlatform)
- .crossType(CrossType.Pure)
- .settings(
- scalacOptions += raw"""-Xplugin:${(packageBin in `compilerplugins-BangNotation` in Compile).value}""",
- scalacOptions += raw"""-Xplugin:${(packageBin in `compilerplugins-ResetEverywhere` in Compile).value}"""
- )
- .dependsOn(Dsl, `keywords-Each` % Test)
-
-lazy val `keywords-ContinueJS` = `keywords-Continue`.js
-lazy val `keywords-ContinueJVM` = `keywords-Continue`.jvm
-
-lazy val `keywords-Get` =
- crossProject(JSPlatform, JVMPlatform)
- .crossType(CrossType.Pure)
- .settings(
- scalacOptions += raw"""-Xplugin:${(packageBin in `compilerplugins-BangNotation` in Compile).value}""",
- scalacOptions += raw"""-Xplugin:${(packageBin in `compilerplugins-ResetEverywhere` in Compile).value}"""
- )
- .dependsOn(Dsl)
-
-lazy val `keywords-GetJS` = `keywords-Get`.js
-lazy val `keywords-GetJVM` = `keywords-Get`.jvm
-
-lazy val `keywords-Put` =
- crossProject(JSPlatform, JVMPlatform)
- .crossType(CrossType.Pure)
- .settings(
- scalacOptions += raw"""-Xplugin:${(packageBin in `compilerplugins-BangNotation` in Compile).value}""",
- scalacOptions += raw"""-Xplugin:${(packageBin in `compilerplugins-ResetEverywhere` in Compile).value}"""
- )
- .dependsOn(Dsl, `keywords-Get` % Test, `keywords-Yield` % Test, `keywords-Return` % Test)
-lazy val `keywords-PutJS` = `keywords-Put`.js
-lazy val `keywords-PutJVM` = `keywords-Put`.jvm
-
-lazy val `keywords-AsynchronousIo` =
- crossProject(JSPlatform, JVMPlatform)
- .crossType(CrossType.Pure)
- .settings(
- scalacOptions += raw"""-Xplugin:${(packageBin in `compilerplugins-BangNotation` in Compile).value}""",
- scalacOptions += raw"""-Xplugin:${(packageBin in `compilerplugins-ResetEverywhere` in Compile).value}"""
- )
- .dependsOn(`keywords-Shift`, `keywords-Each` % Test, `keywords-Using` % Test, `comprehension` % Test, `domains-task` % Test)
-lazy val `keywords-AsynchronousIoJS` = `keywords-AsynchronousIo`.js
-lazy val `keywords-AsynchronousIoJVM` = `keywords-AsynchronousIo`.jvm
-
-lazy val `keywords-Shift` =
- crossProject(JSPlatform, JVMPlatform)
- .crossType(CrossType.Pure)
- .settings(
- scalacOptions += raw"""-Xplugin:${(packageBin in `compilerplugins-BangNotation` in Compile).value}""",
- scalacOptions += raw"""-Xplugin:${(packageBin in `compilerplugins-ResetEverywhere` in Compile).value}"""
- )
- .dependsOn(Dsl)
-lazy val `keywords-ShiftJS` = `keywords-Shift`.js
-lazy val `keywords-ShiftJVM` = `keywords-Shift`.jvm
-
-lazy val `keywords-Using` =
- crossProject(JSPlatform, JVMPlatform)
- .crossType(CrossType.Pure)
- .settings(
- scalacOptions += raw"""-Xplugin:${(packageBin in `compilerplugins-BangNotation` in Compile).value}""",
- scalacOptions += raw"""-Xplugin:${(packageBin in `compilerplugins-ResetEverywhere` in Compile).value}"""
- )
- .dependsOn(Dsl, `keywords-Shift`, `keywords-Catch`)
-lazy val `keywords-UsingJS` = `keywords-Using`.js
-lazy val `keywords-UsingJVM` = `keywords-Using`.jvm
-
-lazy val `keywords-Catch` =
- crossProject(JSPlatform, JVMPlatform)
- .crossType(CrossType.Pure)
- .settings(
- scalacOptions += raw"""-Xplugin:${(packageBin in `compilerplugins-BangNotation` in Compile).value}""",
- scalacOptions += raw"""-Xplugin:${(packageBin in `compilerplugins-ResetEverywhere` in Compile).value}"""
- )
- .dependsOn(Dsl, `keywords-Shift`, `keywords-Yield` % Test)
-lazy val `keywords-CatchJS` = `keywords-Catch`.js
-lazy val `keywords-CatchJVM` = `keywords-Catch`.jvm
-
-lazy val `keywords-Map` =
- crossProject(JSPlatform, JVMPlatform)
- .crossType(CrossType.Pure)
- .settings(
- scalacOptions += raw"""-Xplugin:${(packageBin in `compilerplugins-BangNotation` in Compile).value}""",
- scalacOptions += raw"""-Xplugin:${(packageBin in `compilerplugins-ResetEverywhere` in Compile).value}"""
- )
- .dependsOn(Dsl)
-lazy val `keywords-MapJS` = `keywords-Map`.js
-lazy val `keywords-MapJVM` = `keywords-Map`.jvm
-
-lazy val `keywords-FlatMap` =
- crossProject(JSPlatform, JVMPlatform)
- .crossType(CrossType.Pure)
- .settings(
- scalacOptions += raw"""-Xplugin:${(packageBin in `compilerplugins-BangNotation` in Compile).value}""",
- scalacOptions += raw"""-Xplugin:${(packageBin in `compilerplugins-ResetEverywhere` in Compile).value}"""
- )
- .dependsOn(Dsl)
-lazy val `keywords-FlatMapJS` = `keywords-FlatMap`.js
-lazy val `keywords-FlatMapJVM` = `keywords-FlatMap`.jvm
-
-lazy val `keywords-WithFilter` =
- crossProject(JSPlatform, JVMPlatform)
- .crossType(CrossType.Pure)
- .settings(
- scalacOptions += raw"""-Xplugin:${(packageBin in `compilerplugins-BangNotation` in Compile).value}""",
- scalacOptions += raw"""-Xplugin:${(packageBin in `compilerplugins-ResetEverywhere` in Compile).value}"""
- )
- .dependsOn(`keywords-Continue`)
-lazy val `keywords-WithFilterJS` = `keywords-WithFilter`.js
-lazy val `keywords-WithFilterJVM` = `keywords-WithFilter`.jvm
-
-lazy val `keywords-NoneSafe` =
- crossProject(JSPlatform, JVMPlatform)
- .crossType(CrossType.Pure)
- .settings(
- scalacOptions += raw"""-Xplugin:${(packageBin in `compilerplugins-BangNotation` in Compile).value}""",
- scalacOptions += raw"""-Xplugin:${(packageBin in `compilerplugins-ResetEverywhere` in Compile).value}"""
- )
- .dependsOn(Dsl, `keywords-Return`)
-lazy val `keywords-NoneSafeJS` = `keywords-NoneSafe`.js
-lazy val `keywords-NoneSafeJVM` = `keywords-NoneSafe`.jvm
-
-lazy val `keywords-NullSafe` =
- crossProject(JSPlatform, JVMPlatform)
- .crossType(CrossType.Pure)
- .settings(
- scalacOptions += raw"""-Xplugin:${(packageBin in `compilerplugins-BangNotation` in Compile).value}""",
- scalacOptions += raw"""-Xplugin:${(packageBin in `compilerplugins-ResetEverywhere` in Compile).value}"""
- )
- .dependsOn(Dsl)
-lazy val `keywords-NullSafeJS` = `keywords-NullSafe`.js
-lazy val `keywords-NullSafeJVM` = `keywords-NullSafe`.jvm
-
-lazy val `keywords-ForEach` =
- crossProject(JSPlatform, JVMPlatform)
- .crossType(CrossType.Pure)
- .settings(
- scalacOptions += raw"""-Xplugin:${(packageBin in `compilerplugins-BangNotation` in Compile).value}""",
- scalacOptions += raw"""-Xplugin:${(packageBin in `compilerplugins-ResetEverywhere` in Compile).value}"""
- )
- .dependsOn(Dsl, `keywords-Each` % Test)
-lazy val `keywords-ForEachJS` = `keywords-ForEach`.js
-lazy val `keywords-ForEachJVM` = `keywords-ForEach`.jvm
-
-lazy val `keywords-Each` =
- crossProject(JSPlatform, JVMPlatform)
- .crossType(CrossType.Pure)
- .settings(
- scalacOptions += raw"""-Xplugin:${(packageBin in `compilerplugins-BangNotation` in Compile).value}""",
- scalacOptions += raw"""-Xplugin:${(packageBin in `compilerplugins-ResetEverywhere` in Compile).value}"""
- )
- .dependsOn(Dsl, `keywords-Shift`)
-lazy val `keywords-EachJS` = `keywords-Each`.js
-lazy val `keywords-EachJVM` = `keywords-Each`.jvm
-
-lazy val `keywords-Await` =
- crossProject(JSPlatform, JVMPlatform)
- .crossType(CrossType.Pure)
- .settings(
- scalacOptions += raw"""-Xplugin:${(packageBin in `compilerplugins-BangNotation` in Compile).value}""",
- scalacOptions += raw"""-Xplugin:${(packageBin in `compilerplugins-ResetEverywhere` in Compile).value}"""
- )
- .dependsOn(Dsl,
- `domains-task` % Test,
- `keywords-Catch` % Test,
- `keywords-Get` % Test,
- `keywords-Return` % Test,
- `keywords-Yield` % Test,
- )
-lazy val `keywords-AwaitJS` = `keywords-Await`.js
-lazy val `keywords-AwaitJVM` = `keywords-Await`.jvm
-
-lazy val `keywords-Yield` =
- crossProject(JSPlatform, JVMPlatform)
- .crossType(CrossType.Pure)
- .settings(
- scalacOptions += raw"""-Xplugin:${(packageBin in `compilerplugins-BangNotation` in Compile).value}""",
- scalacOptions += raw"""-Xplugin:${(packageBin in `compilerplugins-ResetEverywhere` in Compile).value}"""
- )
- .dependsOn(Dsl, `keywords-Shift` % Test, `keywords-Each` % Test, `keywords-Continue` % Test)
-lazy val `keywords-YieldJS` = `keywords-Yield`.js
-lazy val `keywords-YieldJVM` = `keywords-Yield`.jvm
-
-lazy val `keywords-Monadic` =
- crossProject(JSPlatform, JVMPlatform)
- .crossType(CrossType.Pure)
- .dependsOn(Dsl)
-lazy val `keywords-MonadicJS` = `keywords-Monadic`.js
-lazy val `keywords-MonadicJVM` = `keywords-Monadic`.jvm
-
-lazy val `domains-scalaz` =
- crossProject(JSPlatform, JVMPlatform)
- .crossType(CrossType.Pure)
- .settings(
- scalacOptions += raw"""-Xplugin:${(packageBin in `compilerplugins-BangNotation` in Compile).value}""",
- scalacOptions += raw"""-Xplugin:${(packageBin in `compilerplugins-ResetEverywhere` in Compile).value}"""
- )
- .dependsOn(Dsl,
- `keywords-Catch`,
- `keywords-Monadic`,
- `keywords-Return`,
- `keywords-Shift` % Test,
- `keywords-Yield` % Test)
-lazy val `domains-scalazJS` = `domains-scalaz`.js
-lazy val `domains-scalazJVM` = `domains-scalaz`.jvm
-
lazy val `domains-cats` =
crossProject(JSPlatform, JVMPlatform)
.crossType(CrossType.Pure)
- .settings(
- scalacOptions += raw"""-Xplugin:${(packageBin in `compilerplugins-BangNotation` in Compile).value}""",
- scalacOptions += raw"""-Xplugin:${(packageBin in `compilerplugins-ResetEverywhere` in Compile).value}"""
- )
- .dependsOn(Dsl,
- `keywords-Catch`,
- `keywords-Monadic`,
- `keywords-Return`,
- `keywords-Shift` % Test,
- `keywords-Yield` % Test)
lazy val `domains-catsJVM` = `domains-cats`.jvm
lazy val `domains-catsJS` = `domains-cats`.js
-lazy val comprehension =
- crossProject(JSPlatform, JVMPlatform)
- .crossType(CrossType.Pure)
- .settings(
- scalacOptions += raw"""-Xplugin:${(packageBin in `compilerplugins-BangNotation` in Compile).value}""",
- scalacOptions += raw"""-Xplugin:${(packageBin in `compilerplugins-ResetEverywhere` in Compile).value}"""
- )
- .dependsOn(
- `keywords-Map`,
- `keywords-FlatMap`,
- `keywords-WithFilter`,
- `keywords-Return`,
- `keywords-Each` % Test,
- `keywords-Yield` % Test,
- `keywords-Using` % Test,
- `keywords-Continue` % Test,
- )
-lazy val comprehensionJS = comprehension.js
-lazy val comprehensionJVM = comprehension.jvm
-
-lazy val `package` = project
- .settings(
- scalacOptions += raw"""-Xplugin:${(packageBin in `compilerplugins-BangNotation` in Compile).value}""",
- scalacOptions += raw"""-Xplugin:${(packageBin in `compilerplugins-ResetEverywhere` in Compile).value}"""
- )
- .dependsOn(
- `domains-catsJVM`,
- `domains-scalazJVM`,
- `keywords-GetJVM`,
- `keywords-PutJVM`,
- `keywords-ContinueJVM`,
- `keywords-ReturnJVM`,
- `keywords-ShiftJVM`,
- `keywords-ForEachJVM`,
- `keywords-EachJVM`,
- `keywords-YieldJVM`,
- `keywords-ForkJVM`,
- `keywords-NoneSafeJVM`,
- `keywords-NullSafeJVM`,
- `keywords-AwaitJVM`,
- `keywords-AsynchronousIoJVM`,
- `keywords-UsingJVM`,
- `keywords-MapJVM`,
- `keywords-FlatMapJVM`,
- `keywords-WithFilterJVM`,
- `comprehensionJVM`,
- `domains-taskJVM`,
- DslJVM
- )
-
organization in ThisBuild := "com.thoughtworks.dsl"
scalacOptions in ThisBuild ++= {
@@ -338,52 +18,6 @@ scalacOptions in ThisBuild ++= {
}
}
-lazy val unidoc =
- project
- .enablePlugins(ScalaUnidocPlugin)
- .settings(
- publishArtifact := false,
- unidocProjectFilter in ScalaUnidoc in BaseUnidocPlugin.autoImport.unidoc := {
- import Ordering.Implicits._
- if (VersionNumber(scalaVersion.value).numbers >= Seq(2L, 13L)) {
- // Workaround for https://github.com/scala/bug/issues/11045
- (
- inDependencies(`package`) ||
- inDependencies(`compilerplugins-BangNotation`) ||
- inDependencies(`compilerplugins-ResetEverywhere`)
- ) --
- inProjects(DslJVM,
- `keywords-ContinueJVM`,
- `keywords-YieldJVM`,
- `domains-taskJVM`,
- `keywords-EachJVM`,
- `keywords-ForkJVM`)
- } else {
- inDependencies(`package`) ||
- inDependencies(`compilerplugins-BangNotation`) ||
- inDependencies(`compilerplugins-ResetEverywhere`)
- }
- },
- addCompilerPlugin("org.spire-math" %% "kind-projector" % "0.9.7"),
- scalacOptions += "-Xexperimental",
- scalacOptions ++= {
- import Ordering.Implicits._
- if (VersionNumber(scalaVersion.value).numbers >= Seq(2L, 13L)) {
- Seq("-Ymacro-annotations")
- } else {
- Nil
- }
- },
- libraryDependencies ++= {
- import Ordering.Implicits._
- if (VersionNumber(scalaVersion.value).numbers >= Seq(2L, 13L)) {
- Nil
- } else {
- Seq(compilerPlugin("org.scalamacros" % "paradise" % "2.1.1" cross CrossVersion.full))
- }
- }
- )
-
skip in publish := true
parallelExecution in Global := {
diff --git a/compilerplugins-BangNotation/build.sbt b/compilerplugins-BangNotation/build.sbt
deleted file mode 100644
index 13684a0d..00000000
--- a/compilerplugins-BangNotation/build.sbt
+++ /dev/null
@@ -1,11 +0,0 @@
-libraryDependencies += "org.scala-lang" % "scala-compiler" % scalaVersion.value % Provided
-
-scalacOptions ++= {
- if (scalaBinaryVersion.value == "2.11") {
- Seq("–Yexperimental")
- } else {
- Seq()
- }
-}
-
-libraryDependencies += "org.scalatest" %%% "scalatest" % "3.0.6-SNAP2" % Test
diff --git a/compilerplugins-BangNotation/src/main/resources/scalac-plugin.xml b/compilerplugins-BangNotation/src/main/resources/scalac-plugin.xml
deleted file mode 100644
index d2126ac2..00000000
--- a/compilerplugins-BangNotation/src/main/resources/scalac-plugin.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
- BangNotation
- com.thoughtworks.dsl.compilerplugins.BangNotation
-
diff --git a/compilerplugins-BangNotation/src/main/scala/com/thoughtworks/dsl/compilerplugins/BangNotation.scala b/compilerplugins-BangNotation/src/main/scala/com/thoughtworks/dsl/compilerplugins/BangNotation.scala
deleted file mode 100644
index 27012e4f..00000000
--- a/compilerplugins-BangNotation/src/main/scala/com/thoughtworks/dsl/compilerplugins/BangNotation.scala
+++ /dev/null
@@ -1,534 +0,0 @@
-package com.thoughtworks.dsl
-package compilerplugins
-
-import com.thoughtworks.dsl.Dsl.{ResetAnnotation, nonTypeConstraintReset, shift}
-import com.thoughtworks.dsl.compilerplugins.BangNotation.HasReturn
-
-import scala.annotation.tailrec
-import scala.tools.nsc.plugins.{Plugin, PluginComponent}
-import scala.tools.nsc.transform.Transform
-import scala.tools.nsc.typechecker.ContextMode
-import scala.tools.nsc.{Global, Mode, Phase}
-private object BangNotation {
- sealed trait HasReturn
- object HasReturn {
- case object Yes extends HasReturn
- case object No extends HasReturn
- }
-
-}
-
-/** The Scala compiler plug-in to convert ordinary Scala control flows to continuation-passing style,
- * which will then be interpreted by [[Dsl]].
- *
- * = Usage =
- *
- * `
- * // In your build.sbt
- * addCompilerPlugin("com.thoughtworks.dsl" %% "compilerplugins-bangnotation" % "latest.release")
- *
`
- *
- * @author 杨博 (Yang Bo)
- */
-final class BangNotation(override val global: Global) extends Plugin {
- import global._
- import global.analyzer._
-
- private val hasScalaJsPlugin =
- global.settings.plugin.value.exists(_.matches("""^.*scalajs-compiler_.*\.jar$"""))
-
- private var active = true
- private def deactAnalyzerPlugins[A](run: => A): A = {
- synchronized {
- active = false
- try {
- run
- } finally {
- active = true
- }
- }
- }
-
- private type CpsAttachment = (Tree => Tree) => Tree
-
- private trait Deactable extends AnalyzerPlugin {
- override def isActive(): Boolean = {
- active && phase.id < currentRun.picklerPhase.id
- }
- }
-
- /** An [[AnalyzerPlugin]] that replaces trees annatated as [[ResetAnnotation]] to its cps transformed trees */
- private trait TreeResetter extends AnalyzerPlugin with AnnotationSymbols {
- override def canAdaptAnnotations(tree: Tree, typer: Typer, mode: Mode, pt: Type): Boolean = {
- super.canAdaptAnnotations(tree, typer, mode, pt) || {
- mode.inExprMode && tree.tpe.hasAnnotation(resetAnnotationSymbol) && tree.hasAttachment[CpsAttachment]
- }
- }
-
- /** Avoid [[UnApply]] in `tree` to suppress compiler crash due to `unexpected UnApply xxx`.
- *
- * @see https://github.com/scala/bug/issues/8825
- */
- private def scalaBug8825Workaround(tree: Tree): Tree = {
- val transformer = new Transformer {
- override def transform(tree: global.Tree): global.Tree = {
- tree match {
- case UnApply(
- Apply(Select(prefix, termNames.unapply | termNames.unapplySeq), List(Ident(termNames.SELECTOR_DUMMY))),
- args) =>
- pq"$prefix(..${transformTrees(args)})"
- case _ =>
- super.transform(tree)
- }
- }
- }
- transformer.transform(tree)
- }
-
- override def adaptAnnotations(tree0: Tree, typer: Typer, mode: Mode, pt: Type): Tree = {
- val tree = super.adaptAnnotations(tree0, typer, mode, pt)
- tree.tpe.annotations.collectFirst {
- case annotation if annotation.matches(resetAnnotationSymbol) =>
- val Some(attachment) = tree.attachments.get[CpsAttachment]
- val cpsTree = scalaBug8825Workaround(resetAttrs(attachment(identity)))
-// reporter.info(tree.pos, s"Translating to continuation-passing style: $cpsTree", true)
- deactAnalyzerPlugins {
- typer.context.withMode(ContextMode.ReTyping) {
- typer.typed(cpsTree, Mode.EXPRmode)
- }
- }
- } match {
- case Some(typedCpsTree) =>
-// reporter.info(tree.pos, s"Translating to continuation-passing style: $typedCpsTree", true)
- typedCpsTree.modifyType(_.filterAnnotations(!_.matches(resetAnnotationSymbol)))
- case None =>
- tree
- }
-
- }
-
- }
-
- private trait BangNotationTransformer extends AnalyzerPlugin with AnnotationSymbols {
-
- private def cpsAttachment(tree: Tree)(continue: Tree => Tree): Tree = {
- tree.attachments.get[CpsAttachment] match {
- case Some(attachment) => attachment(continue)
- case None => continue(tree)
- }
- }
- private def cpsParameter(parameters: List[Tree])(continue: List[Tree] => Tree): Tree = {
- parameters match {
- case Nil =>
- continue(Nil)
- case head :: tail =>
- cpsAttachment(head) { headValue =>
- cpsParameter(tail) { tailValues =>
- continue(headValue :: tailValues)
- }
- }
- }
- }
- private def cpsParameterList(parameterLists: List[List[Tree]])(continue: List[List[Tree]] => Tree): Tree = {
- parameterLists match {
- case Nil =>
- continue(Nil)
- case headList :: tailList =>
- cpsParameter(headList) { headValue =>
- cpsParameterList(tailList) { tailValues =>
- continue(headValue :: tailValues)
- }
- }
- }
- }
-
- private def isCpsTree(tree: Tree) = {
- def hasCpsAttachment(child: Any): Boolean = {
- child match {
- case list: List[_] => list.exists(hasCpsAttachment)
- case TypeApply(fun, args) => hasCpsAttachment(fun)
- case Apply(fun, args) => hasCpsAttachment(fun) || args.exists(hasCpsAttachment)
- case CaseDef(pat, guard, body) => hasCpsAttachment(body)
- case ValDef(mods, name, tpt, rhs) => hasCpsAttachment(rhs)
- case childTree: Tree => childTree.hasAttachment[CpsAttachment]
- case _ => false
- }
- }
- tree.productIterator.exists(hasCpsAttachment)
- }
-
- private lazy val catchIdent: Tree = {
- try {
- Ident(rootMirror.staticModule("_root_.com.thoughtworks.dsl.keywords.Catch"))
- } catch {
- case e: ScalaReflectionException =>
- abort("""The BangNotation compiler plug-in requires the runtime library `keywords-catch` to enable !-notation in `try` / `catch` / `finally` expressions:
- libraryDependencies += "com.thoughtworks.dsl" %% "keywords-catch" % "latest.release"
-""")
- }
- }
-
- private val whileName = currentUnit.freshTermName("while")
- private val whileDef = {
- val domainName = currentUnit.freshTypeName("Domain")
- val conditionName = currentUnit.freshTermName("condition")
- val conditionValueName = currentUnit.freshTermName("conditionValue")
- val bodyName = currentUnit.freshTermName("body")
- val endWhileName = currentUnit.freshTermName("endWhile")
- q"""
- @${definitions.ScalaInlineClass} def $whileName[$domainName]($endWhileName: => $domainName)(
- $bodyName: (=> $domainName) => $domainName,
- $conditionName: (_root_.scala.Boolean => $domainName) => $domainName): $domainName = {
- $conditionName { $conditionValueName: ${TypeTree()} =>
- if ($conditionValueName) {
- $bodyName {
- $whileName[$domainName]($endWhileName)($bodyName, $conditionName)
- }
- } else {
- $endWhileName
- }
- }
- }
- """
- }
- private val doWhileName = currentUnit.freshTermName("doWhile")
-
- private val doWhileDef = {
- val domainName = currentUnit.freshTypeName("Domain")
- val conditionName = currentUnit.freshTermName("condition")
- val conditionValueName = currentUnit.freshTermName("conditionValue")
- val bodyName = currentUnit.freshTermName("body")
- val endDoWhileName = currentUnit.freshTermName("endDoWhile")
- q"""
- @${definitions.ScalaInlineClass} def $doWhileName[$domainName]($endDoWhileName: => $domainName)(
- $bodyName: (=> $domainName) => $domainName,
- $conditionName: (_root_.scala.Boolean => $domainName) => $domainName): $domainName = {
- $bodyName {
- $conditionName { $conditionValueName: ${TypeTree()} =>
- if ($conditionValueName) {
- $doWhileName[$domainName]($endDoWhileName)($bodyName, $conditionName)
- } else {
- $endDoWhileName
- }
- }
- }
- }
- """
- }
- private def notPure(head: Tree): List[Tree] = {
- head match {
- case (_: Ident) | (_: Literal) =>
- Nil
- case _ =>
- head :: Nil
- }
- }
-
- private def toFunction1(continue: Tree => Tree, parameterTypes: Type) = {
- val parameterName = currentUnit.freshTermName("a")
- val id = q"$parameterName"
- continue(id) match {
- case q"${f: Ident}.apply(${`id`})" =>
- f
- case transformed =>
- q"""
- { ($parameterName: $parameterTypes) =>
- ${transformed}
- }
- """
- }
- }
-
- private def hasReturnTree(tree: Tree): Boolean = {
- tree.attachments.get[HasReturn] match {
- case Some(HasReturn.Yes) =>
- true
- case Some(HasReturn.No) =>
- false
-
- case _ =>
- tree match {
- case _: Return =>
- true
- case valDef: ValDef =>
- hasReturnTree(valDef.rhs)
- case _: MemberDef =>
- false
- case _ =>
- tree.children.exists(hasReturnTree)
- }
- }
-
- }
-
- override def pluginsTyped(tpe0: Type, typer: Typer, tree: Tree, mode: Mode, pt: Type): Type = {
- val tpe = super.pluginsTyped(tpe0, typer, tree, mode, pt)
-
- def cps(continue: Tree => Tree): Tree = atPos(tree.pos) {
- tree match {
- case q"$prefix.$methodName[..$typeParameters](...$parameterLists)" =>
- cpsAttachment(prefix) { prefixValue =>
- cpsParameterList(parameterLists) { parameterListsValues =>
- continue(atPos(tree.pos) {
- q"$prefixValue.$methodName[..$typeParameters](...$parameterListsValues)"
- })
- }
- }
- case q"${method: Ident}[..$typeParameters](...$parameterLists)" =>
- cpsParameterList(parameterLists) { parameterListsValues =>
- continue(atPos(tree.pos) {
- q"$method[..$typeParameters](...$parameterListsValues)"
- })
- }
- case q"new $constructor[..$typeParameters](...$parameterLists)" =>
- cpsParameterList(parameterLists) { parameterListsValues =>
- continue(atPos(tree.pos) {
- q"new $constructor[..$typeParameters](...$parameterListsValues)"
- })
- }
- case Typed(expr, tpt) =>
- cpsAttachment(expr) { exprValue =>
- atPos(tree.pos) {
- if (tpt.tpe.hasAnnotation(resetAnnotationSymbol)) {
- continue(exprValue)
- } else {
- tpt match {
- case tpt: TypeTree =>
- // Create a new TypeTree with a null original, as a workaround of https://github.com/ThoughtWorksInc/Dsl.scala/issues/114
- val noOriginal = TypeTree(tpt.tpe).setPos(tpt.pos)
- continue(Typed(exprValue, noOriginal))
- case _ =>
- continue(Typed(exprValue, tpt))
- }
- }
- }
- }
- case Block(stats, expr) =>
- def loop(stats: List[Tree]): Tree = {
- stats match {
- case Nil =>
- cpsAttachment(expr) {
- case block: Block =>
- continue(block)
- case notBlock =>
- continue(treeCopy.Block(tree, Nil, notBlock))
- }
- case (valDef @ ValDef(mods, name, tpt, rhs)) :: tail =>
- // TODO: lazy val
- cpsAttachment(rhs) { rhsValue =>
- atPos(valDef.pos) {
- q"${treeCopy.ValDef(valDef, mods, name, tpt, rhsValue)}; ${loop(tail)}"
- }
- }
- case head :: tail =>
- cpsAttachment(head) { headValue =>
- q"..${notPure(headValue)}; ${loop(tail)}"
- }
- }
- }
- loop(stats)
- case If(cond, thenp, elsep) =>
- val endIfName = currentUnit.freshTermName("endIf")
-
- q"""
- ${
- val endIfBody = toFunction1(continue, tpe)
- if (hasReturnTree(endIfBody)) {
- q"""
- val $endIfName = $endIfBody
- """.updateAttachment(HasReturn.Yes)
- } else {
- q"""
- @${definitions.ScalaInlineClass} def $endIfName = $endIfBody
- """.updateAttachment(HasReturn.No)
- }
- }
-
- ${cpsAttachment(cond) { condValue =>
- atPos(tree.pos) {
- q"""
- if ($condValue) ${cpsAttachment(thenp) { result =>
- q"$endIfName.apply($result)"
- }} else ${cpsAttachment(elsep) { result =>
- q"$endIfName.apply($result)"
- }}
- """
- }
- }}
- """
- case Match(selector, cases) =>
- val endMatchName = currentUnit.freshTermName("endMatch")
- q"""
- ${
- val endMatchBody = toFunction1(continue, tpe)
- if (hasReturnTree(endMatchBody)) {
- q"""
- val $endMatchName = $endMatchBody
- """.updateAttachment(HasReturn.Yes)
- } else {
- q"""
- @${definitions.ScalaInlineClass} def $endMatchName = $endMatchBody
- """.updateAttachment(HasReturn.No)
- }
- }
-
- ${cpsAttachment(selector) { selectorValue =>
- atPos(tree.pos) {
- Match(
- selectorValue,
- cases.map {
- case caseDef @ CaseDef(pat, guard, body) =>
- treeCopy.CaseDef(caseDef, pat, guard, cpsAttachment(body) { bodyValue =>
- q"$endMatchName.apply($bodyValue)"
- })
- }
- )
- }
- }}
- """
- case _: CaseDef =>
- // This CaseDef tree contains some bang notations, and will be translated by enclosing Try or Match tree, not here
- EmptyTree
- case Try(block, catches, finalizer) =>
- val finalizerName = currentUnit.freshTermName("finalizer")
- val resultName = currentUnit.freshTermName("result")
-
- q"""
- $catchIdent.tryCatch { ($resultName: $tpe) => ${{
- cpsAttachment(finalizer) { finalizerValue =>
- q"""
- ..${notPure(finalizerValue)}
- ${continue(q"$resultName")}
- """
- }
- }}}.apply(
- { $finalizerName: ${TypeTree()} => ${cpsAttachment(block) { blockValue =>
- q"$finalizerName.apply($blockValue)"
- }}},
- {
- case ..${catches.map { caseDef =>
- atPos(caseDef.pos) {
- treeCopy.CaseDef(
- caseDef,
- caseDef.pat,
- caseDef.guard,
- q"""{ $finalizerName: ${TypeTree()} => ${{
- cpsAttachment(caseDef.body) { bodyValue =>
- q"$finalizerName.apply($bodyValue)"
- }
- }}}"""
- )
- }
- }}}
- )
- """
- case Assign(lhs, rhs) =>
- cpsAttachment(rhs) { rhsValue =>
- continue(treeCopy.Assign(tree, lhs, rhsValue))
- }
- case q"while($condition) $body" =>
- // TODO: Trampoline
- val continueName = currentUnit.freshTermName("continue")
- val conditionHandlerName = currentUnit.freshTermName("conditionHandler")
- q"""
- $whileDef
- $whileName({
- ${continue(q"()")}
- })({ $continueName: ${TypeTree()} => ${cpsAttachment(body) { bodyValue =>
- q"""
- ..${notPure(bodyValue)}
- $continueName
- """
- }}},
- { $conditionHandlerName: ${TypeTree()} => ${cpsAttachment(condition) { conditionValue =>
- q"$conditionHandlerName.apply($conditionValue)"
- }}})
- """
- case q"do $body while($condition)" =>
- // TODO: Trampoline
- val continueName = currentUnit.freshTermName("continue")
- val conditionHandlerName = currentUnit.freshTermName("conditionHandler")
- q"""
- $doWhileDef
-
- $doWhileName({
- ${continue(q"()")}
- })({ $continueName: ${TypeTree()} => ${cpsAttachment(body) { bodyValue =>
- q"""
- ..${notPure(bodyValue)}
- $continueName
- """
- }}},
- { $conditionHandlerName: ${TypeTree()} => ${cpsAttachment(condition) { conditionValue =>
- q"$conditionHandlerName.apply($conditionValue)"
- }}})
- """
- case Throw(expr) =>
- cpsAttachment(expr) { exprValue =>
- continue(treeCopy.Throw(tree, exprValue))
- }
- case Return(expr) =>
- cpsAttachment(expr) { exprValue =>
- continue(treeCopy.Return(tree, exprValue))
- }
- case tree =>
- reporter.info(tree.pos, "CPS-transformation is skipped for this tree", force = false)
- continue(tree)
- }
- }
-
- if (mode.inExprMode) {
- val symbol = tree.symbol
- tree match {
- case q"$shiftOps.$shiftMethod" if symbol != null && symbol.hasAnnotation(shiftSymbol) =>
- def attachment: CpsAttachment = { continue: (Tree => Tree) =>
- // FIXME: tpe is a by-name type. I don't know why.
- cpsAttachment(shiftOps) { shiftOpsValue =>
- atPos(tree.pos) {
- q"""
- $shiftOpsValue.cpsApply(${toFunction1(continue, tpe)})
- """
- }
- }
- }
- tree.updateAttachment[CpsAttachment](attachment)
- case _ =>
- if (isCpsTree(tree)) {
- tree.updateAttachment[CpsAttachment](cps)
- }
- }
- }
-
- tpe
- }
-
- }
-
- private trait AnnotationSymbols {
- private[BangNotation] lazy val resetAnnotationSymbol = symbolOf[ResetAnnotation]
- private[BangNotation] lazy val shiftSymbol = symbolOf[shift]
- }
-
- val name: String = "BangNotation"
-
- override def init(options: List[String], error: String => Unit): Boolean = {
- super.init(options, error) && {
- try {
- global.analyzer.addAnalyzerPlugin(new Deactable with TreeResetter with BangNotationTransformer)
- true
- } catch {
- case e: ScalaReflectionException =>
- error("""The BangNotation compiler plug-in requires the runtime library:
- libraryDependencies += "com.thoughtworks.dsl" %% "dsl" % "latest.release"
-""")
- false
- }
- }
- }
-
- val description: String =
- "A compiler plugin that converts native imperative syntax to monadic expressions or continuation-passing style expressions"
-
- val components = Nil
-
-}
diff --git a/compilerplugins-BangNotation/src/test/scala/com/thoughtworks/dsl/compilerplugin/BangNotationSpec.scala b/compilerplugins-BangNotation/src/test/scala/com/thoughtworks/dsl/compilerplugin/BangNotationSpec.scala
deleted file mode 100644
index 41729a5f..00000000
--- a/compilerplugins-BangNotation/src/test/scala/com/thoughtworks/dsl/compilerplugin/BangNotationSpec.scala
+++ /dev/null
@@ -1,34 +0,0 @@
-package com.thoughtworks.dsl.compilerplugin
-
-import com.thoughtworks.dsl.Dsl.shift
-import org.scalatest.{FreeSpec, Matchers}
-
-/**
- * @author 杨博 (Yang Bo)
- */
-class BangNotationSpec extends FreeSpec with Matchers {
-
- "printf problem" in {
-
- object IntPlaceholder {
- @shift def unary_! : String = ???
- def cpsApply[Domain](f: String => Domain): Int => Domain = { i: Int =>
- f(i.toString)
- }
- }
-
- object StringPlaceholder {
- @shift def unary_! : String = ???
- def cpsApply[Domain](f: String => Domain): String => Domain = f
- }
-
- def f1 = "Hello World!"
- def f2 = "Hello " + !StringPlaceholder + "!"
- def f3 = "The value of " + !StringPlaceholder + " is " + !IntPlaceholder + "."
-
- f1 should be("Hello World!")
- f2.asInstanceOf[String => String]("World") should be("Hello World!")
- f3.asInstanceOf[String => Int => String]("x")(3) should be("The value of x is 3.")
- }
-
-}
diff --git a/compilerplugins-ResetEverywhere/build.sbt b/compilerplugins-ResetEverywhere/build.sbt
deleted file mode 100644
index 02a6401f..00000000
--- a/compilerplugins-ResetEverywhere/build.sbt
+++ /dev/null
@@ -1,9 +0,0 @@
-libraryDependencies += "org.scala-lang" % "scala-compiler" % scalaVersion.value % Provided
-
-scalacOptions ++= {
- if (scalaBinaryVersion.value == "2.11") {
- Seq("–Yexperimental")
- } else {
- Seq()
- }
-}
diff --git a/compilerplugins-ResetEverywhere/src/main/resources/scalac-plugin.xml b/compilerplugins-ResetEverywhere/src/main/resources/scalac-plugin.xml
deleted file mode 100644
index 622eca89..00000000
--- a/compilerplugins-ResetEverywhere/src/main/resources/scalac-plugin.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
- ResetEverywhere
- com.thoughtworks.dsl.compilerplugins.ResetEverywhere
-
diff --git a/compilerplugins-ResetEverywhere/src/main/scala/com/thoughtworks/dsl/compilerplugins/ResetEverywhere.scala b/compilerplugins-ResetEverywhere/src/main/scala/com/thoughtworks/dsl/compilerplugins/ResetEverywhere.scala
deleted file mode 100644
index 4b265aa8..00000000
--- a/compilerplugins-ResetEverywhere/src/main/scala/com/thoughtworks/dsl/compilerplugins/ResetEverywhere.scala
+++ /dev/null
@@ -1,154 +0,0 @@
-package com.thoughtworks.dsl.compilerplugins
-
-import com.thoughtworks.dsl.Dsl.{ResetAnnotation, nonTypeConstraintReset, shift}
-
-import scala.reflect.internal.FatalError
-import scala.tools.nsc.plugins.{Plugin, PluginComponent}
-import scala.tools.nsc.transform.Transform
-import scala.tools.nsc.typechecker.ContextMode
-import scala.tools.nsc.{Global, Mode, Phase}
-
-/** A Scala compiler plug-in to enable [[Dsl.Keyword#unary_$bang !-notation]] for every methods and functions.
- *
- * Add the following setting in your `build.sbt` to enable this plug-in.
- *
- * `
- * // build.sbt
- * addCompilerPlugin("com.thoughtworks.dsl" %% "compilerplugins-reseteverywhere" % "latest.release")
- *
`
- *
- * @note Once this [[ResetEverywhere]] plug-in is enabled,
- * the `@[[Dsl.reset reset]]` annotations are added to class fields, every methods and every functions automatically.
- * Some other macros or compiler plug-ins may conflict with those `@[[Dsl.reset reset]]` annotations.
- *
- * @author 杨博 (Yang Bo)
- */
-final class ResetEverywhere(override val global: Global) extends Plugin {
- import global._
- import global.analyzer._
-
- private var active = true
- private def deactAnalyzerPlugins[A](run: => A): A = {
- synchronized {
- active = false
- try {
- run
- } finally {
- active = true
- }
- }
- }
-
- private type CpsAttachment = (Tree => Tree) => Tree
-
- private var nonTypeConstraintResetSymbol: Symbol = _ // = symbolOf[nonTypeConstraintReset]
-
- override def init(options: List[String], error: String => Unit): Boolean = {
- super.init(options, error) && {
- try {
- nonTypeConstraintResetSymbol = symbolOf[nonTypeConstraintReset]
- true
- } catch {
- case e: ScalaReflectionException =>
- error("""This compiler plug-in requires the runtime library:
- libraryDependencies += "com.thoughtworks.dsl" %% "dsl" % "latest.release"
-""")
- false
- }
- }
- }
- val name: String = "ResetEverywhere"
-
- private final class ResetAnnotationCreator extends PluginComponent with Transform {
-
- val global: ResetEverywhere.this.global.type = ResetEverywhere.this.global
- val phaseName: String = "ResetAnnotationCreator"
- val runsAfter = "parser" :: Nil
- override val runsBefore = "namer" :: Nil
-
- protected def newTransformer(unit: CompilationUnit): Transformer = new Transformer {
-
- private def annotatedReset(tree: Tree) = {
- if (tree.isEmpty) {
- tree
- } else {
- Annotated(q"new $nonTypeConstraintResetSymbol()", transform(tree))
- }
- }
-
- private def typedReset(tree: Tree, typeTree: Tree) = {
- if (tree.isEmpty) {
- tree
- } else if (typeTree.isEmpty) {
- Annotated(q"new $nonTypeConstraintResetSymbol()", transform(tree))
- } else {
- Annotated(q"new $nonTypeConstraintResetSymbol()", Typed(transform(tree), typeTree))
- }
- }
-
- private def transformRootValDef(tree: ValDef) = {
- val ValDef(mods, name, tpt, rhs) = tree
- treeCopy.ValDef(tree, mods, name, tpt, typedReset(rhs, tpt))
- }
-
- override def transformTemplate(tree: Template): Template = {
- val Template(parents, self, body) = tree
- treeCopy.Template(
- tree,
- parents,
- self,
- body.mapConserve {
- case valDef: ValDef if !valDef.mods.isParamAccessor =>
- transformRootValDef(valDef)
- case initializer: TermTree =>
- annotatedReset(initializer)
- case stat =>
- transform(stat)
- }
- )
- }
-
- private def annotateArgsAsReset(tree: Tree): Tree = {
- tree match {
- case tree: Apply =>
- treeCopy.Apply(tree, annotateArgsAsReset(tree.fun), tree.args.mapConserve(annotatedReset))
- case fun =>
- fun
- }
- }
-
- override def transform(tree: global.Tree): global.Tree = {
- tree match {
- case tree: TypeTree =>
- tree
- case Typed(expr, tpt) =>
- treeCopy.Typed(tree, transform(expr), tpt)
- case Function(vparams, body) =>
- treeCopy.Function(tree, vparams, annotatedReset(body))
- case DefDef(mods, name, tparams, vparamss, tpt, rhs)
- if name != termNames.CONSTRUCTOR && name != termNames.MIXIN_CONSTRUCTOR && rhs.nonEmpty && !mods
- .hasAnnotationNamed(definitions.TailrecClass.name) =>
- treeCopy.DefDef(tree, mods, name, tparams, transformValDefss(vparamss), tpt, typedReset(rhs, tpt))
- case valDef: ValDef if valDef.mods.hasDefault =>
- transformRootValDef(valDef)
- case Match(EmptyTree, cases) =>
- treeCopy.Match(tree, EmptyTree, cases.mapConserve {
- case caseDef @ CaseDef(pat, guard, body) =>
- treeCopy.CaseDef(caseDef, pat, guard, annotatedReset(body))
- })
- case q"${Ident(termNames.CONSTRUCTOR)}(...$argss)" =>
- annotateArgsAsReset(tree)
- case q"super.${termNames.CONSTRUCTOR}(...$argss)" =>
- annotateArgsAsReset(tree)
- case _ =>
- super.transform(tree)
- }
- }
- }
- }
-
- val description: String = "Add @reset annotation for every methods and functions automatically"
-
- val components: List[PluginComponent] = List(new ResetAnnotationCreator)
-
-}
diff --git a/comprehension/.js/build.sbt b/comprehension/.js/build.sbt
deleted file mode 120000
index 0569694f..00000000
--- a/comprehension/.js/build.sbt
+++ /dev/null
@@ -1 +0,0 @@
-../build.sbt
\ No newline at end of file
diff --git a/comprehension/.jvm/build.sbt b/comprehension/.jvm/build.sbt
deleted file mode 120000
index 0569694f..00000000
--- a/comprehension/.jvm/build.sbt
+++ /dev/null
@@ -1 +0,0 @@
-../build.sbt
\ No newline at end of file
diff --git a/comprehension/build.sbt b/comprehension/build.sbt
deleted file mode 100644
index ff892bd9..00000000
--- a/comprehension/build.sbt
+++ /dev/null
@@ -1,18 +0,0 @@
-enablePlugins(Example)
-
-import meta._
-exampleSuperTypes := exampleSuperTypes.value.map {
- case ctor"_root_.org.scalatest.FreeSpec" =>
- ctor"_root_.org.scalatest.AsyncFreeSpec"
- case otherTrait =>
- otherTrait
-}
-
-scalacOptions in Compile ++= {
- scalaBinaryVersion.value match {
- case "2.11" => Some("–Xexperimental")
- case _ => None
- }
-}
-
-libraryDependencies += "org.scalatest" %%% "scalatest" % "3.0.6-SNAP2" % Test
diff --git a/comprehension/src/main/scala/com/thoughtworks/dsl/comprehension.scala b/comprehension/src/main/scala/com/thoughtworks/dsl/comprehension.scala
deleted file mode 100644
index b0c021a7..00000000
--- a/comprehension/src/main/scala/com/thoughtworks/dsl/comprehension.scala
+++ /dev/null
@@ -1,158 +0,0 @@
-package com.thoughtworks.dsl
-
-import scala.language.higherKinds
-import scala.language.implicitConversions
-import com.thoughtworks.dsl.keywords._
-
-private[dsl] sealed trait LowPriorityComprehension0 {
- import com.thoughtworks.dsl.comprehension._
-
- implicit def comprehensionOps[From, Keyword, Value](from: From)(
- implicit asKeyword: From => Dsl.Keyword[Keyword, Value] with Keyword): ComprehensionOps[Keyword, Value] =
- new ComprehensionOps[Keyword, Value](from)
-}
-
-/** Provides utilities to perform `for`-comprehension on [[Dsl.Keyword]].
- *
- *
- * Add the following import statement to enable `for`-comprehension on keywords:
- *
- * {{{
- * import com.thoughtworks.dsl.comprehension._
- * }}}
- *
- * @example `for` / `yield` expressions can be used on keywords.
- *
- * {{{
- * import com.thoughtworks.dsl.keywords._
- *
- * def cartesianProduct = for {
- * i <- Each(Array(1, 2, 3))
- * j <- Each(Vector(1, 10, 100, 1000))
- * } yield i * j
- * }}}
- *
- * The results of `for` / `yield` expressions are also keywords.
- *
- * {{{
- * cartesianProduct should be(a[Dsl.Keyword[_, _]])
- * }}}
- *
- * You can use !-notation extract the value from the produced keyword.
- *
- * {{{
- * def resultAsList = List(!cartesianProduct)
- * resultAsList should be(List(1, 10, 100, 1000, 2, 20, 200, 2000, 3, 30, 300, 3000))
- *
- * def resultAsSet: Set[Int] = !Return(!cartesianProduct)
- * resultAsSet should be(Set(1, 10, 100, 1000, 2, 20, 200, 2000, 3, 30, 300, 3000))
- * }}}
- *
- * Alternatively, [[comprehension.ComprehensionOps.to]] can be used to convert the result of a keyword to other types of values as well.
- *
- * {{{
- * cartesianProduct.to[List] should be(List(1, 10, 100, 1000, 2, 20, 200, 2000, 3, 30, 300, 3000))
- * }}}
- * @example This example implements the same feature as the example on Scaladoc of [[keywords.Yield]],
- * except this example use `for`-comprehension instead of !-notation.
- *
- * {{{
- * import com.thoughtworks.dsl.Dsl
- * import com.thoughtworks.dsl.keywords._
- * import com.thoughtworks.dsl.comprehension._
- *
- * def gccFlagBuilder(sourceFile: String, includes: String*) = {
- * for {
- * _ <- Yield("gcc")
- * _ <- Yield("-c")
- * _ <- Yield(sourceFile)
- * include <- Each(includes)
- * _ <- Yield("-I")
- * _ <- Yield(include)
- * r <- Continue
- * } yield r: String
- * }
- *
- * gccFlagBuilder("main.c", "lib1/include", "lib2/include").to[Stream] should be(Stream("gcc", "-c", "main.c", "-I", "lib1/include", "-I", "lib2/include"))
- * }}}
- *
- * Alternatively, you can use Scala native `yield` keyword to produce the last value.
- *
- * {{{
- * def gccFlagBuilder2(sourceFile: String, includes: String*) = {
- * for {
- * _ <- Yield("gcc")
- * _ <- Yield("-c")
- * _ <- Yield(sourceFile)
- * include <- Each(includes)
- * _ <- Yield("-I")
- * } yield include
- * }
- * gccFlagBuilder2("main.c", "lib1/include", "lib2/include").to[Stream] should be(Stream("gcc", "-c", "main.c", "-I", "lib1/include", "-I", "lib2/include"))
- * }}}
- *
- * You can also omit the explicit constructor of [[keywords.Yield]] with the help of implicit conversion [[keywords.Yield.implicitYield]].
- *
- * {{{
- * import com.thoughtworks.dsl.keywords.Yield.implicitYield
- *
- * def augmentString = ()
- * def wrapString = ()
- * }}}
- *
- * Note that [[scala.Predef.augmentString]] and [[scala.Predef.wrapString]] must be disabled in order to use `flatMap` for [[keywords.Yield]].
- *
- * {{{
- * def gccFlagBuilder3(sourceFile: String, includes: String*) = {
- * for {
- * _ <- "gcc"
- * _ <- "-c"
- * _ <- sourceFile
- * include <- Each(includes)
- * _ <- "-I"
- * } yield include
- * }
- * gccFlagBuilder3("main.c", "lib1/include", "lib2/include").to[Stream] should be(Stream("gcc", "-c", "main.c", "-I", "lib1/include", "-I", "lib2/include"))
- * }}}
- *
- */
-object comprehension extends LowPriorityComprehension0 {
-
- @inline
- private def resetDomain[Keyword, Domain](keyword: Keyword)(implicit dsl: Dsl[Keyword, Domain, Domain]): Domain = {
- dsl.cpsApply(keyword, implicitly)
- }
-
- final class ComprehensionOps[Keyword, Value] private[dsl] (private val keyword: Keyword) extends AnyVal {
-
- import keywords._
-
- def map[MapResult](mapper: Value => MapResult): Map[Keyword, Value, MapResult] = Map(keyword, mapper)
-
- def flatMap[MapResult, NestedKeyword, NestedValue](mapper: Value => MapResult)(
- implicit asKeywordMapper: (
- Value => MapResult) => Value => Dsl.Keyword[NestedKeyword, NestedValue] with NestedKeyword)
- : FlatMap[Keyword, Value, NestedKeyword, NestedValue] = FlatMap(keyword, mapper)
-
- def withFilter(condition: Value => Boolean): WithFilter[Keyword, Value] = WithFilter(keyword, condition)
-
- def to[Output[_]](implicit dsl: Dsl[Keyword, Output[Value], Value],
- returnDsl: Dsl[Return[Value], Output[Value], Nothing]): Output[Value] = {
- dsl.cpsApply(keyword, { value: Value =>
- resetDomain(Return(value))
- })
- }
- def as[Domain](implicit dsl: Dsl[Keyword, Domain, Value],
- returnDsl: Dsl[Return[Value], Domain, Nothing]): Domain = {
- dsl.cpsApply(keyword, { value: Value =>
- resetDomain(Return(value))
- })
- }
-
- }
-
- implicit def nothingComprehensionOps[From, Keyword](from: From)(
- implicit asKeyword: From => Dsl.Keyword[Keyword, Nothing] with Keyword): ComprehensionOps[Keyword, Nothing] =
- new ComprehensionOps[Keyword, Nothing](from)
-
-}
diff --git a/domains-cats/build.sbt b/domains-cats/build.sbt
index b2856764..f5760155 100644
--- a/domains-cats/build.sbt
+++ b/domains-cats/build.sbt
@@ -6,6 +6,21 @@ libraryDependencies += "org.typelevel" %%% "cats-core" % "1.4.0"
libraryDependencies += "org.scalatest" %%% "scalatest" % "3.0.6-SNAP2" % Test
+libraryDependencies += "com.thoughtworks.dsl" %%% "keywords-catch" % "1.3.1"
+
+libraryDependencies += "com.thoughtworks.dsl" %%% "keywords-monadic" % "1.3.1"
+
+libraryDependencies += "com.thoughtworks.dsl" %%% "keywords-return" % "1.3.1"
+
+libraryDependencies += "com.thoughtworks.dsl" %%% "keywords-shift" % "1.3.1" % Optional
+
+libraryDependencies += "com.thoughtworks.dsl" %%% "keywords-yield" % "1.3.1" % Optional
+
+addCompilerPlugin("com.thoughtworks.dsl" %% "compilerplugins-bangnotation" % "1.3.1")
+
+addCompilerPlugin("com.thoughtworks.dsl" %% "compilerplugins-reseteverywhere" % "1.3.1")
+
+
scalacOptions ++= {
import Ordering.Implicits._
if (VersionNumber(scalaVersion.value).numbers < Seq(2L, 12L)) {
diff --git a/domains-scalaz/.js/build.sbt b/domains-scalaz/.js/build.sbt
deleted file mode 120000
index 0569694f..00000000
--- a/domains-scalaz/.js/build.sbt
+++ /dev/null
@@ -1 +0,0 @@
-../build.sbt
\ No newline at end of file
diff --git a/domains-scalaz/.jvm/build.sbt b/domains-scalaz/.jvm/build.sbt
deleted file mode 120000
index 0569694f..00000000
--- a/domains-scalaz/.jvm/build.sbt
+++ /dev/null
@@ -1 +0,0 @@
-../build.sbt
\ No newline at end of file
diff --git a/domains-scalaz/.jvm/jvm.sbt b/domains-scalaz/.jvm/jvm.sbt
deleted file mode 100644
index 2e36c246..00000000
--- a/domains-scalaz/.jvm/jvm.sbt
+++ /dev/null
@@ -1,23 +0,0 @@
-enablePlugins(Example)
-
-
-sourceGenerators in Test := {
- (sourceGenerators in Test).value.filterNot { sourceGenerator =>
- import Ordering.Implicits._
- VersionNumber(scalaVersion.value).numbers >= Seq(2L, 13L) &&
- sourceGenerator.info
- .get(taskDefinitionKey)
- .exists { scopedKey: ScopedKey[_] =>
- scopedKey.key == generateExample.key
- }
- }
-}
-
-import scala.meta._
-exampleSuperTypes += ctor"_root_.org.scalatest.Inside"
-
-libraryDependencies += "org.scalaz" %% "scalaz-concurrent" % "7.2.26" % Test
-
-libraryDependencies += "com.thoughtworks.tryt" %% "invariant" % "2.1.0" % Test
-
-libraryDependencies += "com.thoughtworks.tryt" %% "invariant" % "2.1.0" % Optional // For scaladoc
diff --git a/domains-scalaz/.jvm/src/test/scala/com/thoughtworks/dsl/domains/scalazSpec.scala b/domains-scalaz/.jvm/src/test/scala/com/thoughtworks/dsl/domains/scalazSpec.scala
deleted file mode 100644
index 5b157e89..00000000
--- a/domains-scalaz/.jvm/src/test/scala/com/thoughtworks/dsl/domains/scalazSpec.scala
+++ /dev/null
@@ -1,114 +0,0 @@
-package com.thoughtworks.dsl.domains
-
-import com.thoughtworks.dsl.Dsl.!!
-import org.scalatest.{FreeSpec, Matchers}
-import _root_.scalaz.OptionT
-import _root_.scalaz.concurrent.Task
-import _root_.scalaz.std.stream._
-import com.thoughtworks.dsl.domains.scalaz._
-import com.thoughtworks.dsl.keywords.{Monadic, Shift, Yield}
-
-/**
- * @author 杨博 (Yang Bo)
- */
-class scalazSpec extends FreeSpec with Matchers {
-
- "MonadError" in {
- def task: Task[Int] = Task.now {
- import com.thoughtworks.dsl.keywords.Monadic._
- try {
- 0 / 0
- } catch {
- case e: ArithmeticException =>
- 42
- } finally {
- !Task.now(())
- }
- }
- task.unsafePerformSync should be(42)
- }
-
- "Given a continuation that uses Yield and Monadic expressions" - {
-
- def asyncFunction: Stream[String] !! Unit = _ {
- !Yield("Entering asyncFunction")
- val subThreadId = !Monadic(Stream(0, 1))
- !Yield(s"Fork sub-thread $subThreadId")
- !Yield("Leaving asyncFunction")
- }
-
- "When create a generator that contains Yield, Shift, and Monadic expressions" - {
-
- def generator: Stream[String] = {
- !Yield("Entering generator")
- val threadId = !Monadic(Stream(0, 1))
- !Yield(s"Fork thread $threadId")
- !Shift(asyncFunction)
- Stream("Leaving generator")
- }
-
- "Then the generator should contains yield values" in {
- generator should be(
- Seq(
- /**/ "Entering generator",
- /****/ "Fork thread 0",
- /******/ "Entering asyncFunction",
- /********/ "Fork sub-thread 0",
- /**********/ "Leaving asyncFunction",
- /**********/ "Leaving generator",
- /********/ "Fork sub-thread 1",
- /**********/ "Leaving asyncFunction",
- /**********/ "Leaving generator",
- /****/ "Fork thread 1",
- /******/ "Entering asyncFunction",
- /********/ "Fork sub-thread 0",
- /**********/ "Leaving asyncFunction",
- /**********/ "Leaving generator",
- /********/ "Fork sub-thread 1",
- /**********/ "Leaving asyncFunction",
- /**********/ "Leaving generator"
- ))
- }
-
- }
-
- }
-
- "Given a monadic expression that contains a Scalaz OptionT" - {
- def myOptionalList: OptionT[Stream, String] = {
- // TODO: Is it possible to have `Yield` expressions here?
- val threadId = !Monadic(Stream(0, 1, 2))
- val subThreadId = !Monadic(OptionT(Stream(Some(10), None, Some(30))))
- val subSubThreadId = !Monadic(OptionT(Stream(Some(100), Some(200), None)))
- OptionT[Stream, String](Stream(Some(s"Fork thread $threadId-$subThreadId-$subSubThreadId")))
- }
-
- "Then it should skips those elements that contains a None" in {
- myOptionalList.run should be(
- Seq(
- Some("Fork thread 0-10-100"),
- Some("Fork thread 0-10-200"),
- None,
- None,
- Some("Fork thread 0-30-100"),
- Some("Fork thread 0-30-200"),
- None,
- Some("Fork thread 1-10-100"),
- Some("Fork thread 1-10-200"),
- None,
- None,
- Some("Fork thread 1-30-100"),
- Some("Fork thread 1-30-200"),
- None,
- Some("Fork thread 2-10-100"),
- Some("Fork thread 2-10-200"),
- None,
- None,
- Some("Fork thread 2-30-100"),
- Some("Fork thread 2-30-200"),
- None
- ))
- }
-
- }
-}
diff --git a/domains-scalaz/build.sbt b/domains-scalaz/build.sbt
deleted file mode 100644
index 4eb5cae7..00000000
--- a/domains-scalaz/build.sbt
+++ /dev/null
@@ -1,12 +0,0 @@
-libraryDependencies += "org.scalaz" %%% "scalaz-core" % "7.2.26"
-
-addCompilerPlugin("org.spire-math" %% "kind-projector" % "0.9.7")
-
-scalacOptions in Compile ++= {
- scalaBinaryVersion.value match {
- case "2.11" => Seq("–Xexperimental")
- case _ => Seq.empty
- }
-}
-
-libraryDependencies += "org.scalatest" %%% "scalatest" % "3.0.6-SNAP2" % Test
diff --git a/domains-scalaz/src/main/scala/com/thoughtworks/dsl/domains/scalaz.scala b/domains-scalaz/src/main/scala/com/thoughtworks/dsl/domains/scalaz.scala
deleted file mode 100644
index 44945b63..00000000
--- a/domains-scalaz/src/main/scala/com/thoughtworks/dsl/domains/scalaz.scala
+++ /dev/null
@@ -1,193 +0,0 @@
-package com.thoughtworks.dsl.domains
-
-import com.thoughtworks.Extractor._
-import com.thoughtworks.dsl.Dsl
-import com.thoughtworks.dsl.Dsl.{!!, Keyword}
-
-import scala.language.higherKinds
-import scala.language.implicitConversions
-import _root_.scalaz.{Applicative, Bind, Monad, MonadError, MonadTrans, Unapply}
-import com.thoughtworks.dsl.keywords.Catch.CatchDsl
-import com.thoughtworks.dsl.keywords.{Catch, Monadic, Return}
-
-import scala.util.control.Exception.Catcher
-import scala.util.control.{ControlThrowable, NonFatal}
-
-/** Contains interpreters to enable [[Dsl.Keyword#unary_$bang !-notation]]
- * for [[keywords.Monadic Monadic]] and other keywords
- * in code blocks whose type support [[scalaz.Bind]], [[scalaz.MonadError]] and [[scalaz.MonadTrans]].
- *
- * @example [[scalaz.Free.Trampoline]] is a monadic data type that performs tail call optimization.
- * It can be built from a `@[[Dsl.reset reset]]` code block within some [[Dsl.Keyword#unary_$bang !-notation]],
- * similar to the [[com.thoughtworks.each.Monadic.EachOps#each each]] method in
- * [[https://github.com/ThoughtWorksInc/each ThoughtWorks Each]].
- *
- * {{{
- * import _root_.scalaz.Trampoline
- * import _root_.scalaz.Free.Trampoline
- * import com.thoughtworks.dsl.keywords.Monadic._
- * import com.thoughtworks.dsl.domains.scalaz._
- * import com.thoughtworks.dsl.Dsl.reset
- *
- * val trampoline3 = Trampoline.done(3)
- *
- * def dslSquare = Trampoline.delay {
- * s"This string is produced by a trampoline: ${!trampoline3 * !trampoline3}"
- * }: @reset
- *
- * dslSquare.run should be("This string is produced by a trampoline: 9")
- * }}}
- *
- * `!trampoline3` is a shortcut of `!Monadic(trampoline3)`,
- * which will be converted to `flatMap` calls by our DSL interpreter.
- * Thus, the method `dslSquare` is equivalent to the following code in [[scalaz.syntax]]:
- *
- * {{{
- *
- * def scalazSyntaxSquare = trampoline3.flatMap { tmp1 =>
- * trampoline3.flatMap { tmp2 =>
- * Trampoline.delay {
- * s"This string is produced by a trampoline: ${tmp1 * tmp2}"
- * }
- * }
- * }
- *
- * scalazSyntaxSquare.run should be("This string is produced by a trampoline: 9")
- * }}}
- *
- *
- *
- * A `@[[Dsl.reset reset]]` code block can contain `try` / `catch` / `finally`
- * if the monadic data type supports [[scalaz.MonadError]].
- *
- * [[https://github.com/ThoughtWorksInc/tryt.scala tryt.scala]] is a monad transformer that provides
- * [[scalaz.MonadError]],
- * therefore `try` / `catch` / `finally` expressions can be used inside a `@[[Dsl.reset reset]]` code block
- * whose return type is `TryT[Trampoline, ?]`.
- *
- * {{{
- * import com.thoughtworks.tryt.invariant.TryT, TryT._
- * import scala.util.{Try, Success}
- * type TryTTransfomredTrampoline[A] = TryT[Trampoline, A]
- *
- * val trampolineSuccess0: TryTTransfomredTrampoline[Int] = TryT(Trampoline.done(Try(0)))
- *
- * def dslTryCatch: TryTTransfomredTrampoline[String] = TryT(Trampoline.delay(Try {
- * try {
- * s"Division result: ${!trampoline3 / !trampolineSuccess0}"
- * } catch {
- * case e: ArithmeticException =>
- * s"Cannot divide ${!trampoline3} by ${!trampolineSuccess0}"
- * }
- * })): @reset
- *
- * inside(dslTryCatch) {
- * case TryT(trampoline) =>
- * trampoline.run should be(Success("Cannot divide 3 by 0"))
- * }
- * }}}
- *
- * Note that [[Dsl.Keyword#unary_$bang !-notation]] can be used on
- * both `trampoline3` and `trampolineSuccess0` even when they are different types,
- * i.e. `trampoline3` is a vanilla [[scalaz.Free.Trampoline Trampoline]],
- * while `trampolineSuccess0` is a [[com.thoughtworks.tryt.invariant.TryT TryT]]-transfomred
- * [[scalaz.Free.Trampoline Trampoline]].
- * It is possible because the interpreters of the [[keywords.Monadic]] invoke
- * [[scalaz.MonadTrans.liftM]] automatically.
- *
- * The above `dslTryCatch` method is equivalent to the following code in [[scalaz.syntax]]:
- *
- * {{{
- * def scalazSyntaxTryCatch: TryTTransfomredTrampoline[String] = {
- * import _root_.scalaz.syntax.monadError._
- * trampoline3.liftM[TryT].flatMap { tmp0 =>
- * trampolineSuccess0.flatMap { tmp1 =>
- * TryT(Trampoline.delay(Try(s"Division result: ${tmp0 / tmp1}")))
- * }
- * }.handleError {
- * case e: ArithmeticException =>
- * trampoline3.liftM[TryT].flatMap { tmp2 =>
- * trampolineSuccess0.flatMap { tmp3 =>
- * TryT(Trampoline.delay(Try(s"Cannot divide ${tmp2} by ${tmp3}")))
- * }
- * }
- * case e =>
- * e.raiseError[TryTTransfomredTrampoline, String]
- * }
- * }
- *
- * inside(scalazSyntaxTryCatch) {
- * case TryT(trampoline) =>
- * trampoline.run should be(Success("Cannot divide 3 by 0"))
- * }
- * }}}
- *
- * @author 杨博 (Yang Bo)
- */
-object scalaz {
-
- protected type MonadThrowable[F[_]] = MonadError[F, Throwable]
-
- implicit def scalazCatchDsl[F[_], A, B](implicit monadError: MonadThrowable[F]): CatchDsl[F[A], F[B], A] =
- new CatchDsl[F[A], F[B], A] {
- def tryCatch(block: F[A] !! A, catcher: Catcher[F[A] !! A], handler: A => F[B]): F[B] = {
- import _root_.scalaz.syntax.all._
- val fa = monadError.bind(monadError.pure(block))(_(monadError.pure(_)))
- val protectedFa = monadError.handleError(fa) {
- case catcher.extract(recovered) =>
- recovered(monadError.pure(_))
- case e =>
- monadError.raiseError[A](e)
- }
- monadError.bind(protectedFa)(handler)
- }
- }
-
- implicit def scalazReturnDsl[F[_], A, B](implicit applicative: Applicative[F],
- restReturnDsl: Dsl[Return[A], B, Nothing]) =
- new Dsl[Return[A], F[B], Nothing] {
- def cpsApply(keyword: Return[A], handler: Nothing => F[B]): F[B] = {
- applicative.pure(restReturnDsl.cpsApply(keyword, identity))
- }
- }
-
- implicit def scalazMonadTransformerDsl1[F[_[_], _], H[_], G[_], A, B](
- implicit monadTrans: MonadTrans[F],
- rest: ScalazTransformerDsl[H, G, A, B]): ScalazTransformerDsl[H, F[G, ?], A, B] =
- new ScalazTransformerDsl[H, F[G, ?], A, B] {
-
- def monad: Monad[F[G, ?]] = monadTrans(rest.monad)
-
- def lift(fa: H[A]): F[G, A] = monadTrans.liftM(rest.lift(fa))(rest.monad)
-
- }
-
- implicit def scalazMonadTransformerDsl0[F[_[_], _], G[_], A, B](
- implicit monadTrans: MonadTrans[F],
- monad0: Monad[G]): ScalazTransformerDsl[G, F[G, ?], A, B] =
- new ScalazTransformerDsl[G, F[G, ?], A, B] {
- def monad = monadTrans(monad0)
-
- def lift(fa: G[A]): F[G, A] = monadTrans.liftM(fa)
-
- }
-
- implicit def scalazMonadicDsl[F[_], A, B](implicit bind: Bind[F]): Dsl[Monadic[F, A], F[B], A] =
- new Dsl[Monadic[F, A], F[B], A] {
- def cpsApply(keyword: Monadic[F, A], handler: A => F[B]): F[B] = {
- bind.bind(keyword.fa)(handler)
- }
- }
-
- abstract class ScalazTransformerDsl[F[_], G[_], A, B] extends Dsl[Monadic[F, A], G[B], A] {
- def monad: Monad[G]
-
- def lift(fa: F[A]): G[A]
-
- final def cpsApply(keyword: Monadic[F, A], handler: A => G[B]): G[B] = {
- monad.bind(lift(keyword.fa))(handler)
- }
-
- }
-
-}
diff --git a/domains-task/.js/build.sbt b/domains-task/.js/build.sbt
deleted file mode 120000
index 0569694f..00000000
--- a/domains-task/.js/build.sbt
+++ /dev/null
@@ -1 +0,0 @@
-../build.sbt
\ No newline at end of file
diff --git a/domains-task/.jvm/build.sbt b/domains-task/.jvm/build.sbt
deleted file mode 120000
index 0569694f..00000000
--- a/domains-task/.jvm/build.sbt
+++ /dev/null
@@ -1 +0,0 @@
-../build.sbt
\ No newline at end of file
diff --git a/domains-task/.jvm/jvm.sbt b/domains-task/.jvm/jvm.sbt
deleted file mode 100644
index 155e6c6c..00000000
--- a/domains-task/.jvm/jvm.sbt
+++ /dev/null
@@ -1,9 +0,0 @@
-enablePlugins(Example)
-
-import scala.meta._
-exampleSuperTypes := exampleSuperTypes.value.map {
- case ctor"_root_.org.scalatest.FreeSpec" =>
- ctor"_root_.org.scalatest.AsyncFreeSpec"
- case otherTrait =>
- otherTrait
-}
diff --git a/domains-task/.jvm/src/test/scala/com/thoughtworks/dsl/domains/RaiiSpec.scala b/domains-task/.jvm/src/test/scala/com/thoughtworks/dsl/domains/RaiiSpec.scala
deleted file mode 100644
index 5735af55..00000000
--- a/domains-task/.jvm/src/test/scala/com/thoughtworks/dsl/domains/RaiiSpec.scala
+++ /dev/null
@@ -1,258 +0,0 @@
-package com.thoughtworks.dsl
-package domains
-
-import com.thoughtworks.dsl.Dsl.{!!, Continuation, reset}
-import com.thoughtworks.dsl.keywords.{Catch, Shift, Yield}
-import org.scalatest.{FreeSpec, Matchers}
-import com.thoughtworks.dsl.domains.task._
-
-import scala.util.control.NonFatal
-
-/**
- * @author 杨博 (Yang Bo)
- */
-final class RaiiSpec extends FreeSpec with Matchers {
-
- @inline
- private def jvmCatch[Domain](eh: => Domain !! Throwable)(failureHandler: Throwable => Domain)(
- implicit shiftDsl: Dsl[Shift[Domain, Throwable], Domain, Throwable]): Domain = {
- val protectedContinuation: Domain !! Throwable = try {
- eh
- } catch {
- case NonFatal(e) =>
- return failureHandler(e)
- }
- shiftDsl.cpsApply(protectedContinuation, failureHandler)
- }
-
- /**
- * Exit the current scope then hang up
- */
- def successContinuation[LeftDomain](domain: LeftDomain): (LeftDomain !! Throwable) @reset = Continuation.empty(domain)
-
- def failureContinuation[LeftDomain](throwable: Throwable): (LeftDomain !! Throwable) @reset = Continuation.now(throwable)
-
- "Given a continuation that throws an exception" - {
- object MyException extends Exception
-
- "Given a generator" - {
-
- object MyException extends Exception
- def generator: Stream[Int] !! Throwable = {
- !Yield(1)
- throw {
- !Yield(2)
- MyException
- }
- !Yield(3)
- successContinuation(Stream.empty)
- }
-
- "When catching exception thrown from the generator" - {
- val catching = generator { e: Throwable =>
- e should be(MyException)
- Stream(100)
- }
- "Then it should contain all elements before throwing exception and the element when catching the exception" in {
- catching should be(Seq(1, 2, 100))
- }
- }
-
- }
- }
- "try/catch" - {
- "yield and catch" in {
- def continuation: Stream[Int] !! Throwable !! String = _ {
- val tryResult = try {
- 0 / 0
- } catch {
- case e: ArithmeticException =>
- !Yield(3)
- "catch"
- }
- "returns " + tryResult
- }
- continuation { result: String =>
- result should be("returns catch")
- successContinuation(Stream.empty)
- } { e =>
- Stream.empty
- } should be(Seq(3))
- }
-
- "simple catch" in {
-
- object MyException extends Exception
- def generator: Stream[String] !! Throwable !! Int = { continue =>
- try {
- !Yield("before catch")
- continue(43)
- } catch {
- case e: Throwable =>
- e should be(MyException)
- !Yield("catch")
- continue(42)
- }
- }
-
- object MyException2 extends Exception
-
- def generator2: Stream[String] !! Throwable = {
- import Throwable._
- val i = !Shift(generator)
- !Yield(i.toString)
- i should be(43)
- failureContinuation(MyException)
- }
-
- generator2 { e =>
- e should be(MyException)
-
- Stream("end")
- } should be(Stream("before catch", "43", "end"))
- }
-
- "issue 2" in {
- def continuation: Stream[Int] !! Throwable !! String = { continue =>
- !Yield(1)
- try {} catch {
- case e: ArithmeticException =>
- !Yield(2)
- }
- !Yield(3)
- failureContinuation(new ArithmeticException)
- }
-
- continuation { result: String =>
- failureContinuation(new AssertionError())
- } { e =>
- e should be(a[ArithmeticException])
- Stream.empty
- } should be(Stream(1, 3))
-
- }
-
- "empty finally" in {
- def continuation: Stream[Int] !! Throwable !! String = _ {
- val tryResult = try {
- 0 / 0
- !Yield(-1)
- } finally {}
- "returns " + tryResult
- }
-
- jvmCatch(continuation { result: String =>
- failureContinuation(new AssertionError())
- }) { e =>
- e should be(a[ArithmeticException])
- Stream.empty
- } should be(Seq())
- }
- "rethrow" in {
- def continuation: Stream[Int] !! Throwable !! String = _ {
- val tryResult = try {
- 0 / 0
- } catch {
- case e: ArithmeticException =>
- !Yield(42)
- throw e
- }
- "returns " + tryResult
- }
- continuation { result: String =>
- failureContinuation(new AssertionError())
- } { e =>
- e should be(a[ArithmeticException])
- Stream.empty
- } should be(Seq(42))
- }
-
- "complex" in {
- def continuation: Stream[Int] !! Throwable !! String = _ {
- !Yield(0)
- val tryResult = try {
- !Yield(1)
- try {} catch {
- case e: ArithmeticException =>
- !Yield(2)
- }
- !Yield(3)
-
- 0 / 0
- !Yield(4)
- "try"
- } catch {
- case e: ArithmeticException =>
- !Yield(5)
- "catch"
- } finally {
- !Yield(6)
-
- def ignoredFinalResult = "finally"
- ignoredFinalResult
- }
- !Yield(7)
- "returns " + tryResult
- }
-
- continuation { result: String =>
- result should be("returns catch")
- successContinuation(Stream.empty)
- } { e =>
- Stream.empty
- } should be(Seq(0, 1, 3, 5, 6, 7))
- }
- }
- //
-// "Given a continuation that throws an exception" - {
-// object MyException extends Exception
-//
-// "Given a generator" - {
-//
-// object MyException extends Exception
-// def generator: Throwable[Stream[Int]] = {
-// !Yield(1)
-// throw {
-// !Yield(2)
-// MyException
-// }
-// !Yield(3)
-// Throwable.success(Stream.empty)
-// }
-//
-// "When catching exception thrown from the generator" - {
-// val catching = generator.apply { e: Throwable =>
-// e should be(MyException)
-// Stream(100)
-// }
-// "Then it should contain all elements before throwing exception and the element when catching the exception" in {
-// catching should be(Seq(1, 2, 100))
-// }
-// }
-//
-// }
-// }
-//
-// "try/catch" - {
-// "yield and catch" in {
-// def continuation: Continuation[Throwable[Stream[Int]], String] = _ {
-// val tryResult = try {
-// 0 / 0
-// } catch {
-// case e: ArithmeticException =>
-// !Yield(3)
-// "catch"
-// }
-// "returns " + tryResult
-// }
-//
-// continuation.onComplete { r =>
-// r.get should be("returns catch")
-//
-// Stream(5)
-//
-// } should be(Stream(3, 5))
-// }
-// }
-
-}
diff --git a/domains-task/.jvm/src/test/scala/com/thoughtworks/dsl/domains/UsingSpec.scala b/domains-task/.jvm/src/test/scala/com/thoughtworks/dsl/domains/UsingSpec.scala
deleted file mode 100644
index a74536ef..00000000
--- a/domains-task/.jvm/src/test/scala/com/thoughtworks/dsl/domains/UsingSpec.scala
+++ /dev/null
@@ -1,53 +0,0 @@
-package com.thoughtworks.dsl
-package domains
-
-import com.thoughtworks.dsl.Dsl.{!!, Continuation, reset}
-import com.thoughtworks.dsl.keywords.{Using, Yield}
-import org.scalatest.{Assertion, FreeSpec, Matchers}
-
-/**
- * @author 杨博 (Yang Bo)
- */
-class UsingSpec extends FreeSpec with Matchers {
-
- def successContinuation[Domain](domain: Domain): (Domain !! Throwable) @reset = Continuation.empty(domain)
-
- "AutoCloseable" - {
-
- "scope" - {
-
- "arm" in {
- var isOpen = false
-
- def raii: Stream[Int] !! Throwable !! Assertion = Continuation.apply {
- !Yield(1)
- isOpen should be(false)
- val a = !Using {
- !Yield(2)
- new AutoCloseable {
- isOpen should be(false)
- isOpen = true
-
- def close(): Unit = {
- isOpen should be(true)
- isOpen = false
- }
- }
- }
- !Yield(3)
- isOpen should be(true)
- }
-
- isOpen should be(false)
-
- val myException = new Exception
-
- val stream = raii(_ => _ => Stream.empty)(throw _)
-
- stream should be(Stream(1, 2, 3))
- isOpen should be(false)
- }
- }
-
- }
-}
diff --git a/domains-task/.jvm/src/test/scala/com/thoughtworks/dsl/domains/taskSpec.scala b/domains-task/.jvm/src/test/scala/com/thoughtworks/dsl/domains/taskSpec.scala
deleted file mode 100644
index 16d30716..00000000
--- a/domains-task/.jvm/src/test/scala/com/thoughtworks/dsl/domains/taskSpec.scala
+++ /dev/null
@@ -1,207 +0,0 @@
-package com.thoughtworks.dsl
-package domains
-
-import com.thoughtworks.dsl.Dsl.{!!, reset}
-import org.scalatest.{Assertion, AsyncFreeSpec, Matchers}
-
-import com.thoughtworks.dsl.keywords.{Using, Each, Fork}
-import com.thoughtworks.dsl.domains.task._
-import com.thoughtworks.dsl.keywords.Shift.implicitShift
-
-import scala.collection.mutable.ArrayBuffer
-import scala.util.control.TailCalls
-import scala.util.{Failure, Success}
-
-/**
- * @author 杨博 (Yang Bo)
- */
-final class taskSpec extends AsyncFreeSpec with Matchers {
-
- "tailRecurision" in Task.toFuture(Task.apply {
- def loop(i: Int = 0, accumulator: Int = 0): task.Task[Int] = _ {
- if (i < 1000) {
- !loop(i + 1, accumulator + i)
- } else {
- accumulator
- }
- }
-
- val result = !loop()
- result should be(499500)
- })
-
- "taskToFuture" in Task.toFuture(Task.apply {
- succeed
- })
-
- "loop" in Task.toFuture(Task.apply {
-
- val task1: Task[Int] = Task.now(1)
-
- val ts = Task.join {
- !Fork(0 until 10) + !task1
- }
-
- !ts should be(1 until 11)
-
- })
-
- "try" in Task.toFuture(Task.apply {
- class MyException extends Exception
- val task1: Task[Int] = Task.apply {
- throw new MyException
- }
-
- val task2 = Task.apply {
- val v = try {
- !task1
- "no exception"
- } catch {
- case myException: MyException =>
- "my exception"
- }
-
- s"try: $v"
- }
-
- !task2 should be("try: my exception")
- })
-
- "empty try" in {
- val logs = ArrayBuffer.empty[String]
-
- class MyException extends Exception {
- logs += "MyException"
- }
- val task1: Task[String] = _ {
- throw new MyException
- }
-
- val task2: Task[String] = _ {
- try {
- "no exception"
- } catch {
- case myException: MyException =>
- "my exception"
- }
- !task1
- }
-
- Task.onComplete(task2) {
- case Success(s) =>
- logs += s
- throw new AssertionError()
- case Failure(e) =>
- e should be(a[MyException])
- logs += "uncaught MyException"
- }
- logs should be(ArrayBuffer("MyException", "uncaught MyException"))
- }
-
- "autoClose" in {
- val logs = ArrayBuffer.empty[Int]
-
- val task: Task[Unit] = Task.apply {
-
- logs += 0
-
- !Using(new AutoCloseable {
- logs += 10
- def close(): Unit = {
- logs += 20
- }
- })
- !Using(new AutoCloseable {
- logs += 11
- def close(): Unit = {
- logs += 21
- }
- })
- !Using(new AutoCloseable {
- logs += 12
- def close(): Unit = {
- logs += 22
- }
- })
-
- !Task.apply {
- logs += 3
-
- !Using(new AutoCloseable {
- logs += 40
- def close(): Unit = {
- logs += 50
- }
- })
- !Using(new AutoCloseable {
- logs += 41
- def close(): Unit = {
- logs += 51
- }
- })
- !Using(new AutoCloseable {
- logs += 42
- def close(): Unit = {
- logs += 52
- }
- })
-
- logs += 6
- }
-
- logs += 7
-
- }
-
- Task.toFuture(task).map { _ =>
- logs should be(ArrayBuffer(0, 10, 11, 12, 3, 40, 41, 42, 6, 52, 51, 50, 7, 22, 21, 20))
- }
-
- }
-
- "nested seq of task" in {
-
- def composeTask(t0: Task[Seq[Task[Seq[Task[Seq[Task[Seq[Float]]]]]]]]): Task[Seq[Seq[Seq[Seq[Float]]]]] = {
- // TODO: remove explicit type parameters when https://github.com/scala/bug/issues/11068 is fixed
- Task.join[Seq[Seq[Seq[Float]]], Seq[Seq[Seq[Seq[Float]]]]] {
- val t1 = !Each(!t0)
- !Task.join[Seq[Seq[Float]], Seq[Seq[Seq[Float]]]] {
- val t2 = !Each(!t1)
- !Task.join[Seq[Float], Seq[Seq[Float]]] {
- val t3 = !Each(!t2)
- !t3
- }
- }
- }
- }
-
- Task
- .toFuture(
- composeTask(Task.now(
- 1 to 2 map { i =>
- Task.now(1 to 3 map { j =>
- Task.now(1 to 4 map { k =>
- Task.now(1 to 5 map { l =>
- (i * 1000 + j * 100 + k * 10 + l).toFloat
- })
- })
- })
- }
- )))
- .map { s =>
- s should be(
- 1 to 2 map { i =>
- 1 to 3 map { j =>
- 1 to 4 map { k =>
- 1 to 5 map { l =>
- (i * 1000 + j * 100 + k * 10 + l).toFloat
- }
- }
- }
- }
- )
-
- }
-
- }
-}
diff --git a/domains-task/build.sbt b/domains-task/build.sbt
deleted file mode 100644
index 5e4c92b9..00000000
--- a/domains-task/build.sbt
+++ /dev/null
@@ -1,30 +0,0 @@
-libraryDependencies += "org.scala-lang" % "scala-reflect" % scalaVersion.value % Provided
-
-libraryDependencies += "org.scalatest" %%% "scalatest" % "3.0.6-SNAP2" % Optional
-
-scalacOptions in Compile ++= {
- scalaBinaryVersion.value match {
- case "2.11" => Some("–Xexperimental")
- case _ => None
- }
-}
-
-scalacOptions ++= {
- import Ordering.Implicits._
- if (VersionNumber(scalaVersion.value).numbers >= Seq(2L, 13L)) {
- Seq("-Ymacro-annotations")
- } else {
- Nil
- }
-}
-
-libraryDependencies ++= {
- import Ordering.Implicits._
- if (VersionNumber(scalaVersion.value).numbers >= Seq(2L, 13L)) {
- Nil
- } else {
- Seq(compilerPlugin("org.scalamacros" % "paradise" % "2.1.1" cross CrossVersion.full))
- }
-}
-
-libraryDependencies += "com.thoughtworks.enableIf" %% "enableif" % "1.1.6"
\ No newline at end of file
diff --git a/domains-task/src/main/scala/com/thoughtworks/dsl/domains/task.scala b/domains-task/src/main/scala/com/thoughtworks/dsl/domains/task.scala
deleted file mode 100644
index a35f15d7..00000000
--- a/domains-task/src/main/scala/com/thoughtworks/dsl/domains/task.scala
+++ /dev/null
@@ -1,191 +0,0 @@
-package com.thoughtworks.dsl
-package domains
-
-import com.thoughtworks.dsl.Dsl.{!!, Continuation, reset}
-import com.thoughtworks.dsl.keywords.Shift
-import com.thoughtworks.{enableIf, enableMembersIf}
-
-import scala.collection._
-import scala.collection.generic.CanBuildFrom
-import scala.collection.mutable.Builder
-import scala.concurrent.duration.Duration
-import scala.concurrent.{ExecutionContext, Future, Promise, SyncVar}
-import scala.util.control.{NonFatal, TailCalls}
-import scala.util.{Failure, Success, Try}
-import scala.util.control.TailCalls.TailRec
-
-/**
- * @author 杨博 (Yang Bo)
- */
-object task {
-
- type TaskDomain = TailRec[Unit] !! Throwable
-
- /** The asynchronous task that supports exception handling, resource management, and is stack-safe.
- *
- * @template
- * @example A [[Task]] can be created from `for`-comprehension,
- * where [[keywords.Each]] and [[keywords.Fork]] can be used together to asynchronously iterate collections.
- *
- * For example, the above `concatenateRemoteData` downloads and concatenates data from multiple URLs.
- *
- * {{{
- * import com.thoughtworks.dsl.comprehension._
- * import com.thoughtworks.dsl.keywords._
- * import com.thoughtworks.dsl.keywords.Shift._
- * import com.thoughtworks.dsl.domains.task.Task
- * import java.net.URL
- * def concatenateRemoteData(urls: List[URL], downloader: URL => Task[Vector[Byte]]): Task[Vector[Byte]] = {
- * for {
- * url <- Fork(urls)
- * data <- downloader(url)
- * byte <- Each(data)
- * } yield byte
- * }.as[Task[Vector[Byte]]]
- * }}}
- *
- * A [[Task]] can be also created from [[Task.apply]]
- *
- * {{{
- * def mockDownloader(url: URL) = Task {
- * "mock data\n".getBytes.toVector
- * }
- * }}}
- *
- * A [[Task]] can be then converted to [[scala.concurrent.Future]] via [[Task.toFuture]],
- * in order to integrate into other frameworks.
- *
- * In this example, it's a `Future[Assertion]` required by [[org.scalatest.AsyncFreeSpec]].
- *
- * {{{
- * val mockUrls = List(new URL("http://example.com/file1"), new URL("http://example.com/file2"))
- *
- * import org.scalatest.Assertion
- * def assertion: Task[Assertion] = Task {
- * !concatenateRemoteData(mockUrls, mockDownloader) should be("mock data\nmock data\n".getBytes.toVector)
- * }
- *
- * Task.toFuture(assertion)
- * }}}
- */
- type Task[+A] = TaskDomain !! A
-
- object Task {
-
- @inline
- def now[A](a: A): Task[A] = _(a)
-
- @inline
- def delay[A](f: () => A): Task[A] = _(f())
-
- @inline
- def apply[A](a: => A): Task[A] @reset = delay(a _)
-
- /** Returns a task that does nothing but let the succeeding tasks run on `executionContext`
- *
- * @example All the code after a `!switchExecutionContext` should be executed on `executionContext`
- * {{{
- * import com.thoughtworks.dsl.domains.task.Task
- * import org.scalatest.Assertion
- * import scala.concurrent.ExecutionContext
- * import com.thoughtworks.dsl.keywords.Shift.implicitShift
- * def myTask: Task[Assertion] = _ {
- * val originalThread = Thread.currentThread
- * !Task.switchExecutionContext(ExecutionContext.global)
- * Thread.currentThread should not be originalThread
- * }
- *
- * Task.toFuture(myTask)
- *
- * }}}
- */
- @inline
- def switchExecutionContext(executionContext: ExecutionContext): Task[Unit] = { continue => failureHandler =>
- executionContext.execute(new Runnable {
-
- @inline
- private def stackSafeRun(): TailRec[Unit] = {
- val protectedContinuation = try {
- continue(())
- } catch {
- case NonFatal(e) =>
- return failureHandler(e)
- }
- protectedContinuation(failureHandler)
- }
-
- def run(): Unit = stackSafeRun().result
-
- })
- TailCalls.done(())
- }
- @enableMembersIf(scala.util.Properties.versionNumberString.matches("""^2\.1(1|2)\..*$"""))
- private[task] object Scala211Or212 {
- type Factory[-A, +C] = scala.collection.generic.CanBuildFrom[Nothing, A, C]
-
- @inline
- def newBuilder[A, C](implicit factory: Factory[A, C]): Builder[A, C] = {
- factory()
- }
-
- }
-
- @enableMembersIf(scala.util.Properties.versionNumberString.matches("""^2\.13\..*$"""))
- private[task] object Scala213 {
-
- @inline
- def newBuilder[A, C](implicit factory: Factory[A, C]): Builder[A, C] = {
- factory.newBuilder
- }
-
- }
-
- import Scala211Or212._
- import Scala213._
-
- def join[Element, That](element: Element)(implicit factory: Factory[Element, That]): Task[That] @reset = now {
- (newBuilder[Element, That] += element).result()
- }
-
- def onComplete[A](task: Task[A])(continue: Try[A] => Unit) = {
- Continuation
- .toTryContinuation(task) { result =>
- TailCalls.done(continue(result))
- }
- .result
- }
-
- @enableIf(c => !c.compilerSettings.exists(_.matches("""^-Xplugin:.*scalajs-compiler_.*\.jar$""")))
- def blockingAwait[A](task: Task[A], timeout: Duration = Duration.Inf): A = {
- val syncVar = new SyncVar[Try[A]]
- Continuation
- .toTryContinuation(task) { result =>
- syncVar.put(result)
- TailCalls.done(())
- }
- .result
-
- if (timeout.isFinite()) {
- syncVar.take(timeout.toMillis).get
- } else {
- syncVar.take.get
- }
- }
-
- /** Converts a [[Task]] to a [[scala.concurrent.Future]].
- *
- * @see [[keywords.Await]] for converting a [[scala.concurrent.Future]] to a [[Task]].
- */
- def toFuture[A](task: Task[A]): Future[A] = {
- val promise = Promise[A]()
- Continuation
- .toTryContinuation(task) { tryResult =>
- promise.complete(tryResult)
- TailCalls.done(())
- }
- .result
- promise.future
- }
- }
-
-}
diff --git a/keywords-AsynchronousIo/.js/build.sbt b/keywords-AsynchronousIo/.js/build.sbt
deleted file mode 120000
index 0569694f..00000000
--- a/keywords-AsynchronousIo/.js/build.sbt
+++ /dev/null
@@ -1 +0,0 @@
-../build.sbt
\ No newline at end of file
diff --git a/keywords-AsynchronousIo/.jvm/build.sbt b/keywords-AsynchronousIo/.jvm/build.sbt
deleted file mode 120000
index 0569694f..00000000
--- a/keywords-AsynchronousIo/.jvm/build.sbt
+++ /dev/null
@@ -1 +0,0 @@
-../build.sbt
\ No newline at end of file
diff --git a/keywords-AsynchronousIo/.jvm/jvm.sbt b/keywords-AsynchronousIo/.jvm/jvm.sbt
deleted file mode 100644
index 3912b18c..00000000
--- a/keywords-AsynchronousIo/.jvm/jvm.sbt
+++ /dev/null
@@ -1,11 +0,0 @@
-enablePlugins(Example)
-
-import meta._
-exampleSuperTypes := exampleSuperTypes.value.map {
- case ctor"_root_.org.scalatest.FreeSpec" =>
- ctor"_root_.org.scalatest.AsyncFreeSpec"
- case otherTrait =>
- otherTrait
-}
-
-libraryDependencies += "org.scalatest" %%% "scalatest" % "3.0.6-SNAP2" % Test
diff --git a/keywords-AsynchronousIo/build.sbt b/keywords-AsynchronousIo/build.sbt
deleted file mode 100644
index 38ad40bd..00000000
--- a/keywords-AsynchronousIo/build.sbt
+++ /dev/null
@@ -1,9 +0,0 @@
-scalacOptions ++= {
- import Ordering.Implicits._
- if (VersionNumber(scalaVersion.value).numbers < Seq(2L, 12L)) {
- // Enable SAM types for Scala 2.11
- Some("-Xexperimental")
- } else {
- None
- }
-}
diff --git a/keywords-AsynchronousIo/src/main/scala/com/thoughtworks/dsl/keywords/AsynchronousIo.scala b/keywords-AsynchronousIo/src/main/scala/com/thoughtworks/dsl/keywords/AsynchronousIo.scala
deleted file mode 100644
index a32b7931..00000000
--- a/keywords-AsynchronousIo/src/main/scala/com/thoughtworks/dsl/keywords/AsynchronousIo.scala
+++ /dev/null
@@ -1,153 +0,0 @@
-package com.thoughtworks.dsl
-package keywords
-import java.net.SocketAddress
-import java.nio.ByteBuffer
-import java.nio.channels._
-
-import com.thoughtworks.dsl.Dsl.{!!, Keyword}
-
-import scala.util.control.NonFatal
-
-/** The base keyword to perform asynchronous IO in [[domains.task.Task]]s.
- *
- * @example The following `readAll` is a [[com.thoughtworks.dsl.domains.task.Task Task]] to read file content
- * with the help of [[AsynchronousIo.ReadFile]]
- *
- * {{{
- * import java.nio._, file._, channels._
- * import com.thoughtworks.dsl.domains.task.Task
- * import com.thoughtworks.dsl.keywords._
- * import com.thoughtworks.dsl.keywords.Shift._
- * import com.thoughtworks.dsl.keywords.AsynchronousIo.ReadFile
- * import scala.collection.mutable.ArrayBuffer
- * import scala.io.Codec
- * def readAll(channel: AsynchronousFileChannel, temporaryBufferSize: Int = 4096): Task[ArrayBuffer[CharBuffer]] = Task {
- * val charBuffers = ArrayBuffer.empty[CharBuffer]
- * val decoder = Codec.UTF8.decoder
- * val byteBuffer = ByteBuffer.allocate(temporaryBufferSize)
- * var position: Long = 0L
- * while (!ReadFile(channel, byteBuffer, position) != -1) {
- * position += byteBuffer.position()
- * byteBuffer.flip()
- * charBuffers += decoder.decode(byteBuffer)
- * byteBuffer.clear()
- * }
- * charBuffers
- * }
- * }}}
- *
- * `Task`s created from !-notation can be used in `for`-comprehension,
- * and other keywords can be used together in the same `for` block.
- *
- * For example, the following `cat` function contains a single `for` block to concatenate file contents.
- * It asynchronously iterates elements `Seq`, `ArrayBuffer` and `String` with the help of [[keywords.Each]],
- * managed native resources with the help of [[keywords.Using]],
- * performs previously created `readAll` task with the help of [[keywords.Shift]],
- * and finally converts the return type [[comprehension.ComprehensionOps.as as]] a `Task[Vector[Char]]`.
- *
- * {{{
- * import com.thoughtworks.dsl.comprehension._
- * import com.thoughtworks.dsl.keywords._
- * import com.thoughtworks.dsl.keywords.Shift._
- * import com.thoughtworks.dsl.domains.task.Task
- * import java.net.URL
- * def cat(paths: Path*) = {
- * for {
- * path <- Each(paths)
- * channel <- Using(AsynchronousFileChannel.open(path))
- * charBuffers <- readAll(channel)
- * charBuffer <- Each(charBuffers)
- * char <- Each(charBuffer.toString)
- * } yield char
- * }.as[Task[Vector[Char]]]
- * }}}
- *
- * Then the `cat` function is used to concatenate files from this project, as shown below:
- *
- * {{{
- * Task.toFuture(Task {
- * (!cat(Paths.get(".sbtopts"), Paths.get(".scalafmt.conf"))).mkString should be(
- * "-J-XX:MaxMetaspaceSize=512M\n-J-Xmx5G\n-J-Xss6M\nversion = \"1.5.1\"\nmaxColumn = 120"
- * )
- * })
- * }}}
- */
-trait AsynchronousIo[Value] extends Any with Keyword[AsynchronousIo[Value], Value] {
-
- /** Starts the asynchronous operations */
- protected def start[Attachment](attachment: Attachment, handler: CompletionHandler[Value, _ >: Attachment]): Unit
-}
-
-object AsynchronousIo {
-
- final case class Connect(socket: AsynchronousSocketChannel, remote: SocketAddress) extends AsynchronousIo[Void] {
- protected def start[Attachment](attachment: Attachment, handler: CompletionHandler[Void, _ >: Attachment]): Unit = {
- socket.connect(remote, attachment, handler)
- }
- }
-
- final case class Accept(socket: AsynchronousServerSocketChannel)
- extends AnyVal
- with AsynchronousIo[AsynchronousSocketChannel] {
- protected def start[Attachment](attachment: Attachment,
- handler: CompletionHandler[AsynchronousSocketChannel, _ >: Attachment]): Unit = {
- socket.accept(attachment, handler)
- }
- }
-
- final case class ReadFile(channel: AsynchronousFileChannel, destination: ByteBuffer, position: Long)
- extends AsynchronousIo[Integer] {
- protected def start[Attachment](attachment: Attachment,
- handler: CompletionHandler[Integer, _ >: Attachment]): Unit = {
- channel.read(destination, position, attachment, handler)
- }
- }
-
- final case class WriteFile(channel: AsynchronousFileChannel, source: ByteBuffer, position: Long)
- extends AsynchronousIo[Integer] {
- protected def start[Attachment](attachment: Attachment,
- handler: CompletionHandler[Integer, _ >: Attachment]): Unit = {
- channel.write(source, position, attachment, handler)
- }
- }
-
- final case class Read(channel: AsynchronousByteChannel, destination: ByteBuffer) extends AsynchronousIo[Integer] {
- protected def start[Attachment](attachment: Attachment,
- handler: CompletionHandler[Integer, _ >: Attachment]): Unit = {
- channel.read(destination, attachment, handler)
- }
- }
-
- final case class Write(channel: AsynchronousByteChannel, source: ByteBuffer) extends AsynchronousIo[Integer] {
- private[dsl] def destination = source
-
- protected def start[Attachment](attachment: Attachment,
- handler: CompletionHandler[Integer, _ >: Attachment]): Unit = {
- channel.write(source, attachment, handler)
- }
- }
-
- private def completionHandler[Value](successHandler: Value => (Unit !! Throwable)) = {
- new CompletionHandler[Value, Throwable => Unit] {
- def failed(exc: Throwable, failureHandler: Throwable => Unit): Unit = {
- failureHandler(exc)
- }
-
- def completed(result: Value, failureHandler: Throwable => Unit): Unit = {
- val protectedContinuation = try {
- successHandler(result)
- } catch {
- case NonFatal(e) =>
- val () = failureHandler(e)
- return
- }
- protectedContinuation(failureHandler)
- }
- }
- }
-
- implicit def asynchronousIoDsl[Value]: Dsl[AsynchronousIo[Value], Unit !! Throwable, Value] = { (keyword, handler) =>
- keyword.start(_, completionHandler(handler))
- }
-
-}
diff --git a/keywords-Await/.js/build.sbt b/keywords-Await/.js/build.sbt
deleted file mode 120000
index 0569694f..00000000
--- a/keywords-Await/.js/build.sbt
+++ /dev/null
@@ -1 +0,0 @@
-../build.sbt
\ No newline at end of file
diff --git a/keywords-Await/.jvm/build.sbt b/keywords-Await/.jvm/build.sbt
deleted file mode 120000
index 0569694f..00000000
--- a/keywords-Await/.jvm/build.sbt
+++ /dev/null
@@ -1 +0,0 @@
-../build.sbt
\ No newline at end of file
diff --git a/keywords-Await/.jvm/jvm.sbt b/keywords-Await/.jvm/jvm.sbt
deleted file mode 100644
index b0e5027b..00000000
--- a/keywords-Await/.jvm/jvm.sbt
+++ /dev/null
@@ -1,22 +0,0 @@
-import Ordering.Implicits._
-
-libraryDependencies ++= {
- if (VersionNumber(scalaVersion.value).numbers >= Seq(2L, 13L)) {
- Nil
- } else {
- Seq(
- "com.typesafe.akka" %% "akka-actor" % "2.5.14" % Test,
- "com.typesafe.akka" %% "akka-stream" % "2.5.14" % Test,
- "com.typesafe.akka" %% "akka-http" % "10.1.3" % Test
- )
- }
-}
-
-// Skip tests in Scala 2.13 because Akka does not support Scala 2.13 yet
-unmanagedSourceDirectories in Test --= {
- if (VersionNumber(scalaVersion.value).numbers >= Seq(2L, 13L)) {
- Seq((scalaSource in Test).value)
- } else {
- Nil
- }
-}
diff --git a/keywords-Await/.jvm/src/test/scala/com/thoughtworks/dsl/keywords/AwaitSpec.scala b/keywords-Await/.jvm/src/test/scala/com/thoughtworks/dsl/keywords/AwaitSpec.scala
deleted file mode 100644
index 2c179913..00000000
--- a/keywords-Await/.jvm/src/test/scala/com/thoughtworks/dsl/keywords/AwaitSpec.scala
+++ /dev/null
@@ -1,114 +0,0 @@
-package com.thoughtworks.dsl.keywords
-
-import akka.actor.ActorSystem
-import akka.http.scaladsl.Http
-import akka.http.scaladsl.model.Uri.Path
-import akka.http.scaladsl.model._
-import akka.http.scaladsl.server._
-import akka.stream.ActorMaterializer
-import akka.util.ByteString
-import com.thoughtworks.dsl.Dsl.reset
-import org.scalatest.{AsyncFreeSpec, BeforeAndAfterAll, Matchers}
-//import org.scalamock.scalatest.MockFactory
-
-import scala.concurrent.Future
-import scala.concurrent.duration._
-
-/**
- * @author 杨博 (Yang Bo)
- */
-final class AwaitSpec extends AsyncFreeSpec with Matchers with BeforeAndAfterAll with Directives {
- implicit val system = ActorSystem()
-
- implicit val materializer = ActorMaterializer()
-
- def downloadTwoPages(): Future[(ByteString, ByteString)] = Future {
- val response1 = !Await(Http().singleRequest(HttpRequest(HttpMethods.GET, !Await(pingUri))))
- val content1 = !Await(response1.entity.toStrict(timeout = 5.seconds))
- val response2 = !Await(Http().singleRequest(HttpRequest(HttpMethods.GET, !Await(pongUri))))
- val content2 = !Await(response2.entity.toStrict(timeout = 5.seconds))
- (content1.data, content2.data)
- }
-
- private val mockServer = {
- val route =
- get {
- path("ping") {
- complete("PING!")
- } ~ path("pong") {
- complete("PONG!")
- }
- }
- Http().bindAndHandle(route, "localhost", 0)
- }
- override protected def afterAll(): Unit = {
- val _ = Future {
- val binding = !Await(mockServer)
- !Await(binding.unbind())
- system.terminate()
- }: @reset
- }
-
- "download two pages" in {
- downloadTwoPages().map {
- case (bytes1, bytes2) =>
- bytes1.decodeString(io.Codec.UTF8.charSet) should be("PING!")
- bytes2.decodeString(io.Codec.UTF8.charSet) should be("PONG!")
- }
- }
-
- private def pingUri = Future {
- Uri.from(scheme = "http",
- host = (!Await(mockServer)).localAddress.getHostName,
- port = (!Await(mockServer)).localAddress.getPort,
- path = "/ping")
- }
-
- private def pongUri = Future {
- Uri.from(scheme = "http",
- host = (!Await(mockServer)).localAddress.getHostName,
- port = (!Await(mockServer)).localAddress.getPort,
- path = "/pong")
- }
-
- "http get" in ({
- val response = !Await(Http().singleRequest(HttpRequest(uri = !Await(pingUri))))
- response.status should be(StatusCodes.OK)
- }: @reset)
-
- "Downloading two web pages as an asynchronous generator, in the style of !-notation" in ({
- def downloadTwoPagesGenerator(): Stream[Future[ByteString]] = {
- val response1 = !Await(Http().singleRequest(HttpRequest(HttpMethods.GET, !Await(pingUri))))
- val content1 = !Await(response1.entity.toStrict(timeout = 5.seconds))
- !Yield(content1.data)
- val response2 = !Await(Http().singleRequest(HttpRequest(HttpMethods.GET, !Await(pongUri))))
- val content2 = !Await(response2.entity.toStrict(timeout = 5.seconds))
- !Yield(content2.data)
-
- Stream.empty[Future[ByteString]]
- }
-
- val stream = downloadTwoPagesGenerator()
- (!Await(stream(0))).decodeString(io.Codec.UTF8.charSet) should be("PING!")
- (!Await(stream(1))).decodeString(io.Codec.UTF8.charSet) should be("PONG!")
- }: @reset)
-
- "multiple http" in ({
-
- def createAsynchronousStream(): Stream[Future[Int]] = {
- val response1 = !Await(Http().singleRequest(HttpRequest(uri = !Await(pingUri))))
- !Yield(response1.status.intValue())
- response1.discardEntityBytes()
- val response2 = !Await(Http().singleRequest(HttpRequest(uri = !Await(pongUri))))
- !Yield(response2.status.intValue())
- response2.discardEntityBytes()
- Stream.empty[Future[Int]]
- }
-
- val asynchronousStream = createAsynchronousStream()
- !Await(asynchronousStream(0)) should be(StatusCodes.OK.intValue)
- !Await(asynchronousStream(1)) should be(StatusCodes.OK.intValue)
-
- }: @reset)
-
-}
diff --git a/keywords-Await/build.sbt b/keywords-Await/build.sbt
deleted file mode 100644
index e98b04fa..00000000
--- a/keywords-Await/build.sbt
+++ /dev/null
@@ -1,11 +0,0 @@
-enablePlugins(Example)
-
-import scala.meta._
-exampleSuperTypes := exampleSuperTypes.value.map {
- case ctor"_root_.org.scalatest.FreeSpec" =>
- ctor"_root_.org.scalatest.AsyncFreeSpec"
- case otherTrait =>
- otherTrait
-}
-
-libraryDependencies += "org.scalatest" %%% "scalatest" % "3.0.6-SNAP2" % Test
diff --git a/keywords-Await/src/main/scala/com/thoughtworks/dsl/keywords/Await.scala b/keywords-Await/src/main/scala/com/thoughtworks/dsl/keywords/Await.scala
deleted file mode 100644
index b88206ec..00000000
--- a/keywords-Await/src/main/scala/com/thoughtworks/dsl/keywords/Await.scala
+++ /dev/null
@@ -1,135 +0,0 @@
-package com.thoughtworks.dsl.keywords
-
-import com.thoughtworks.dsl.Dsl
-import com.thoughtworks.dsl.Dsl.{!!, Keyword}
-
-import scala.concurrent.Await.result
-import scala.concurrent.duration.Duration
-import scala.concurrent.{ExecutionContext, Future}
-import scala.language.implicitConversions
-
-/** [[Await]] is a [[Dsl.Keyword Keyword]] to extract value from a [[scala.concurrent.Future]].
- *
- * This keyword is available in functions whose return types are
- * [[scala.concurrent.Future Future]], [[domains.task.Task]],
- * or any exception aware continuations as `(_ !! Throwable !! _)`.
- *
- * @example Given a [[scala.concurrent.Future Future]]:
- * {{{
- * import scala.concurrent.Future
- * val myFuture40 = Future {
- * 40
- * }
- * }}}
- *
- * You can [[Await]] the [[scala.concurrent.Future Future]] in another [[scala.concurrent.Future Future]]
- *
- * {{{
- * def myFuture42 = Future {
- * !Await(myFuture40) + 2
- * }
- * }}}
- *
- * A [[scala.concurrent.Future Future]] can be converted to a [[domains.task.Task]]
- * with the help of [[Await]].
- *
- * {{{
- * import com.thoughtworks.dsl.domains.task.Task
- * import com.thoughtworks.dsl.keywords.Await
- * val myTask = Task {
- * !Await(myFuture42)
- * }
- * }}}
- *
- * Then a [[domains.task.Task]] can be converted back to a [[scala.concurrent.Future]]
- * via [[domains.task.Task.toFuture]].
- *
- * {{{
- * val myAssertionTask = Task {
- * !Shift(myTask) should be(42)
- * }
- * Task.toFuture(myAssertionTask)
- * }}}
- * @example `!Await` can be used together with `try` / `catch` / `finally`.
- * {{{
- * import scala.concurrent.Future
- * val buffer = new StringBuffer
- * def recoverFuture = Future {
- * buffer.append("Oh")
- * }
- * def exceptionalFuture = Future[StringBuffer] {
- * throw new IllegalStateException("No")
- * }
- * def myFuture = Future {
- * try {
- * !Await(exceptionalFuture)
- * } catch {
- * case e: IllegalStateException =>
- * !Await(recoverFuture)
- * buffer.append(' ')
- * buffer.append(e.getMessage)
- * } finally {
- * buffer.append("!")
- * }
- * }
- * myFuture.map(_.toString should be("Oh No!"))
- * }}}
- * @example Other keywords, including [[Return]] or [[Get]], can be used together with [[Await]]
- * {{{
- * import scala.concurrent.Future
- * import com.thoughtworks.dsl.keywords.{Get, Return}
- * val buffer = new StringBuffer
- * def recoverFuture = Future {
- * buffer.append("Oh")
- * }
- * def exceptionalFuture = Future[StringBuffer] {
- * throw new IllegalStateException("No")
- * }
- * def myFuture: Char => Future[StringBuffer] = !Return {
- * try {
- * !Await(exceptionalFuture)
- * } catch {
- * case e: IllegalStateException =>
- * !Await(recoverFuture)
- * buffer.append(!Get[Char])
- * buffer.append(e.getMessage)
- * } finally {
- * buffer.append("!")
- * }
- * }
- * myFuture(' ').map(_.toString should be("Oh No!"))
- * }}}
- * @author 杨博 (Yang Bo)
- */
-final case class Await[Value](future: Future[Value]) extends AnyVal with Keyword[Await[Value], Value]
-
-object Await {
-
- implicit def implicitAwait[Value](future: Future[Value]): Await[Value] = Await[Value](future)
-
- implicit def streamAwaitDsl[Value, That](
- implicit executionContext: ExecutionContext): Dsl[Await[Value], Stream[Future[That]], Value] =
- new Dsl[Await[Value], Stream[Future[That]], Value] {
- def cpsApply(keyword: Await[Value], handler: Value => Stream[Future[That]]): Stream[Future[That]] = {
- import keyword.future
- val futureOfStream = future.map(handler)
- new Stream.Cons(futureOfStream.flatMap(_.head), result(futureOfStream, Duration.Inf).tail)
- }
- }
-
- implicit def awaitDsl[Value, That](
- implicit executionContext: ExecutionContext): Dsl[Await[Value], Future[That], Value] =
- new Dsl[Await[Value], Future[That], Value] {
- def cpsApply(keyword: Await[Value], handler: Value => Future[That]): Future[That] = {
- keyword.future.flatMap(handler)
- }
- }
-
- implicit def continuationAwaitDsl[Value](
- implicit executionContext: ExecutionContext): Dsl[Await[Value], Unit !! Throwable, Value] =
- new Dsl[Await[Value], Unit !! Throwable, Value] {
- def cpsApply(keyword: Await[Value], handler: Value => Unit !! Throwable): Unit !! Throwable =
- !!.fromTryContinuation(keyword.future.onComplete)(handler)
- }
-
-}
diff --git a/keywords-Catch/.js/build.sbt b/keywords-Catch/.js/build.sbt
deleted file mode 120000
index 0569694f..00000000
--- a/keywords-Catch/.js/build.sbt
+++ /dev/null
@@ -1 +0,0 @@
-../build.sbt
\ No newline at end of file
diff --git a/keywords-Catch/.jvm/build.sbt b/keywords-Catch/.jvm/build.sbt
deleted file mode 120000
index 0569694f..00000000
--- a/keywords-Catch/.jvm/build.sbt
+++ /dev/null
@@ -1 +0,0 @@
-../build.sbt
\ No newline at end of file
diff --git a/keywords-Catch/build.sbt b/keywords-Catch/build.sbt
deleted file mode 100644
index a368460f..00000000
--- a/keywords-Catch/build.sbt
+++ /dev/null
@@ -1,12 +0,0 @@
-libraryDependencies += "org.scala-lang" % "scala-reflect" % scalaVersion.value % Provided
-
-libraryDependencies += "org.scalatest" %%% "scalatest" % "3.0.6-SNAP2" % Test
-
-scalacOptions in Compile ++= {
- scalaBinaryVersion.value match {
- case "2.11" => Seq("–Xexperimental")
- case _ => Seq.empty
- }
-}
-
-libraryDependencies += "com.thoughtworks.extractor" %%% "extractor" % "2.1.1"
diff --git a/keywords-Catch/src/main/scala/com/thoughtworks/dsl/keywords/Catch.scala b/keywords-Catch/src/main/scala/com/thoughtworks/dsl/keywords/Catch.scala
deleted file mode 100644
index dbaa93b3..00000000
--- a/keywords-Catch/src/main/scala/com/thoughtworks/dsl/keywords/Catch.scala
+++ /dev/null
@@ -1,206 +0,0 @@
-package com.thoughtworks.dsl.keywords
-
-import com.thoughtworks.Extractor._
-import com.thoughtworks.dsl.Dsl
-import com.thoughtworks.dsl.Dsl.{!!, Continuation, Keyword}
-import com.thoughtworks.dsl.keywords.Catch.{CatchDsl, DslCatch}
-
-import scala.annotation.implicitNotFound
-import scala.concurrent.{ExecutionContext, Future}
-import scala.util.control.Exception.Catcher
-import scala.util.control.NonFatal
-
-/**
- * @author 杨博 (Yang Bo)
- */
-final case class Catch[Domain, Value](block: Domain !! Value, catcher: Catcher[Domain !! Value])
- extends Keyword[Catch[Domain, Value], Value]
-
-private[keywords] trait LowPriorityCatch1 { this: Catch.type =>
- @deprecated("Use Dsl[Catch[...], ...] as implicit parameters instead of CatchDsl[...]", "Dsl.scala 1.2.0")
- private[keywords] def liftFunction1CatchDsl[InnerDomain, OuterDomain, State, Value](
- implicit leftCatchDsl: CatchDsl[InnerDomain, OuterDomain, Value])
- : CatchDsl[State => InnerDomain, State => OuterDomain, Value] = {
- new LiftFunction1CatchDsl
- }
-
- implicit def liftFunction1CatchDsl[InnerDomain, OuterDomain, State, Value](
- implicit leftCatchDsl: DslCatch[InnerDomain, OuterDomain, Value])
- : DslCatch[State => InnerDomain, State => OuterDomain, Value] = {
- new LiftFunction1CatchDsl
- }
-}
-
-private[keywords] trait LowPriorityCatch0 extends LowPriorityCatch1 { this: Catch.type =>
-
- implicit def liftContinuationCatchDsl[LeftDomain, RightDomain, Value](
- implicit leftCatchDsl: DslCatch[LeftDomain, LeftDomain, Value])
- : CatchDsl[LeftDomain !! Value, LeftDomain !! RightDomain, Value] = {
- new LiftContinuationCatchDsl
- }
-
- @deprecated("Use Dsl[Catch[...], ...] as implicit parameters instead of CatchDsl[...]", "Dsl.scala 1.2.0")
- private[keywords] def liftContinuationCatchDsl[LeftDomain, RightDomain, Value](
- implicit leftCatchDsl: CatchDsl[LeftDomain, LeftDomain, Value])
- : CatchDsl[LeftDomain !! Value, LeftDomain !! Nothing, Value] = {
- new LiftContinuationCatchDsl
- }
-}
-
-object Catch extends LowPriorityCatch0 {
-
- type DslCatch[InnerDomain, OuterDomain, Value] = Dsl[Catch[InnerDomain, Value], OuterDomain, Value]
-
- @implicitNotFound("Use Dsl[Catch[...], ...] as implicit parameters instead of CatchDsl[...]")
- private[dsl] trait CatchDsl[InnerDomain, OuterDomain, Value] extends DslCatch[InnerDomain, OuterDomain, Value] {
-
- def tryCatch(block: InnerDomain !! Value,
- catcher: Catcher[InnerDomain !! Value],
- handler: Value => OuterDomain): OuterDomain
-
- @inline final def cpsApply(keyword: Catch[InnerDomain, Value], handler: Value => OuterDomain): OuterDomain = {
- tryCatch(keyword.block, keyword.catcher, handler)
- }
- }
-
- @inline
- def tryCatch[InnerDomain, OuterDomain, Value](finalizer: Value => OuterDomain)(
- implicit catchDsl: DslCatch[InnerDomain, OuterDomain, Value])
- : (InnerDomain !! Value, Catcher[InnerDomain !! Value]) => OuterDomain = {
- (block: InnerDomain !! Value, catcher: Catcher[InnerDomain !! Value]) =>
- catchDsl.cpsApply(Catch(block, catcher), finalizer)
- }
-
- @deprecated("Use Dsl[Catch[...], ...] as implicit parameters instead of CatchDsl[...]", "Dsl.scala 1.2.0")
- private[Catch] def tryCatch[InnerDomain, OuterDomain, Value](finalizer: Value => OuterDomain)(
- implicit catchDsl: CatchDsl[InnerDomain, OuterDomain, Value]) = {
- (block: InnerDomain !! Value, catcher: Catcher[InnerDomain !! Value]) =>
- catchDsl.tryCatch(block, catcher, finalizer)
- }
-
- implicit def futureCatchDsl[InnerValue, OuterValue](
- implicit executionContext: ExecutionContext): CatchDsl[Future[InnerValue], Future[OuterValue], InnerValue] =
- new CatchDsl[Future[InnerValue], Future[OuterValue], InnerValue] {
- def tryCatch(block: Future[InnerValue] !! InnerValue,
- catcher: Catcher[Future[InnerValue] !! InnerValue],
- handler: InnerValue => Future[OuterValue]): Future[OuterValue] = {
- val fa = Future(block).flatMap(_(Future.successful))
-
- val protectedFa = fa.recoverWith(catcher.andThen { recovered =>
- try {
- recovered(Future.successful)
- } catch {
- case NonFatal(e) =>
- Future.failed(e)
- }
- })
- protectedFa.flatMap { outerValue =>
- try {
- handler(outerValue)
- } catch {
- case NonFatal(e) =>
- Future.failed(e)
- }
- }
- }
- }
-
- implicit def throwableCatchDsl[LeftDomain, Value](
- implicit shiftDsl: Dsl[Shift[LeftDomain, Throwable], LeftDomain, Throwable])
- : CatchDsl[LeftDomain !! Throwable, LeftDomain !! Throwable, Value] =
- new CatchDsl[LeftDomain !! Throwable, LeftDomain !! Throwable, Value] {
- @inline
- def tryCatch(block: LeftDomain !! Throwable !! Value,
- catcher: Catcher[LeftDomain !! Throwable !! Value],
- handler: Value => LeftDomain !! Throwable): LeftDomain !! Throwable = {
- new (LeftDomain !! Throwable) {
- def apply(outerFailureHandler: Throwable => LeftDomain): LeftDomain = {
-
- def recover(e: Throwable): LeftDomain = {
- e match {
- case catcher.extract(recovered) =>
- val outerContinuation = try {
- recovered(handler)
- } catch {
- case NonFatal(e) =>
- return outerFailureHandler(e)
- }
- outerContinuation(outerFailureHandler)
- case e =>
- outerFailureHandler(e)
- }
- }
-
- val protectedContinuation = try {
- block { value =>
- new (LeftDomain !! Throwable) {
- def apply(ignored: Throwable => LeftDomain): LeftDomain = {
- val rest = try {
- handler(value)
- } catch {
- case NonFatal(e) =>
- return outerFailureHandler(e)
- }
- rest(outerFailureHandler)
- }
- }
- }
- } catch {
- case NonFatal(e) =>
- return recover(e)
- }
- shiftDsl.cpsApply(protectedContinuation, recover)
- }
-
- }
-
- }
- }
-
- private[keywords] class LiftContinuationCatchDsl[LeftDomain, RightDomain, Value](
- implicit leftCatchDsl: DslCatch[LeftDomain, LeftDomain, Value])
- extends CatchDsl[LeftDomain !! Value, LeftDomain !! RightDomain, Value] {
- def tryCatch(block: LeftDomain !! Value !! Value,
- catcher: Catcher[LeftDomain !! Value !! Value],
- handler: Value => LeftDomain !! RightDomain): LeftDomain !! RightDomain = { outerHandler =>
- leftCatchDsl.cpsApply(
- Catch(
- block = block(Continuation.now),
- catcher = {
- case catcher.extract(recoveredValueContinuation) =>
- recoveredValueContinuation(Continuation.now)
- }
- ),
- handler = { value: Value =>
- handler(value)(outerHandler)
- }
- )
- }
- }
-
- private[keywords] class LiftFunction1CatchDsl[InnerDomain, OuterDomain, State, Value](
- implicit leftCatchDsl: DslCatch[InnerDomain, OuterDomain, Value])
- extends CatchDsl[State => InnerDomain, State => OuterDomain, Value] {
- def tryCatch(block: (State => InnerDomain) !! Value,
- catcher: Catcher[(State => InnerDomain) !! Value],
- handler: Value => State => OuterDomain): State => OuterDomain = { state =>
- leftCatchDsl.cpsApply(
- Catch(
- block = { (continue: Value => InnerDomain) =>
- block { value: Value => _ =>
- continue(value)
- }(state)
- },
- catcher = {
- case catcher.extract(recoveredValueContinuation) =>
- continue =>
- recoveredValueContinuation { value: Value => _ =>
- continue(value)
- }(state)
- }
- ),
- handler = handler(_)(state)
- )
- }
- }
-}
diff --git a/keywords-Continue/.js/build.sbt b/keywords-Continue/.js/build.sbt
deleted file mode 120000
index 0569694f..00000000
--- a/keywords-Continue/.js/build.sbt
+++ /dev/null
@@ -1 +0,0 @@
-../build.sbt
\ No newline at end of file
diff --git a/keywords-Continue/.jvm/build.sbt b/keywords-Continue/.jvm/build.sbt
deleted file mode 120000
index 0569694f..00000000
--- a/keywords-Continue/.jvm/build.sbt
+++ /dev/null
@@ -1 +0,0 @@
-../build.sbt
\ No newline at end of file
diff --git a/keywords-Continue/build.sbt b/keywords-Continue/build.sbt
deleted file mode 100644
index a72b81d7..00000000
--- a/keywords-Continue/build.sbt
+++ /dev/null
@@ -1,21 +0,0 @@
-enablePlugins(Example)
-
-libraryDependencies += "org.scalatest" %%% "scalatest" % "3.0.6-SNAP2" % Test
-
-scalacOptions ++= {
- import Ordering.Implicits._
- if (VersionNumber(scalaVersion.value).numbers >= Seq(2L, 13L)) {
- Seq("-Ymacro-annotations")
- } else {
- Nil
- }
-}
-
-libraryDependencies ++= {
- import Ordering.Implicits._
- if (VersionNumber(scalaVersion.value).numbers >= Seq(2L, 13L)) {
- Nil
- } else {
- Seq(compilerPlugin("org.scalamacros" % "paradise" % "2.1.1" cross CrossVersion.full))
- }
-}
diff --git a/keywords-Continue/src/main/scala/com/thoughtworks/dsl/keywords/Continue.scala b/keywords-Continue/src/main/scala/com/thoughtworks/dsl/keywords/Continue.scala
deleted file mode 100644
index c0eb6b29..00000000
--- a/keywords-Continue/src/main/scala/com/thoughtworks/dsl/keywords/Continue.scala
+++ /dev/null
@@ -1,90 +0,0 @@
-package com.thoughtworks.dsl.keywords
-
-import com.thoughtworks.dsl.Dsl
-import com.thoughtworks.dsl.Dsl.{!!, Keyword}
-import com.thoughtworks.enableMembersIf
-
-import scala.language.implicitConversions
-import scala.language.higherKinds
-import scala.util.control.TailCalls
-import scala.util.control.TailCalls.TailRec
-import scala.collection._
-
-/** The base type of [[Continue$ Continue]] keyword.
- *
- * @see The [[Continue$ Continue]] object, which is the only instance of this [[Continue]] class.
- */
-sealed class Continue extends Keyword[Continue, Nothing]
-
-/** A keyword to skip the current iteration in a collection comprehension block.
- *
- * @note This [[Continue$ Continue]] keyword is usually used with [[Each]], to skip an element in the loop.
- * @see [[Each]] for creating collection comprehensions.
- * @example [[Each]] and [[Continue$ Continue]] can be used to calculate composite numbers and prime numbers.
- *
- * {{{
- * def compositeNumbersBelow(maxNumber: Int) = collection.immutable.HashSet {
- * val factor = !Each(2 until math.ceil(math.sqrt(maxNumber)).toInt)
- * !Each(2 * factor until maxNumber by factor)
- * }
- *
- * compositeNumbersBelow(13) should be(Set(4, 6, 8, 9, 10, 12))
- *
- * def primeNumbersBelow(maxNumber: Int) = Seq {
- * val compositeNumbers = compositeNumbersBelow(maxNumber)
- * val i = !Each(2 until maxNumber)
- * if (compositeNumbers(i)) !Continue
- * i
- * }
- *
- * primeNumbersBelow(13) should be(Array(2, 3, 5, 7, 11))
- * }}}
- * @author 杨博 (Yang Bo)
- */
-case object Continue extends Continue with Keyword[Continue, Nothing] {
-
- implicit def continueUnitDsl[Value]: Dsl[Continue, Unit, Value] = new Dsl[Continue, Unit, Value] {
- def cpsApply(keyword: Continue, handler: Value => Unit): Unit = ()
- }
-
- @enableMembersIf(scala.util.Properties.versionNumberString.matches("""^2\.1(1|2)\..*$"""))
- private[dsl] object Scala211Or212 {
- type Factory[-A, +C] = scala.collection.generic.CanBuildFrom[Nothing, A, C]
-
- @inline
- def empty[A, C](implicit factory: Factory[A, C]): C = {
- factory().result()
- }
-
- }
-
- @enableMembersIf(scala.util.Properties.versionNumberString.matches("""^2\.13\..*$"""))
- private[dsl] object Scala213 {
-
- @inline
- def empty[A, C](implicit factory: Factory[A, C]): C = {
- factory.newBuilder.result()
- }
-
- }
-
- import Scala211Or212._
- import Scala213._
-
- implicit def collectionContinueDsl[Value, Element, Collection[_]](
- implicit factory: Factory[Element, Collection[Element]]): Dsl[Continue, Collection[Element], Value] =
- new Dsl[Continue, Collection[Element], Value] {
- def cpsApply(keyword: Continue, handler: Value => Collection[Element]): Collection[Element] = {
- empty[Element, Collection[Element]]
- }
- }
-
- implicit def OptionContinueDsl[Value, Element](
- implicit factory: Factory[Element, Option[Element]]): Dsl[Continue, Option[Element], Value] =
- new Dsl[Continue, Option[Element], Value] {
- def cpsApply(keyword: Continue, handler: Value => Option[Element]): Option[Element] = {
- None
- }
- }
-
-}
diff --git a/keywords-Each/.js/build.sbt b/keywords-Each/.js/build.sbt
deleted file mode 120000
index 0569694f..00000000
--- a/keywords-Each/.js/build.sbt
+++ /dev/null
@@ -1 +0,0 @@
-../build.sbt
\ No newline at end of file
diff --git a/keywords-Each/.jvm/build.sbt b/keywords-Each/.jvm/build.sbt
deleted file mode 120000
index 0569694f..00000000
--- a/keywords-Each/.jvm/build.sbt
+++ /dev/null
@@ -1 +0,0 @@
-../build.sbt
\ No newline at end of file
diff --git a/keywords-Each/build.sbt b/keywords-Each/build.sbt
deleted file mode 100644
index 6a73059a..00000000
--- a/keywords-Each/build.sbt
+++ /dev/null
@@ -1,33 +0,0 @@
-enablePlugins(Example)
-
-addCompilerPlugin("org.spire-math" %% "kind-projector" % "0.9.7")
-
-libraryDependencies += "org.scalatest" %%% "scalatest" % "3.0.6-SNAP2" % Test
-
-scalacOptions in Compile ++= {
- scalaBinaryVersion.value match {
- case "2.11" => Seq("–Xexperimental")
- case _ => Seq.empty
- }
-}
-
-scalacOptions ++= {
- import Ordering.Implicits._
- if (VersionNumber(scalaVersion.value).numbers >= Seq(2L, 13L)) {
- Seq("-Ymacro-annotations")
- } else {
- Nil
- }
-}
-
-libraryDependencies ++= {
- import Ordering.Implicits._
- if (VersionNumber(scalaVersion.value).numbers >= Seq(2L, 13L)) {
- Nil
- } else {
- Seq(compilerPlugin("org.scalamacros" % "paradise" % "2.1.1" cross CrossVersion.full))
- }
-}
-
-libraryDependencies += "com.thoughtworks.enableIf" %% "enableif" % "1.1.6"
-
diff --git a/keywords-Each/src/main/scala/com/thoughtworks/dsl/keywords/Each.scala b/keywords-Each/src/main/scala/com/thoughtworks/dsl/keywords/Each.scala
deleted file mode 100644
index 5657e1ca..00000000
--- a/keywords-Each/src/main/scala/com/thoughtworks/dsl/keywords/Each.scala
+++ /dev/null
@@ -1,111 +0,0 @@
-package com.thoughtworks.dsl.keywords
-
-import com.thoughtworks.enableMembersIf
-import com.thoughtworks.dsl.Dsl
-import com.thoughtworks.dsl.Dsl.{!!, Keyword}
-
-import scala.collection._
-import scala.language.implicitConversions
-import Shift.implicitShift
-
-import scala.collection.mutable.Builder
-
-/**
- * Iterates though each element in [[elements]].
- * @author 杨博 (Yang Bo)
- *
- * @example [[Each]] keywords can be used to calculate cartesian product.
- *
- * {{{
- * def cartesianProduct = List(!Each(Array(1, 2, 3)) * !Each(Vector(1, 10, 100, 1000)))
- * cartesianProduct should be(List(1, 10, 100, 1000, 2, 20, 200, 2000, 3, 30, 300, 3000))
- * }}}
- * @see [[comprehension]] if you want to use traditional `for` comprehension instead of !-notation.
- */
-final case class Each[Element](elements: Traversable[Element]) extends Keyword[Each[Element], Element]
-object Each {
-
- @enableMembersIf(scala.util.Properties.versionNumberString.matches("""^2\.1(1|2)\..*$"""))
- private[Each] object Scala211Or212 {
- type Factory[-A, +C] = scala.collection.generic.CanBuildFrom[Nothing, A, C]
-
- @inline
- def flatMapBreakOut[Element, Domain, DomainElement](
- fa: Traversable[Element],
- f: Element => GenTraversableOnce[DomainElement])(implicit factory: Factory[DomainElement, Domain]): Domain = {
- fa.flatMap(f)(collection.breakOut(factory))
- }
-
- @inline
- def newBuilder[A, C](implicit factory: Factory[A, C]): Builder[A, C] = {
- factory()
- }
-
- }
-
- @enableMembersIf(scala.util.Properties.versionNumberString.matches("""^2\.13\..*$"""))
- private[Each] object Scala213 {
-
- @inline
- def flatMapBreakOut[Element, Domain, DomainElement](
- fa: Traversable[Element],
- f: Element => GenTraversableOnce[DomainElement])(implicit factory: Factory[DomainElement, Domain]): Domain = {
- factory.fromSpecific(new View.FlatMap(fa, f))
- }
-
- @inline
- def newBuilder[A, C](implicit factory: Factory[A, C]): Builder[A, C] = {
- factory.newBuilder
- }
-
- }
-
- import Scala211Or212._
- import Scala213._
-
- implicit def implicitEach[Element](elements: Traversable[Element]): Each[Element] = Each[Element](elements)
-
- implicit def eachDsl[Element, Domain, DomainElement](
- implicit thatIsTraversableOnce: (Element => Domain) => (Element => GenTraversableOnce[DomainElement]),
- factory: Factory[DomainElement, Domain]
- ): Dsl[Each[Element], Domain, Element] =
- new Dsl[Each[Element], Domain, Element] {
- def cpsApply(keyword: Each[Element], handler: Element => Domain): Domain = {
- flatMapBreakOut(keyword.elements, handler)
- }
- }
-
- private[dsl] def foreachDsl[Element]: Dsl[Each[Element], Unit, Element] =
- new Dsl[Each[Element], Unit, Element] {
- def cpsApply(keyword: Each[Element], handler: Element => Unit): Unit = {
- keyword.elements.foreach(handler)
- }
- }
-
- implicit def continuationEachDsl[Element, LeftDomain, RightDomain, DomainElement](
- implicit rightDomainIsTraversableOnce: (Element => LeftDomain !! RightDomain) => (
- Element => LeftDomain !! TraversableOnce[DomainElement]),
- factory: Factory[DomainElement, RightDomain],
- shiftDsl: Dsl[Shift[LeftDomain, TraversableOnce[DomainElement]], LeftDomain, TraversableOnce[DomainElement]]
- ): Dsl[Each[Element], LeftDomain !! RightDomain, Element] = {
- new Dsl[Each[Element], LeftDomain !! RightDomain, Element] {
- def cpsApply(keyword: Each[Element],
- handler0: Element => LeftDomain !! RightDomain): LeftDomain !! RightDomain = {
- val i = keyword.elements.toIterator
- val builder = newBuilder[DomainElement, RightDomain]
- val handler = rightDomainIsTraversableOnce(handler0)
- @inline
- def loop(continue: RightDomain => LeftDomain): LeftDomain = {
- if (i.hasNext) {
- builder ++= !handler(i.next())
- loop(continue)
- } else {
- continue(builder.result())
- }
- }
- loop
- }
- }
- }
-
-}
diff --git a/keywords-Each/src/test/scala/com/thoughtworks/dsl/keywords/EachSpec.scala b/keywords-Each/src/test/scala/com/thoughtworks/dsl/keywords/EachSpec.scala
deleted file mode 100644
index 73e04fc9..00000000
--- a/keywords-Each/src/test/scala/com/thoughtworks/dsl/keywords/EachSpec.scala
+++ /dev/null
@@ -1,154 +0,0 @@
-package com.thoughtworks.dsl.keywords
-
-import org.scalatest.{FreeSpec, Matchers}
-import com.thoughtworks.dsl.Dsl.{!!, reset}
-
-/**
- * @author 杨博 (Yang Bo)
- */
-class EachSpec extends FreeSpec with Matchers {
-
- "reset helper" - {
- def resetReturnValue[A](a: A): A @reset = a
- def forceParameter[A](a: => A @reset): A = a
-
- "@reset parameter" ignore {
- val seq = 1 to 10
- def run(): Seq[Int] = Seq {
- val plus100 = forceParameter(Seq {
- !Each(seq) + 100
- })
- plus100.length should be(10)
- !Each(plus100)
- }
-
- val result = run()
- result.length should be(10)
- result.last should be(110)
- }
-
- "@reset block" in {
- val seq = 1 to 10
- def run(): Seq[Int] = Seq {
- val plus100 = resetReturnValue {
- Seq(!Each(seq) + 100)
- }
- plus100.length should be(10)
- !Each(plus100)
- }
-
- val result = run()
- result.length should be(10)
- result.last should be(110)
- }
-
- "@reset result value" ignore {
- val seq = 1 to 10
- def run(): Seq[Int] = Seq {
- val plus100 = {
- val element = !Each(seq)
- resetReturnValue {
- Seq(element + 100)
- }
- }
- plus100.length should be(1)
- !Each(plus100)
- }
-
- val result = run()
- result.length should be(10)
- result.last should be(110)
- }
-
- }
-
- "nested" - {
-
- "each" - {
- "explicit @reset" in {
- val seq = 1 to 10
-
- def run(): Seq[Int] = Seq {
- val plus100: Seq[Int] @reset = Seq {
- !Each(seq) + 100
- }
- plus100.length should be(1)
- !Each(plus100)
- }
-
- val result = run()
- result.length should be(10)
- result.last should be(110)
- }
-
- "val" in {
- val seq = 1 to 10
-
- def run(): Seq[Int] = Seq {
- val plus100 = Seq {
- !Each(seq) + 100
- }
- plus100.length should be(1)
- !Each(plus100)
- }
-
- val result = run()
- result.length should be(10)
- result.last should be(110)
- }
-
- "def" in {
- val seq = 1 to 10
-
- def run(): Seq[Int] = Seq {
- def plus100 = Seq {
- !Each(seq) + 100
- }
- plus100.length should be(10)
- !Each(plus100)
- }
-
- val result = run()
- result.length should be(10)
- result.last should be(110)
- }
- }
- }
-
- "default parameter" in {
-
- def foo(s: Seq[Int] = Seq {
- !Each(Seq(1, 2, 3)) + 100
- }) = s
-
- foo() should be(Seq(101, 102, 103))
-
- }
-
- "val in class" in {
- class C {
- val ascii: Set[Int] = Set(
- !Each(Seq(1, 2, 3, 2)) + 100
- )
- }
-
- (new C).ascii should be(Set(101, 102, 103))
- }
-
- "pattern matching" - {
- "val" in {
- def foo: Seq[String] =
- Seq {
- // OK
- val s0 = !Each(Seq("a"))
-
- // not OK
- val (s1, s2) = !Each(Seq(("b", "c")))
- s1
- }: @reset
-
- foo should be(Seq("b"))
- }
- }
-
-}
diff --git a/keywords-FlatMap/.js/build.sbt b/keywords-FlatMap/.js/build.sbt
deleted file mode 120000
index 0569694f..00000000
--- a/keywords-FlatMap/.js/build.sbt
+++ /dev/null
@@ -1 +0,0 @@
-../build.sbt
\ No newline at end of file
diff --git a/keywords-FlatMap/.jvm/build.sbt b/keywords-FlatMap/.jvm/build.sbt
deleted file mode 120000
index 0569694f..00000000
--- a/keywords-FlatMap/.jvm/build.sbt
+++ /dev/null
@@ -1 +0,0 @@
-../build.sbt
\ No newline at end of file
diff --git a/keywords-FlatMap/build.sbt b/keywords-FlatMap/build.sbt
deleted file mode 100644
index 128585bd..00000000
--- a/keywords-FlatMap/build.sbt
+++ /dev/null
@@ -1,6 +0,0 @@
-scalacOptions in Compile ++= {
- scalaBinaryVersion.value match {
- case "2.11" => Some("–Xexperimental")
- case _ => None
- }
-}
diff --git a/keywords-FlatMap/src/main/scala/com/thoughtworks/dsl/keywords/FlatMap.scala b/keywords-FlatMap/src/main/scala/com/thoughtworks/dsl/keywords/FlatMap.scala
deleted file mode 100644
index 775202d4..00000000
--- a/keywords-FlatMap/src/main/scala/com/thoughtworks/dsl/keywords/FlatMap.scala
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.thoughtworks.dsl.keywords
-import com.thoughtworks.dsl.Dsl
-
-final case class FlatMap[UpstreamKeyword, UpstreamValue, NestedKeyword, NestedValue](
- upstream: UpstreamKeyword,
- flatMapper: UpstreamValue => NestedKeyword)
- extends Dsl.Keyword[FlatMap[UpstreamKeyword, UpstreamValue, NestedKeyword, NestedValue], NestedValue]
-
-object FlatMap {
- implicit def flatMapDsl[UpstreamKeyword, UpstreamValue, Domain, NestedKeyword, NestedValue](
- implicit
- upstreamDsl: Dsl[UpstreamKeyword, Domain, UpstreamValue],
- nestedDsl: Dsl[NestedKeyword, Domain, NestedValue]
- ): Dsl[FlatMap[UpstreamKeyword, UpstreamValue, NestedKeyword, NestedValue], Domain, NestedValue] =
- new Dsl[FlatMap[UpstreamKeyword, UpstreamValue, NestedKeyword, NestedValue], Domain, NestedValue] {
- def cpsApply(keyword: FlatMap[UpstreamKeyword, UpstreamValue, NestedKeyword, NestedValue],
- handler: NestedValue => Domain) = {
- val FlatMap(upstream, flatMapper) = keyword
- upstreamDsl.cpsApply(upstream, { upstreamValue =>
- nestedDsl.cpsApply(flatMapper(upstreamValue), handler)
- })
- }
- }
-}
diff --git a/keywords-ForEach/.js/build.sbt b/keywords-ForEach/.js/build.sbt
deleted file mode 120000
index 0569694f..00000000
--- a/keywords-ForEach/.js/build.sbt
+++ /dev/null
@@ -1 +0,0 @@
-../build.sbt
\ No newline at end of file
diff --git a/keywords-ForEach/.jvm/build.sbt b/keywords-ForEach/.jvm/build.sbt
deleted file mode 120000
index 0569694f..00000000
--- a/keywords-ForEach/.jvm/build.sbt
+++ /dev/null
@@ -1 +0,0 @@
-../build.sbt
\ No newline at end of file
diff --git a/keywords-ForEach/build.sbt b/keywords-ForEach/build.sbt
deleted file mode 100644
index 699fb9a6..00000000
--- a/keywords-ForEach/build.sbt
+++ /dev/null
@@ -1,12 +0,0 @@
-enablePlugins(Example)
-
-addCompilerPlugin("org.spire-math" %% "kind-projector" % "0.9.7")
-
-libraryDependencies += "org.scalatest" %%% "scalatest" % "3.0.6-SNAP2" % Test
-
-scalacOptions in Compile ++= {
- scalaBinaryVersion.value match {
- case "2.11" => Seq("–Xexperimental")
- case _ => Seq.empty
- }
-}
diff --git a/keywords-ForEach/src/main/scala/com/thoughtworks/dsl/keywords/ForEach.scala b/keywords-ForEach/src/main/scala/com/thoughtworks/dsl/keywords/ForEach.scala
deleted file mode 100644
index 164ff4d3..00000000
--- a/keywords-ForEach/src/main/scala/com/thoughtworks/dsl/keywords/ForEach.scala
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.thoughtworks.dsl.keywords
-
-import com.thoughtworks.dsl.Dsl
-import com.thoughtworks.dsl.Dsl.{!!, Keyword}
-
-import scala.collection._
-import scala.language.implicitConversions
-
-import scala.collection.mutable.Builder
-
-/** Iterates though each element in [[elements]]. */
-final case class ForEach[Element](elements: Traversable[Element]) extends Keyword[ForEach[Element], Element]
-object ForEach {
-
- implicit def implicitForEach[Element](elements: Traversable[Element]): ForEach[Element] = ForEach[Element](elements)
-
- implicit def foreachDsl[Element]: Dsl[ForEach[Element], Unit, Element] =
- new Dsl[ForEach[Element], Unit, Element] {
- def cpsApply(keyword: ForEach[Element], handler: Element => Unit): Unit = {
- keyword.elements.foreach(handler)
- }
- }
-
-}
diff --git a/keywords-ForEach/src/test/scala/com/thoughtworks/dsl/keywords/ForEachSpec.scala b/keywords-ForEach/src/test/scala/com/thoughtworks/dsl/keywords/ForEachSpec.scala
deleted file mode 100644
index 9fec0034..00000000
--- a/keywords-ForEach/src/test/scala/com/thoughtworks/dsl/keywords/ForEachSpec.scala
+++ /dev/null
@@ -1,40 +0,0 @@
-package com.thoughtworks.dsl.keywords
-
-import org.scalatest.{FreeSpec, Matchers}
-import com.thoughtworks.dsl.Dsl.{!!, reset}
-
-/**
- * @author 杨博 (Yang Bo)
- */
-class ForEachSpec extends FreeSpec with Matchers {
-
- "foreach" - {
-
- "val" in {
- val seq = 1 to 10
-
- def run(): Unit = {
- val plus100 = Seq {
- !ForEach(seq) + 100
- }
- plus100.length should be(1)
- !ForEach(plus100)
- }
-
- run()
- }
- "def" in {
- val seq = 1 to 10
-
- def run(): Unit = {
- def plus100 = Seq {
- !Each(seq) + 100
- }
- plus100.length should be(10)
- !ForEach(plus100)
- }
-
- run()
- }
- }
-}
diff --git a/keywords-Fork/.js/build.sbt b/keywords-Fork/.js/build.sbt
deleted file mode 120000
index 0569694f..00000000
--- a/keywords-Fork/.js/build.sbt
+++ /dev/null
@@ -1 +0,0 @@
-../build.sbt
\ No newline at end of file
diff --git a/keywords-Fork/.jvm/build.sbt b/keywords-Fork/.jvm/build.sbt
deleted file mode 120000
index 0569694f..00000000
--- a/keywords-Fork/.jvm/build.sbt
+++ /dev/null
@@ -1 +0,0 @@
-../build.sbt
\ No newline at end of file
diff --git a/keywords-Fork/build.sbt b/keywords-Fork/build.sbt
deleted file mode 100644
index 107cbaa8..00000000
--- a/keywords-Fork/build.sbt
+++ /dev/null
@@ -1,19 +0,0 @@
-scalacOptions ++= {
- import Ordering.Implicits._
- if (VersionNumber(scalaVersion.value).numbers >= Seq(2L, 13L)) {
- Seq("-Ymacro-annotations")
- } else {
- Nil
- }
-}
-
-libraryDependencies ++= {
- import Ordering.Implicits._
- if (VersionNumber(scalaVersion.value).numbers >= Seq(2L, 13L)) {
- Nil
- } else {
- Seq(compilerPlugin("org.scalamacros" % "paradise" % "2.1.1" cross CrossVersion.full))
- }
-}
-
-libraryDependencies += "com.thoughtworks.enableIf" %% "enableif" % "1.1.6"
diff --git a/keywords-Fork/src/main/scala/com/thoughtworks/dsl/keywords/Fork.scala b/keywords-Fork/src/main/scala/com/thoughtworks/dsl/keywords/Fork.scala
deleted file mode 100644
index 1013ac25..00000000
--- a/keywords-Fork/src/main/scala/com/thoughtworks/dsl/keywords/Fork.scala
+++ /dev/null
@@ -1,170 +0,0 @@
-package com.thoughtworks.dsl.keywords
-
-import java.io.{PrintStream, PrintWriter}
-import java.util.concurrent.atomic.AtomicInteger
-
-import com.thoughtworks.dsl.Dsl
-import com.thoughtworks.dsl.Dsl.{!!, Keyword}
-import com.thoughtworks.dsl.keywords.Catch.{CatchDsl, DslCatch}
-import com.thoughtworks.enableMembersIf
-
-import scala.collection._
-import scala.collection.generic.CanBuildFrom
-import scala.collection.mutable.Builder
-import scala.language.implicitConversions
-
-final case class Fork[Element](elements: Traversable[Element]) extends AnyVal with Keyword[Fork[Element], Element]
-
-object Fork {
-
- @enableMembersIf(scala.util.Properties.versionNumberString.matches("""^2\.1(1|2)\..*$"""))
- private[Fork] object Scala211Or212 {
- type Factory[-A, +C] = scala.collection.generic.CanBuildFrom[Nothing, A, C]
-
- @inline
- def flatMapBreakOut[Element, Domain, DomainElement](
- fa: Traversable[Element],
- f: Element => GenTraversableOnce[DomainElement])(implicit factory: Factory[DomainElement, Domain]): Domain = {
- fa.flatMap(f)(collection.breakOut(factory))
- }
-
- @inline
- def newBuilder[A, C](implicit factory: Factory[A, C]): Builder[A, C] = {
- factory()
- }
-
- }
-
- @enableMembersIf(scala.util.Properties.versionNumberString.matches("""^2\.13\..*$"""))
- private[Fork] object Scala213 {
-
- @inline
- def flatMapBreakOut[Element, Domain, DomainElement](
- fa: Traversable[Element],
- f: Element => GenTraversableOnce[DomainElement])(implicit factory: Factory[DomainElement, Domain]): Domain = {
- factory.fromSpecific(new View.FlatMap(fa, f))
- }
-
- @inline
- def newBuilder[A, C](implicit factory: Factory[A, C]): Builder[A, C] = {
- factory.newBuilder
- }
-
- }
-
- import Scala211Or212._
- import Scala213._
-
- implicit def implicitFork[Element](elements: Traversable[Element]): Fork[Element] = Fork[Element](elements)
-
- final case class MultipleException(throwableSet: Set[Throwable])
- extends RuntimeException("Multiple exceptions found") {
- override def toString: String = throwableSet.mkString("\n")
-
- override def printStackTrace(): Unit = {
- for (throwable <- throwableSet) {
- throwable.printStackTrace()
- }
- }
-
- override def printStackTrace(s: PrintStream): Unit = {
- for (throwable <- throwableSet) {
- throwable.printStackTrace(s)
- }
- }
-
- override def printStackTrace(s: PrintWriter): Unit = {
- for (throwable <- throwableSet) {
- throwable.printStackTrace(s)
- }
- }
-
- override def getStackTrace: Array[StackTraceElement] = synchronized {
- super.getStackTrace match {
- case null =>
- setStackTrace(throwableSet.view.flatMap(_.getStackTrace).toArray)
- super.getStackTrace
- case stackTrace =>
- stackTrace
- }
- }
-
- override def fillInStackTrace(): this.type = {
- this
- }
-
- }
-
- implicit def forkContinuationDsl[NarrowElement, LeftDomain, WidenElement, RightDomain](
- implicit eachDsl: Dsl[ForEach[NarrowElement], LeftDomain, NarrowElement],
- booleanEachDsl: Dsl[ForEach[Boolean], LeftDomain, Boolean],
- isTraversableOnce: RightDomain => TraversableOnce[WidenElement],
- canBuildFrom: Factory[WidenElement, RightDomain],
- continueDsl: Dsl[Continue, LeftDomain, Nothing],
- catchDsl: DslCatch[LeftDomain, LeftDomain, Unit]
- ): Dsl[Fork[NarrowElement], LeftDomain !! RightDomain, NarrowElement] =
- new Dsl[Fork[NarrowElement], LeftDomain !! RightDomain, NarrowElement] {
- def cpsApply(fork: Fork[NarrowElement],
- mapper: NarrowElement => LeftDomain !! RightDomain): LeftDomain !! RightDomain = _ {
- val builder: mutable.Builder[WidenElement, RightDomain] = newBuilder[WidenElement, RightDomain]
- val exceptionBuilder = Set.newBuilder[Throwable]
- val counter = new AtomicInteger(1)
- if (!ForEach(Seq(true, false))) {
- val element = !ForEach(fork.elements)
- counter.incrementAndGet()
- try {
- builder ++= !Shift(mapper(element));
- ()
- } catch {
- case MultipleException(throwableSet) =>
- exceptionBuilder ++= throwableSet;
- ()
- case e: Throwable =>
- exceptionBuilder += e;
- ()
- } finally {
- if (counter.decrementAndGet() > 0) {
- !Continue
- }
- }
- } else {
- if (counter.decrementAndGet() > 0) {
- !Continue
- }
- }
-
- val exceptions = exceptionBuilder.result()
- if (exceptions.isEmpty) {
- builder.result()
- } else {
- val i = exceptions.iterator
- val firstException = i.next()
- if (i.hasNext) {
- throw MultipleException(exceptions)
- } else {
- throw firstException
- }
- }
- }
- }
-
- @deprecated("Use Dsl[Catch[...], ...] as implicit parameters instead of CatchDsl[...]", "Dsl.scala 1.2.0")
- private[Fork] def forkContinuationDsl[NarrowElement, LeftDomain, WidenElement, RightDomain](
- implicit eachDsl: Dsl[ForEach[NarrowElement], LeftDomain, NarrowElement],
- booleanEachDsl: Dsl[ForEach[Boolean], LeftDomain, Boolean],
- isTraversableOnce: RightDomain => TraversableOnce[WidenElement],
- canBuildFrom: Factory[WidenElement, RightDomain],
- continueDsl: Dsl[Continue, LeftDomain, Nothing],
- catchDsl: CatchDsl[LeftDomain, LeftDomain, Unit]
- ): Dsl[Fork[NarrowElement], LeftDomain !! RightDomain, NarrowElement] = {
- forkContinuationDsl(
- eachDsl: Dsl[ForEach[NarrowElement], LeftDomain, NarrowElement],
- booleanEachDsl: Dsl[ForEach[Boolean], LeftDomain, Boolean],
- isTraversableOnce: RightDomain => TraversableOnce[WidenElement],
- canBuildFrom: Factory[WidenElement, RightDomain],
- continueDsl: Dsl[Continue, LeftDomain, Nothing],
- catchDsl: DslCatch[LeftDomain, LeftDomain, Unit]
- )
- }
-
-}
diff --git a/keywords-Get/src/main/scala/com/thoughtworks/dsl/keywords/Get.scala b/keywords-Get/src/main/scala/com/thoughtworks/dsl/keywords/Get.scala
deleted file mode 100644
index fda75807..00000000
--- a/keywords-Get/src/main/scala/com/thoughtworks/dsl/keywords/Get.scala
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.thoughtworks.dsl.keywords
-import com.thoughtworks.dsl.Dsl
-import com.thoughtworks.dsl.Dsl.Keyword
-
-/**
- * @see [[Put]]
- * @author 杨博 (Yang Bo)
- */
-final case class Get[S]() extends Keyword[Get[S], S]
-
-object Get {
-
- implicit def getDsl[S0, S <: S0, A] = new Dsl[Get[S0], S => A, S0] {
- def cpsApply(keyword: Get[S0], handler: S0 => S => A): S => A = { b =>
- handler(b)(b)
- }
- }
-
-}
diff --git a/keywords-Map/.js/build.sbt b/keywords-Map/.js/build.sbt
deleted file mode 120000
index 0569694f..00000000
--- a/keywords-Map/.js/build.sbt
+++ /dev/null
@@ -1 +0,0 @@
-../build.sbt
\ No newline at end of file
diff --git a/keywords-Map/.jvm/build.sbt b/keywords-Map/.jvm/build.sbt
deleted file mode 120000
index 0569694f..00000000
--- a/keywords-Map/.jvm/build.sbt
+++ /dev/null
@@ -1 +0,0 @@
-../build.sbt
\ No newline at end of file
diff --git a/keywords-Map/build.sbt b/keywords-Map/build.sbt
deleted file mode 100644
index 128585bd..00000000
--- a/keywords-Map/build.sbt
+++ /dev/null
@@ -1,6 +0,0 @@
-scalacOptions in Compile ++= {
- scalaBinaryVersion.value match {
- case "2.11" => Some("–Xexperimental")
- case _ => None
- }
-}
diff --git a/keywords-Map/src/main/scala/com/thoughtworks/dsl/keywords/Map.scala b/keywords-Map/src/main/scala/com/thoughtworks/dsl/keywords/Map.scala
deleted file mode 100644
index 8e9f35bf..00000000
--- a/keywords-Map/src/main/scala/com/thoughtworks/dsl/keywords/Map.scala
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.thoughtworks.dsl.keywords
-import com.thoughtworks.dsl.Dsl
-
-final case class Map[UpstreamKeyword, UpstreamValue, Value](upstream: UpstreamKeyword, mapper: UpstreamValue => Value)
- extends Dsl.Keyword[Map[UpstreamKeyword, UpstreamValue, Value], Value]
-
-object Map {
- implicit def mapDsl[UpstreamKeyword, UpstreamValue, Domain, Value](
- implicit upstreamDsl: Dsl[UpstreamKeyword, Domain, UpstreamValue]
- ): Dsl[Map[UpstreamKeyword, UpstreamValue, Value], Domain, Value] =
- new Dsl[Map[UpstreamKeyword, UpstreamValue, Value], Domain, Value] {
- def cpsApply(keyword: Map[UpstreamKeyword, UpstreamValue, Value], handler: Value => Domain) = {
- val Map(upstream, mapper) = keyword
- upstreamDsl.cpsApply(upstream, mapper.andThen(handler))
- }
- }
-}
diff --git a/keywords-Monadic/.js/build.sbt b/keywords-Monadic/.js/build.sbt
deleted file mode 120000
index 0569694f..00000000
--- a/keywords-Monadic/.js/build.sbt
+++ /dev/null
@@ -1 +0,0 @@
-../build.sbt
\ No newline at end of file
diff --git a/keywords-Monadic/.jvm/build.sbt b/keywords-Monadic/.jvm/build.sbt
deleted file mode 120000
index 0569694f..00000000
--- a/keywords-Monadic/.jvm/build.sbt
+++ /dev/null
@@ -1 +0,0 @@
-../build.sbt
\ No newline at end of file
diff --git a/keywords-Monadic/build.sbt b/keywords-Monadic/build.sbt
deleted file mode 100644
index e69de29b..00000000
diff --git a/keywords-Monadic/src/main/scala/com/thoughtworks/dsl/keywords/Monadic.scala b/keywords-Monadic/src/main/scala/com/thoughtworks/dsl/keywords/Monadic.scala
deleted file mode 100644
index 41625bc5..00000000
--- a/keywords-Monadic/src/main/scala/com/thoughtworks/dsl/keywords/Monadic.scala
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.thoughtworks.dsl.keywords
-
-import com.thoughtworks.dsl.Dsl.Keyword
-import scala.language.higherKinds
-import scala.language.implicitConversions
-
-/** A keyword for extracting monadic value from the monadic expression [[fa]].
- *
- * @see [[com.thoughtworks.dsl.domains.cats]] for using this [[Monadic]] keyword with [[cats.Monad]].
- * @see [[com.thoughtworks.dsl.domains.scalaz]] for using this [[Monadic]] keyword with [[scalaz.Monad]].
- * @todo [[Monadic]] should be a [[scala.AnyVal]] after [[https://github.com/scala/bug/issues/10595]] is resolved.
- */
-final case class Monadic[F[_], A](fa: F[A]) extends Keyword[Monadic[F, A], A]
-
-object Monadic {
- implicit def implicitMonadic[F[_], A](fa: F[A]): Monadic[F, A] = Monadic(fa)
-}
diff --git a/keywords-NoneSafe/src/main/scala/com/thoughtworks/dsl/keywords/NoneSafe.scala b/keywords-NoneSafe/src/main/scala/com/thoughtworks/dsl/keywords/NoneSafe.scala
deleted file mode 100644
index 93389a2e..00000000
--- a/keywords-NoneSafe/src/main/scala/com/thoughtworks/dsl/keywords/NoneSafe.scala
+++ /dev/null
@@ -1,25 +0,0 @@
-package com.thoughtworks.dsl
-package keywords
-import com.thoughtworks.dsl.Dsl.Keyword
-import scala.language.implicitConversions
-
-final case class NoneSafe[A](option: Option[A]) extends AnyVal with Keyword[NoneSafe[A], A]
-
-object NoneSafe {
-
- implicit def noneSafeDsl[A, Domain](
- implicit continueDsl: Dsl[Return[None.type], Domain, Nothing]): Dsl[NoneSafe[A], Domain, A] =
- new Dsl[NoneSafe[A], Domain, A] {
- def cpsApply(keyword: NoneSafe[A], handler: A => Domain): Domain = {
- keyword.option match {
- case None =>
- continueDsl.cpsApply(Return(None), identity)
- case Some(a) =>
- handler(a)
- }
- }
- }
-
- implicit def implicitNoneSafe[A](option: Option[A]): NoneSafe[A] = NoneSafe(option)
-
-}
diff --git a/keywords-NullSafe/.jvm/build.sbt b/keywords-NullSafe/.jvm/build.sbt
deleted file mode 100644
index 0391fa23..00000000
--- a/keywords-NullSafe/.jvm/build.sbt
+++ /dev/null
@@ -1,3 +0,0 @@
-enablePlugins(Example)
-
-libraryDependencies += "org.scalatest" %%% "scalatest" % "3.0.6-SNAP2" % Test
diff --git a/keywords-NullSafe/src/main/scala/com/thoughtworks/dsl/keywords/NullSafe.scala b/keywords-NullSafe/src/main/scala/com/thoughtworks/dsl/keywords/NullSafe.scala
deleted file mode 100644
index b7f865bd..00000000
--- a/keywords-NullSafe/src/main/scala/com/thoughtworks/dsl/keywords/NullSafe.scala
+++ /dev/null
@@ -1,177 +0,0 @@
-package com.thoughtworks.dsl.keywords
-import com.thoughtworks.dsl.Dsl.{reset, shift}
-import com.thoughtworks.dsl.keywords.NullSafe.?
-import com.thoughtworks.dsl.keywords.NullSafe.NotNull
-
-import scala.language.implicitConversions
-import scala.language.higherKinds
-import scala.annotation.compileTimeOnly
-
-/** [[NullSafe]] is a keyword to perform `null` check.
- *
- * @example You can use [[NullSafe$.? ?]] annotation to represent a nullable value.
- *
- * {{{
- * import com.thoughtworks.dsl.keywords.NullSafe._
- *
- * case class Tree(left: Tree @ $qmark = null, right: Tree @ $qmark = null, value: String @ $qmark = null)
- *
- * val root: Tree @ $qmark = Tree(
- * left = Tree(
- * left = Tree(value = "left-left"),
- * right = Tree(value = "left-right")
- * ),
- * right = Tree(value = "right")
- * )
- * }}}
- *
- * A normal `.` is not null safe, when selecting `left`, `right` or `value` on a `null` value.
- *
- * {{{
- * a[NullPointerException] should be thrownBy {
- * root.right.left.right.value
- * }
- * }}}
- *
- * The above code throws an exception because `root.right.left` is `null`.
- *
- * The exception can be avoided by using [[?]] on a nullable value:
- *
- * {{{
- * root.?.right.?.left.?.right.?.value should be(null)
- * }}}
- *
- * The entire expression will be `null` if one of [[?]] is performed on a `null` value.
- *
- *
- *
- * The boundary of a null safe operator [[?]] is the nearest enclosing expression
- * whose type is annotated as `@ ?`.
- *
- * {{{
- * ("Hello " + ("world " + root.?.right.?.left.?.value)) should be("Hello world null")
- * ("Hello " + (("world " + root.?.right.?.left.?.value.?): @ $qmark)) should be("Hello null")
- * (("Hello " + ("world " + root.?.right.?.left.?.value.?)): @ $qmark) should be(null)
- * }}}
- *
- * @example The [[?]] operator usually works with Java libraries that may produce `null`.
- *
- * {{{
- * import com.thoughtworks.dsl.keywords.NullSafe._
- *
- * val myMap = new java.util.HashMap[String, String]();
- * ((myMap.get("key1").? + myMap.get("key2").?): @ $qmark) should be(null)
- * }}}
- *
- * @note The [[?]] operator is only available on nullable values.
- *
- * A type is considered as nullable if it is a reference type,
- * no matter it is annotated as `@ ?` or not.
- *
- * {{{
- * import com.thoughtworks.dsl.keywords.NullSafe._
- *
- * val explicitNullable: String @ $qmark = null
- * ((explicitNullable.? + " Doe") : @ $qmark) should be(null)
- * }}}
- *
- * {{{
- * val implicitNullable: String = null
- * ((implicitNullable.? + " Doe") : @ $qmark) should be(null)
- * }}}
- *
- * A type is considered as not nullable if it is a value type.
- *
- * {{{
- * val implicitNotNullable: Int = 0
- * "(implicitNotNullable.? + 42) : @ $qmark" shouldNot compile
- * }}}
- *
- * Alternatively, a type can be considered as not nullable
- * by explicitly converting it to [[com.thoughtworks.dsl.keywords.NullSafe.NotNull[A]* NotNull]].
- *
- * {{{
- * val explicitNotNullable: NotNull[String] = NotNull("John")
- * """(explicitNotNullable.? + " Doe") : @ $qmark""" shouldNot compile
- * }}}
- *
- * @see [[NoneSafe]] for similar checks on [[scala.Option]]s.
- * @author 杨博 (Yang Bo)
- *
- * @define qmark ?
- *
- */
-final case class NullSafe[A <: AnyRef](nullable: A @ ?) extends AnyVal {
-
- @inline
- final def cpsApply[Domain >: Null](handler: NotNull[A] => Domain @ ?): Domain @ ? = {
- if (nullable == null) {
- null
- } else {
- handler(NullSafe.OpaqueTypes.toNotNull(nullable))
- }
- }
-
- @shift
- @compileTimeOnly(
- """This method requires the compiler plugin: `addCompilerPlugin("com.thoughtworks.dsl" %% "compilerplugins-bangnotation" % "latest.release")` and must only be called inside a code block annotated as `@reset`.""")
- final def ? : NotNull[A] = {
- throw new IllegalAccessException(
- """This method requires the compiler plugin: `addCompilerPlugin("com.thoughtworks.dsl" %% "compilerplugins-bangnotation" % "latest.release")` and must only be called inside a code block annotated as `@reset`."""
- )
- }
-
-}
-
-object NullSafe {
-
- private[NullSafe] trait OpaqueTypes {
- type NotNull[+A] <: A
-
- private[NullSafe] def toNotNull[A](a: A): NotNull[A]
- }
-
- private[NullSafe] val OpaqueTypes: OpaqueTypes = new OpaqueTypes {
- type NotNull[+A] = A
- private[NullSafe] def toNotNull[A](a: A) = a
- }
-
- /**
- * @usecase type NotNull[+A] <: A
- */
- type NotNull[+A] = OpaqueTypes.NotNull[A]
-
- /** Returns `a` if `a` is not `null`.
- *
- * @return `a` if `a` is not `null`.
- *
- * {{{
- * import com.thoughtworks.dsl.keywords.NullSafe._
- *
- * val o = new AnyRef
- * NotNull(o) should be(o)
- * }}}
- *
- * @throws java.lang.NullPointerException if `a` is `null`.
- *
- * {{{
- * import com.thoughtworks.dsl.keywords.NullSafe._
- * a[NullPointerException] should be thrownBy {
- * NotNull(null)
- * }
- * }}}
- */
- def NotNull[A](a: A): NotNull[A] = {
- if (a == null) {
- throw new NullPointerException
- } else {
- OpaqueTypes.toNotNull(a)
- }
- }
-
- /** @template */
- type ? = reset
-
- implicit def implicitNullSafe[A <: AnyRef](nullable: A @ ?) = new NullSafe[A](nullable)
-
-}
diff --git a/keywords-Put/.js/build.sbt b/keywords-Put/.js/build.sbt
deleted file mode 120000
index 0569694f..00000000
--- a/keywords-Put/.js/build.sbt
+++ /dev/null
@@ -1 +0,0 @@
-../build.sbt
\ No newline at end of file
diff --git a/keywords-Put/.jvm/build.sbt b/keywords-Put/.jvm/build.sbt
deleted file mode 120000
index 0569694f..00000000
--- a/keywords-Put/.jvm/build.sbt
+++ /dev/null
@@ -1 +0,0 @@
-../build.sbt
\ No newline at end of file
diff --git a/keywords-Put/build.sbt b/keywords-Put/build.sbt
deleted file mode 100644
index 0391fa23..00000000
--- a/keywords-Put/build.sbt
+++ /dev/null
@@ -1,3 +0,0 @@
-enablePlugins(Example)
-
-libraryDependencies += "org.scalatest" %%% "scalatest" % "3.0.6-SNAP2" % Test
diff --git a/keywords-Put/src/main/scala/com/thoughtworks/dsl/keywords/Put.scala b/keywords-Put/src/main/scala/com/thoughtworks/dsl/keywords/Put.scala
deleted file mode 100644
index 042b2663..00000000
--- a/keywords-Put/src/main/scala/com/thoughtworks/dsl/keywords/Put.scala
+++ /dev/null
@@ -1,66 +0,0 @@
-package com.thoughtworks.dsl
-package keywords
-import com.thoughtworks.dsl.Dsl.Keyword
-
-/** [[Put]] is a [[Dsl.Keyword Keyword]] to replace the [[value]] of the current context.
- *
- * Purely functional programming languages usually do not support native first-class mutable variables.
- * In those languages, mutable states can be implemented in state monads.
- *
- * [[Put]] and [[Get]] are the [[Dsl]]-based replacements of state monads.
- *
- * We use unary function as the domain of mutable state.
- * The parameter of the unary function can be read from the [[Get]] keyword, and changed by the [[Put]] keyword.
- *
- * @example The following example creates a function that accepts a string parameter
- * and returns the upper-cased last character of the parameter.
- *
- * {{{
- * def upperCasedLastCharacter: String => Char = {
- * val initialValue = !Get[String]()
- * !Put(initialValue.toUpperCase)
- *
- * val upperCased = !Get[String]()
- * Function.const(upperCased.last)
- * }
- * }}}
- *
- * For example, given a string of `foo`, the upper-cased last character should be `O`.
- *
- * {{{
- * // Output: O
- * upperCasedLastCharacter("foo") should be('O')
- * }}}
- *
- * @example [[Put]] and [[Get]] support multiple states.
- *
- * The following code creates a formatter that [[Put]] parts of content into a `Vector[Any]` of string buffers.
- *
- * {{{
- * def formatter: Double => Int => Vector[Any] => String = {
- * !Put(!Get[Vector[Any]] :+ "x=")
- * !Put(!Get[Vector[Any]] :+ !Get[Double])
- * !Put(!Get[Vector[Any]] :+ ",y=")
- * !Put(!Get[Vector[Any]] :+ !Get[Int])
- *
- * !Return((!Get[Vector[Any]]).mkString)
- * }
- *
- * formatter(0.5)(42)(Vector.empty) should be("x=0.5,y=42")
- * }}}
- * @see [[Get]]
- * @author 杨博 (Yang Bo)
- */
-final case class Put[S](value: S) extends AnyVal with Keyword[Put[S], Unit]
-
-object Put {
-
- implicit def putDsl[S0, S >: S0, A] = new Dsl[Put[S0], S => A, Unit] {
- def cpsApply(keyword: Put[S0], handler: Unit => S => A): S => A = {
- val newValue = keyword.value;
- { oldValue =>
- handler(())(newValue)
- }
- }
- }
-}
diff --git a/keywords-Return/.js/build.sbt b/keywords-Return/.js/build.sbt
deleted file mode 120000
index 0569694f..00000000
--- a/keywords-Return/.js/build.sbt
+++ /dev/null
@@ -1 +0,0 @@
-../build.sbt
\ No newline at end of file
diff --git a/keywords-Return/.jvm/build.sbt b/keywords-Return/.jvm/build.sbt
deleted file mode 120000
index 0569694f..00000000
--- a/keywords-Return/.jvm/build.sbt
+++ /dev/null
@@ -1 +0,0 @@
-../build.sbt
\ No newline at end of file
diff --git a/keywords-Return/build.sbt b/keywords-Return/build.sbt
deleted file mode 100644
index 0391fa23..00000000
--- a/keywords-Return/build.sbt
+++ /dev/null
@@ -1,3 +0,0 @@
-enablePlugins(Example)
-
-libraryDependencies += "org.scalatest" %%% "scalatest" % "3.0.6-SNAP2" % Test
diff --git a/keywords-Return/src/main/scala/com/thoughtworks/dsl/keywords/Return.scala b/keywords-Return/src/main/scala/com/thoughtworks/dsl/keywords/Return.scala
deleted file mode 100644
index bd06dd18..00000000
--- a/keywords-Return/src/main/scala/com/thoughtworks/dsl/keywords/Return.scala
+++ /dev/null
@@ -1,68 +0,0 @@
-package com.thoughtworks.dsl.keywords
-
-import com.thoughtworks.dsl.Dsl
-import com.thoughtworks.dsl.Dsl.Keyword
-
-import scala.language.implicitConversions
-
-/** A [[Dsl.Keyword]] to early return a lifted value from the enclosing function.
- *
- * @author 杨博 (Yang Bo)
- * @example Suppose you are generating a random integer less than 100,
- * whose first digit and second digit is different.
- * A solution is generating integers in an infinite loop,
- * and [[Return]] from the loop when the generated integer conforms with requirements.
- *
- * {{{
- * import scala.util.Random
- * import scala.util.control.TailCalls
- * import scala.util.control.TailCalls.TailRec
- * def randomInt(): TailRec[Int] = {
- * while (true) {
- * val r = Random.nextInt(100)
- * if (r % 10 != r / 10) {
- * !Return(TailCalls.done(r))
- * }
- * }
- * throw new AssertionError("Unreachable code");
- * }
- *
- * val r = randomInt().result
- * r should be < 100
- * r % 10 should not be r / 10
- * }}}
- *
- * @example Since this [[Return]] keyword can automatically lift the return type,
- * `TailCalls.done` can be omitted.
- *
- * {{{
- * import scala.util.Random
- * import scala.util.control.TailCalls
- * import scala.util.control.TailCalls.TailRec
- * def randomInt(): TailRec[Int] = {
- * while (true) {
- * val r = Random.nextInt(100)
- * if (r % 10 != r / 10) {
- * !Return(r)
- * }
- * }
- * throw new AssertionError("Unreachable code");
- * }
- *
- * val r = randomInt().result
- * r should be < 100
- * r % 10 should not be r / 10
- * }}}
- *
- */
-final case class Return[ReturnValue](returnValue: ReturnValue) extends AnyVal with Keyword[Return[ReturnValue], Nothing]
-
-object Return {
-
- implicit def returnDsl[ReturnValue, Domain >: ReturnValue]: Dsl[Return[ReturnValue], Domain, Nothing] =
- new Dsl[Return[ReturnValue], Domain, Nothing] {
- def cpsApply(keyword: Return[ReturnValue], handler: Nothing => Domain): Domain = {
- keyword.returnValue
- }
- }
-}
diff --git a/keywords-Return/src/test/scala/com/thoughtworks/dsl/keywords/ReturnSpec.scala b/keywords-Return/src/test/scala/com/thoughtworks/dsl/keywords/ReturnSpec.scala
deleted file mode 100644
index 84ed63ec..00000000
--- a/keywords-Return/src/test/scala/com/thoughtworks/dsl/keywords/ReturnSpec.scala
+++ /dev/null
@@ -1,59 +0,0 @@
-package com.thoughtworks.dsl.keywords
-import org.scalatest.{FreeSpec, Matchers}
-import com.thoughtworks.dsl.Dsl.!!
-
-/**
- * @author 杨博 (Yang Bo)
- */
-final class ReturnSpec extends FreeSpec with Matchers {
-
- "return a Stream" in {
- def stream: Stream[Int] = !Return[Int](1)
- stream should be(Stream(1))
- }
-
- "return the left domain" in {
- def continuation: Int !! String = !Return(42)
-
- continuation { s =>
- throw new AssertionError(s)
- } should be(42)
- }
-
- "return the right domain" in {
- def continuation: Int !! String = !Return("right value")
-
- continuation { s =>
- s should be("right value")
- 43
- } should be(43)
- }
-
- "return the middle domain" - {
-
- "as the return value" in {
- def continuation: Int !! Double !! String = !Return(1.23)
-
- continuation { s =>
- throw new AssertionError(s)
- } { d =>
- d should be(1.23)
- 43
- } should be(43)
- }
-
- "then the throw expression will not be executed" in {
- def continuation: Int !! Double !! String = {
- throw !Return(1.23)
- }
-
- continuation { s =>
- throw new AssertionError(s)
- } { d =>
- d should be(1.23)
- 43
- } should be(43)
- }
- }
-
-}
diff --git a/keywords-Shift/.js/build.sbt b/keywords-Shift/.js/build.sbt
deleted file mode 120000
index 0569694f..00000000
--- a/keywords-Shift/.js/build.sbt
+++ /dev/null
@@ -1 +0,0 @@
-../build.sbt
\ No newline at end of file
diff --git a/keywords-Shift/.jvm/build.sbt b/keywords-Shift/.jvm/build.sbt
deleted file mode 120000
index 0569694f..00000000
--- a/keywords-Shift/.jvm/build.sbt
+++ /dev/null
@@ -1 +0,0 @@
-../build.sbt
\ No newline at end of file
diff --git a/keywords-Shift/build.sbt b/keywords-Shift/build.sbt
deleted file mode 100644
index 128585bd..00000000
--- a/keywords-Shift/build.sbt
+++ /dev/null
@@ -1,6 +0,0 @@
-scalacOptions in Compile ++= {
- scalaBinaryVersion.value match {
- case "2.11" => Some("–Xexperimental")
- case _ => None
- }
-}
diff --git a/keywords-Shift/src/main/scala/com/thoughtworks/dsl/keywords/Shift.scala b/keywords-Shift/src/main/scala/com/thoughtworks/dsl/keywords/Shift.scala
deleted file mode 100644
index 9d5728aa..00000000
--- a/keywords-Shift/src/main/scala/com/thoughtworks/dsl/keywords/Shift.scala
+++ /dev/null
@@ -1,136 +0,0 @@
-package com.thoughtworks.dsl.keywords
-
-import com.thoughtworks.dsl.Dsl
-import com.thoughtworks.dsl.Dsl.{!!, Continuation, Keyword}
-import com.thoughtworks.dsl.keywords.Shift.{SameDomainStackSafeShiftDsl, StackSafeShiftDsl}
-
-import scala.annotation.tailrec
-import scala.language.implicitConversions
-import scala.util.control.{NonFatal, TailCalls}
-import scala.util.control.TailCalls.TailRec
-
-/**
- * @author 杨博 (Yang Bo)
- */
-final case class Shift[Domain, Value](continuation: Domain !! Value)
- extends AnyVal
- with Keyword[Shift[Domain, Value], Value]
-
-private[keywords] trait LowPriorityShift1 {
-
- @inline
- implicit def stackUnsafeShiftDsl[Domain, Value]: Dsl[Shift[Domain, Value], Domain, Value] =
- new Dsl[Shift[Domain, Value], Domain, Value] {
- def cpsApply(shift: Shift[Domain, Value], handler: Value => Domain) =
- shift.continuation(handler)
- }
-
-}
-
-private[keywords] trait LowPriorityShift0 extends LowPriorityShift1 {
-
- @inline
- implicit def stackSafeShiftDsl[Domain, NewDomain, Value](
- implicit stackSafeShiftDsl: StackSafeShiftDsl[Domain, NewDomain, Value])
- : Dsl[Shift[Domain, Value], NewDomain, Value] = {
- stackSafeShiftDsl
- }
-
-}
-
-object Shift extends LowPriorityShift0 {
-
- trait StackSafeShiftDsl[Domain, NewDomain, Value] extends Dsl[Shift[Domain, Value], NewDomain, Value]
-
- private type SameDomainStackSafeShiftDsl[Domain, Value] = StackSafeShiftDsl[Domain, Domain, Value]
-
- @inline
- implicit def implicitShift[Domain, Value](fa: Domain !! Value): Shift[Domain, Value] = new Shift[Domain, Value](fa)
-
- private def shiftTailRec[R, Value](continuation: TailRec[R] !! Value, handler: Value => TailRec[R]) = {
- continuation { a =>
- val handler1 = handler
- TailCalls.tailcall(handler1(a))
- }
- }
-
- @inline
- implicit def tailRecShiftDsl[R, Value]: SameDomainStackSafeShiftDsl[TailRec[R], Value] =
- new SameDomainStackSafeShiftDsl[TailRec[R], Value] {
- def cpsApply(keyword: Shift[TailRec[R], Value], handler: Value => TailRec[R]): TailRec[R] = {
- shiftTailRec(keyword.continuation, handler)
- }
- }
-
- private abstract class TrampolineContinuation[LeftDomain] extends (LeftDomain !! Throwable) {
- protected def step(): LeftDomain !! Throwable
-
- @tailrec
- private final def last(): LeftDomain !! Throwable = {
- step() match {
- case trampoline: TrampolineContinuation[LeftDomain] =>
- trampoline.last()
- case notTrampoline =>
- notTrampoline
- }
- }
-
- final def apply(handler: Throwable => LeftDomain): LeftDomain = {
- val protectedContinuation: LeftDomain !! Throwable = try {
- last()
- } catch {
- case NonFatal(e) =>
- return handler(e)
- }
- protectedContinuation(handler)
- }
- }
-
- private def suspend[LeftDomain, Value](
- continuation: LeftDomain !! Throwable !! Value,
- handler: Value => LeftDomain !! Throwable): TrampolineContinuation[LeftDomain] =
- new TrampolineContinuation[LeftDomain] {
- protected def step() = continuation(handler)
- }
-
- @inline
- implicit def stackSafeThrowableShiftDsl[LeftDomain, Value] =
- new SameDomainStackSafeShiftDsl[LeftDomain !! Throwable, Value] {
-
- def cpsApply(keyword: Shift[LeftDomain !! Throwable, Value],
- handler: Value => LeftDomain !! Throwable): !![LeftDomain, Throwable] =
- suspend(keyword.continuation, handler)
- }
-
- private def flatMapTrampoline[LeftDomain, RightDomain, Value](
- handler: Value => LeftDomain !! Throwable !! RightDomain,
- value: Value,
- continue: RightDomain => LeftDomain !! Throwable): TrampolineContinuation[LeftDomain] =
- new TrampolineContinuation[LeftDomain] {
- protected def step() = {
- handler(value)(continue)
- }
- }
-
- private def taskFlatMap[LeftDomain, RightDomain, Value](
- task: LeftDomain !! Throwable !! Value,
- handler0: Value => LeftDomain !! Throwable !! RightDomain): LeftDomain !! Throwable !! RightDomain = {
- continue0 =>
- val handler1 = handler0
- task { value =>
- val handler = handler1
- val continue = continue0
- flatMapTrampoline(handler, value, continue)
- }
- }
-
- @inline
- implicit def taskStackSafeShiftDsl[LeftDomain, RightDomain, Value] =
- new StackSafeShiftDsl[LeftDomain !! Throwable, LeftDomain !! Throwable !! RightDomain, Value] {
- def cpsApply(
- keyword: Shift[!![LeftDomain, Throwable], Value],
- handler: Value => !![!![LeftDomain, Throwable], RightDomain]): !![!![LeftDomain, Throwable], RightDomain] =
- taskFlatMap(keyword.continuation, handler)
- }
-
-}
diff --git a/keywords-Using/.js/build.sbt b/keywords-Using/.js/build.sbt
deleted file mode 120000
index 0569694f..00000000
--- a/keywords-Using/.js/build.sbt
+++ /dev/null
@@ -1 +0,0 @@
-../build.sbt
\ No newline at end of file
diff --git a/keywords-Using/.jvm/build.sbt b/keywords-Using/.jvm/build.sbt
deleted file mode 120000
index 0569694f..00000000
--- a/keywords-Using/.jvm/build.sbt
+++ /dev/null
@@ -1 +0,0 @@
-../build.sbt
\ No newline at end of file
diff --git a/keywords-Using/build.sbt b/keywords-Using/build.sbt
deleted file mode 100644
index 2d4a4864..00000000
--- a/keywords-Using/build.sbt
+++ /dev/null
@@ -1,21 +0,0 @@
-libraryDependencies += "org.scalatest" %%% "scalatest" % "3.0.6-SNAP2" % Test
-
-enablePlugins(Example)
-
-import meta._
-exampleSuperTypes := exampleSuperTypes.value.map {
- case ctor"_root_.org.scalatest.FreeSpec" =>
- ctor"_root_.org.scalatest.AsyncFreeSpec"
- case otherTrait =>
- otherTrait
-}
-
-scalacOptions ++= {
- import Ordering.Implicits._
- if (VersionNumber(scalaVersion.value).numbers < Seq(2L, 12L)) {
- // Enable SAM types for Scala 2.11
- Some("-Xexperimental")
- } else {
- None
- }
-}
diff --git a/keywords-Using/src/main/scala/com/thoughtworks/dsl/keywords/Using.scala b/keywords-Using/src/main/scala/com/thoughtworks/dsl/keywords/Using.scala
deleted file mode 100644
index 584b839f..00000000
--- a/keywords-Using/src/main/scala/com/thoughtworks/dsl/keywords/Using.scala
+++ /dev/null
@@ -1,125 +0,0 @@
-package com.thoughtworks.dsl
-package keywords
-
-import com.thoughtworks.dsl.Dsl
-import com.thoughtworks.dsl.Dsl.{!!, Keyword}
-import com.thoughtworks.dsl.keywords.Catch.{CatchDsl, DslCatch}
-
-import scala.concurrent.{ExecutionContext, Future}
-import scala.language.implicitConversions
-import scala.util.control.NonFatal
-
-/** This [[Using]] keyword automatically manage resources in [[scala.concurrent.Future]], [[domains.task.Task]],
- * and other asynchrounous domains derived from `Future` or `Task`.
- *
- * @author 杨博 (Yang Bo)
- * @see [[dsl]] for usage of this [[Using]] keyword in continuations
- */
-final case class Using[R <: AutoCloseable](open: () => R) extends AnyVal with Keyword[Using[R], R]
-
-object Using {
-
- implicit def implicitUsing[R <: AutoCloseable](r: => R): Using[R] = Using[R](r _)
-
- trait ScopeExitHandler extends AutoCloseable
-
- /** Returns a [[Using]] keyword to execute a [[ScopeExitHandler]] when exiting the nearest enclosing scope
- * that is annotated as [[Dsl.reset @reset]],
- * (or the nearest enclosing function if [[compilerplugins.ResetEverywhere]] is enabled).
- *
- * @note This method is similar to [[apply]],
- * except the parameter type is changed from a generic `R` to the SAM type [[ScopeExitHandler]],
- * which allows for function literal expressions
- * in Scala 2.12+ or Scala 2.11 with `-Xexperimental` compiler option.
- *
- * @example The following function will perform `n *= 2` after `n += 20`:
- *
- * {{{
- * import scala.concurrent.Future
- * import com.thoughtworks.dsl.keywords.Using.scopeExit
- * var n = 1
- * def multiplicationAfterAddition = Future {
- * !scopeExit { () =>
- * n *= 2
- * }
- * n += 20
- * }
- * }}}
- *
- * Therefore, the final value of `n` should be `(1 + 20) * 2 = 42`.
- *
- * {{{
- * multiplicationAfterAddition.map { _ =>
- * n should be(42)
- * }
- * }}}
- *
- */
- def scopeExit(r: => ScopeExitHandler) = new Using(r _)
-
- def apply[R <: AutoCloseable](r: => R)(
- implicit dummyImplicit: DummyImplicit = DummyImplicit.dummyImplicit): Using[R] = new Using(r _)
-
- implicit def throwableContinuationUsingDsl[Domain, Value, R <: AutoCloseable](
- implicit catchDsl: DslCatch[Domain, Domain, Value],
- shiftDsl: Dsl[Shift[Domain, Value], Domain, Value]
- ): Dsl[Using[R], Domain !! Value, R] = { (keyword: Using[R], handler: R => Domain !! Value) =>
- _ {
- val r = keyword.open()
- try {
- !Shift(handler(r))
- } finally {
- r.close()
- }
- }
- }
-
- @deprecated("Use Dsl[Catch[...], ...] as implicit parameters instead of CatchDsl[...]", "Dsl.scala 1.2.0")
- private[Using] def throwableContinuationUsingDsl[Domain, Value, R <: AutoCloseable](
- implicit catchDsl: CatchDsl[Domain, Domain, Value],
- shiftDsl: Dsl[Shift[Domain, Value], Domain, Value]
- ): Dsl[Using[R], Domain !! Value, R] = {
- throwableContinuationUsingDsl(catchDsl: DslCatch[Domain, Domain, Value],
- shiftDsl: Dsl[Shift[Domain, Value], Domain, Value])
- }
-
- implicit def scalaFutureUsingDsl[R <: AutoCloseable, A](implicit executionContext: ExecutionContext)
- : Dsl[Using[R], Future[A], R] = { (keyword: Using[R], handler: R => Future[A]) =>
- Future(keyword.open()).flatMap { r: R =>
- def onFailure(e: Throwable): Future[Nothing] = {
- try {
- r.close()
- Future.failed(e)
- } catch {
- case NonFatal(e2) =>
- Future.failed(e2)
- }
- }
-
- def onSuccess(a: A): Future[A] = {
- try {
- r.close()
- Future.successful(a)
- } catch {
- case NonFatal(e2) =>
- Future.failed(e2)
- }
- }
-
- def returnableBlock(): Future[A] = {
- val fa: Future[A] = try {
- handler(r)
- } catch {
- case NonFatal(e) =>
- return onFailure(e)
- }
- fa.recoverWith {
- case NonFatal(e) =>
- onFailure(e)
- }
- .flatMap(onSuccess)
- }
- returnableBlock()
- }
- }
-}
diff --git a/keywords-WithFilter/.js/build.sbt b/keywords-WithFilter/.js/build.sbt
deleted file mode 120000
index 0569694f..00000000
--- a/keywords-WithFilter/.js/build.sbt
+++ /dev/null
@@ -1 +0,0 @@
-../build.sbt
\ No newline at end of file
diff --git a/keywords-WithFilter/.jvm/build.sbt b/keywords-WithFilter/.jvm/build.sbt
deleted file mode 120000
index 0569694f..00000000
--- a/keywords-WithFilter/.jvm/build.sbt
+++ /dev/null
@@ -1 +0,0 @@
-../build.sbt
\ No newline at end of file
diff --git a/keywords-WithFilter/build.sbt b/keywords-WithFilter/build.sbt
deleted file mode 100644
index 128585bd..00000000
--- a/keywords-WithFilter/build.sbt
+++ /dev/null
@@ -1,6 +0,0 @@
-scalacOptions in Compile ++= {
- scalaBinaryVersion.value match {
- case "2.11" => Some("–Xexperimental")
- case _ => None
- }
-}
diff --git a/keywords-WithFilter/src/main/scala/com/thoughtworks/dsl/keywords/WithFilter.scala b/keywords-WithFilter/src/main/scala/com/thoughtworks/dsl/keywords/WithFilter.scala
deleted file mode 100644
index 356a7cea..00000000
--- a/keywords-WithFilter/src/main/scala/com/thoughtworks/dsl/keywords/WithFilter.scala
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.thoughtworks.dsl.keywords
-import com.thoughtworks.dsl.Dsl
-
-final case class WithFilter[UpstreamKeyword, UpstreamValue](upstream: UpstreamKeyword,
- condition: UpstreamValue => Boolean)
- extends Dsl.Keyword[WithFilter[UpstreamKeyword, UpstreamValue], UpstreamValue]
-
-object WithFilter {
- implicit def withFilterDsl[UpstreamKeyword, Domain, UpstreamValue](
- implicit
- upstreamDsl: Dsl[UpstreamKeyword, Domain, UpstreamValue],
- continueDsl: Dsl[Continue, Domain, Nothing]
- ): Dsl[WithFilter[UpstreamKeyword, UpstreamValue], Domain, UpstreamValue] =
- new Dsl[WithFilter[UpstreamKeyword, UpstreamValue], Domain, UpstreamValue] {
- def cpsApply(keyword: WithFilter[UpstreamKeyword, UpstreamValue], handler: UpstreamValue => Domain) = {
- val WithFilter(upstream, condition) = keyword
- upstreamDsl.cpsApply(upstream, { upstreamValue =>
- if (condition(upstreamValue)) {
- handler(upstreamValue)
- } else {
- continueDsl.cpsApply(Continue, identity)
- }
- })
- }
- }
-}
diff --git a/keywords-Yield/.js/build.sbt b/keywords-Yield/.js/build.sbt
deleted file mode 120000
index 0569694f..00000000
--- a/keywords-Yield/.js/build.sbt
+++ /dev/null
@@ -1 +0,0 @@
-../build.sbt
\ No newline at end of file
diff --git a/keywords-Yield/.jvm/build.sbt b/keywords-Yield/.jvm/build.sbt
deleted file mode 120000
index 0569694f..00000000
--- a/keywords-Yield/.jvm/build.sbt
+++ /dev/null
@@ -1 +0,0 @@
-../build.sbt
\ No newline at end of file
diff --git a/keywords-Yield/.jvm/jvm.sbt b/keywords-Yield/.jvm/jvm.sbt
deleted file mode 100644
index a2c568f7..00000000
--- a/keywords-Yield/.jvm/jvm.sbt
+++ /dev/null
@@ -1,2 +0,0 @@
-enablePlugins(Example)
-
diff --git a/keywords-Yield/build.sbt b/keywords-Yield/build.sbt
deleted file mode 100644
index b1e49767..00000000
--- a/keywords-Yield/build.sbt
+++ /dev/null
@@ -1,26 +0,0 @@
-libraryDependencies += "org.scalatest" %%% "scalatest" % "3.0.6-SNAP2" % Test
-
-scalacOptions in Compile ++= {
- scalaBinaryVersion.value match {
- case "2.11" => Seq("–Xexperimental")
- case _ => Seq.empty
- }
-}
-
-scalacOptions ++= {
- import Ordering.Implicits._
- if (VersionNumber(scalaVersion.value).numbers >= Seq(2L, 13L)) {
- Seq("-Ymacro-annotations")
- } else {
- Nil
- }
-}
-
-libraryDependencies ++= {
- import Ordering.Implicits._
- if (VersionNumber(scalaVersion.value).numbers >= Seq(2L, 13L)) {
- Nil
- } else {
- Seq(compilerPlugin("org.scalamacros" % "paradise" % "2.1.1" cross CrossVersion.full))
- }
-}
diff --git a/keywords-Yield/src/main/scala/com/thoughtworks/dsl/keywords/Yield.scala b/keywords-Yield/src/main/scala/com/thoughtworks/dsl/keywords/Yield.scala
deleted file mode 100644
index 204e912d..00000000
--- a/keywords-Yield/src/main/scala/com/thoughtworks/dsl/keywords/Yield.scala
+++ /dev/null
@@ -1,213 +0,0 @@
-package com.thoughtworks.dsl.keywords
-
-import com.thoughtworks.dsl.Dsl
-import com.thoughtworks.dsl.Dsl.Keyword
-import com.thoughtworks.dsl.keywords.Yield.From
-import com.thoughtworks.enableMembersIf
-
-import scala.collection._
-import scala.collection.generic.CanBuildFrom
-import scala.concurrent.Future
-import scala.language.implicitConversions
-import scala.language.higherKinds
-
-/**
- * @author 杨博 (Yang Bo)
- * @example This `Yield` keyword must be put inside a function that returns `Seq[Element]` or `Seq[Element] !! ...`,
- * or it will not compile.
- *
- * {{{
- * "def f(): Int = !Yield(1)" shouldNot compile
- * }}}
- *
- * @example [[Yield]] keywords can be used together with other keywords.
- * {{{
- * def gccFlagBuilder(sourceFile: String, includes: String*): Stream[String] = {
- * !Yield("gcc")
- * !Yield("-c")
- * !Yield(sourceFile)
- * val include = !Each(includes)
- * !Yield("-I")
- * !Yield(include)
- * !Continue
- * }
- *
- * gccFlagBuilder("main.c", "lib1/include", "lib2/include") should be(Stream("gcc", "-c", "main.c", "-I", "lib1/include", "-I", "lib2/include"))
- * }}}
- * @see [[comprehension]] if you want to use traditional `for` comprehension instead of !-notation.
- */
-final case class Yield[Element](element: Element) extends AnyVal with Keyword[Yield[Element], Unit]
-
-private[keywords] trait LowPriorityYield2 {
-
- def apply[A](elements: A*) = {
- From(elements)
- }
-
- implicit def iteratorYieldFromDsl[A, FromCollection <: TraversableOnce[A]]
- : Dsl[From[FromCollection], Iterator[A], Unit] =
- new Dsl[From[FromCollection], Iterator[A], Unit] {
- def cpsApply(keyword: From[FromCollection], generateTail: Unit => Iterator[A]): Iterator[A] = {
- keyword.elements.toIterator ++ generateTail(())
- }
- }
-
- implicit def iteratorYieldDsl[A, B >: A]: Dsl[Yield[A], Iterator[B], Unit] =
- new Dsl[Yield[A], Iterator[B], Unit] {
- def cpsApply(keyword: Yield[A], generateTail: Unit => Iterator[B]): Iterator[B] = {
- Iterator.single(keyword.element) ++ generateTail(())
- }
- }
-
-}
-
-private[keywords] object YieldScalaVersions {
-
- @enableMembersIf(scala.util.Properties.versionNumberString.matches("""^2\.1(1|2)\..*$"""))
- object Scala211Or212 {
-
- trait LowPriorityYield1 extends LowPriorityYield2 {
-
- implicit def seqViewYieldFromDsl[A, FromCollection <: Traversable[A], Coll1, Coll2](
- implicit canBuildFrom: CanBuildFrom[SeqView[A, Coll1], A, SeqView[A, Coll2]])
- : Dsl[From[FromCollection], SeqView[A, Coll1], Unit] =
- new Dsl[From[FromCollection], SeqView[A, Coll1], Unit] {
- def cpsApply(keyword: From[FromCollection], generateTail: Unit => SeqView[A, Coll1]): SeqView[A, Coll1] = {
- (keyword.elements.toIterable ++: generateTail(()))(canBuildFrom).asInstanceOf[SeqView[A, Coll1]]
- }
- }
-
- implicit def seqViewYieldDsl[A, B >: A, Coll1, Coll2](
- implicit canBuildFrom: CanBuildFrom[scala.collection.SeqView[B, Coll1], B, SeqView[B, Coll2]])
- : Dsl[Yield[A], SeqView[B, Coll1], Unit] =
- new Dsl[Yield[A], SeqView[B, Coll1], Unit] {
- def cpsApply(keyword: Yield[A], generateTail: Unit => SeqView[B, Coll1]): SeqView[B, Coll1] = {
- (keyword.element +: generateTail(()))(canBuildFrom).asInstanceOf[SeqView[B, Coll1]]
- }
- }
- }
-
- trait LowPriorityYield0 extends LowPriorityYield1 {
-
- implicit def seqYieldFromDsl[A, FromCollection <: Iterable[A], Collection[X] <: SeqLike[X, Collection[X]]](
- implicit canBuildFrom: CanBuildFrom[Collection[A], A, Collection[A]])
- : Dsl[From[FromCollection], Collection[A], Unit] =
- new Dsl[From[FromCollection], Collection[A], Unit] {
- def cpsApply(keyword: From[FromCollection], generateTail: Unit => Collection[A]): Collection[A] = {
- keyword.elements ++: generateTail(())
- }
- }
-
- implicit def seqYieldDsl[A, B >: A, Collection[X] <: SeqLike[X, Collection[X]]](
- implicit canBuildFrom: CanBuildFrom[Collection[B], B, Collection[B]]): Dsl[Yield[A], Collection[B], Unit] =
- new Dsl[Yield[A], Collection[B], Unit] {
- def cpsApply(keyword: Yield[A], generateTail: Unit => Collection[B]): Collection[B] = {
- keyword.element +: generateTail(())
- }
- }
-
- }
- }
-
- @enableMembersIf(scala.util.Properties.versionNumberString.matches("""^2\.13\..*$"""))
- object Scala213 {
-
- trait LowPriorityYield1 extends LowPriorityYield2 {
-
- implicit def viewYieldFromDsl[A, FromCollection <: View.SomeIterableOps[A]]
- : Dsl[From[FromCollection], View[A], Unit] =
- new Dsl[From[FromCollection], View[A], Unit] {
- def cpsApply(keyword: From[FromCollection], generateTail: Unit => View[A]): View[A] = {
- new View.Concat(keyword.elements, generateTail(()))
- }
- }
-
- implicit def seqViewYieldDsl[A, B >: A]: Dsl[Yield[A], SeqView[B], Unit] =
- new Dsl[Yield[A], SeqView[B], Unit] {
- def cpsApply(keyword: Yield[A], generateTail: Unit => SeqView[B]): SeqView[B] = {
- generateTail(()).prepended(keyword.element)
- }
- }
-
- implicit def indexedSeqViewYieldDsl[A, B >: A]: Dsl[Yield[A], IndexedSeqView[B], Unit] =
- new Dsl[Yield[A], IndexedSeqView[B], Unit] {
- def cpsApply(keyword: Yield[A], generateTail: Unit => IndexedSeqView[B]): IndexedSeqView[B] = {
- generateTail(()).prepended(keyword.element)
- }
- }
-
- implicit def viewYieldDsl[A, B >: A]: Dsl[Yield[A], View[B], Unit] =
- new Dsl[Yield[A], View[B], Unit] {
- def cpsApply(keyword: Yield[A], generateTail: Unit => View[B]): View[B] = {
- new View.Concat[B](new View.Single(keyword.element), generateTail(()))
- }
- }
- }
-
- trait LowPriorityYield0 extends LowPriorityYield1 {
- implicit def seqYieldFromDsl[A,
- FromCollection <: View.SomeIterableOps[A],
- Collection[X] <: SeqOps[X, Collection, Collection[X]]]
- : Dsl[From[FromCollection], Collection[A], Unit] =
- new Dsl[From[FromCollection], Collection[A], Unit] {
- def cpsApply(keyword: From[FromCollection], generateTail: Unit => Collection[A]): Collection[A] = {
- keyword.elements.toIterable ++: generateTail(())
- }
- }
-
- implicit def seqYieldDsl[A, B >: A, Collection[+X] <: SeqOps[X, Collection, Collection[X]]]
- : Dsl[Yield[A], Collection[B], Unit] =
- new Dsl[Yield[A], Collection[B], Unit] {
- def cpsApply(keyword: Yield[A], generateTail: Unit => Collection[B]): Collection[B] = {
- keyword.element +: generateTail(())
- }
- }
-
- }
- }
-
-}
-
-import YieldScalaVersions.Scala211Or212._
-import YieldScalaVersions.Scala213._
-
-object Yield extends LowPriorityYield0 {
-
- final case class From[FromCollection <: TraversableOnce[_]](elements: FromCollection)
- extends AnyVal
- with Keyword[From[FromCollection], Unit]
-
- implicit def implicitYieldFrom[FromCollection <: TraversableOnce[_]](elements: FromCollection): From[FromCollection] =
- From(elements)
-
- implicit def streamYieldFromDsl[A, FromCollection <: Iterable[A]]: Dsl[From[FromCollection], Stream[A], Unit] =
- new Dsl[From[FromCollection], Stream[A], Unit] {
- def cpsApply(keyword: From[FromCollection], generateTail: Unit => Stream[A]): Stream[A] = {
- keyword.elements.toStream.append(generateTail(()))
- }
- }
-
- implicit def futureStreamYieldFromDsl[A, FromCollection <: Iterable[A]]
- : Dsl[From[FromCollection], Stream[Future[A]], Unit] =
- new Dsl[From[FromCollection], Stream[Future[A]], Unit] {
- def cpsApply(keyword: From[FromCollection], generateTail: Unit => Stream[Future[A]]): Stream[Future[A]] = {
- keyword.elements.toStream.map(Future.successful).append(generateTail(()))
- }
- }
-
- implicit def implicitYield[Element](element: Element): Yield[Element] = Yield[Element](element)
-
- implicit def streamYieldDsl[Element, That >: Element]: Dsl[Yield[Element], Stream[That], Unit] =
- new Dsl[Yield[Element], Stream[That], Unit] {
- def cpsApply(keyword: Yield[Element], generateTail: Unit => Stream[That]): Stream[That] = {
- new Stream.Cons(keyword.element, generateTail(()))
- }
- }
-
- implicit def futureStreamYieldDsl[Element, That >: Element]: Dsl[Yield[Element], Stream[Future[That]], Unit] =
- new Dsl[Yield[Element], Stream[Future[That]], Unit] {
- def cpsApply(keyword: Yield[Element], generateTail: Unit => Stream[Future[That]]): Stream[Future[That]] = {
- new Stream.Cons(Future.successful(keyword.element), generateTail(()))
- }
- }
-}
diff --git a/keywords-Yield/src/test/scala/com/thoughtworks/dsl/keywords/YieldSpec.scala b/keywords-Yield/src/test/scala/com/thoughtworks/dsl/keywords/YieldSpec.scala
deleted file mode 100644
index 915ba8ab..00000000
--- a/keywords-Yield/src/test/scala/com/thoughtworks/dsl/keywords/YieldSpec.scala
+++ /dev/null
@@ -1,385 +0,0 @@
-package com.thoughtworks.dsl.keywords
-
-import com.thoughtworks.dsl.Dsl.!!
-import com.thoughtworks.enableMembersIf
-import org.scalatest.{FreeSpec, Matchers}
-
-import scala.annotation.tailrec
-import scala.collection.{LinearSeq, SeqView}
-import scala.runtime.NonLocalReturnControl
-
-/**
- * @author 杨博 (Yang Bo)
- */
-class YieldSpec extends FreeSpec with Matchers {
-
- "Given a continuation that uses Yield and Each expressions" - {
-
- def asyncFunction: Stream[String] !! Unit = _ {
- !Yield("Entering asyncFunction")
- val subThreadId: Int = !Each(Seq(0, 1))
- !Yield(s"Fork sub-thread $subThreadId")
- !Yield("Leaving asyncFunction")
- }
-
- "When create a generator that contains Yield, Shift, and Each expressions" - {
-
- def generator: Stream[String] = {
- !Yield("Entering generator")
- val threadId = !Each(Seq(0, 1))
- !Yield(s"Fork thread $threadId")
- !Shift(asyncFunction)
- Stream("Leaving generator")
- }
-
- "Then the generator should contains yield values" in {
- generator should be(
- Seq(
- /**/ "Entering generator",
- /****/ "Fork thread 0",
- /******/ "Entering asyncFunction",
- /********/ "Fork sub-thread 0",
- /**********/ "Leaving asyncFunction",
- /**********/ "Leaving generator",
- /********/ "Fork sub-thread 1",
- /**********/ "Leaving asyncFunction",
- /**********/ "Leaving generator",
- /****/ "Fork thread 1",
- /******/ "Entering asyncFunction",
- /********/ "Fork sub-thread 0",
- /**********/ "Leaving asyncFunction",
- /**********/ "Leaving generator",
- /********/ "Fork sub-thread 1",
- /**********/ "Leaving asyncFunction",
- /**********/ "Leaving generator"
- ))
- }
-
- }
-
- }
-
- "stream" - {
-
- def shouldCompile = {
- !Yield("naked")
- Stream.empty[String]
- }
-
- "local method" in {
- def generator: Stream[Int] = {
- def id[A](a: A) = a
- id(!Yield(100))
- Stream.empty[Int]
- }
- generator should be(Stream(100))
- }
-
- "yield from" in {
- def generator: Stream[Int] = {
- def id[A](a: A) = a
- id(!Yield(100, 200))
- Stream.empty
- }
- generator should be(Stream(100, 200))
- }
-
- "local function" in {
- def generator: Stream[Int] = {
- def id[A](a: A) = a
- (id[Unit] _)(!Yield(100))
- Stream.empty[Int]
- }
- generator should be(Stream(100))
- }
-
- "do/while" - {
- "empty body" in {
- def generator: Stream[Int] = {
- do {} while ({
- !Yield(100)
- false
- })
- Stream.empty[Int]
- }
- generator should be(Stream(100))
- }
-
- "false" in {
- def generator: Stream[Int] = {
- do {
- !Yield(100)
- } while (false)
- Stream.empty[Int]
- }
- generator should be(Stream(100))
- }
-
- "with var" in {
- def generator: Stream[Int] = {
- var i = 5
- do {
- i -= {
- !Yield(i)
- 1
- }
- } while ({
- !Yield(-i)
- i > 0
- })
- Stream.empty[Int]
- }
- generator should be(Stream(5, -4, 4, -3, 3, -2, 2, -1, 1, 0))
- }
- }
-
- "while" - {
- "false" in {
- def whileFalse: Stream[Int] = {
- while (false) {
- !Yield(100)
- }
- Stream.empty[Int]
- }
-
- whileFalse should be(Stream.empty)
- }
- }
-
- "match/case" in {
-
- def loop(i: Int): Stream[Int] = {
- i match {
- case 100 =>
- Stream.empty
- case _ =>
- !Yield(i)
- loop(i + 1)
- }
- }
-
- loop(90) should be(Stream(90, 91, 92, 93, 94, 95, 96, 97, 98, 99))
-
- }
-
- "recursive" in {
- def loop(i: Int): Stream[Int] = {
- if (i < 100) {
- !Yield(i)
- loop(i + 1)
- } else {
- Stream.empty
- }
- }
-
- loop(90) should be(Stream(90, 91, 92, 93, 94, 95, 96, 97, 98, 99))
-
- }
-
- "Given a generator that contains conditional Yield" - {
- def generator = {
- if (false) {
- !Yield(0)
- }
- if (true) {
- !Yield(1)
- }
- if ({ !Yield(2); false }) {
- !Yield(3)
- } else {
- !Yield(4)
- }
- Stream.empty[Int]
- }
-
- "Then the generator should contains values in selected branches" in {
- generator should be(Seq(1, 2, 4))
- }
-
- }
-
- "Given a continuation that uses Yield" - {
-
- def yield4243: Stream[Int] !! Unit = _ {
- !Yield(42)
- !Yield(43)
- }
-
- "when create a generator that contains multiple Yield expression followed by a bang notation and a Stream.empty" - {
-
- def generator: Stream[Int] = {
- !Yield(0)
- !Shift(yield4243)
- !Yield(1)
- Stream.empty[Int]
- }
-
- "Then the generator should contains yield values" in {
- generator should be(Seq(0, 42, 43, 1))
- }
-
- }
-
- }
-
- "apply" in {
- def generator: Stream[Int] = {
- val f = {
- !Yield(1)
-
- { (x: Int) =>
- -x
- }
- }
-
- val result = f({
- !Yield(2)
- 42
- })
- Stream(result)
- }
- generator should be(Stream(1, 2, -42))
- }
-
- "return" in {
- def generator: Stream[Int] = {
- if (true) {
- return {
- !Yield(100)
- Stream(42)
- }
- }
- Stream.empty[Int]
- }
-
- a[NonLocalReturnControl[Stream[Int]]] should be thrownBy generator.last
- }
- "partial function" - {
- "empty" in {
- Seq.empty[Any].flatMap {
- case i: Int =>
- !Yield(100)
- Stream(42)
- } should be(empty)
- }
-
- "flatMap" in {
- Seq(100, 200).flatMap {
- case i: Int =>
- !Yield(100)
- Stream(42 + i)
- } should be(Seq(100, 142, 100, 242))
- }
- }
-
- "nested function call" - {
- "call by value" in {
- def nested() = {
- "foo" +: !Yield("bar") +: Stream.empty[Any]
- }
- nested() should be(Stream("bar", "foo", ()))
- }
- "call by name" in {
- def nested() = {
- "foo" #:: !Yield("bar") #:: Stream.empty[Any]
- }
- nested() should be(Stream("bar", "foo", ()))
- }
- }
-
- }
-
- "view" - {
-
- def shouldCompile = {
- !Yield("naked")
- Vector.empty[String].view
- }
-
- "local method" in {
- def generator = {
- def id[A](a: A) = a
- id(!Yield(100))
- Seq.empty[Int].view
- }
- generator.toList should be(List(100))
- }
-
- @enableMembersIf(scala.util.Properties.versionNumberString.startsWith("2.11."))
- object Scala211 {
- def ignoreInScala211(title: String)(f: => Any) = {
- title ignore f
- }
- }
- @enableMembersIf(!scala.util.Properties.versionNumberString.startsWith("2.11."))
- object Scala212And213 {
- def ignoreInScala211(title: String)(f: => Any) = {
- title in f
- }
- }
- import Scala212And213._
- import Scala211._
-
- ignoreInScala211("yield from") {
- def generator = {
- def id[A](a: A) = a
- id(!Yield(100, 200))
- Seq.empty[Int].view ++ Nil
- }
- generator.toList should be(List(100, 200))
- }
-
- }
-
- "iterator" - {
-
- def shouldCompile: Iterator[String] = {
- !Yield("naked")
- Iterator.empty
- }
-
- "local method" in {
- def generator: Iterator[Int] = {
- def id[A](a: A) = a
- id(!Yield(100))
- Iterator.empty
- }
- generator.toList should be(List(100))
- }
-
- "yield from" in {
- def generator: Iterator[Int] = {
- def id[A](a: A) = a
- id(!Yield(100, 200))
- Iterator.empty
- }
- generator.toList should be(List(100, 200))
- }
- }
-
- "seq" - {
-
- def shouldCompile: LinearSeq[String] = {
- !Yield("naked")
- LinearSeq.empty[String]
- }
-
- "local method" in {
- def generator: LinearSeq[Int] = {
- def id[A](a: A) = a
- id(!Yield(100))
- LinearSeq.empty
- }
- generator should be(LinearSeq(100))
- }
-
- "yield from" in {
- def generator: LinearSeq[Int] = {
- def id[A](a: A) = a
- id(!Yield(100, 200))
- LinearSeq.empty
- }
- generator should be(LinearSeq(100, 200))
- }
- }
-}
diff --git a/package/build.sbt b/package/build.sbt
deleted file mode 100644
index 76206fa3..00000000
--- a/package/build.sbt
+++ /dev/null
@@ -1,74 +0,0 @@
-enablePlugins(Example)
-
-libraryDependencies += "org.scalatest" %%% "scalatest" % "3.0.6-SNAP2" % Test
-
-publishArtifact := false
-
-libraryDependencies ++= {
- import Ordering.Implicits._
- if (VersionNumber(scalaVersion.value).numbers >= Seq(2L, 13L)) {
- Nil
- } else {
- Seq(
- "org.scala-lang.plugins" %% "scala-continuations-library" % "1.0.3" % Optional,
- "org.scala-lang.modules" %% "scala-async" % "0.9.7" % Optional,
- "com.typesafe.akka" %% "akka-actor" % "2.5.14" % Optional,
- "com.twitter" %% "algebird-core" % "0.13.4" % Optional,
- "com.thoughtworks.binding" %% "binding" % "11.0.1" % Optional,
- "org.scala-lang.modules" %% "scala-parser-combinators" % "1.1.1" % Optional,
- "org.scalacheck" %% "scalacheck" % "1.14.0" % Optional,
- "com.thoughtworks.each" %% "each" % "3.3.1" % Optional,
- "com.lihaoyi" %% "sourcecode" % "0.1.4" % Optional,
- "io.monix" %% "monix" % "2.3.3" % Optional,
- "com.typesafe.akka" %% "akka-stream" % "2.5.14" % Optional,
- "com.typesafe.akka" %% "akka-http" % "10.1.3" % Optional
- )
- }
-}
-
-sourceGenerators in Test := {
- (sourceGenerators in Test).value.filterNot { sourceGenerator =>
- import Ordering.Implicits._
- VersionNumber(scalaVersion.value).numbers >= Seq(2L, 13L) &&
- sourceGenerator.info
- .get(taskDefinitionKey)
- .exists { scopedKey: ScopedKey[_] =>
- scopedKey.key == generateExample.key
- }
- }
-}
-
-libraryDependencies += "org.scalaz" %% "scalaz-concurrent" % "7.2.26"
-
-import scala.meta._
-
-exampleSuperTypes := exampleSuperTypes.value.filter {
- case ctor"_root_.org.scalatest.FreeSpec" =>
- false
- case _ =>
- true
-}
-
-exampleSuperTypes := ctor"_root_.org.scalatest.AsyncFreeSpec" +: exampleSuperTypes.value
-exampleSuperTypes += ctor"_root_.org.scalatest.Inside"
-exampleSuperTypes += ctor"_root_.com.thoughtworks.dsl.MockPingPongServer"
-
-addCompilerPlugin("org.spire-math" %% "kind-projector" % "0.9.7")
-
-scalacOptions ++= {
- import Ordering.Implicits._
- if (VersionNumber(scalaVersion.value).numbers >= Seq(2L, 13L)) {
- Seq("-Ymacro-annotations")
- } else {
- Nil
- }
-}
-
-libraryDependencies ++= {
- import Ordering.Implicits._
- if (VersionNumber(scalaVersion.value).numbers >= Seq(2L, 13L)) {
- Nil
- } else {
- Seq(compilerPlugin("org.scalamacros" % "paradise" % "2.1.1" cross CrossVersion.full))
- }
-}
diff --git a/package/src/main/scala/com/thoughtworks/dsl/package.scala b/package/src/main/scala/com/thoughtworks/dsl/package.scala
deleted file mode 100644
index 1c6b8b80..00000000
--- a/package/src/main/scala/com/thoughtworks/dsl/package.scala
+++ /dev/null
@@ -1,578 +0,0 @@
-package com.thoughtworks
-
-/** This project, '''Dsl.scala''', is a framework to create embedded '''D'''omain-'''S'''pecific '''L'''anguages.
- *
- * DSLs written in '''Dsl.scala''' are collaborative with others DSLs and Scala control flows.
- * DSL users can create functions that contains interleaved DSLs implemented by different vendors,
- * along with ordinary Scala control flows.
- *
- * We also provide some built-in DSLs for asynchronous programming, collection manipulation,
- * and adapters to [[scalaz.Monad]] or [[cats.Monad]].
- * Those built-in DSLs can be used as a replacement of
- * [[https://docs.scala-lang.org/tour/for-comprehensions.html `for` comprehension]],
- * [[https://github.com/scala/scala-continuations scala-continuations]],
- * [[https://github.com/scala/scala-async scala-async]],
- * [[http://monadless.io/ Monadless]],
- * [[https://github.com/pelotom/effectful effectful]]
- * and [[https://github.com/ThoughtWorksInc/each ThoughtWorks Each]].
- *
- * = Introduction =
- *
- * == Reinventing control flow in DSL ==
- *
- * Embedded DSLs usually consist of a set of domain-specific keywords,
- * which can be embedded in the their hosting languages.
- *
- * Ideally, a domain-specific keyword should be an optional extension,
- * which can be present everywhere in the ordinary control flow of the hosting language.
- * However, previous embedded DSLs usually badly interoperate with hosting language control flow.
- * Instead, they reinvent control flow in their own DSL.
- *
- * For example, the [[https://akka.io akka]] provides
- * [[https://doc.akka.io/docs/akka/2.5.10/fsm.html a DSL to create finite-state machines]],
- * which consists of some domain-specific keywords like [[akka.actor.FSM!.when when]],
- * [[akka.actor.FSM!.goto goto]] and [[akka.actor.FSM!.stay stay]].
- * Unfortunately, you cannot embedded those keywords into your ordinary `if` / `while` / `try` control flows,
- * because Akka's DSL is required to be split into small closures,
- * preventing ordinary control flows from crossing the boundary of those closures.
- *
- * TensorFlow's [[https://www.tensorflow.org/api_guides/python/control_flow_ops control flow operations]] and
- * Caolan's [[https://github.com/caolan/async async]] library are examples of reinventing control flow
- * in languages other than Scala.
- *
- * == Monad: the generic interface of control flow ==
- *
- * It's too trivial to reinvent the whole set of control flows for each DSL.
- * A simpler approach is only implementing a minimal interface required for control flows for each domain,
- * while the syntax of other control flow operations are derived from the interface, shared between different domains.
- *
- * Since [[https://www.sciencedirect.com/science/article/pii/0890540191900524 computation can be represented as monads]],
- * some libraries use monad as the interface of control flow,
- * including [[scalaz.Monad]], [[cats.Monad]] and [[com.twitter.algebird.Monad]].
- * A DSL author only have to implement two abstract method in [[scalaz.Monad]],
- * and all the derived control flow operations
- * like [[scalaz.syntax.MonadOps.whileM]], [[scalaz.syntax.BindOps.ifM]] are available.
- * In addition, those monadic data type can be created and composed
- * from Scala's built-in [[https://docs.scala-lang.org/tour/for-comprehensions.html `for` comprehension]].
- *
- * For example, you can use the same [[scalaz.syntax syntax]] or `for` comprehension
- * to create [[org.scalacheck.Gen random value generators]]
- * and [[com.thoughtworks.binding.Binding data-binding expressions]],
- * as long as there are [[scalaz.Monad Monad]] instances
- * for [[org.scalacheck.Gen]] and [[com.thoughtworks.binding.Binding]] respectively.
- *
- * Although the effort of creating a DSL is minimized with the help of monads,
- * the syntax is still unsatisfactory.
- * Methods in `MonadOps` still seem like a duplicate of ordinary control flow,
- * and `for` comprehension supports only a limited set of functionality in comparison to ordinary control flows.
- * `if` / `while` / `try` and other block expressions cannot appear in the enumerator clause of `for` comprehension.
- *
- * == Enabling ordinary control flows in DSL via macros ==
- *
- * An idea to avoid inconsistency between domain-specific control flow and ordinary control flow is
- * converting ordinary control flow to domain-specific control flow at compiler time.
- *
- * For example, [[https://github.com/scala/scala-async scala.async]] provides a macro
- * to generate asynchronous control flow.
- * The users just wrap normal synchronous code in a [[scala.async.Async.async async]] block,
- * and it runs asynchronously.
- *
- * This approach can be generalized to any monadic data types.
- * [[https://github.com/ThoughtWorksInc/each ThoughtWorks Each]], [[http://monadless.io/ Monadless]]
- * and [[https://github.com/pelotom/effectful effectful]] are macros
- * that convert ordinary control flow to monadic control flow.
- *
- * For example, with the help of [[https://github.com/ThoughtWorksInc/each ThoughtWorks Each]],
- * [[https://github.com/ThoughtWorksInc/Binding.scala Binding.scala]] is used to create reactive HTML templating
- * from ordinary Scala control flow.
- *
- * == Delimited continuations ==
- *
- * Another generic interface of control flow is continuation,
- * which is known as
- * [[https://www.schoolofhaskell.com/user/dpiponi/the-mother-of-all-monads the mother of all monads]],
- * where control flows in specific domain can be supported by specific final result types of continuations.
- *
- * [[https://github.com/scala/scala-continuations scala-continuations]]
- * and [[https://github.com/qifun/stateless-future stateless-future]]
- * are two delimited continuation implementations.
- * Both projects can convert ordinary control flow to continuation-passing style closure chains at compiler time.
- *
- * For example, [[https://github.com/qifun/stateless-future-akka stateless-future-akka]],
- * based on `stateless-future`,
- * provides a special final result type for akka actors.
- * Unlike [[akka.actor.FSM]]'s inconsistent control flows, users can create complex finite-state machines
- * from simple ordinary control flows along with `stateless-future-akka`'s domain-specific keyword `nextMessage`.
- *
- * == Collaborative DSLs ==
- *
- * All the above approaches lack of the ability to collaborate with other DSLs.
- * Each of the above DSLs can be only exclusively enabled in a code block.
- * For example,
- * [[https://github.com/scala/scala-continuations scala-continuations]]
- * enables calls to `@cps` method in [[scala.util.continuations.reset]] blocks,
- * and [[https://github.com/ThoughtWorksInc/each ThoughtWorks Each]]
- * enables the magic `each` method for [[scalaz.Monad]] in [[com.thoughtworks.each.Monadic.monadic]] blocks.
- * It is impossible to enable both DSLs in one function.
- *
- * This [[https://github.com/ThoughtWorksInc/Dsl.scala Dsl.scala]] project resolves this problem.
- *
- * We also provide adapters to all the above kinds of DSLs.
- * Instead of switching different DSLs between different functions,
- * DSL users can use multiple DSLs together in one function,
- * by simply adding [[com.thoughtworks.dsl.compilerplugins.BangNotation our Scala compiler plug-in]].
- *
- * @example Suppose you want to create an [[https://en.wikipedia.org/wiki/Xorshift Xorshift]] random number generator.
- *
- * The generated numbers should be stored in a lazily evaluated infinite [[scala.collection.immutable.Stream Stream]],
- * which can be implemented as a recursive function that produce the next random number in each iteration,
- * with the help of our built-in domain-specific keyword [[com.thoughtworks.dsl.keywords.Yield Yield]].
- *
- * {{{
- * import com.thoughtworks.dsl.Dsl.reset
- * import com.thoughtworks.dsl.keywords.Yield
- *
- * def xorshiftRandomGenerator(seed: Int): Stream[Int] = {
- * val tmp1 = seed ^ (seed << 13)
- * val tmp2 = tmp1 ^ (tmp1 >>> 17)
- * val tmp3 = tmp2 ^ (tmp2 << 5)
- * !Yield(tmp3)
- * xorshiftRandomGenerator(tmp3)
- * }: @reset
- *
- * val myGenerator = xorshiftRandomGenerator(seed = 123)
- *
- * myGenerator(0) should be(31682556)
- * myGenerator(1) should be(-276305998)
- * myGenerator(2) should be(2101636938)
- * }}}
- *
- * [[com.thoughtworks.dsl.keywords.Yield Yield]] is an keyword to produce a value
- * for a lazily evaluated [[scala.collection.immutable.Stream Stream]].
- * That is to say, [[scala.collection.immutable.Stream Stream]] is the domain
- * where the DSL [[com.thoughtworks.dsl.keywords.Yield Yield]] can be used,
- * which was interpreted like the `yield` keyword in C#, JavaScript or Python.
- *
- * Note that the body of `xorshiftRandomGenerator` is annotated as `@[[Dsl.reset reset]]`,
- * which enables the [[Dsl.Keyword#unary_$bang !-notation]] in the code block.
- *
- * Alternatively, you can also use the
- * [[com.thoughtworks.dsl.compilerplugins.ResetEverywhere ResetEverywhere]] compiler plug-in,
- * which enable [[Dsl.Keyword#unary_$bang !-notation]] for every methods and functions.
- * @example [[com.thoughtworks.dsl.keywords.Yield Yield]] and [[scala.collection.immutable.Stream Stream]]
- * can be also used for logging.
- *
- * Suppose you have a function to parse an JSON file,
- * you can append log records to a [[scala.collection.immutable.Stream Stream]] during parsing.
- *
- * {{{
- * import com.thoughtworks.dsl.keywords.Yield
- * import com.thoughtworks.dsl.Dsl.!!
- * import scala.util.parsing.json._
- * def parseAndLog1(jsonContent: String, defaultValue: JSONType): Stream[String] !! JSONType = { (callback: JSONType => Stream[String]) =>
- * !Yield(s"I am going to parse the JSON text $jsonContent...")
- * JSON.parseRaw(jsonContent) match {
- * case Some(json) =>
- * !Yield(s"Succeeded to parse $jsonContent")
- * callback(json)
- * case None =>
- * !Yield(s"Failed to parse $jsonContent")
- * callback(defaultValue)
- * }
- * }
- * }}}
- *
- * Since the function produces both a [[scala.util.parsing.json.JSONType JSONType]]
- * and a [[scala.collection.immutable.Stream Stream]] of logs,
- * the return type is now `Stream[String] !! JSONType`,
- * where [[com.thoughtworks.dsl.Dsl.$bang$bang !!]] is
- * `(JSONType => Stream[String]) => Stream[String]`,
- * an alias of continuation-passing style function,
- * indicating it produces both a [[scala.util.parsing.json.JSONType JSONType]] and a [[scala.Stream Stream]] of logs.
- *
- * {{{
- * val logs = parseAndLog1(""" { "key": "value" } """, JSONArray(Nil)) { json =>
- * json should be(JSONObject(Map("key" -> "value")))
- * Stream("done")
- * }
- *
- * logs should be(Stream("I am going to parse the JSON text { \"key\": \"value\" } ...",
- * "Succeeded to parse { \"key\": \"value\" } ",
- * "done"))
- * }}}
- * @example The closure in the previous example can be simplified with the help of Scala's placeholder syntax:
- *
- * {{{
- * import com.thoughtworks.dsl.keywords.Yield
- * import com.thoughtworks.dsl.Dsl.!!
- * import scala.util.parsing.json._
- * def parseAndLog2(jsonContent: String, defaultValue: JSONType): Stream[String] !! JSONType = _ {
- * !Yield(s"I am going to parse the JSON text $jsonContent...")
- * JSON.parseRaw(jsonContent) match {
- * case Some(json) =>
- * !Yield(s"Succeeded to parse $jsonContent")
- * json
- * case None =>
- * !Yield(s"Failed to parse $jsonContent")
- * defaultValue
- * }
- * }
- *
- * val logs = parseAndLog2(""" { "key": "value" } """, JSONArray(Nil)) { json =>
- * json should be(JSONObject(Map("key" -> "value")))
- * Stream("done")
- * }
- *
- * logs should be(Stream("I am going to parse the JSON text { \"key\": \"value\" } ...",
- * "Succeeded to parse { \"key\": \"value\" } ",
- * "done"))
- * }}}
- *
- * Note that `parseAndLog2` is equivelent to `parseAndLog1`.
- * The code block after underscore is still inside a function whose return type is `Stream[String]`.
- * @example Instead of manually create the continuation-passing style function,
- * you can also create the function from a [[com.thoughtworks.dsl.Dsl.$bang$bang !!]] block.
- *
- * {{{
- * import com.thoughtworks.dsl.keywords.Yield
- * import com.thoughtworks.dsl.Dsl.!!
- * import scala.util.parsing.json._
- * def parseAndLog3(jsonContent: String, defaultValue: JSONType): Stream[String] !! JSONType = !! {
- * !Yield(s"I am going to parse the JSON text $jsonContent...")
- * JSON.parseRaw(jsonContent) match {
- * case Some(json) =>
- * !Yield(s"Succeeded to parse $jsonContent")
- * json
- * case None =>
- * !Yield(s"Failed to parse $jsonContent")
- * defaultValue
- * }
- * }
- *
- * val logs = parseAndLog3(""" { "key": "value" } """, JSONArray(Nil)) { json =>
- * json should be(JSONObject(Map("key" -> "value")))
- * Stream("done")
- * }
- *
- * logs should be(Stream("I am going to parse the JSON text { \"key\": \"value\" } ...",
- * "Succeeded to parse { \"key\": \"value\" } ",
- * "done"))
- * }}}
- *
- * Unlike the `parseAndLog2` example, The code inside a `!!` block is not in an anonymous function.
- * Instead, they are directly inside `parseAndLog3`, whose return type is `Stream[String] !! JSONType`.
- *
- * That is to say,
- * the domain of those [[com.thoughtworks.dsl.keywords.Yield Yield]] keywords in `parseAndLog3`
- * is not `Stream[String]` any more, the domain is `Stream[String] !! JSONType` now,
- * which supports more keywords, which you will learnt from the next examples,
- * than the `Stream[String]` domain.
- * @example [[com.thoughtworks.dsl.Dsl.$bang$bang !!]], or [[com.thoughtworks.dsl.Dsl.Continuation Continuation]],
- * is the preferred approach to enable multiple domains in one function.
- *
- * For example, you can create a function that
- * lazily read each line of a [[java.io.BufferedReader BufferedReader]] to a [[scala.Stream Stream]],
- * automatically close the [[java.io.BufferedReader BufferedReader]] after reading the last line,
- * and finally return the total number of lines in the `Stream[String] !! Throwable !! Int` domain.
- *
- * {{{
- * import com.thoughtworks.dsl.Dsl.!!
- * import com.thoughtworks.dsl.keywords.Using
- * import com.thoughtworks.dsl.keywords.Yield
- * import com.thoughtworks.dsl.keywords.Shift._
- * import java.io._
- *
- * def readerToStream(createReader: () => BufferedReader): Stream[String] !! Throwable !! Int = !! {
- * val reader = !Using(createReader())
- *
- * def loop(lineNumber: Int): Stream[String] !! Throwable !! Int = _ {
- * reader.readLine() match {
- * case null =>
- * lineNumber
- * case line =>
- * !Yield(line)
- * !loop(lineNumber + 1)
- * }
- * }
- *
- * !loop(0)
- * }
- * }}}
- *
- * `!loop(0)` is a shortcut of `!Shift(loop(0))`,
- * because there is [[keywords.Shift.implicitShift an implicit conversion]]
- * from `Stream[String] !! Throwable !! Int` to a [[keywords.Shift]] case class,
- * which is similar to the `await` keyword in JavaScript, Python or C#.
- *
- * A type like `A !! B !! C` means a domain-specific value of type `C` in the domain of `A` and `B`.
- * When `B` is [[scala.Throwable Throwable]], the [[keywords.Using]]
- * is available, which will close a resource when exiting the current function.
- *
- * {{{
- * import scala.util.Success
- *
- * var isClosed = false
- * def createReader() = {
- * new BufferedReader(new StringReader("line1\nline2\nline3")) {
- * override def close() = {
- * isClosed = true
- * }
- * }
- * }
- *
- * val stream = readerToStream(createReader _) { numberOfLines: Int =>
- * numberOfLines should be(3)
- *
- * Function.const(Stream.empty)(_)
- * } { e: Throwable =>
- * throw new AssertionError("Unexpected exception during readerToStream", e)
- * }
- *
- * isClosed should be(false)
- * stream should be(Stream("line1", "line2", "line3"))
- * isClosed should be(true)
- * }}}
- * @example If you don't need to collaborate to [[scala.Stream Stream]] or other domains,
- * you can use `TailRec[Unit] !! Throwable !! A`
- * or the alias [[domains.task.Task]] as the return type,
- * which can be used as an asynchronous task that support RAII,
- * as a higher-performance replacement of
- * [[scala.concurrent.Future]], [[scalaz.concurrent.Task]] or [[monix.eval.Task]].
- *
- * Also, there are some keywords in [[keywords.AsynchronousIo]]
- * to asynchronously perform Java NIO.2 IO operations in a [[domains.task.Task]] domain.
- * For example, you can implement an HTTP client from those keywords.
- *
- * {{{
- * import com.thoughtworks.dsl.domains.task._
- * import com.thoughtworks.dsl.keywords._
- * import com.thoughtworks.dsl.keywords.Shift.implicitShift
- * import com.thoughtworks.dsl.keywords.AsynchronousIo._
- * import java.io._
- * import java.net._
- * import java.nio._, channels._
- *
- * def readAll(channel: AsynchronousByteChannel, destination: ByteBuffer): Task[Unit] = _ {
- * if (destination.remaining > 0) {
- * val numberOfBytesRead: Int = !Read(channel, destination)
- * numberOfBytesRead match {
- * case -1 =>
- * case _ => !readAll(channel, destination)
- * }
- * } else {
- * throw new IOException("The response is too big to read.")
- * }
- * }
- *
- * def writeAll[Domain](channel: AsynchronousByteChannel, destination: ByteBuffer): Task[Unit] = _ {
- * while (destination.remaining > 0) {
- * !Write(channel, destination)
- * }
- * }
- *
- * def httpClient(url: URL): Task[String] = _ {
- * val socket = AsynchronousSocketChannel.open()
- * try {
- * val port = if (url.getPort == -1) 80 else url.getPort
- * val address = new InetSocketAddress(url.getHost, port)
- * !AsynchronousIo.Connect(socket, address)
- * val request = ByteBuffer.wrap(s"GET ${url.getPath} HTTP/1.1\r\nHost:${url.getHost}\r\nConnection:Close\r\n\r\n".getBytes)
- * !writeAll(socket, request)
- * val response = ByteBuffer.allocate(100000)
- * !readAll(socket, response)
- * response.flip()
- * io.Codec.UTF8.decoder.decode(response).toString
- * } finally {
- * socket.close()
- * }
- * }
- * }}}
- *
- * The usage of `Task` is similar to previous examples.
- * You can check the result or exception in asynchronous handlers.
- *
- * But we also provides [[com.thoughtworks.dsl.domains.task.Task.blockingAwait blockingAwait]] and some other utilities
- * at [[domains.task.Task]].
- *
- * {{{
- * import com.thoughtworks.dsl.domains.task.Task.blockingAwait
- *
- * val url = new URL("http://localhost:4001/ping")
- * val fileContent = blockingAwait(httpClient(url))
- * fileContent should startWith("HTTP/1.1 200 OK")
- * }}}
- *
- * Another useful keyword for asynchronous programming is [[com.thoughtworks.dsl.keywords.Fork Fork]],
- * which duplicate the current control flow, and the child control flows are executed in parallel,
- * similar to the POSIX `fork` system call.
- *
- * [[com.thoughtworks.dsl.keywords.Fork Fork]] should be used inside
- * a [[com.thoughtworks.dsl.domains.task.Task#join]] block, which collects the result of each forked control flow.
- *
- * {{{
- * import com.thoughtworks.dsl.keywords.Fork
- * import com.thoughtworks.dsl.keywords.Return
- * val Urls = Seq(
- * new URL("http://localhost:4001/ping"),
- * new URL("http://localhost:4001/pong")
- * )
- * def parallelTask: Task[Seq[String]] = {
- * val url = !Fork(Urls)
- * !Return(!httpClient(url))
- * }
- *
- * inside(blockingAwait(parallelTask)) {
- * case Seq(fileContent0, fileContent1) =>
- * fileContent0 should startWith("HTTP/1.1 200 OK")
- * fileContent1 should startWith("HTTP/1.1 200 OK")
- * }
- * }}}
- * @example The built-in [[keywords.Monadic]] can be used as an adaptor
- * to [[scalaz.Monad]] and [[scalaz.MonadTrans]],
- * to create monadic code from imperative syntax,
- * similar to the !-notation in Idris.
- *
- * For example, suppose you are creating a program that counts lines of code under a directory.
- * You want to store the result in a [[scala.Stream Stream]] of line count of each file.
- *
- * {{{
- * import java.io.File
- * import com.thoughtworks.dsl.keywords.Monadic
- * import com.thoughtworks.dsl.domains.scalaz._
- * import scalaz.std.stream._
- *
- * def countMonadic(file: File): Stream[Int] = Stream {
- * if (file.isDirectory) {
- * file.listFiles() match {
- * case null =>
- * // Unable to open `file`
- * !Monadic(Stream.empty[Int])
- * case children =>
- * // Import this implicit conversion to omit the Monadic keyword
- * import com.thoughtworks.dsl.keywords.Monadic.implicitMonadic
- *
- * val child: File = !children.toStream
- * !countMonadic(child)
- * }
- * } else {
- * scala.io.Source.fromFile(file).getLines.size
- * }
- * }
- *
- *
- * val countCurrentSourceFile = countMonadic(new File(sourcecode.File()))
- *
- * inside(countCurrentSourceFile) {
- * case Stream(lineCount) =>
- * lineCount should be > 0
- * }
- *
- * }}}
- * @example The previous code requires a `toStream` conversion on `children`,
- * because `children`'s type `Array[File]` does not fit the `F` type parameter in [[scalaz.Monad.bind]].
- *
- * The conversion can be avoided if using [[scala.collection.generic.CanBuildFrom CanBuildFrom]] type class
- * instead of monads.
- *
- * We provide a [[com.thoughtworks.dsl.keywords.Each Each]]
- * keyword to extract each element in a Scala collection.
- * The behavior is similar to monad, except the collection type can vary.
- *
- * For example, you can extract each element from an [[scala.Array Array]],
- * even when the return type (or the domain) is a [[scala.collection.immutable.Stream Stream]].
- *
- *
- * {{{
- * import java.io.File
- * import com.thoughtworks.dsl.keywords.Monadic, Monadic.implicitMonadic
- * import com.thoughtworks.dsl.keywords.Each
- * import com.thoughtworks.dsl.domains.scalaz._
- * import scalaz.std.stream._
- *
- * def countEach(file: File): Stream[Int] = Stream {
- * if (file.isDirectory) {
- * file.listFiles() match {
- * case null =>
- * // Unable to open `file`
- * !Stream.empty[Int]
- * case children =>
- * val child: File = !Each(children)
- * !countEach(child)
- * }
- * } else {
- * scala.io.Source.fromFile(file).getLines.size
- * }
- * }
- *
- *
- * val countCurrentSourceFile = countEach(new File(sourcecode.File()))
- *
- * inside(countCurrentSourceFile) {
- * case Stream(lineCount) =>
- * lineCount should be > 0
- * }
- *
- * }}}
- *
- * Unlike Haskell's do-notation or Idris's !-notation,
- * Dsl.scala allows non-monadic keywords like [[com.thoughtworks.dsl.keywords.Each Each]] works along with
- * monads.
- * @example Dsl.scala also supports [[scalaz.MonadTrans]].
- *
- * Considering the line counter implemented in previous example may be failed for some files,
- * due to permission issue or other IO problem,
- * you can use [[scalaz.OptionT]] monad transformer to mark those failed file as a [[scala.None None]].
- *
- * {{{
- * import scalaz._
- * import java.io.File
- * import com.thoughtworks.dsl.keywords.Monadic, Monadic.implicitMonadic
- * import com.thoughtworks.dsl.domains.scalaz._
- * import scalaz.std.stream._
- *
- * def countLift(file: File): OptionT[Stream, Int] = OptionT.some {
- * if (file.isDirectory) {
- * file.listFiles() match {
- * case null =>
- * // Unable to open `file`
- * !OptionT.none[Stream, Int]
- * case children =>
- * val child: File = !Stream(children: _*)
- * !countLift(child)
- * }
- * } else {
- * scala.io.Source.fromFile(file).getLines.size
- * }
- * }
- *
- *
- * val countCurrentSourceFile = countLift(new File(sourcecode.File())).run
- *
- * inside(countCurrentSourceFile) {
- * case Stream(Some(lineCount)) =>
- * lineCount should be > 0
- * }
- * }}}
- *
- *
- * Note that our keywords are adaptive to the domain it belongs to.
- * Thus, instead of explicit `!Monadic(OptionT.optionTMonadTrans.liftM(Stream(children: _*)))`,
- * you can simply have `!Stream(children: _*)`.
- * The implicit lifting feature looks like Idris's effect monads,
- * though the mechanisms is different from `implicit lift` in Idris.
- * @see [[Dsl]] for the guideline to create your custom DSL.
- * @see [[domains.scalaz]] for using [[Dsl.Keyword#unary_$bang !-notation]] with [[scalaz]].
- * @see [[domains.cats]] for using [[Dsl.Keyword#unary_$bang !-notation]] with [[cats]].
- *
- *
- */
-package object dsl
-
-package dsl {
-
- /** Contains built-in domain-specific [[com.thoughtworks.dsl.Dsl.Keyword Keyword]]s and their corresponding interpreters.
- *
- *
- */
- package object keywords
-}
diff --git a/package/src/test/scala/com/thoughtworks/dsl/MockPingPongServer.scala b/package/src/test/scala/com/thoughtworks/dsl/MockPingPongServer.scala
deleted file mode 100644
index 4737b427..00000000
--- a/package/src/test/scala/com/thoughtworks/dsl/MockPingPongServer.scala
+++ /dev/null
@@ -1,39 +0,0 @@
-package com.thoughtworks.dsl
-import com.thoughtworks.enableMembersIf
-import org.scalatest.{AsyncTestSuite, BeforeAndAfterAll, Suite}
-
-import scala.concurrent.ExecutionContext
-import scala.concurrent.duration.Duration
-
-/**
- * @author 杨博 (Yang Bo)
- */
-@enableMembersIf(scala.util.Properties.versionNumberString.matches("""^2\.1(1|2)\..*$"""))
-trait MockPingPongServer extends BeforeAndAfterAll { this: Suite =>
-
- implicit def executionContext: ExecutionContext
-
- protected implicit val system = akka.actor.ActorSystem()
-
- protected implicit val materializer = akka.stream.ActorMaterializer()
-
- protected val mockServer = {
- import akka.http.scaladsl.server.Directives._
- val route =
- get {
- path("ping") {
- complete("PING!")
- } ~ path("pong") {
- complete("PONG!")
- }
- }
- concurrent.Await.result(akka.http.scaladsl.Http().bindAndHandle(route, "localhost", 4001), Duration.Inf)
- }
-
- override protected def afterAll(): Unit = {
- mockServer
- .unbind()
- .onComplete(_ => system.terminate())
- }
-
-}