Package-level declarations

Information about Inikio's compiler plug-in, that creates Builders automatically for your initial-style DSLs.

Step 1, add the plug-in to your build

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 "1.7.22-1.0.8"
}
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.

Step 2, annotate your DSLs

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 }
}

Step 3, enjoy your new Builder

From 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)
}
}

Types

Link copied to clipboard
annotation class FixedResultType(val type: String)

Indicates that this DSL has a fixed result type, instead of being polymorphic on the result type.

Link copied to clipboard
annotation class InitialStyleDSL

Instructs Inikio's KSP plug-in to create a Builder based on this hierarchy.