-
Notifications
You must be signed in to change notification settings - Fork 29
/
Catch.scala
113 lines (97 loc) · 4.02 KB
/
Catch.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
package com.thoughtworks.dsl.keywords
import com.thoughtworks.Extractor._
import com.thoughtworks.dsl.Dsl
import com.thoughtworks.dsl.Dsl.{!!, Continuation, Keyword}
import com.thoughtworks.dsl.keywords.Catch.CatchDsl
import scala.util.control.Exception.Catcher
import scala.util.control.NonFatal
/**
* @author 杨博 (Yang Bo)
*/
final case class Catch[Domain, Value](block: Domain !! Value, catcher: Catcher[Domain !! Value])
extends Keyword[Catch[Domain, Value], Value]
private[keywords] trait LowPriorityCatch0 { this: Catch.type =>
implicit def liftContinuationCatchDsl[LeftDomain, RightDomain, Value](
implicit leftCatchDsl: CatchDsl[LeftDomain, LeftDomain, Value])
: CatchDsl[LeftDomain !! Value, LeftDomain !! RightDomain, Value] = {
new CatchDsl[LeftDomain !! Value, LeftDomain !! RightDomain, Value] {
def tryCatch(block: LeftDomain !! Value !! Value,
catcher: Catcher[LeftDomain !! Value !! Value],
handler: Value => LeftDomain !! RightDomain): LeftDomain !! RightDomain = { outerHandler =>
leftCatchDsl.tryCatch(
block = block(Continuation.now),
catcher = {
case catcher.extract(recoveredValueContinuation) =>
recoveredValueContinuation(Continuation.now)
},
handler = { value: Value =>
handler(value)(outerHandler)
}
)
}
}
}
}
object Catch extends LowPriorityCatch0 {
trait CatchDsl[InnerDomain, OuterDomain, Value] extends Dsl[Catch[InnerDomain, Value], OuterDomain, Value] {
def tryCatch(block: InnerDomain !! Value,
catcher: Catcher[InnerDomain !! Value],
handler: Value => OuterDomain): OuterDomain
@inline final def cpsApply(keyword: Catch[InnerDomain, Value], handler: Value => OuterDomain): OuterDomain = {
tryCatch(keyword.block, keyword.catcher, handler)
}
}
@inline
def tryCatch[InnerDomain, OuterDomain, Value](finalizer: Value => OuterDomain)(
implicit catchDsl: CatchDsl[InnerDomain, OuterDomain, Value]) = {
(block: InnerDomain !! Value, catcher: Catcher[InnerDomain !! Value]) =>
catchDsl.tryCatch(block, catcher, finalizer)
}
implicit def throwableCatchDsl[LeftDomain, Value](
implicit shiftDsl: Dsl[Shift[LeftDomain, Throwable], LeftDomain, Throwable])
: CatchDsl[LeftDomain !! Throwable, LeftDomain !! Throwable, Value] =
new CatchDsl[LeftDomain !! Throwable, LeftDomain !! Throwable, Value] {
@inline
def tryCatch(block: LeftDomain !! Throwable !! Value,
catcher: Catcher[LeftDomain !! Throwable !! Value],
handler: Value => LeftDomain !! Throwable): LeftDomain !! Throwable = {
new (LeftDomain !! Throwable) {
def apply(outerFailureHandler: Throwable => LeftDomain): LeftDomain = {
def recover(e: Throwable): LeftDomain = {
e match {
case catcher.extract(recovered) =>
val outerContinuation = try {
recovered(handler)
} catch {
case NonFatal(e) =>
return outerFailureHandler(e)
}
outerContinuation(outerFailureHandler)
case e =>
outerFailureHandler(e)
}
}
val protectedContinuation = try {
block { value =>
new (LeftDomain !! Throwable) {
def apply(ignored: Throwable => LeftDomain): LeftDomain = {
val rest = try {
handler(value)
} catch {
case NonFatal(e) =>
return outerFailureHandler(e)
}
rest(outerFailureHandler)
}
}
}
} catch {
case NonFatal(e) =>
return recover(e)
}
shiftDsl.cpsApply(protectedContinuation, recover)
}
}
}
}
}