@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,76 @@
|
|
|
1
|
+
; [ [f1, f2, f3, f4| fields | prompt], [f1, f2, f3, f4| fields | prompt]... ]
|
|
2
|
+
(define-record Stack (
|
|
3
|
+
[immutable frames]
|
|
4
|
+
[immutable arena]
|
|
5
|
+
[immutable prompt]))
|
|
6
|
+
|
|
7
|
+
(define-record Substack (
|
|
8
|
+
[immutable frames]
|
|
9
|
+
[immutable arena]
|
|
10
|
+
[immutable field-backup]
|
|
11
|
+
[immutable prompt]))
|
|
12
|
+
|
|
13
|
+
; MetaCont = (non-empty-list-of Stack)
|
|
14
|
+
; SubCont = (non-empty-list-of Stack)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
; An Arena is a pointer to a list of cells
|
|
18
|
+
(define (make-arena) (box '()))
|
|
19
|
+
|
|
20
|
+
(define (fresh arena init)
|
|
21
|
+
(let* ([cell (box init)]
|
|
22
|
+
[cells (unbox arena)])
|
|
23
|
+
(set-box! arena (cons cell cells))
|
|
24
|
+
cell))
|
|
25
|
+
|
|
26
|
+
; with-region { arena => ... }
|
|
27
|
+
(define (with-region body)
|
|
28
|
+
(lambda (mk)
|
|
29
|
+
(let* ([stack (car mk)]
|
|
30
|
+
[arena (Stack-arena stack)])
|
|
31
|
+
((body arena) mk))))
|
|
32
|
+
|
|
33
|
+
; Backup = List<(Cell, Value)>
|
|
34
|
+
|
|
35
|
+
; Arena -> Backup
|
|
36
|
+
(define (backup arena)
|
|
37
|
+
(let ([fields (unbox arena)])
|
|
38
|
+
(map (lambda (cell) (cons cell (unbox cell))) fields)))
|
|
39
|
+
|
|
40
|
+
; Backup -> ()
|
|
41
|
+
(define (restore data)
|
|
42
|
+
(for-each (lambda (cell-data)
|
|
43
|
+
(set-box! (car cell-data) (cdr cell-data)))
|
|
44
|
+
data))
|
|
45
|
+
|
|
46
|
+
; Prompt MetaCont -> SubCont, MetaCont
|
|
47
|
+
(define (splitSeq p seq)
|
|
48
|
+
(define (split sub s)
|
|
49
|
+
(if (null? s)
|
|
50
|
+
(error 'splitSeq "prompt ~s not found on stack" p)
|
|
51
|
+
(let* ([stack (car s)]
|
|
52
|
+
[frames (Stack-frames stack)]
|
|
53
|
+
[arena (Stack-arena stack)]
|
|
54
|
+
[prompt (Stack-prompt stack)]
|
|
55
|
+
[rest (cdr s)])
|
|
56
|
+
(define sub* (cons (make-Substack frames arena (backup arena) prompt) sub))
|
|
57
|
+
(if (not (eq? prompt p))
|
|
58
|
+
(split sub* rest)
|
|
59
|
+
(values sub* rest)))))
|
|
60
|
+
(split (list) seq))
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
(define (appendSeq subcont meta)
|
|
64
|
+
(if (null? subcont)
|
|
65
|
+
meta
|
|
66
|
+
(let* ([stack (car subcont)]
|
|
67
|
+
[frames (Substack-frames stack)]
|
|
68
|
+
[arena (Substack-arena stack)]
|
|
69
|
+
[fields (Substack-field-backup stack)]
|
|
70
|
+
[prompt (Substack-prompt stack)]
|
|
71
|
+
[_ (restore fields)]
|
|
72
|
+
[rest (cdr subcont)])
|
|
73
|
+
(appendSeq rest (cons (make-Stack frames arena prompt) meta)))))
|
|
74
|
+
|
|
75
|
+
; (define ex (list (make-Stack '(1 2 3) (list (box 1)) 4) (make-Stack '(1 2 3) (list (box 2)) 3) (make-Stack '(1 2 3) (list (box 3)) 2) (make-Stack '(4 5 6) (list (box 4)) 1)))
|
|
76
|
+
; (let-values ([(cont meta) (splitSeq 2 ex)]) (appendSeq cont meta))
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
module effekt
|
|
2
|
+
|
|
3
|
+
// Runtime
|
|
4
|
+
// TODO split runtime into monadic and direct
|
|
5
|
+
extern include "effekt_runtime.js"
|
|
6
|
+
|
|
7
|
+
// Builtins
|
|
8
|
+
extern include "effekt_builtins.js"
|
|
9
|
+
|
|
10
|
+
def locally[R] { f: => R }: R = f()
|
|
11
|
+
|
|
12
|
+
// Side effecting ops
|
|
13
|
+
// ==================
|
|
14
|
+
extern io def println[R](value: R): Unit =
|
|
15
|
+
"println$impl(${value})"
|
|
16
|
+
|
|
17
|
+
extern io def inspect[R](value: R): Unit =
|
|
18
|
+
"console.log(${value})"
|
|
19
|
+
|
|
20
|
+
extern io def random(): Double =
|
|
21
|
+
"Math.random()"
|
|
22
|
+
|
|
23
|
+
extern io def timestamp(): Int =
|
|
24
|
+
"Date.now()"
|
|
25
|
+
|
|
26
|
+
// References and state
|
|
27
|
+
// ====================
|
|
28
|
+
// the following type is defined in builtins.scala
|
|
29
|
+
// interface Ref[T] { def get(): T; def put(t: T): Unit }
|
|
30
|
+
extern io def freshIn[T](t: T) {r: Region}: Ref[T] at {r} = "r.fresh(${t})"
|
|
31
|
+
extern io def freshGlobal[T](t: T): Ref[T] at {global} = "$effekt.fresh(${t})"
|
|
32
|
+
|
|
33
|
+
// String ops
|
|
34
|
+
// ==========
|
|
35
|
+
extern pure def show[R](value: R): String =
|
|
36
|
+
"show$impl(${value})"
|
|
37
|
+
|
|
38
|
+
extern pure def infixConcat(s1: String, s2: String): String =
|
|
39
|
+
"${s1} + ${s2}"
|
|
40
|
+
|
|
41
|
+
// Math ops
|
|
42
|
+
// ========
|
|
43
|
+
extern pure def infixAdd(x: Int, y: Int): Int =
|
|
44
|
+
"(${x} + ${y})"
|
|
45
|
+
|
|
46
|
+
extern pure def infixMul(x: Int, y: Int): Int =
|
|
47
|
+
"(${x} * ${y})"
|
|
48
|
+
|
|
49
|
+
extern pure def infixDiv(x: Int, y: Int): Int =
|
|
50
|
+
"Math.floor(${x} / ${y})"
|
|
51
|
+
|
|
52
|
+
extern pure def infixSub(x: Int, y: Int): Int =
|
|
53
|
+
"(${x} - ${y})"
|
|
54
|
+
|
|
55
|
+
extern pure def mod(x: Int, y: Int): Int =
|
|
56
|
+
"(${x} % ${y})"
|
|
57
|
+
|
|
58
|
+
extern pure def infixAdd(x: Double, y: Double): Double =
|
|
59
|
+
"(${x} + ${y})"
|
|
60
|
+
|
|
61
|
+
extern pure def infixMul(x: Double, y: Double): Double =
|
|
62
|
+
"(${x} * ${y})"
|
|
63
|
+
|
|
64
|
+
extern pure def infixSub(x: Double, y: Double): Double =
|
|
65
|
+
"(${x} - ${y})"
|
|
66
|
+
|
|
67
|
+
extern pure def infixDiv(x: Double, y: Double): Double =
|
|
68
|
+
"(${x} / ${y})"
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
extern pure def cos(x: Double): Double =
|
|
72
|
+
"Math.cos(${x})"
|
|
73
|
+
|
|
74
|
+
extern pure def sin(x: Double): Double =
|
|
75
|
+
"Math.sin(${x})"
|
|
76
|
+
|
|
77
|
+
extern pure def atan(x: Double): Double =
|
|
78
|
+
"Math.atan(${x})"
|
|
79
|
+
|
|
80
|
+
extern pure def tan(x: Double): Double =
|
|
81
|
+
"Math.tan(${x})"
|
|
82
|
+
|
|
83
|
+
extern pure def sqrt(x: Double): Double =
|
|
84
|
+
"Math.sqrt(${x})"
|
|
85
|
+
|
|
86
|
+
extern pure def square(x: Double): Double =
|
|
87
|
+
"(${x} * ${x})"
|
|
88
|
+
|
|
89
|
+
extern pure def log(x: Double): Double =
|
|
90
|
+
"Math.log(${x})"
|
|
91
|
+
|
|
92
|
+
extern pure def log1p(x: Double): Double =
|
|
93
|
+
"Math.log1p(${x})"
|
|
94
|
+
|
|
95
|
+
extern pure def exp(x: Double): Double =
|
|
96
|
+
"Math.exp(${x})"
|
|
97
|
+
|
|
98
|
+
// since we do not have "extern val", yet
|
|
99
|
+
extern pure def _pi(): Double =
|
|
100
|
+
"Math.PI"
|
|
101
|
+
|
|
102
|
+
val PI: Double = _pi()
|
|
103
|
+
|
|
104
|
+
extern pure def toInt(d: Double): Int =
|
|
105
|
+
"Math.round(${d})"
|
|
106
|
+
|
|
107
|
+
extern pure def toDouble(d: Int): Double =
|
|
108
|
+
"${d}"
|
|
109
|
+
|
|
110
|
+
extern pure def floor(d: Double): Int =
|
|
111
|
+
"Math.floor(${d})"
|
|
112
|
+
|
|
113
|
+
extern pure def ceil(d: Double): Int =
|
|
114
|
+
"Math.ceil(${d})"
|
|
115
|
+
|
|
116
|
+
def min(n: Int, m: Int): Int =
|
|
117
|
+
if (n < m) n else m
|
|
118
|
+
|
|
119
|
+
def max(n: Int, m: Int): Int =
|
|
120
|
+
if (n > m) n else m
|
|
121
|
+
|
|
122
|
+
// Comparison ops
|
|
123
|
+
// ==============
|
|
124
|
+
extern pure def infixEq[R](x: R, y: R): Boolean =
|
|
125
|
+
"equals$impl(${x}, ${y})"
|
|
126
|
+
|
|
127
|
+
extern pure def infixNeq[R](x: R, y: R): Boolean =
|
|
128
|
+
"!equals$impl(${x}, ${y})"
|
|
129
|
+
|
|
130
|
+
extern pure def infixLt(x: Int, y: Int): Boolean =
|
|
131
|
+
"(${x} < ${y})"
|
|
132
|
+
|
|
133
|
+
extern pure def infixLte(x: Int, y: Int): Boolean =
|
|
134
|
+
"(${x} <= ${y})"
|
|
135
|
+
|
|
136
|
+
extern pure def infixGt(x: Int, y: Int): Boolean =
|
|
137
|
+
"(${x} > ${y})"
|
|
138
|
+
|
|
139
|
+
extern pure def infixGte(x: Int, y: Int): Boolean =
|
|
140
|
+
"(${x} >= ${y})"
|
|
141
|
+
|
|
142
|
+
extern pure def infixLt(x: Double, y: Double): Boolean =
|
|
143
|
+
"(${x} < ${y})"
|
|
144
|
+
|
|
145
|
+
extern pure def infixLte(x: Double, y: Double): Boolean =
|
|
146
|
+
"(${x} <= ${y})"
|
|
147
|
+
|
|
148
|
+
extern pure def infixGt(x: Double, y: Double): Boolean =
|
|
149
|
+
"(${x} > ${y})"
|
|
150
|
+
|
|
151
|
+
extern pure def infixGte(x: Double, y: Double): Boolean =
|
|
152
|
+
"(${x} >= ${y})"
|
|
153
|
+
|
|
154
|
+
extern pure def infixLt(x: String, y: String): Boolean =
|
|
155
|
+
"(${x} < ${y})"
|
|
156
|
+
|
|
157
|
+
extern pure def infixLte(x: String, y: String): Boolean =
|
|
158
|
+
"(${x} <= ${y})"
|
|
159
|
+
|
|
160
|
+
extern pure def infixGt(x: String, y: String): Boolean =
|
|
161
|
+
"(${x} > ${y})"
|
|
162
|
+
|
|
163
|
+
extern pure def infixGte(x: String, y: String): Boolean =
|
|
164
|
+
"(${x} >= ${y})"
|
|
165
|
+
|
|
166
|
+
// Boolean ops
|
|
167
|
+
// ===========
|
|
168
|
+
// for now those are considered eager
|
|
169
|
+
extern pure def not(b: Boolean): Boolean =
|
|
170
|
+
"!${b}"
|
|
171
|
+
|
|
172
|
+
extern pure def infixOr(x: Boolean, y: Boolean): Boolean =
|
|
173
|
+
"(${x} || ${y})"
|
|
174
|
+
|
|
175
|
+
extern pure def infixAnd(x: Boolean, y: Boolean): Boolean =
|
|
176
|
+
"(${x} && ${y})"
|
|
177
|
+
|
|
178
|
+
// Undefined and Null
|
|
179
|
+
// ==================
|
|
180
|
+
// Should only be used for interop with JS, since values in Effekt should not be undefined
|
|
181
|
+
|
|
182
|
+
// Is something an undefined JavaScript value?
|
|
183
|
+
extern pure def isUndefined[A](value: A): Boolean =
|
|
184
|
+
"(${value} === undefined)"
|
|
185
|
+
|
|
186
|
+
// Is something a JavaScript null value?
|
|
187
|
+
extern pure def isNull[A](value: A): Boolean =
|
|
188
|
+
"(${value} === null)"
|
|
189
|
+
|
|
190
|
+
// Pairs
|
|
191
|
+
// =====
|
|
192
|
+
record Tuple2[A, B](first: A, second: B)
|
|
193
|
+
record Tuple3[A, B, C](first: A, second: B, third: C)
|
|
194
|
+
record Tuple4[A, B, C, D](first: A, second: B, third: C, fourth: D)
|
|
195
|
+
record Tuple5[A, B, C, D, E](first: A, second: B, third: C, fourth: D, fifth: E)
|
|
196
|
+
record Tuple6[A, B, C, D, E, F](first: A, second: B, third: C, fourth: D, fifth: E, sixth: F)
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
// Exceptions
|
|
200
|
+
// ==========
|
|
201
|
+
// a fatal runtime error that cannot be caught
|
|
202
|
+
extern io def panic[R](msg: String): R =
|
|
203
|
+
"(function() { throw ${msg} })()"
|
|
204
|
+
|
|
205
|
+
interface Exception[E] {
|
|
206
|
+
def raise(exception: E, msg: String): Nothing
|
|
207
|
+
}
|
|
208
|
+
record RuntimeError()
|
|
209
|
+
|
|
210
|
+
def raise[A](msg: String): A / Exception[RuntimeError] = do raise(RuntimeError(), msg) match {}
|
|
211
|
+
def raise[A, E](exception: E, msg: String): A / Exception[E] = do raise(exception, msg) match {}
|
|
212
|
+
|
|
213
|
+
// converts exceptions of (static) type E to an uncatchable panic that aborts the program
|
|
214
|
+
def panicOn[E] { prog: => Unit / Exception[E] }: Unit =
|
|
215
|
+
try { prog() } with Exception[E] { def raise(exception: E, msg: String) = panic(msg) }
|
|
216
|
+
|
|
217
|
+
// reports exceptions of (static) type E to the console
|
|
218
|
+
def report[E] { prog: => Unit / Exception[E] }: Unit =
|
|
219
|
+
try { prog() } with Exception[E] { def raise(exception: E, msg: String) = println(msg) }
|
|
220
|
+
|
|
221
|
+
// ignores exceptions of (static) type E
|
|
222
|
+
// TODO this should be called "ignore" but that name currently clashes with internal pattern matching names on $effekt
|
|
223
|
+
def ignoring[E] { prog: => Unit / Exception[E] }: Unit =
|
|
224
|
+
try { prog() } with Exception[E] { def raise(exception: E, msg: String) = () }
|
|
225
|
+
|
|
226
|
+
// Control Flow
|
|
227
|
+
// ============
|
|
228
|
+
interface Control {
|
|
229
|
+
def break(): Unit
|
|
230
|
+
def continue(): Unit
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
def loop { f: () => Unit / Control }: Unit = try {
|
|
234
|
+
def go(): Unit = { f(); go() }
|
|
235
|
+
go()
|
|
236
|
+
} with Control {
|
|
237
|
+
def break() = ()
|
|
238
|
+
def continue() = loop { f }
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Calls provided action repeatedly. `start` is inclusive, `end` is not.
|
|
243
|
+
*/
|
|
244
|
+
def each(start: Int, end: Int) { action: (Int) => Unit / Control } = {
|
|
245
|
+
var i = start;
|
|
246
|
+
loop {
|
|
247
|
+
if (i < end) { val el = i; i = i + 1; action(el) }
|
|
248
|
+
else { do break() }
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
def repeat(n: Int) { action: () => Unit / Control } = each(0, n) { n => action() }
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
// Benchmarking
|
|
256
|
+
// ============
|
|
257
|
+
|
|
258
|
+
// Current time in nanoseconds
|
|
259
|
+
// TODO use a better timer
|
|
260
|
+
extern control def currentTimeNanos(): Int =
|
|
261
|
+
"$effekt.delayed(() => new Date().getTime() * 1000000)"
|
|
262
|
+
|
|
263
|
+
extern io def setTimeout(callback: () => Unit at {}, timeout: Int): Unit =
|
|
264
|
+
"(function() { window.setTimeout(() => ${callback}().run(), ${timeout}); return $effekt.unit; })()"
|
|
265
|
+
|
|
266
|
+
// runs the block and returns the time in nanoseconds
|
|
267
|
+
def timed { block: => Unit }: Int = {
|
|
268
|
+
val before = currentTimeNanos()
|
|
269
|
+
block()
|
|
270
|
+
val after = currentTimeNanos()
|
|
271
|
+
after - before
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
def measure(warmup: Int, iterations: Int) { block: => Unit }: Unit = {
|
|
275
|
+
def run(n: Int, report: Boolean): Unit = {
|
|
276
|
+
if (n <= 0) { () } else {
|
|
277
|
+
val time = timed { block() };
|
|
278
|
+
if (report) { println(time) } else { () };
|
|
279
|
+
run(n - 1, report)
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
run(warmup, false)
|
|
283
|
+
run(iterations, true)
|
|
284
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
function show$impl(obj) {
|
|
2
|
+
if (!!obj && !!obj.__reflect) {
|
|
3
|
+
const meta = obj.__reflect()
|
|
4
|
+
return meta.__name + "(" + meta.__data.map(show$impl).join(", ") + ")"
|
|
5
|
+
}
|
|
6
|
+
else if (!!obj && obj.__unit) {
|
|
7
|
+
return "()";
|
|
8
|
+
} else {
|
|
9
|
+
return "" + obj;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function equals$impl(obj1, obj2) {
|
|
14
|
+
if (!!obj1.__equals) {
|
|
15
|
+
return obj1.__equals(obj2)
|
|
16
|
+
} else {
|
|
17
|
+
return (obj1.__unit && obj2.__unit) || (obj1 === obj2);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function println$impl(obj) {
|
|
22
|
+
//return $effekt.delayed(() => { console.log(show(obj)); return $effekt.unit; });
|
|
23
|
+
console.log(show$impl(obj)); return $effekt.unit;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
$effekt.unit = { __unit: true }
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// matchers: Any -> List[Any] | null
|
|
2
|
+
const $matching = (function() {
|
|
3
|
+
|
|
4
|
+
const any = x => [x]
|
|
5
|
+
|
|
6
|
+
const ignore = x => []
|
|
7
|
+
|
|
8
|
+
const bind = matcher => x => {
|
|
9
|
+
const matched = matcher(x)
|
|
10
|
+
if (matched == null) return null;
|
|
11
|
+
return [x].concat(matched)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const literal = c => x => {
|
|
15
|
+
if (equals$impl(c, x))
|
|
16
|
+
return []
|
|
17
|
+
else
|
|
18
|
+
return null
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function tagged(tag) {
|
|
22
|
+
const matchers = arguments
|
|
23
|
+
return x => {
|
|
24
|
+
if (!x || !x.__tag || x.__tag !== tag) return null;
|
|
25
|
+
var extracted = [];
|
|
26
|
+
// we start at 1 since matchers are shifted by 1
|
|
27
|
+
for (var i = 1; i < matchers.length; i++) {
|
|
28
|
+
const matched = matchers[i](x.__data[i - 1]);
|
|
29
|
+
if (matched === null) return null;
|
|
30
|
+
Array.prototype.push.apply(extracted, matched)
|
|
31
|
+
}
|
|
32
|
+
return extracted;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function match(x, alternatives) {
|
|
37
|
+
for (var i in alternatives) {
|
|
38
|
+
const alt = alternatives[i]
|
|
39
|
+
const matched = alt.pattern(x)
|
|
40
|
+
if (matched !== null) {
|
|
41
|
+
return alt.exec.apply(null, matched)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
any: any,
|
|
48
|
+
ignore: ignore,
|
|
49
|
+
tagged: tagged,
|
|
50
|
+
bind: bind,
|
|
51
|
+
literal: literal,
|
|
52
|
+
match: match
|
|
53
|
+
}
|
|
54
|
+
})();
|
|
55
|
+
|
|
56
|
+
Object.assign($effekt, $matching);
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
// p0 = bind(tagged("Nil"))
|
|
60
|
+
// p1 = bind(tagged("Cons", any, any))
|
|
61
|
+
// p2 = tagged("Cons", any, bind(tagged("Cons", any, ignore)))
|
|
62
|
+
|
|
63
|
+
// l0 = { tag: "Nil", data: [] }
|
|
64
|
+
// l1 = { tag: "Cons", data: [1, l0] }
|
|
65
|
+
// l2 = { tag: "Cons", data: [1, { tag: "Cons", data: [2, { tag: "Nil", data: [] }] }] }
|
|
66
|
+
|
|
67
|
+
// console.log(p1(l0))
|
|
68
|
+
// console.log(p1(l1))
|
|
69
|
+
// console.log(p1(l2))
|
|
70
|
+
|
|
71
|
+
// console.log(p2(l0))
|
|
72
|
+
// console.log(p2(l1))
|
|
73
|
+
// console.log(p2(l2))
|
|
74
|
+
|
|
75
|
+
// match(l2, [
|
|
76
|
+
// { pattern: p0, exec: () => console.log("It is Nil!") },
|
|
77
|
+
// { pattern: p2, exec: (x, y) => console.log("It has at least two elements", x, y) },
|
|
78
|
+
// { pattern: p1, exec: (x, rest) => console.log("It only has one element", x) }
|
|
79
|
+
// ])
|