Implement basic support for coroutines in JVM backend
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
// WITH_RUNTIME
|
||||
// FULL_JDK
|
||||
|
||||
fun box(): String {
|
||||
val x = gen().joinToString()
|
||||
if (x != "1, 2") return "fail1: $x"
|
||||
|
||||
val y = gen().joinToString()
|
||||
if (y != "-1") return "fail2: $y"
|
||||
return "OK"
|
||||
}
|
||||
|
||||
var was = false
|
||||
|
||||
fun gen() = generate<Int> {
|
||||
if (was) {
|
||||
yield(-1)
|
||||
return@generate
|
||||
}
|
||||
for (i in 1..2) {
|
||||
yield(i)
|
||||
}
|
||||
was = true
|
||||
}
|
||||
|
||||
// LIBRARY CODE
|
||||
fun <T> generate(coroutine c: GeneratorController<T>.() -> Continuation<Unit>): Sequence<T> = object : Sequence<T> {
|
||||
override fun iterator(): Iterator<T> {
|
||||
val iterator = GeneratorController<T>()
|
||||
iterator.setNextStep(c(iterator))
|
||||
return iterator
|
||||
}
|
||||
}
|
||||
|
||||
class GeneratorController<T>() : AbstractIterator<T>() {
|
||||
private lateinit var nextStep: Continuation<Unit>
|
||||
|
||||
override fun computeNext() {
|
||||
nextStep.resume(Unit)
|
||||
}
|
||||
|
||||
fun setNextStep(step: Continuation<Unit>) {
|
||||
this.nextStep = step
|
||||
}
|
||||
|
||||
suspend fun yield(value: T, c: Continuation<Unit>) {
|
||||
setNext(value)
|
||||
setNextStep(c)
|
||||
}
|
||||
|
||||
fun handleResult(result: Unit, c: Continuation<Nothing>) {
|
||||
done()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
class Controller {
|
||||
var i = 0
|
||||
suspend fun suspendHere(x: Continuation<String>) {
|
||||
x.resume((i++).toString())
|
||||
}
|
||||
}
|
||||
|
||||
fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
|
||||
c(Controller()).resume(Unit)
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
var result = ""
|
||||
|
||||
builder {
|
||||
result += "-"
|
||||
result += suspendHere()
|
||||
|
||||
if (result == "-0") {
|
||||
builder {
|
||||
result += "+"
|
||||
result += suspendHere()
|
||||
result += suspendHere()
|
||||
result += "#"
|
||||
}
|
||||
|
||||
result += suspendHere()
|
||||
result += "&"
|
||||
}
|
||||
}
|
||||
|
||||
if (result != "-0+01#1&") return "fail: $result"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
class Controller {
|
||||
var res = 0
|
||||
suspend fun suspendHere(x: Continuation<String>) {
|
||||
x.resume("OK")
|
||||
}
|
||||
|
||||
operator fun handleResult(x: Int, y: Continuation<Nothing>) {
|
||||
res = x
|
||||
}
|
||||
}
|
||||
|
||||
fun builder(coroutine c: Controller.() -> Continuation<Unit>): Int {
|
||||
val controller = Controller()
|
||||
c(controller).resume(Unit)
|
||||
|
||||
return controller.res
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
var result = ""
|
||||
|
||||
val handledResult = builder {
|
||||
result = suspendHere()
|
||||
return@builder 56
|
||||
}
|
||||
|
||||
if (handledResult != 56) return "fail 1: $handledResult"
|
||||
|
||||
return result
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<String>) {
|
||||
x.resume("OK")
|
||||
}
|
||||
}
|
||||
|
||||
fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
|
||||
c(Controller()).resume(Unit)
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
var result = ""
|
||||
|
||||
builder {
|
||||
result = suspendHere()
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<String>) {
|
||||
x.resumeWithException(RuntimeException("OK"))
|
||||
}
|
||||
}
|
||||
|
||||
fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
|
||||
c(Controller()).resume(Unit)
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
var result = ""
|
||||
|
||||
builder {
|
||||
try {
|
||||
suspendHere()
|
||||
result = "fail"
|
||||
} catch (e: RuntimeException) {
|
||||
result = "OK"
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
class Controller {
|
||||
var res = 0
|
||||
suspend fun suspendHere(x: Continuation<String>) {
|
||||
x.resume("OK")
|
||||
}
|
||||
|
||||
operator fun handleResult(x: Int, y: Continuation<Nothing>) {
|
||||
res = x
|
||||
}
|
||||
}
|
||||
|
||||
fun builder(coroutine c: Controller.() -> Continuation<Unit>): Int {
|
||||
val controller = Controller()
|
||||
c(controller).resume(Unit)
|
||||
|
||||
return controller.res
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
var result = ""
|
||||
|
||||
val handledResult = builder {
|
||||
result = suspendHere()
|
||||
56
|
||||
}
|
||||
|
||||
if (handledResult != 56) return "fail 1: $handledResult"
|
||||
|
||||
return result
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
class Controller {
|
||||
var i = 0
|
||||
suspend fun suspendHere(x: Continuation<Int>) {
|
||||
x.resume(i++)
|
||||
}
|
||||
suspend fun suspendThere(x: Continuation<String>) {
|
||||
x.resume("?")
|
||||
}
|
||||
}
|
||||
|
||||
fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
|
||||
c(Controller()).resume(Unit)
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
var result = ""
|
||||
|
||||
builder {
|
||||
result += "-"
|
||||
for (i in 0..5) {
|
||||
if (i % 2 == 0) {
|
||||
result += suspendHere().toString()
|
||||
}
|
||||
else if (i == 3) {
|
||||
result += suspendThere()
|
||||
}
|
||||
}
|
||||
result += "+"
|
||||
}
|
||||
|
||||
if (result != "-01?2+") return "fail: $result"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
// WITH_RUNTIME
|
||||
// FULL_JDK
|
||||
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
fun foo(): CompletableFuture<String> = CompletableFuture.supplyAsync { "foo" }
|
||||
fun bar(v: String): CompletableFuture<String> = CompletableFuture.supplyAsync { "bar with $v" }
|
||||
fun exception(v: String): CompletableFuture<String> = CompletableFuture.supplyAsync { throw RuntimeException(v) }
|
||||
|
||||
fun foobar(x: String, y: String) = x + y
|
||||
|
||||
fun box(): String {
|
||||
var result = ""
|
||||
fun log(x: String) {
|
||||
synchronized(result) {
|
||||
if (result.isNotEmpty()) result += "\n"
|
||||
result += x
|
||||
}
|
||||
}
|
||||
|
||||
val future = async<String> {
|
||||
log("start")
|
||||
val x = await(foo())
|
||||
log("got '$x'")
|
||||
val y = foobar("123 ", await(bar(x)))
|
||||
log("got '$y' after '$x'")
|
||||
y
|
||||
}
|
||||
|
||||
future.whenComplete { value, t ->
|
||||
log("completed with '$value'")
|
||||
}
|
||||
|
||||
future.join()
|
||||
java.lang.Thread.sleep(1000)
|
||||
|
||||
val readResult = synchronized(result) {
|
||||
result
|
||||
}
|
||||
|
||||
val expectedResult =
|
||||
"""
|
||||
|start
|
||||
|got 'foo'
|
||||
|got '123 bar with foo' after 'foo'
|
||||
|completed with '123 bar with foo'""".trimMargin().trim('\n', ' ')
|
||||
|
||||
if (expectedResult != readResult) return readResult
|
||||
|
||||
return "OK"
|
||||
}
|
||||
|
||||
// LIBRARY CODE
|
||||
|
||||
fun <T> async(coroutine c: FutureController<T>.() -> Continuation<Unit>): CompletableFuture<T> {
|
||||
val controller = FutureController<T>()
|
||||
c(controller).resume(Unit)
|
||||
return controller.future
|
||||
}
|
||||
|
||||
class FutureController<T> {
|
||||
val future = CompletableFuture<T>()
|
||||
|
||||
|
||||
suspend fun <V> await(f: CompletableFuture<V>, machine: Continuation<V>) {
|
||||
f.whenComplete { value, throwable ->
|
||||
if (throwable == null)
|
||||
machine.resume(value)
|
||||
else
|
||||
machine.resumeWithException(throwable)
|
||||
}
|
||||
}
|
||||
|
||||
fun handleResult(value: T, c: Continuation<Nothing>) {
|
||||
future.complete(value)
|
||||
}
|
||||
|
||||
fun handleException(t: Throwable, c: Continuation<Nothing>) {
|
||||
future.completeExceptionally(t)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
// WITH_RUNTIME
|
||||
// FULL_JDK
|
||||
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
fun exception(v: String): CompletableFuture<String> = CompletableFuture.supplyAsync { throw RuntimeException(v) }
|
||||
|
||||
fun foobar(x: String, y: String) = x + y
|
||||
|
||||
fun box(): String {
|
||||
var result = ""
|
||||
|
||||
val future = async<String>() {
|
||||
try {
|
||||
await(exception("OK"))
|
||||
} catch (e: Exception) {
|
||||
result = e.cause?.message!!
|
||||
}
|
||||
"56"
|
||||
}
|
||||
|
||||
future.join()
|
||||
|
||||
if (future.get() != "56") return "fail: ${future.get()}"
|
||||
|
||||
java.lang.Thread.sleep(1000)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
fun <T> async(coroutine c: FutureController<T>.() -> Continuation<Unit>): CompletableFuture<T> {
|
||||
val controller = FutureController<T>()
|
||||
c(controller).resume(Unit)
|
||||
return controller.future
|
||||
}
|
||||
|
||||
class FutureController<T> {
|
||||
val future = CompletableFuture<T>()
|
||||
|
||||
|
||||
suspend fun <V> await(f: CompletableFuture<V>, machine: Continuation<V>) {
|
||||
f.whenComplete { value, throwable ->
|
||||
try {
|
||||
if (throwable == null)
|
||||
machine.resume(value)
|
||||
else
|
||||
machine.resumeWithException(throwable)
|
||||
} catch (e: Exception) {
|
||||
future.completeExceptionally(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun handleResult(value: T, c: Continuation<Nothing>) {
|
||||
future.complete(value)
|
||||
}
|
||||
|
||||
fun handleException(t: Throwable, c: Continuation<Nothing>) {
|
||||
future.completeExceptionally(t)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user