Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 45 additions & 29 deletions Dsl/src/main/scala/com/thoughtworks/dsl/Dsl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -67,43 +67,20 @@ private[dsl] trait LowPriorityDsl1 { this: Dsl.type =>

private[dsl] trait LowPriorityDsl0 extends LowPriorityDsl1 { this: Dsl.type =>

// // FIXME: Shift
// implicit def continuationDsl[Keyword, LeftDomain, RightDomain, Value](
// implicit restDsl: Dsl.Original[Keyword, LeftDomain, Value],
// shiftDsl2: Dsl.Original[Shift[LeftDomain, RightDomain], LeftDomain, RightDomain]
// ): Dsl.Original[Keyword, LeftDomain !! RightDomain, Value] = {
// new Dsl.Original[Keyword, LeftDomain !! RightDomain, Value] {
// def cpsApply(keyword: Keyword, handler: Value => LeftDomain !! RightDomain): LeftDomain !! RightDomain = {
// (continue: RightDomain => LeftDomain) =>
// restDsl.cpsApply(keyword, { a =>
// restDsl2.cpsApply(handler(a), continue)
// })
// }
// }
// }

private def throwableContinuationDsl[Keyword, LeftDomain, Value](implicit
restDsl: Dsl.Searching[Keyword, LeftDomain, Value]
): Dsl[Keyword, LeftDomain !! Throwable, Value] = Dsl {
(keyword, handler) => continue =>
(keyword, handler) => (continue: Throwable => LeftDomain) =>
restDsl(
keyword,
// Use `new` to support the `return`
new (Value => LeftDomain) {
def apply(value: Value): LeftDomain = {
val protectedContinuation =
try {
handler(value)
} catch {
case NonFatal(e) =>
return continue(e)
}
// FIXME: Shift[Domain, Throwable]
protectedContinuation(continue)
}
{ value =>
TrampolineContinuation { () =>
handler(value)
}(continue)
}
)
}

given [Keyword, LeftDomain, Value](using
Dsl.IsStackSafe[LeftDomain],
Dsl.Searching[Keyword, LeftDomain, Value]
Expand All @@ -125,6 +102,45 @@ object Dsl extends LowPriorityDsl0 {
) => Domain
) =:= Dsl[Keyword, Domain, Value] =
summon
private[dsl] abstract class TrampolineFunction1[-A, +R] extends (A => R) {
protected def step(): A => R
@tailrec
protected final def last(): A => R = {
step() match {
case trampoline: TrampolineFunction1[A, R] =>
trampoline.last()
case notTrampoline =>
notTrampoline
}
}

def apply(state: A): R = {
last()(state)
}

}
object TrampolineFunction1 {
def apply[A, R](trampoline: TrampolineFunction1[A, R]) = trampoline
}

private[dsl] abstract class TrampolineContinuation[LeftDomain]
extends TrampolineFunction1[Throwable => LeftDomain, LeftDomain] {

override final def apply(handler: Throwable => LeftDomain): LeftDomain = {
val protectedContinuation: LeftDomain !! Throwable =
try {
last()
} catch {
case NonFatal(e) =>
return handler(e)
}
protectedContinuation(handler)
}
}
private[dsl] object TrampolineContinuation {
def apply[LeftDomain](continuation: TrampolineContinuation[LeftDomain]) =
continuation
}

trait IsStackSafe[Domain]
object IsStackSafe extends IsStackSafe.LowPriority0:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,37 +142,11 @@ object Shift extends LowPriorityShift0 {

}

private abstract class TrampolineContinuation[LeftDomain]
extends (LeftDomain !! Throwable) {
protected def step(): LeftDomain !! Throwable

@tailrec
private final def last(): LeftDomain !! Throwable = {
step() match {
case trampoline: TrampolineContinuation[LeftDomain] =>
trampoline.last()
case notTrampoline =>
notTrampoline
}
}

final def apply(handler: Throwable => LeftDomain): LeftDomain = {
val protectedContinuation: LeftDomain !! Throwable =
try {
last()
} catch {
case NonFatal(e) =>
return handler(e)
}
protectedContinuation(handler)
}
}

private def suspend[LeftDomain, Value](
continuation: LeftDomain !! Throwable !! Value,
handler: Value => LeftDomain !! Throwable
): TrampolineContinuation[LeftDomain] =
new TrampolineContinuation[LeftDomain] {
): Dsl.TrampolineContinuation[LeftDomain] =
new Dsl.TrampolineContinuation[LeftDomain] {
protected def step() = continuation(handler)
}

Expand All @@ -192,8 +166,8 @@ object Shift extends LowPriorityShift0 {
handler: Value => LeftDomain !! Throwable !! RightDomain,
value: Value,
continue: RightDomain => LeftDomain !! Throwable
): TrampolineContinuation[LeftDomain] =
new TrampolineContinuation[LeftDomain] {
): Dsl.TrampolineContinuation[LeftDomain] =
new Dsl.TrampolineContinuation[LeftDomain] {
protected def step() = {
handler(value)(continue)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.thoughtworks.dsl
package keywords
import Dsl.IsKeyword
import Dsl.!!
import Dsl.cpsApply
import scala.concurrent.Future
import scala.concurrent.ExecutionContext
Expand All @@ -17,19 +18,26 @@ object Suspend extends Suspend.LowPriority0 {
upstreamIsKeyword: => IsKeyword[Upstream, UpstreamValue]
): IsKeyword[Suspend[Upstream], UpstreamValue] with {}

private[Suspend] trait LowPriority0:
private[Suspend] trait LowPriority1:
given [Keyword, Domain, Value](using
Dsl.Searching[Keyword, Domain, Value]
): Dsl.Composed[Suspend[Keyword], Domain, Value] = Dsl.Composed {
(keyword: Suspend[Keyword], handler: Value => Domain) =>
keyword().cpsApply(handler)
}
private[Suspend] trait LowPriority0 extends LowPriority1:
given [Keyword, State, Domain, Value](using
Dsl.Searching[Keyword, State => Domain, Value]
): Dsl.Composed[Suspend[Keyword], State => Domain, Value] = Dsl.Composed {
(keyword: Suspend[Keyword], handler: Value => State => Domain) =>
Dsl.TrampolineFunction1(() => keyword().cpsApply(handler))
}

given [Keyword, State, Domain, Value](using
Dsl.Searching[Keyword, State => Domain, Value]
): Dsl.Composed[Suspend[Keyword], State => Domain, Value] = Dsl.Composed {
(keyword: Suspend[Keyword], handler: Value => State => Domain) => value =>
keyword().cpsApply(handler)(value)
given [Keyword, Domain, Value](using
Dsl.Searching[Keyword, Domain !! Throwable, Value]
): Dsl.Composed[Suspend[Keyword], Domain !! Throwable, Value] = Dsl.Composed {
(keyword: Suspend[Keyword], handler: Value => (Domain !! Throwable)) =>
Dsl.TrampolineContinuation(() => keyword().cpsApply(handler))
}

given [Keyword, Result, Value](using
Expand Down