diff --git a/README.md b/README.md index 1680815..9beab0a 100644 --- a/README.md +++ b/README.md @@ -232,11 +232,11 @@ data class Customer(val something: String, @Component val name: Name, @Component on(something).match( case( Customer[Name[Is(), Is()], Partner(Is())] ) - .thenThis {{ first, last, id -> + .thenThis { first, last, id -> // You can use the `this` keyword to refer to the `Customer` instance (also `this` can be omitted entirely). // (the components first, last, id are also available here for convenience) this.something + this.somethingElse - }} + } // Other cases... ) ``` diff --git a/decomat-core/src/main/kotlin/io/decomat/ThenPattern1.kt b/decomat-core/src/main/kotlin/io/decomat/ThenPattern1.kt index 80ac85b..97bdbfa 100644 --- a/decomat-core/src/main/kotlin/io/decomat/ThenPattern1.kt +++ b/decomat-core/src/main/kotlin/io/decomat/ThenPattern1.kt @@ -11,9 +11,9 @@ class ThenIs( } inline fun thenIf(crossinline f: (R) -> Boolean) = ThenIs(pat) { r: R -> useComponents(r, f) } - inline fun thenIfThis(crossinline f: R.() -> (R) -> Boolean) = ThenIs(pat) { r: R -> useComponents(r, f(r)) } + inline fun thenIfThis(crossinline f: R.(R) -> Boolean) = ThenIs(pat) { r: R -> useComponents(r, { c -> f(r, c) }) } inline fun then(crossinline f: (R) -> O): Case = StageCase(pat, check) { r: R -> useComponents(r, f) } - inline fun thenThis(crossinline f: R.() -> (R) -> O): Case = StageCase(pat, check) { r: R -> useComponents(r, f(r)) } + inline fun thenThis(crossinline f: R.(R) -> O): Case = StageCase(pat, check) { r: R -> useComponents(r, { c -> f(r, c) }) } } @@ -24,15 +24,15 @@ class Then0, R1, R>( override val pat: Pattern1, override val check: (R) -> Boolean ): Stage, R> { - inline fun useComponents(r: R, f: (Components1) -> O): O { + inline fun useComponents(r: R, f: (R1) -> O): O { val (r1) = pat.divideIntoComponentsAny(r as Any) - return f(Components1(r1)) + return f(r1) } - inline fun thenIf(crossinline f: (Components1) -> Boolean) = Then0(pat) { r: R -> useComponents(r, f) } - inline fun thenIfThis(crossinline f: R.() -> (Components1) -> Boolean) = Then0(pat) { r: R -> useComponents(r, f(r)) } - inline fun then(crossinline f: (Components1) -> O): Case = StageCase(pat, check) { r: R -> useComponents(r, f) } - inline fun thenThis(crossinline f: R.() -> (Components1) -> O): Case = StageCase(pat, check) { r: R -> useComponents(r, f(r)) } + inline fun thenIf(crossinline f: (R1) -> Boolean) = Then0(pat) { r: R -> useComponents(r, f) } + inline fun thenIfThis(crossinline f: R.(R1) -> Boolean) = Then0(pat) { r: R -> useComponents(r, { c -> f(r, c) }) } + inline fun then(crossinline f: (R1) -> O): Case = StageCase(pat, check) { r: R -> useComponents(r, f) } + inline fun thenThis(crossinline f: R.(R1) -> O): Case = StageCase(pat, check) { r: R -> useComponents(r, { c -> f(r, c) }) } } fun , P11: Pattern, R11, R1, R> case(pat: Pattern1) = Then1(pat, {true}) @@ -48,9 +48,9 @@ class Then1, P11: Pattern, R11, R1, R>( } inline fun thenIf(crossinline f: (Components1) -> Boolean) = Then1(pat) { r: R -> useComponents(r, f) } - inline fun thenIfThis(crossinline f: R.() -> (Components1) -> Boolean) = Then1(pat) { r: R -> useComponents(r, f(r)) } + inline fun thenIfThis(crossinline f: R.(Components1) -> Boolean) = Then1(pat) { r: R -> useComponents(r, { c -> f(r, c) }) } inline fun then(crossinline f: (Components1) -> O) = StageCase(pat, check) { r: R -> useComponents(r, f) } - inline fun thenThis(crossinline f: R.() -> (Components1) -> O) = StageCase(pat, check) { r: R -> useComponents(r, f(r)) } + inline fun thenThis(crossinline f: R.(Components1) -> O) = StageCase(pat, check) { r: R -> useComponents(r, { c -> f(r, c) }) } } /** Generic match for Pattern2 where we don't know what A and B are */ @@ -69,9 +69,9 @@ class Then2, P11: Pattern, R11, P12: P } inline fun thenIf(crossinline f: (Components2) -> Boolean) = Then2(pat) { r: R -> useComponents(r, f) } - inline fun thenIfThis(crossinline f: R.() -> (Components2) -> Boolean) = Then2(pat) { r: R -> useComponents(r, f(r)) } + inline fun thenIfThis(crossinline f: R.(Components2) -> Boolean) = Then2(pat) { r: R -> useComponents(r, { c -> f(r, c) }) } inline fun then(crossinline f: (Components2) -> O) = StageCase(pat, check) { r: R -> useComponents(r, f) } - inline fun thenThis(crossinline f: R.() -> (Components2) -> O) = StageCase(pat, check) { r: R -> useComponents(r, f(r)) } + inline fun thenThis(crossinline f: R.(Components2) -> O) = StageCase(pat, check) { r: R -> useComponents(r, { c -> f(r, c) }) } } //fun , P1: Pattern, P2: Pattern, R1, R2, R> case(pat: Pattern2) = GenericThen2X(pat, {true}) diff --git a/decomat-core/src/templates/Pattern3.ftl b/decomat-core/src/templates/Pattern3.ftl index 5c2a020..b806dcb 100644 --- a/decomat-core/src/templates/Pattern3.ftl +++ b/decomat-core/src/templates/Pattern3.ftl @@ -1,7 +1,6 @@ [#ftl] - [#macro Pattern num] [@compress single_line=true] [#if num == 0]Pattern0 @@ -96,6 +95,8 @@ [/@compress] [/#macro] + + [@output file="decomat-core/build/templates/io/decomat/Then2.kt"] package io.decomat @@ -116,12 +117,17 @@ class Then${i1}${i2}( [#if i2 != 0]val [@vars 2 i2 /] = pat.pattern2.divideIntoComponentsAny(r2 as Any)[#else]//skip[/#if] return f([@compVars2 i1, i2 /]) } + inline fun thenIf(crossinline f: ([@Components 1 i1 /], [@Components 2 i2 /]) -> Boolean) = + Then${i1}${i2}(pat) { v -> useComponents(v, { c1, c2 -> f(c1, c2) }) } + + inline fun thenIfThis(crossinline f: R.([@Components 1 i1 /], [@Components 2 i2 /]) -> Boolean) = + Then${i1}${i2}(pat) { v -> useComponents(v, { c1, c2 -> f(v, c1, c2) }) } inline fun then(crossinline f: ([@Components 1 i1 /], [@Components 2 i2 /]) -> O) = - StageCase(pat, check) { value -> useComponents(value, f) } + StageCase(pat, check) { v -> useComponents(v, { c1, c2 -> f(c1, c2) }) } - inline fun thenThis(crossinline f: R.() -> ([@Components 1 i1 /], [@Components 2 i2 /]) -> O) = - StageCase(pat, check) { v -> useComponents(v, f(v)) } + inline fun thenThis(crossinline f: R.([@Components 1 i1 /], [@Components 2 i2 /]) -> O) = + StageCase(pat, check) { v -> useComponents(v, { c1, c2 -> f(v, c1, c2) }) } } [/#list] [/#list] diff --git a/decomat-core/src/test/kotlin/io/decomat/ThenTest.kt b/decomat-core/src/test/kotlin/io/decomat/ThenTest.kt index d869e7e..9839c30 100644 --- a/decomat-core/src/test/kotlin/io/decomat/ThenTest.kt +++ b/decomat-core/src/test/kotlin/io/decomat/ThenTest.kt @@ -1,6 +1,8 @@ package io.decomat import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertNull public class ThenTest: DecomatTest { // Just check that the types don't fail @@ -17,14 +19,14 @@ public class ThenTest: DecomatTest { @Test fun `Then0 - distinct(Is) - Filter`() = - assert( - case(Distinct_M(Is())).then { (a) -> Res1(a) }.eval(Distinct(foo)) == Res1(foo) + assertEquals>( + case(Distinct_M(Is())).then { a -> Res1(a) }.eval(Distinct(foo)), Res1(foo) ) @Test fun `Then0 - distinct(Is)`() = - assert( - case(Distinct_M(Is())).then { (a) -> Res1(a) }.eval(Distinct(foo)) == Res1(foo) + assertEquals( + case(Distinct_M(Is())).then { a -> Res1(a) }.eval(Distinct(foo)), Res1(foo) ) @Test @@ -48,7 +50,7 @@ public class ThenTest: DecomatTest { @Test fun `Then00 - flatMap(Is, Is) - thenThis`() = assert( - case(FlatMap_M(Is(), Is())).thenThis {{ a, b -> Res3(a, b, body) }}.eval(FlatMap(foo, bar)) == Res3(foo, bar, bar) + case(FlatMap_M(Is(), Is())).thenThis { a, b -> Res3(a, b, body) }.eval(FlatMap(foo, bar)) == Res3(foo, bar, bar) ) @Test @@ -57,6 +59,36 @@ public class ThenTest: DecomatTest { case(FlatMap_M(Is(), Is())).then { a, b -> Res2(a, b) }.eval(FlatMap(foo, bar)) == Res2(foo, bar) ) + @Test + fun `Then00-thenIf - flatMap(Is, Is)`() = + assert( + case(FlatMap_M(Is(), Is())).thenIf { a, b -> a == foo && b == bar }.then { a, b -> Res2(a, b) }.eval(FlatMap(foo, bar)) == Res2(foo, bar) + ) + + @Test + fun `Then00-!thenIf - flatMap(Is, Is)`() = + assert( + case(FlatMap_M(Is(), Is())).thenIf { a, b -> a != foo || b != bar }.then { a, b -> Res2(a, b) }.evalSafe(FlatMap(foo, bar)) == null + ) + + @Test + fun `Then00-thenIfThis - flatMap(Is, Is)`() = + assertEquals>( + case(FlatMap_M(Is(), Is())).thenIfThis { a, b -> + a == foo && b == bar && this.head == foo && this.body == bar + }.then { a, b -> Res2(a, b) }.eval(FlatMap(foo, bar)), + // == + Res2(foo, bar) + ) + + @Test + fun `Then00-!thenIfThis - flatMap(Is, Is)`() = + assertNull( + case(FlatMap_M(Is(), Is())).thenIfThis { a, b -> + a != foo || b != bar || this.head != foo || this.body != bar + }.then { a, b -> Res2(a, b) }.evalSafe(FlatMap(foo, bar)) + ) + @Test fun `Then01 - flatMap(Is, Distinct)`() = assert( @@ -104,6 +136,4 @@ public class ThenTest: DecomatTest { assert( case(FlatMap_M(Map_M(Is(), Is()), Map_M(Is(), Is()))).then { (a1, a2), (b1, b2) -> Res4(a1, a2, b1, b2) }.eval(FlatMap(Map(foo, bar), Map(baz, waz))) == Res4(foo, bar, baz, waz) ) - - // TODO Need test for Then31-33 and Then000-Then333 } diff --git a/decomat-ksp/build.gradle.kts b/decomat-ksp/build.gradle.kts index 5d2e151..5c03a82 100644 --- a/decomat-ksp/build.gradle.kts +++ b/decomat-ksp/build.gradle.kts @@ -10,7 +10,7 @@ plugins { dependencies { project(":decomat-core") - implementation("com.google.devtools.ksp:symbol-processing-api:1.9.20-1.0.14") + implementation("com.google.devtools.ksp:symbol-processing-api:2.0.0-Beta2-1.0.16") implementation(kotlin("stdlib-jdk8")) testImplementation(kotlin("test")) //implementation("com.facebook:ktfmt:0.43") diff --git a/settings.gradle.kts b/settings.gradle.kts index 4afc3d2..45193b5 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,7 +1,7 @@ pluginManagement { plugins { - id("com.google.devtools.ksp") version "1.9.20-1.0.14" - kotlin("jvm") version "1.9.20" + id("com.google.devtools.ksp") version "2.0.0-Beta2-1.0.16" + kotlin("jvm") version "2.0.0-Beta2" id("dev.anies.gradle.template") version "0.0.2" } repositories {