Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .scalafmt.conf
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
runner.dialect = "scala213"
version = "3.2.1"
version = "3.1.2"
maxColumn = 120
38 changes: 16 additions & 22 deletions Dsl/src/main/scala/com/thoughtworks/dsl/Dsl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,17 @@ 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`.
/** 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:
* @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]].
* - 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] {
Expand Down Expand Up @@ -239,9 +236,8 @@ object Dsl extends LowPriorityDsl0 {

/** 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.
* @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

Expand All @@ -251,11 +247,9 @@ object Dsl extends LowPriorityDsl0 {
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
/** @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 =>

Expand Down Expand Up @@ -293,8 +287,8 @@ object Dsl extends LowPriorityDsl0 {

/** The type class to support `try` ... `catch` ... `finally` expression for `OutputDomain`.
*
* !-notation is allowed by default for `? !! Throwable` and [[scala.concurrent.Future Future]] domains, with the
* help of this type class.
* !-notation is allowed by default for `? !! Throwable` and [[scala.concurrent.Future Future]] domains,
* with the help of this type class.
*/
@implicitNotFound(
"The `try` ... `catch` ... `finally` expression cannot contain !-notation inside a function that returns ${OuterDomain}."
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,17 @@ private object BangNotation {

}

/** The Scala compiler plug-in to convert ordinary Scala control flows to continuation-passing style, which will then be
* interpreted by [[Dsl]].
/** The Scala compiler plug-in to convert ordinary Scala control flows to continuation-passing style,
* which will then be interpreted by [[Dsl]].
*
* =Usage=
* = Usage =
*
* `<pre> // In your build.sbt addCompilerPlugin("com.thoughtworks.dsl" %% "compilerplugins-bangnotation" %
* "latest.release") </pre>`
* `<pre>
* // In your build.sbt
* addCompilerPlugin("com.thoughtworks.dsl" %% "compilerplugins-bangnotation" % "latest.release")
* </pre>`
*
* @author
* 杨博 (Yang Bo)
* @author 杨博 (Yang Bo)
*/
final class BangNotation(override val global: Global) extends Plugin {
import global._
Expand Down Expand Up @@ -64,8 +65,7 @@ final class BangNotation(override val global: Global) extends Plugin {

/** Avoid [[UnApply]] in `tree` to suppress compiler crash due to `unexpected UnApply xxx`.
*
* @see
* https://github.com/scala/bug/issues/8825
* @see https://github.com/scala/bug/issues/8825
*/
private def scalaBug8825Workaround(tree: Tree): Tree = {
val transformer = new Transformer {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ import com.thoughtworks.dsl.Dsl.shift
import org.scalatest.freespec.AnyFreeSpec
import org.scalatest.matchers.should.Matchers

/** @author
* 杨博 (Yang Bo)
/** @author 杨博 (Yang Bo)
*/
class BangNotationSpec extends AnyFreeSpec with Matchers {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,16 @@ import scala.tools.nsc.{Global, Mode, Phase}
*
* Add the following setting in your `build.sbt` to enable this plug-in.
*
* `<pre> // build.sbt addCompilerPlugin("com.thoughtworks.dsl" %% "compilerplugins-reseteverywhere" %
* "latest.release") </pre>`
* `<pre>
* // build.sbt
* addCompilerPlugin("com.thoughtworks.dsl" %% "compilerplugins-reseteverywhere" % "latest.release")
* </pre>`
*
* @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.
* @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)
* @author 杨博 (Yang Bo)
*/
final class ResetEverywhere(override val global: Global) extends Plugin {
import global._
Expand Down
191 changes: 93 additions & 98 deletions comprehension/src/main/scala/com/thoughtworks/dsl/comprehension.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,104 +21,99 @@ private[dsl] sealed trait LowPriorityComprehension0 {
* 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"))
* }}}
* @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 {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ import com.thoughtworks.dsl.keywords.{Monadic, Shift, Yield}
import org.scalatest.freespec.AnyFreeSpec
import org.scalatest.matchers.should.Matchers

/** @author
* 杨博 (Yang Bo)
/** @author 杨博 (Yang Bo)
*/
class scalazSpec extends AnyFreeSpec with Matchers {

Expand Down
Loading