From a613d46c2e497eef948cf4b159b546a39df1684b Mon Sep 17 00:00:00 2001 From: Sergey Igushkin Date: Tue, 10 Jan 2017 02:29:23 +0300 Subject: [PATCH] Updated to 1.1-M04. --- build.gradle | 3 +- .../github/h0tk3y/kotlinMonads/DoNotation.kt | 58 +++++++++++-------- .../h0tk3y/kotlinMonads/DoNotationTest.kt | 14 +++-- 3 files changed, 43 insertions(+), 32 deletions(-) diff --git a/build.gradle b/build.gradle index 7a10a0c..230d025 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ buildscript { - ext.kotlin_version = '1.1-M03' + ext.kotlin_version = '1.1-M04' repositories { mavenCentral() @@ -19,6 +19,7 @@ repositories { dependencies { compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" + compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" testCompile "junit:junit:4.12" } diff --git a/src/main/kotlin/com/github/h0tk3y/kotlinMonads/DoNotation.kt b/src/main/kotlin/com/github/h0tk3y/kotlinMonads/DoNotation.kt index f20ac29..0760981 100644 --- a/src/main/kotlin/com/github/h0tk3y/kotlinMonads/DoNotation.kt +++ b/src/main/kotlin/com/github/h0tk3y/kotlinMonads/DoNotation.kt @@ -1,55 +1,61 @@ +@file:Suppress("EXPERIMENTAL_FEATURE_WARNING") + package com.github.h0tk3y.kotlinMonads import java.io.Serializable import java.util.* -import kotlin.jvm.internal.CoroutineImpl +import kotlin.coroutines.Continuation +import kotlin.coroutines.CoroutineIntrinsics +import kotlin.coroutines.startCoroutine fun , T> doWith(m: Monad, - coroutine c: DoController.(T) -> Continuation): Monad { - return (m bind { x -> doWith(this, x, c) }) -} + c: suspend DoController.() -> Unit): Monad = + m.bind { t -> doWith(this, t, c) } + fun , T> doWith(aReturn: Return, defaultValue: T, - coroutine c: DoController.(T) -> Continuation): Monad { + c: suspend DoController.() -> Unit): Monad { val controller = DoController(aReturn, defaultValue) - c(controller, defaultValue).resume(Unit) + c.startCoroutine(controller, object : Continuation { + override fun resume(value: Unit) {} + override fun resumeWithException(exception: Throwable) = throw exception + }) return controller.lastResult } -private fun backupLabel(c: Continuation, block: Continuation.() -> R): R { - val reflect = CoroutineImpl::class.java - val labelField = reflect.getDeclaredField("label") +val labelField by lazy { + val jClass = Class.forName("kotlin.jvm.internal.RestrictedCoroutineImpl") + return@lazy jClass.getDeclaredField("label").apply { isAccessible = true } +} - labelField.isAccessible = true - val l = labelField.get(c) - labelField.isAccessible = false +var Continuation.label + get() = labelField.get(this) + set(value) = labelField.set(this@label, value) +private fun backupLabel(c: Continuation, block: Continuation.() -> R): R { + val backupLabel = c.label val r = block(c) - - labelField.isAccessible = true - labelField.set(c, l) - labelField.isAccessible = false - + c.label = backupLabel return r } class DoController, T>(val returning: Return, - initialValue: T) : Serializable { - var lastResult: Monad = returning.returns(initialValue) - private set + val value: T) : Serializable, Return by returning { + var lastResult: Monad = returning.returns(value) + internal set private val stackSignals = Stack().apply { push(false) } - fun returns(t: T) = returning.returns(t) - - suspend fun bind(m: Monad, c: Continuation) { + suspend fun bind(m: Monad): T = CoroutineIntrinsics.suspendCoroutineOrReturn { c -> stackSignals.pop() stackSignals.push(true) var anyCont = false val o = m.bind { x -> stackSignals.push(false) - backupLabel(c) { c.resume(x) } + backupLabel(c) { + c.resume(x) + } val contHasMonad = stackSignals.pop() if (contHasMonad) { anyCont = true @@ -59,9 +65,10 @@ class DoController, T>(val returning: Return, } } lastResult = if (anyCont) o else m + CoroutineIntrinsics.SUSPENDED } - suspend fun then(m: Monad, c: Continuation) { + suspend fun then(m: Monad) = CoroutineIntrinsics.suspendCoroutineOrReturn { c -> stackSignals.pop() stackSignals.push(true) var anyCont = false @@ -77,6 +84,7 @@ class DoController, T>(val returning: Return, } } lastResult = if (anyCont) o else m + CoroutineIntrinsics.SUSPENDED } } diff --git a/src/test/kotlin/com/github/h0tk3y/kotlinMonads/DoNotationTest.kt b/src/test/kotlin/com/github/h0tk3y/kotlinMonads/DoNotationTest.kt index c34b376..28af600 100644 --- a/src/test/kotlin/com/github/h0tk3y/kotlinMonads/DoNotationTest.kt +++ b/src/test/kotlin/com/github/h0tk3y/kotlinMonads/DoNotationTest.kt @@ -1,3 +1,5 @@ +@file:Suppress("EXPERIMENTAL_FEATURE_WARNING") + package com.github.h0tk3y.kotlinMonads import org.junit.Assert.assertEquals @@ -6,8 +8,8 @@ import org.junit.Test class DoNotationTest { @Test fun testLinearDo() { - val m = doWith(just(1)) { i -> - val j = bind(returns(i * 2)) + val m = doWith(just(1)) { + val j = bind(returns(value * 2)) val k = bind(returns(j * 3)) then(returns(k + 1)) } @@ -16,8 +18,8 @@ class DoNotationTest { @Test fun testControlFlow() { var called = false - val m = doWith(just(1)) { i -> - val j = bind(returns(i * 2)) + val m = doWith(just(1)) { + val j = bind(returns(value * 2)) val k = bind(if (j % 2 == 0) none() else just(j)) called = true then(returns(k)) @@ -56,8 +58,8 @@ class DoNotationTest { @Test fun testBindLastStatement() { val results = mutableListOf() - val m = doWith(monadListOf(2)) { i -> - val x = bind(monadListOf(i + 1, i * i)) + val m = doWith(monadListOf(2)) { + val x = bind(monadListOf(value + 1, value * value)) val z = bind(returns(x)) results.add(z) }