@effekt-lang/effekt 0.2.1 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +36 -0
- package/bin/effekt +0 -0
- package/bin/effekt.sh +2 -0
- package/libraries/chez/THIRD-PARTY.txt +11 -0
- package/libraries/chez/callcc/datatype.ss +188 -0
- package/libraries/chez/callcc/effekt.effekt +221 -0
- package/libraries/chez/callcc/effekt.ss +31 -0
- package/libraries/chez/callcc/seq.ss +44 -0
- package/libraries/chez/callcc/seq0.ss +69 -0
- package/libraries/chez/callcc/tail.ss +76 -0
- package/libraries/chez/callcc/tail0.ss +89 -0
- package/libraries/chez/common/effekt_matching.ss +100 -0
- package/libraries/chez/common/effekt_primitives.ss +97 -0
- package/libraries/chez/common/immutable/cslist.effekt +31 -0
- package/libraries/chez/common/immutable/dequeue.effekt +78 -0
- package/libraries/chez/common/immutable/list.effekt +643 -0
- package/libraries/chez/common/immutable/option.effekt +39 -0
- package/libraries/chez/common/immutable/result.effekt +29 -0
- package/libraries/chez/common/io/args.effekt +20 -0
- package/libraries/chez/common/mutable/array.effekt +27 -0
- package/libraries/chez/common/mutable/dict.effekt +30 -0
- package/libraries/chez/common/mutable/heap.effekt +12 -0
- package/libraries/chez/common/test.effekt +59 -0
- package/libraries/chez/common/text/pregexp.scm +772 -0
- package/libraries/chez/common/text/regex.effekt +33 -0
- package/libraries/chez/common/text/string.effekt +46 -0
- package/libraries/chez/lift/effekt.effekt +217 -0
- package/libraries/chez/lift/effekt.ss +118 -0
- package/libraries/chez/monadic/effekt.effekt +218 -0
- package/libraries/chez/monadic/effekt.ss +84 -0
- package/libraries/chez/monadic/seq0.ss +76 -0
- package/libraries/js/effekt.effekt +284 -0
- package/libraries/js/effekt_builtins.js +26 -0
- package/libraries/js/effekt_matching.js +79 -0
- package/libraries/js/effekt_runtime.js +385 -0
- package/libraries/js/immutable/dequeue.effekt +78 -0
- package/libraries/js/immutable/list.effekt +643 -0
- package/libraries/js/immutable/option.effekt +49 -0
- package/libraries/js/immutable/result.effekt +29 -0
- package/libraries/js/io/args.effekt +9 -0
- package/libraries/js/io/async.effekt +28 -0
- package/libraries/js/io/async.js +2 -0
- package/libraries/js/io/file.effekt +50 -0
- package/libraries/js/io/file_include.js +13 -0
- package/libraries/js/mutable/array.effekt +98 -0
- package/libraries/js/mutable/heap.effekt +32 -0
- package/libraries/js/mutable/map.effekt +32 -0
- package/libraries/js/test.effekt +59 -0
- package/libraries/js/text/regex.effekt +34 -0
- package/libraries/js/text/string.effekt +64 -0
- package/libraries/js/unsafe/cont.effekt +11 -0
- package/libraries/js/web/dom.effekt +45 -0
- package/libraries/llvm/buffer.c +181 -0
- package/libraries/llvm/effekt.effekt +243 -0
- package/libraries/llvm/forward-declare-c.ll +24 -0
- package/libraries/llvm/hole.c +11 -0
- package/libraries/llvm/immutable/list.effekt +678 -0
- package/libraries/llvm/immutable/option.effekt +53 -0
- package/libraries/llvm/immutable/result.effekt +29 -0
- package/libraries/llvm/io/args.effekt +24 -0
- package/libraries/llvm/io.c +24 -0
- package/libraries/llvm/main.c +39 -0
- package/libraries/llvm/rts.ll +619 -0
- package/libraries/llvm/sanity.c +16 -0
- package/libraries/llvm/text/string.effekt +179 -0
- package/libraries/llvm/types.c +20 -0
- package/libraries/ml/effekt.effekt +267 -0
- package/libraries/ml/effekt.sml +63 -0
- package/libraries/ml/immutable/dequeue.effekt +81 -0
- package/libraries/ml/immutable/list.effekt +674 -0
- package/libraries/ml/immutable/option.effekt +53 -0
- package/libraries/ml/immutable/result.effekt +29 -0
- package/libraries/ml/immutable/seq.effekt +903 -0
- package/libraries/ml/internal/option.effekt +18 -0
- package/libraries/ml/io/args.effekt +41 -0
- package/libraries/ml/mutable/array.effekt +43 -0
- package/libraries/ml/random.effekt +85 -0
- package/libraries/ml/test.effekt +60 -0
- package/libraries/ml/text/regex.effekt +107 -0
- package/libraries/ml/text/string.effekt +81 -0
- package/licenses/THIRD-PARTY.txt +21 -0
- package/licenses/apache-2.0 - license-2.0.txt +202 -0
- package/licenses/eclipse public license, version 2.0 - epl-2.0.html +61 -0
- package/licenses/kiama-license.txt +373 -0
- package/licenses/kiama-readme.txt +186 -0
- package/licenses/mit license - mit-license.html +769 -0
- package/licenses/the apache software license, version 2.0 - license-2.0.txt +202 -0
- package/licenses/the bsd license - bsd-license.html +762 -0
- package/licenses/the mit license - mit.html +769 -0
- package/package.json +26 -18
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module text/regex
|
|
2
|
+
|
|
3
|
+
import immutable/option
|
|
4
|
+
import immutable/cslist
|
|
5
|
+
import mutable/array
|
|
6
|
+
|
|
7
|
+
extern include "pregexp.scm"
|
|
8
|
+
|
|
9
|
+
extern type Regex
|
|
10
|
+
|
|
11
|
+
record Match(matched: String, index: Int)
|
|
12
|
+
|
|
13
|
+
extern pure def regex(str: String): Regex =
|
|
14
|
+
"(pregexp ${str})"
|
|
15
|
+
|
|
16
|
+
def exec(reg: Regex, str: String): Option[Match] = {
|
|
17
|
+
val matched = reg.unsafeMatchString(str)
|
|
18
|
+
if (matched.isUndefined) { None() }
|
|
19
|
+
else { Some(Match(matched, reg.unsafeMatchIndex(str))) }
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
extern pure def unsafeMatchIndex(reg: Regex, str: String): Int =
|
|
23
|
+
"(let ([m (pregexp-match-positions ${reg} ${str})]) (if m (car (car m)) #f))"
|
|
24
|
+
|
|
25
|
+
// we ignore the captures for now and only return the whole match
|
|
26
|
+
extern pure def unsafeMatchString(reg: Regex, str: String): String =
|
|
27
|
+
"(let ([m (pregexp-match ${reg} ${str})]) (if m (car m) #f))"
|
|
28
|
+
|
|
29
|
+
extern pure def split(reg: Regex, str: String): CSList[String] =
|
|
30
|
+
"(pregexp-split ${reg} ${str})"
|
|
31
|
+
|
|
32
|
+
def split(str: String, sep: String): Array[String] =
|
|
33
|
+
sep.regex.split(str).toArray
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
module text/string
|
|
2
|
+
|
|
3
|
+
import immutable/option
|
|
4
|
+
|
|
5
|
+
// def charAt(str: String, index: Int): Option[String] =
|
|
6
|
+
// str.unsafeCharAt(index).undefinedToOption
|
|
7
|
+
|
|
8
|
+
extern pure def length(str: String): Int =
|
|
9
|
+
"(string-length ${str})"
|
|
10
|
+
|
|
11
|
+
extern pure def repeat(str: String, n: Int): String =
|
|
12
|
+
"(letrec ([repeat (lambda (${n} acc) (if (<= ${n} 0) acc (repeat (- ${n} 1) (string-append acc ${str}))))]) (repeat ${n} (list->string '())))"
|
|
13
|
+
|
|
14
|
+
extern pure def unsafeSubstring(str: String, from: Int, to: Int): String =
|
|
15
|
+
"(substring ${str} ${from} ${to})"
|
|
16
|
+
|
|
17
|
+
def substring(str: String, from: Int, to: Int): String = {
|
|
18
|
+
def clamp(lower: Int, x: Int, upper: Int) = max(lower, min(x, upper))
|
|
19
|
+
|
|
20
|
+
val len = str.length
|
|
21
|
+
val clampedTo = clamp(0, to, len)
|
|
22
|
+
val clampedFrom = clamp(0, from, to)
|
|
23
|
+
|
|
24
|
+
str.unsafeSubstring(clampedFrom, clampedTo)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
def substring(str: String, from: Int): String =
|
|
28
|
+
str.substring(from, str.length)
|
|
29
|
+
|
|
30
|
+
// extern pure def trim(str: String): String =
|
|
31
|
+
// "str.trim()"
|
|
32
|
+
|
|
33
|
+
def toInt(str: String): Option[Int] =
|
|
34
|
+
str.unsafeToInt.undefinedToOption
|
|
35
|
+
|
|
36
|
+
// extern pure def unsafeCharAt(str: String, n: Int): String =
|
|
37
|
+
// "str[n]"
|
|
38
|
+
|
|
39
|
+
// returns #f if not a number
|
|
40
|
+
extern pure def unsafeToInt(str: String): Int =
|
|
41
|
+
"(string->number ${str})"
|
|
42
|
+
|
|
43
|
+
// ANSI escape codes
|
|
44
|
+
val ANSI_GREEN = "\033[32m"
|
|
45
|
+
val ANSI_RED = "\033[31m"
|
|
46
|
+
val ANSI_RESET = "\033[0m"
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
module effekt
|
|
2
|
+
|
|
3
|
+
extern include "../common/effekt_primitives.ss"
|
|
4
|
+
extern include "effekt.ss"
|
|
5
|
+
extern include "../common/effekt_matching.ss"
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def locally[R] { f: => R }: R = f()
|
|
9
|
+
|
|
10
|
+
// String ops
|
|
11
|
+
// ==========
|
|
12
|
+
extern pure def infixConcat(s1: String, s2: String): String =
|
|
13
|
+
"(string-append ${s1} ${s2})"
|
|
14
|
+
|
|
15
|
+
// TODO implement
|
|
16
|
+
extern pure def show[R](value: R): String =
|
|
17
|
+
"(show_impl ${value})"
|
|
18
|
+
|
|
19
|
+
extern io def println[R](r: R): Unit =
|
|
20
|
+
"(println_impl ${r})"
|
|
21
|
+
|
|
22
|
+
extern io def error[R](msg: String): R =
|
|
23
|
+
"(raise ${msg})"
|
|
24
|
+
|
|
25
|
+
extern io def random(): Double =
|
|
26
|
+
"(random 1.0)"
|
|
27
|
+
|
|
28
|
+
// Math ops
|
|
29
|
+
// ========
|
|
30
|
+
extern pure def infixAdd(x: Int, y: Int): Int =
|
|
31
|
+
"(+ ${x} ${y})"
|
|
32
|
+
|
|
33
|
+
extern pure def infixMul(x: Int, y: Int): Int =
|
|
34
|
+
"(* ${x} ${y})"
|
|
35
|
+
|
|
36
|
+
extern pure def infixDiv(x: Int, y: Int): Int =
|
|
37
|
+
"(floor (/ ${x} ${y}))"
|
|
38
|
+
|
|
39
|
+
extern pure def infixSub(x: Int, y: Int): Int =
|
|
40
|
+
"(- ${x} ${y})"
|
|
41
|
+
|
|
42
|
+
extern pure def mod(x: Int, y: Int): Int =
|
|
43
|
+
"(modulo ${x} ${y})"
|
|
44
|
+
|
|
45
|
+
extern pure def infixAdd(x: Double, y: Double): Double =
|
|
46
|
+
"(+ ${x} ${y})"
|
|
47
|
+
|
|
48
|
+
extern pure def infixMul(x: Double, y: Double): Double =
|
|
49
|
+
"(* ${x} ${y})"
|
|
50
|
+
|
|
51
|
+
extern pure def infixDiv(x: Double, y: Double): Double =
|
|
52
|
+
"(/ ${x} ${y})"
|
|
53
|
+
|
|
54
|
+
extern pure def infixSub(x: Double, y: Double): Double =
|
|
55
|
+
"(- ${x} ${y})"
|
|
56
|
+
|
|
57
|
+
extern pure def cos(x: Double): Double =
|
|
58
|
+
"(cos ${x})"
|
|
59
|
+
|
|
60
|
+
extern pure def sin(x: Double): Double =
|
|
61
|
+
"(sin ${x})"
|
|
62
|
+
|
|
63
|
+
extern pure def atan(x: Double): Double =
|
|
64
|
+
"(atan ${x})"
|
|
65
|
+
|
|
66
|
+
extern pure def tan(x: Double): Double =
|
|
67
|
+
"(tan ${x})"
|
|
68
|
+
|
|
69
|
+
extern pure def sqrt(x: Double): Double =
|
|
70
|
+
"(sqrt ${x})"
|
|
71
|
+
|
|
72
|
+
extern pure def square(x: Double): Double =
|
|
73
|
+
"(* x ${x})"
|
|
74
|
+
|
|
75
|
+
extern pure def log(x: Double): Double =
|
|
76
|
+
"(log ${x})"
|
|
77
|
+
|
|
78
|
+
extern pure def log1p(x: Double): Double =
|
|
79
|
+
"(log (+ ${x} 1))"
|
|
80
|
+
|
|
81
|
+
extern pure def exp(x: Double): Double =
|
|
82
|
+
"(exp ${x})"
|
|
83
|
+
|
|
84
|
+
// since we do not have "extern val", yet
|
|
85
|
+
extern pure def _pi(): Double =
|
|
86
|
+
"(* 4 (atan 1))"
|
|
87
|
+
|
|
88
|
+
val PI: Double = _pi()
|
|
89
|
+
|
|
90
|
+
extern pure def toInt(d: Double): Int =
|
|
91
|
+
"(round ${d})"
|
|
92
|
+
|
|
93
|
+
extern pure def toDouble(d: Int): Double =
|
|
94
|
+
"${d}"
|
|
95
|
+
|
|
96
|
+
def min(n: Int, m: Int): Int =
|
|
97
|
+
if (n < m) n else m
|
|
98
|
+
|
|
99
|
+
def max(n: Int, m: Int): Int =
|
|
100
|
+
if (n > m) n else m
|
|
101
|
+
|
|
102
|
+
// Comparison ops
|
|
103
|
+
// ==============
|
|
104
|
+
extern pure def infixEq[R](x: R, y: R): Boolean =
|
|
105
|
+
"(equal_impl ${x} ${y})"
|
|
106
|
+
|
|
107
|
+
extern pure def infixNeq[R](x: R, y: R): Boolean =
|
|
108
|
+
"(not (equal_impl ${x} ${y}))"
|
|
109
|
+
|
|
110
|
+
extern pure def infixLt(x: Int, y: Int): Boolean =
|
|
111
|
+
"(< ${x} ${y})"
|
|
112
|
+
|
|
113
|
+
extern pure def infixLte(x: Int, y: Int): Boolean =
|
|
114
|
+
"(<= ${x} ${y})"
|
|
115
|
+
|
|
116
|
+
extern pure def infixGt(x: Int, y: Int): Boolean =
|
|
117
|
+
"(> ${x} ${y})"
|
|
118
|
+
|
|
119
|
+
extern pure def infixGte(x: Int, y: Int): Boolean =
|
|
120
|
+
"(>= ${x} ${y})"
|
|
121
|
+
|
|
122
|
+
extern pure def infixLt(x: Double, y: Double): Boolean =
|
|
123
|
+
"(< ${x} ${y})"
|
|
124
|
+
|
|
125
|
+
extern pure def infixLte(x: Double, y: Double): Boolean =
|
|
126
|
+
"(<= ${x} ${y})"
|
|
127
|
+
|
|
128
|
+
extern pure def infixGt(x: Double, y: Double): Boolean =
|
|
129
|
+
"(> ${x} ${y})"
|
|
130
|
+
|
|
131
|
+
extern pure def infixGte(x: Double, y: Double): Boolean =
|
|
132
|
+
"(>= ${x} ${y})"
|
|
133
|
+
|
|
134
|
+
// Boolean ops
|
|
135
|
+
// ===========
|
|
136
|
+
// for now those are considered eager
|
|
137
|
+
extern pure def not(b: Boolean): Boolean =
|
|
138
|
+
"(not ${b})"
|
|
139
|
+
|
|
140
|
+
extern pure def infixOr(x: Boolean, y: Boolean): Boolean =
|
|
141
|
+
"(or ${x} ${y})"
|
|
142
|
+
|
|
143
|
+
extern pure def infixAnd(x: Boolean, y: Boolean): Boolean =
|
|
144
|
+
"(and ${x} ${y})"
|
|
145
|
+
|
|
146
|
+
// Should only be used internally since values in Effekt should not be undefined
|
|
147
|
+
extern pure def isUndefined[A](value: A): Boolean =
|
|
148
|
+
"(eq? ${value} #f)"
|
|
149
|
+
|
|
150
|
+
// Pairs
|
|
151
|
+
// =====
|
|
152
|
+
record Tuple2[A, B](first: A, second: B)
|
|
153
|
+
record Tuple3[A, B, C](first: A, second: B, third: C)
|
|
154
|
+
record Tuple4[A, B, C, D](first: A, second: B, third: C, fourth: D)
|
|
155
|
+
record Tuple5[A, B, C, D, E](first: A, second: B, third: C, fourth: D, fifth: E)
|
|
156
|
+
record Tuple6[A, B, C, D, E, F](first: A, second: B, third: C, fourth: D, fifth: E, sixth: F)
|
|
157
|
+
|
|
158
|
+
// Exceptions
|
|
159
|
+
// ==========
|
|
160
|
+
// a fatal runtime error that cannot be caught
|
|
161
|
+
extern io def panic[R](msg: String): R =
|
|
162
|
+
"(raise ${msg})"
|
|
163
|
+
|
|
164
|
+
interface Exception[E] {
|
|
165
|
+
def raise(exception: E, msg: String): Nothing
|
|
166
|
+
}
|
|
167
|
+
record RuntimeError()
|
|
168
|
+
|
|
169
|
+
def raise[A](msg: String): A / Exception[RuntimeError] = do raise(RuntimeError(), msg) match {}
|
|
170
|
+
def raise[A, E](exception: E, msg: String): A / Exception[E] = do raise(exception, msg) match {}
|
|
171
|
+
|
|
172
|
+
// converts exceptions of (static) type E to an uncatchable panic that aborts the program
|
|
173
|
+
def panicOn[E] { prog: => Unit / Exception[E] }: Unit =
|
|
174
|
+
try { prog() } with Exception[E] { def raise(exception: E, msg: String) = panic(msg) }
|
|
175
|
+
|
|
176
|
+
// reports exceptions of (static) type E to the console
|
|
177
|
+
def report[E] { prog: => Unit / Exception[E] }: Unit =
|
|
178
|
+
try { prog() } with Exception[E] { def raise(exception: E, msg: String) = println(msg) }
|
|
179
|
+
|
|
180
|
+
// ignores exceptions of (static) type E
|
|
181
|
+
// TODO this should be called "ignore" but that name currently clashes with internal pattern matching names on $effekt
|
|
182
|
+
def ignoring[E] { prog: => Unit / Exception[E] }: Unit =
|
|
183
|
+
try { prog() } with Exception[E] { def raise(exception: E, msg: String) = () }
|
|
184
|
+
|
|
185
|
+
// Control Flow
|
|
186
|
+
// ============
|
|
187
|
+
interface Control {
|
|
188
|
+
def break(): Unit
|
|
189
|
+
def continue(): Unit
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
def loop { f: () => Unit / Control }: Unit = try {
|
|
193
|
+
def go(): Unit = { f(); go() }
|
|
194
|
+
go()
|
|
195
|
+
} with Control {
|
|
196
|
+
def break() = ()
|
|
197
|
+
def continue() = loop { f }
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Calls provided action repeatedly. `start` is inclusive, `end` is not.
|
|
202
|
+
*/
|
|
203
|
+
def each(start: Int, end: Int) { action: (Int) => Unit / Control } = {
|
|
204
|
+
var i = start;
|
|
205
|
+
loop {
|
|
206
|
+
if (i < end) { val el = i; i = i + 1; action(el) }
|
|
207
|
+
else { do break() }
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
def repeat(n: Int) { action: () => Unit / Control } = each(0, n) { n => action() }
|
|
212
|
+
|
|
213
|
+
// Benchmarking
|
|
214
|
+
// ============
|
|
215
|
+
// should only be used with pure blocks
|
|
216
|
+
extern control def measure(warmup: Int, iterations: Int) { block: => Unit }: Unit =
|
|
217
|
+
"(delayed (display (measure (lambda () (run ((${box block} here)))) ${warmup} ${iterations})))"
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
(define-syntax delayed
|
|
2
|
+
(syntax-rules ()
|
|
3
|
+
[(_ e ...)
|
|
4
|
+
(lambda (k) (k
|
|
5
|
+
(begin e ...)))]))
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
;; EVIDENCE
|
|
9
|
+
|
|
10
|
+
(define (here x) x)
|
|
11
|
+
|
|
12
|
+
; (define-syntax lift
|
|
13
|
+
; (syntax-rules ()
|
|
14
|
+
; [(_ m)
|
|
15
|
+
; (lambda (k1)
|
|
16
|
+
; (lambda (k2)
|
|
17
|
+
; (m (lambda (a) ((k1 a) k2)))))]))
|
|
18
|
+
|
|
19
|
+
(define (lift m)
|
|
20
|
+
(lambda (k1)
|
|
21
|
+
(lambda (k2)
|
|
22
|
+
(m (lambda (a) ((k1 a) k2))))))
|
|
23
|
+
|
|
24
|
+
(define-syntax nested-helper
|
|
25
|
+
(syntax-rules ()
|
|
26
|
+
[(_ (ev) acc) (ev acc)]
|
|
27
|
+
[(_ (ev1 ev2 ...) acc)
|
|
28
|
+
(nested-helper (ev2 ...) (ev1 acc))]))
|
|
29
|
+
|
|
30
|
+
(define-syntax nested
|
|
31
|
+
(syntax-rules ()
|
|
32
|
+
[(_ ev1 ...) (lambda (m) (nested-helper (ev1 ...) m))]))
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
;; HANDLING
|
|
36
|
+
|
|
37
|
+
; (define (reset m) (m (lambda (v) (lambda (k) (k v)))))
|
|
38
|
+
|
|
39
|
+
(define-syntax reset
|
|
40
|
+
(syntax-rules ()
|
|
41
|
+
[(_ m)
|
|
42
|
+
(m (lambda (v) (lambda (k) (k v))))]))
|
|
43
|
+
|
|
44
|
+
; ;; EXAMPLE
|
|
45
|
+
; ; (handle ([Fail_22 (Fail_109 () resume_120 (Nil_74))])
|
|
46
|
+
; ; (let ((tmp86_121 ((Fail_109 Fail_22))))
|
|
47
|
+
; ; (Cons_73 tmp86_121 (Nil_74))))
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
; capabilities first take evidence than require selection!
|
|
51
|
+
(define-syntax handle
|
|
52
|
+
(syntax-rules ()
|
|
53
|
+
[(_ (cap1 ...) body)
|
|
54
|
+
(reset (body lift cap1 ...))]))
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
(define-syntax shift
|
|
58
|
+
(syntax-rules ()
|
|
59
|
+
[(_ ev body)
|
|
60
|
+
(ev body)]))
|
|
61
|
+
|
|
62
|
+
; capabilities first take evidence than require selection!
|
|
63
|
+
(define-syntax handle-old
|
|
64
|
+
(syntax-rules ()
|
|
65
|
+
[(_ ((cap1 (op1 (arg1 ...) kid exp) ...) ...) body)
|
|
66
|
+
(reset (body lift
|
|
67
|
+
(cap1 (define-effect-op ev (arg1 ...) kid exp) ...) ...))]))
|
|
68
|
+
|
|
69
|
+
(define-syntax define-effect-op
|
|
70
|
+
(syntax-rules ()
|
|
71
|
+
[(_ ev1 (arg1 ...) kid exp ...)
|
|
72
|
+
(lambda (ev1 arg1 ...)
|
|
73
|
+
; we apply the outer evidence to the body of the operation
|
|
74
|
+
(ev1 (lambda (resume)
|
|
75
|
+
; k itself also gets evidence!
|
|
76
|
+
(let ([kid (lambda (ev v) (ev (resume v)))])
|
|
77
|
+
exp ...))))]))
|
|
78
|
+
|
|
79
|
+
(define (with-region-non-mono body)
|
|
80
|
+
(define arena (make-arena))
|
|
81
|
+
|
|
82
|
+
(define (lift m) (lambda (k)
|
|
83
|
+
; on suspend
|
|
84
|
+
(define fields (backup arena))
|
|
85
|
+
(m (lambda (a)
|
|
86
|
+
; on resume
|
|
87
|
+
(restore fields)
|
|
88
|
+
(k a)))))
|
|
89
|
+
|
|
90
|
+
(body lift arena))
|
|
91
|
+
|
|
92
|
+
(define (with-region body)
|
|
93
|
+
(define arena (make-arena))
|
|
94
|
+
|
|
95
|
+
(body arena))
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
; An Arena is a pointer to a list of cells
|
|
99
|
+
(define (make-arena) (box '()))
|
|
100
|
+
|
|
101
|
+
(define (fresh arena init)
|
|
102
|
+
(let* ([cell (box init)]
|
|
103
|
+
[cells (unbox arena)])
|
|
104
|
+
(set-box! arena (cons cell cells))
|
|
105
|
+
cell))
|
|
106
|
+
|
|
107
|
+
; Backup = List<(Cell, Value)>
|
|
108
|
+
|
|
109
|
+
; Arena -> Backup
|
|
110
|
+
(define (backup arena)
|
|
111
|
+
(let ([fields (unbox arena)])
|
|
112
|
+
(map (lambda (cell) (cons cell (unbox cell))) fields)))
|
|
113
|
+
|
|
114
|
+
; Backup -> ()
|
|
115
|
+
(define (restore data)
|
|
116
|
+
(for-each (lambda (cell-data)
|
|
117
|
+
(set-box! (car cell-data) (cdr cell-data)))
|
|
118
|
+
data))
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
module effekt
|
|
2
|
+
|
|
3
|
+
extern include "../common/effekt_primitives.ss"
|
|
4
|
+
extern include "seq0.ss"
|
|
5
|
+
extern include "effekt.ss"
|
|
6
|
+
extern include "../common/effekt_matching.ss"
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def locally[R] { f: => R }: R = f()
|
|
10
|
+
|
|
11
|
+
// String ops
|
|
12
|
+
// ==========
|
|
13
|
+
extern pure def infixConcat(s1: String, s2: String): String =
|
|
14
|
+
"(string-append ${s1} ${s2})"
|
|
15
|
+
|
|
16
|
+
// TODO implement
|
|
17
|
+
extern pure def show[R](value: R): String =
|
|
18
|
+
"(show_impl ${value})"
|
|
19
|
+
|
|
20
|
+
extern io def println[R](r: R): Unit =
|
|
21
|
+
"(println_impl ${r})"
|
|
22
|
+
|
|
23
|
+
extern io def error[R](msg: String): R =
|
|
24
|
+
"(raise ${msg})"
|
|
25
|
+
|
|
26
|
+
extern io def random(): Double =
|
|
27
|
+
"(random 1.0)"
|
|
28
|
+
|
|
29
|
+
// Math ops
|
|
30
|
+
// ========
|
|
31
|
+
extern pure def infixAdd(x: Int, y: Int): Int =
|
|
32
|
+
"(+ ${x} ${y})"
|
|
33
|
+
|
|
34
|
+
extern pure def infixMul(x: Int, y: Int): Int =
|
|
35
|
+
"(* ${x} ${y})"
|
|
36
|
+
|
|
37
|
+
extern pure def infixDiv(x: Int, y: Int): Int =
|
|
38
|
+
"(floor (/ ${x} ${y}))"
|
|
39
|
+
|
|
40
|
+
extern pure def infixSub(x: Int, y: Int): Int =
|
|
41
|
+
"(- ${x} ${y})"
|
|
42
|
+
|
|
43
|
+
extern pure def mod(x: Int, y: Int): Int =
|
|
44
|
+
"(modulo ${x} ${y})"
|
|
45
|
+
|
|
46
|
+
extern pure def infixAdd(x: Double, y: Double): Double =
|
|
47
|
+
"(+ ${x} ${y})"
|
|
48
|
+
|
|
49
|
+
extern pure def infixMul(x: Double, y: Double): Double =
|
|
50
|
+
"(* ${x} ${y})"
|
|
51
|
+
|
|
52
|
+
extern pure def infixDiv(x: Double, y: Double): Double =
|
|
53
|
+
"(/ ${x} ${y})"
|
|
54
|
+
|
|
55
|
+
extern pure def infixSub(x: Double, y: Double): Double =
|
|
56
|
+
"(- ${x} ${y})"
|
|
57
|
+
|
|
58
|
+
extern pure def cos(x: Double): Double =
|
|
59
|
+
"(cos ${x})"
|
|
60
|
+
|
|
61
|
+
extern pure def sin(x: Double): Double =
|
|
62
|
+
"(sin ${x})"
|
|
63
|
+
|
|
64
|
+
extern pure def atan(x: Double): Double =
|
|
65
|
+
"(atan ${x})"
|
|
66
|
+
|
|
67
|
+
extern pure def tan(x: Double): Double =
|
|
68
|
+
"(tan ${x})"
|
|
69
|
+
|
|
70
|
+
extern pure def sqrt(x: Double): Double =
|
|
71
|
+
"(sqrt ${x})"
|
|
72
|
+
|
|
73
|
+
extern pure def square(x: Double): Double =
|
|
74
|
+
"(* ${x} ${x})"
|
|
75
|
+
|
|
76
|
+
extern pure def log(x: Double): Double =
|
|
77
|
+
"(log ${x})"
|
|
78
|
+
|
|
79
|
+
extern pure def log1p(x: Double): Double =
|
|
80
|
+
"(log (+ ${x} 1))"
|
|
81
|
+
|
|
82
|
+
extern pure def exp(x: Double): Double =
|
|
83
|
+
"(exp ${x})"
|
|
84
|
+
|
|
85
|
+
// since we do not have "extern val", yet
|
|
86
|
+
extern pure def _pi(): Double =
|
|
87
|
+
"(* 4 (atan 1))"
|
|
88
|
+
|
|
89
|
+
val PI: Double = _pi()
|
|
90
|
+
|
|
91
|
+
extern pure def toInt(d: Double): Int =
|
|
92
|
+
"(round ${d})"
|
|
93
|
+
|
|
94
|
+
extern pure def toDouble(d: Int): Double =
|
|
95
|
+
"${d}"
|
|
96
|
+
|
|
97
|
+
def min(n: Int, m: Int): Int =
|
|
98
|
+
if (n < m) n else m
|
|
99
|
+
|
|
100
|
+
def max(n: Int, m: Int): Int =
|
|
101
|
+
if (n > m) n else m
|
|
102
|
+
|
|
103
|
+
// Comparison ops
|
|
104
|
+
// ==============
|
|
105
|
+
extern pure def infixEq[R](x: R, y: R): Boolean =
|
|
106
|
+
"(equal_impl ${x} ${y})"
|
|
107
|
+
|
|
108
|
+
extern pure def infixNeq[R](x: R, y: R): Boolean =
|
|
109
|
+
"(not (equal_impl ${x} ${y}))"
|
|
110
|
+
|
|
111
|
+
extern pure def infixLt(x: Int, y: Int): Boolean =
|
|
112
|
+
"(< ${x} ${y})"
|
|
113
|
+
|
|
114
|
+
extern pure def infixLte(x: Int, y: Int): Boolean =
|
|
115
|
+
"(<= ${x} ${y})"
|
|
116
|
+
|
|
117
|
+
extern pure def infixGt(x: Int, y: Int): Boolean =
|
|
118
|
+
"(> ${x} ${y})"
|
|
119
|
+
|
|
120
|
+
extern pure def infixGte(x: Int, y: Int): Boolean =
|
|
121
|
+
"(>= ${x} ${y})"
|
|
122
|
+
|
|
123
|
+
extern pure def infixLt(x: Double, y: Double): Boolean =
|
|
124
|
+
"(< ${x} ${y})"
|
|
125
|
+
|
|
126
|
+
extern pure def infixLte(x: Double, y: Double): Boolean =
|
|
127
|
+
"(<= ${x} ${y})"
|
|
128
|
+
|
|
129
|
+
extern pure def infixGt(x: Double, y: Double): Boolean =
|
|
130
|
+
"(> ${x} ${y})"
|
|
131
|
+
|
|
132
|
+
extern pure def infixGte(x: Double, y: Double): Boolean =
|
|
133
|
+
"(>= ${x} ${y})"
|
|
134
|
+
|
|
135
|
+
// Boolean ops
|
|
136
|
+
// ===========
|
|
137
|
+
// for now those are considered eager
|
|
138
|
+
extern pure def not(b: Boolean): Boolean =
|
|
139
|
+
"(not ${b})"
|
|
140
|
+
|
|
141
|
+
extern pure def infixOr(x: Boolean, y: Boolean): Boolean =
|
|
142
|
+
"(or ${x} ${y})"
|
|
143
|
+
|
|
144
|
+
extern pure def infixAnd(x: Boolean, y: Boolean): Boolean =
|
|
145
|
+
"(and ${x} ${y})"
|
|
146
|
+
|
|
147
|
+
// Should only be used internally since values in Effekt should not be undefined
|
|
148
|
+
extern pure def isUndefined[A](value: A): Boolean =
|
|
149
|
+
"(eq? ${value} #f)"
|
|
150
|
+
|
|
151
|
+
// Pairs
|
|
152
|
+
// =====
|
|
153
|
+
record Tuple2[A, B](first: A, second: B)
|
|
154
|
+
record Tuple3[A, B, C](first: A, second: B, third: C)
|
|
155
|
+
record Tuple4[A, B, C, D](first: A, second: B, third: C, fourth: D)
|
|
156
|
+
record Tuple5[A, B, C, D, E](first: A, second: B, third: C, fourth: D, fifth: E)
|
|
157
|
+
record Tuple6[A, B, C, D, E, F](first: A, second: B, third: C, fourth: D, fifth: E, sixth: F)
|
|
158
|
+
|
|
159
|
+
// Exceptions
|
|
160
|
+
// ==========
|
|
161
|
+
// a fatal runtime error that cannot be caught
|
|
162
|
+
extern io def panic[R](msg: String): R =
|
|
163
|
+
"(raise ${msg})"
|
|
164
|
+
|
|
165
|
+
interface Exception[E] {
|
|
166
|
+
def raise(exception: E, msg: String): Nothing
|
|
167
|
+
}
|
|
168
|
+
record RuntimeError()
|
|
169
|
+
|
|
170
|
+
def raise[A](msg: String): A / Exception[RuntimeError] = do raise(RuntimeError(), msg) match {}
|
|
171
|
+
def raise[A, E](exception: E, msg: String): A / Exception[E] = do raise(exception, msg) match {}
|
|
172
|
+
|
|
173
|
+
// converts exceptions of (static) type E to an uncatchable panic that aborts the program
|
|
174
|
+
def panicOn[E] { prog: => Unit / Exception[E] }: Unit =
|
|
175
|
+
try { prog() } with Exception[E] { def raise(exception: E, msg: String) = panic(msg) }
|
|
176
|
+
|
|
177
|
+
// reports exceptions of (static) type E to the console
|
|
178
|
+
def report[E] { prog: => Unit / Exception[E] }: Unit =
|
|
179
|
+
try { prog() } with Exception[E] { def raise(exception: E, msg: String) = println(msg) }
|
|
180
|
+
|
|
181
|
+
// ignores exceptions of (static) type E
|
|
182
|
+
// TODO this should be called "ignore" but that name currently clashes with internal pattern matching names on $effekt
|
|
183
|
+
def ignoring[E] { prog: => Unit / Exception[E] }: Unit =
|
|
184
|
+
try { prog() } with Exception[E] { def raise(exception: E, msg: String) = () }
|
|
185
|
+
|
|
186
|
+
// Control Flow
|
|
187
|
+
// ============
|
|
188
|
+
interface Control {
|
|
189
|
+
def break(): Unit
|
|
190
|
+
def continue(): Unit
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
def loop { f: () => Unit / Control }: Unit = try {
|
|
194
|
+
def go(): Unit = { f(); go() }
|
|
195
|
+
go()
|
|
196
|
+
} with Control {
|
|
197
|
+
def break() = ()
|
|
198
|
+
def continue() = loop { f }
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Calls provided action repeatedly. `start` is inclusive, `end` is not.
|
|
203
|
+
*/
|
|
204
|
+
def each(start: Int, end: Int) { action: (Int) => Unit / Control } = {
|
|
205
|
+
var i = start;
|
|
206
|
+
loop {
|
|
207
|
+
if (i < end) { val el = i; i = i + 1; action(el) }
|
|
208
|
+
else { do break() }
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
def repeat(n: Int) { action: () => Unit / Control } = each(0, n) { n => action() }
|
|
213
|
+
|
|
214
|
+
// Benchmarking
|
|
215
|
+
// ============
|
|
216
|
+
// should only be used with pure blocks
|
|
217
|
+
extern control def measure(warmup: Int, iterations: Int) { block: => Unit }: Unit =
|
|
218
|
+
"(delayed (display (measure (lambda () (run (${box block}))) ${warmup} ${iterations})))"
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
(define-syntax delayed
|
|
2
|
+
(syntax-rules ()
|
|
3
|
+
[(_ e)
|
|
4
|
+
(lambda (mk) (underflow e mk))]))
|
|
5
|
+
|
|
6
|
+
; Control = MetaCont -> Step
|
|
7
|
+
|
|
8
|
+
; a -> Control a
|
|
9
|
+
(define (pure v)
|
|
10
|
+
(lambda (mk) (underflow v mk)))
|
|
11
|
+
|
|
12
|
+
; Step a = (a | Control x), MetaCont x a
|
|
13
|
+
|
|
14
|
+
; (a | Control a), MetaCont -> a
|
|
15
|
+
(define (trampoline c mk)
|
|
16
|
+
(if (null? mk) c
|
|
17
|
+
(call-with-values
|
|
18
|
+
(lambda () (c mk))
|
|
19
|
+
trampoline)))
|
|
20
|
+
|
|
21
|
+
; a, MetaCont -> Step
|
|
22
|
+
(define (underflow v mk)
|
|
23
|
+
(if (null? mk) (values v mk)
|
|
24
|
+
(let* ([stack (car mk)]
|
|
25
|
+
[rest (cdr mk)]
|
|
26
|
+
[frames (Stack-frames stack)]
|
|
27
|
+
[arena (Stack-arena stack)]
|
|
28
|
+
[prompt (Stack-prompt stack)])
|
|
29
|
+
(if (null? frames) (underflow v rest)
|
|
30
|
+
(values ((car frames) v) (cons (make-Stack (cdr frames) arena prompt) rest))))))
|
|
31
|
+
|
|
32
|
+
; Control, Prompt -> Control
|
|
33
|
+
(define (reset p c)
|
|
34
|
+
(lambda (mk)
|
|
35
|
+
(c (cons (make-Stack '() (make-arena) p) mk))))
|
|
36
|
+
|
|
37
|
+
; Prompt, Body -> Control
|
|
38
|
+
(define (shift p f)
|
|
39
|
+
(lambda (mk)
|
|
40
|
+
(let-values ([(k mkrest) (splitSeq p mk)])
|
|
41
|
+
(let ([cont (lambda (a) (lambda (mk) (underflow a (appendSeq k mk))))])
|
|
42
|
+
(values (f cont) mkrest)))))
|
|
43
|
+
|
|
44
|
+
; Frame, MetaCont -> MetaCont
|
|
45
|
+
(define (push-frame f mk)
|
|
46
|
+
(if (null? mk) (error 'push-frame "Cannot push frame, meta cont ~s is empty" mk)
|
|
47
|
+
(let ([stack (car mk)]
|
|
48
|
+
[rest (cdr mk)])
|
|
49
|
+
(let ([frames (Stack-frames stack)]
|
|
50
|
+
[arena (Stack-arena stack)]
|
|
51
|
+
[prompt (Stack-prompt stack)])
|
|
52
|
+
(cons (make-Stack (cons f frames) arena prompt) rest)))))
|
|
53
|
+
|
|
54
|
+
(define-syntax then
|
|
55
|
+
(syntax-rules ()
|
|
56
|
+
[(_ m f)
|
|
57
|
+
(lambda (k) (values m (push-frame f k)))]))
|
|
58
|
+
|
|
59
|
+
(define toplevel 0)
|
|
60
|
+
|
|
61
|
+
; Control a -> a
|
|
62
|
+
(define (run c)
|
|
63
|
+
(trampoline c (cons (make-Stack '() (make-arena) toplevel) '())))
|
|
64
|
+
|
|
65
|
+
(define newPrompt (lambda () (string #\p)))
|
|
66
|
+
|
|
67
|
+
(define-syntax handle
|
|
68
|
+
(syntax-rules ()
|
|
69
|
+
[(_ ((cap1 (op1 (arg1 ...) kid exp) ...) ...) body)
|
|
70
|
+
(let ([p (newPrompt)])
|
|
71
|
+
(reset p (body
|
|
72
|
+
(cap1 (define-effect-op p (arg1 ...) kid exp) ...)
|
|
73
|
+
...)))]))
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
(define-syntax define-effect-op
|
|
77
|
+
(syntax-rules ()
|
|
78
|
+
[(_ p (arg1 ...) kid exp ...)
|
|
79
|
+
(lambda (arg1 ...)
|
|
80
|
+
(shift p (lambda (kid) exp ...)))]))
|
|
81
|
+
|
|
82
|
+
; state(init) { cell => ... }
|
|
83
|
+
(define (state init body)
|
|
84
|
+
(with-region (lambda (arena) (body (fresh arena init)))))
|