Instructs Inikio's KSP plug-in to create a Builder based on this hierarchy.
suspended syntax
14 | * Compiler plug-in
15 | * Examples of DSLs
16 |
17 | suspended syntaxIndicates that this DSL has a fixed result type, instead of being polymorphic on the result type.
The type must be a fully-qualified name. Unfortunately we cannot use a Class here because of limitations of KSP + Kotlin Multiplatform.
Record the execution of an action which doesn't consume any value.
Record the execution of an action which doesn't consume any value, and requires an additional argument of type A.
Record the execution of an action which doesn't consume any value, and requires additional arguments of types A and B.
Record the execution of an action which consumes a value of type R.
Record the execution of an action which consumes a value of type R, and requires an additional argument of type A.
Record the execution of an action which consumes a value of type R, and requires additional arguments of types A and B.
Turns the DSL provided by ProgramBuilder into an actual Action. This version is used for "pure" programs with no exceptional cases.
Reference to the "final" instruction in Action.
Turns the DSL provided by ProgramBuilder into an actual Action.
Reference to the "final" instruction in Action.
Reference to the "error" instruction in Action.
Turns the DSL provided by a subclass T of ProgramBuilder into an actual Action.
Information about Inikio's compiler plug-in, that creates Builders automatically for your initial-style DSLs.
The plug-in is based on KSP. If you are using Gradle you need to add the following to your build file.
repositories {
mavenCentral()
maven(url = "https://jitpack.io")
}
plugins {
id("com.google.devtools.ksp") version "2.0.20-1.0.24"
}
dependencies {
implementation("com.github.serras.inikio:inikio-core:$inikioVersion")
ksp("com.github.serras.inikio:inikio-ksp:$inikioVersion")
}If IntelliJ is your IDE of choice, we recommend configuring your build to make it aware of KSP.
You only need to add the @InitialStyleDSL annotation to the top of your hierarchy. Remember that you need to have one "finished" variant, in the example below is Done.
@InitialStyleDSL
sealed interface Casino<out A>
data class Done<out A>(val result: A): Casino<A>
data class FlipCoin<out A>(val next: (Outcome) -> Casino<A>): Casino<A> {
enum class Outcome { HEADS, TAILS }
}BuilderFrom the definition above the plug-in generates a Builder class and a runner function.
The Builder class contains a method for each variant in the DSL, that is, for each basic instruction in your DSL.
class CasinoBuilder<A> {
suspend fun flipCoin(): FlipCoin.Outcome
}The runner function takes a block with the Builder as receiver, and converts it into the initial-style DSL.
fun <A> casino(block: CasinoBuilder<A>.() -> A): Casino<A>You can use the combination of the runner and the Builder methods to create values of your initial-style DSL. For example, the following defines a game when only two heads win.
val doubleCoin = casino {
val o1 = flipCoin()
val o2 = flipCoin()
if (o1 == Outcome.HEADS && o2 == Outcome.HEADS) WIN
else LOSE
}Note the much nicer syntax with suspend that what you'd get with the data classes themselves. In particular, all the nesting is gone, and there's no need to call the final Done. The code above is equivalent to the following.
val casino =
FlipCoin { o1 ->
FlipCoin { o2 ->
if (o1 == Outcome.HEADS && o2 == Outcome.HEADS)
Done(WIN)
else
Done(LOSE)
}
}Indicates that this DSL has a fixed result type, instead of being polymorphic on the result type.
Instructs Inikio's KSP plug-in to create a Builder based on this hierarchy.