@effekt-lang/effekt 0.2.2 → 0.4.0

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.
Files changed (95) hide show
  1. package/README.md +6 -18
  2. package/bin/effekt +0 -0
  3. package/bin/effekt.sh +1 -1
  4. package/libraries/chez/common/effekt_primitives.ss +10 -2
  5. package/libraries/chez/common/immutable/cslist.effekt +13 -7
  6. package/libraries/chez/common/mutable/dict.effekt +8 -10
  7. package/libraries/chez/common/text/regex.effekt +7 -9
  8. package/libraries/common/args.effekt +68 -0
  9. package/libraries/common/array.effekt +220 -0
  10. package/libraries/common/bench.effekt +86 -0
  11. package/libraries/common/buffer.effekt +123 -0
  12. package/libraries/common/bytes.effekt +125 -0
  13. package/libraries/{js/immutable → common}/dequeue.effekt +18 -4
  14. package/libraries/common/effekt.effekt +725 -0
  15. package/libraries/common/exception.effekt +121 -0
  16. package/libraries/common/io/console.effekt +62 -0
  17. package/libraries/common/io/error.effekt +474 -0
  18. package/libraries/common/io/filesystem.effekt +274 -0
  19. package/libraries/common/io/network.effekt +81 -0
  20. package/libraries/common/io/time.effekt +12 -0
  21. package/libraries/common/io.effekt +88 -0
  22. package/libraries/{llvm/immutable → common}/list.effekt +101 -74
  23. package/libraries/common/option.effekt +72 -0
  24. package/libraries/common/process.effekt +9 -0
  25. package/libraries/common/queue.effekt +140 -0
  26. package/libraries/common/ref.effekt +60 -0
  27. package/libraries/common/result.effekt +45 -0
  28. package/libraries/{ml/immutable → common}/seq.effekt +30 -19
  29. package/libraries/common/string/tty.effekt +66 -0
  30. package/libraries/common/string.effekt +361 -0
  31. package/libraries/common/test.effekt +160 -0
  32. package/libraries/js/effekt_builtins.js +37 -6
  33. package/libraries/js/mutable/map.effekt +8 -9
  34. package/libraries/js/text/regex.effekt +7 -8
  35. package/libraries/js/unsafe/cont.effekt +2 -2
  36. package/libraries/js/web/dom.effekt +13 -13
  37. package/libraries/llvm/array.c +53 -0
  38. package/libraries/llvm/buffer.c +181 -76
  39. package/libraries/llvm/forward-declare-c.ll +27 -8
  40. package/libraries/llvm/io.c +423 -1
  41. package/libraries/llvm/main.c +6 -1
  42. package/libraries/llvm/ref.c +45 -0
  43. package/libraries/llvm/rts.ll +515 -354
  44. package/libraries/llvm/types.c +32 -0
  45. package/licenses/eclipse public license, version 2.0 - epl-2.0.html +4 -4
  46. package/licenses/mit license - mit-license.html +532 -62
  47. package/licenses/the bsd license - bsd-license.html +535 -60
  48. package/licenses/the mit license - mit.html +532 -62
  49. package/package.json +2 -2
  50. package/libraries/chez/callcc/effekt.effekt +0 -221
  51. package/libraries/chez/common/effekt_matching.ss +0 -100
  52. package/libraries/chez/common/immutable/dequeue.effekt +0 -78
  53. package/libraries/chez/common/immutable/list.effekt +0 -643
  54. package/libraries/chez/common/immutable/option.effekt +0 -39
  55. package/libraries/chez/common/immutable/result.effekt +0 -29
  56. package/libraries/chez/common/io/args.effekt +0 -20
  57. package/libraries/chez/common/mutable/array.effekt +0 -27
  58. package/libraries/chez/common/mutable/heap.effekt +0 -12
  59. package/libraries/chez/common/test.effekt +0 -59
  60. package/libraries/chez/common/text/string.effekt +0 -46
  61. package/libraries/chez/lift/effekt.effekt +0 -217
  62. package/libraries/chez/lift/effekt.ss +0 -118
  63. package/libraries/chez/monadic/effekt.effekt +0 -218
  64. package/libraries/js/effekt.effekt +0 -284
  65. package/libraries/js/effekt_matching.js +0 -79
  66. package/libraries/js/immutable/list.effekt +0 -643
  67. package/libraries/js/immutable/option.effekt +0 -49
  68. package/libraries/js/immutable/result.effekt +0 -29
  69. package/libraries/js/io/args.effekt +0 -9
  70. package/libraries/js/io/async.effekt +0 -28
  71. package/libraries/js/io/async.js +0 -2
  72. package/libraries/js/io/file.effekt +0 -50
  73. package/libraries/js/io/file_include.js +0 -13
  74. package/libraries/js/mutable/array.effekt +0 -98
  75. package/libraries/js/mutable/heap.effekt +0 -32
  76. package/libraries/js/test.effekt +0 -59
  77. package/libraries/js/text/string.effekt +0 -64
  78. package/libraries/llvm/effekt.effekt +0 -243
  79. package/libraries/llvm/immutable/option.effekt +0 -53
  80. package/libraries/llvm/immutable/result.effekt +0 -29
  81. package/libraries/llvm/io/args.effekt +0 -24
  82. package/libraries/llvm/text/string.effekt +0 -179
  83. package/libraries/ml/effekt.effekt +0 -267
  84. package/libraries/ml/effekt.sml +0 -63
  85. package/libraries/ml/immutable/dequeue.effekt +0 -81
  86. package/libraries/ml/immutable/list.effekt +0 -674
  87. package/libraries/ml/immutable/option.effekt +0 -53
  88. package/libraries/ml/immutable/result.effekt +0 -29
  89. package/libraries/ml/internal/option.effekt +0 -18
  90. package/libraries/ml/io/args.effekt +0 -41
  91. package/libraries/ml/mutable/array.effekt +0 -43
  92. package/libraries/ml/random.effekt +0 -85
  93. package/libraries/ml/test.effekt +0 -60
  94. package/libraries/ml/text/regex.effekt +0 -107
  95. package/libraries/ml/text/string.effekt +0 -81
@@ -0,0 +1,725 @@
1
+ module effekt
2
+
3
+ namespace js {
4
+ // Runtime
5
+ extern include js "../js/effekt_runtime.js"
6
+
7
+ // Builtins
8
+ extern include js "../js/effekt_builtins.js"
9
+ }
10
+
11
+ namespace chez {
12
+
13
+ // All Chez Scheme backends
14
+ // ------------------------
15
+ extern include chez "../chez/common/effekt_primitives.ss"
16
+
17
+ // call/cc based implementation
18
+ // ----------------------------
19
+ extern include chezCallCC "../chez/callcc/seq0.ss"
20
+ extern include chezCallCC "../chez/callcc/tail0.ss"
21
+ extern include chezCallCC "../chez/callcc/effekt.ss"
22
+
23
+ // CPS implementation
24
+ // ------------------
25
+ extern include chezLift "../chez/lift/effekt.ss"
26
+
27
+ // Monadic implementation
28
+ // ----------------------
29
+ extern include chezMonadic "../chez/monadic/seq0.ss"
30
+ extern include chezMonadic "../chez/monadic/effekt.ss"
31
+ }
32
+
33
+ namespace llvm {
34
+ extern include llvm "../llvm/rts.ll"
35
+ extern include llvm "../llvm/forward-declare-c.ll"
36
+ }
37
+
38
+ // Showing and debugging
39
+ // =====================
40
+
41
+ extern def println(value: String): Unit =
42
+ js "$effekt.println(${value})"
43
+ chez "(println_impl ${value})"
44
+ llvm """
45
+ call void @c_io_println_String(%Pos ${value})
46
+ ret %Pos zeroinitializer ; Unit
47
+ """
48
+
49
+ def println(value: Int): Unit = println(value.show)
50
+ def println(value: Unit): Unit = println(value.show)
51
+ def println(value: Double): Unit = println(value.show)
52
+ def println(value: Bool): Unit = println(value.show)
53
+ def println(value: Byte): Unit = println(value.show)
54
+
55
+ extern pure def show(value: Int): String =
56
+ js "'' + ${value}"
57
+ chez "(show-number ${value})"
58
+ llvm """
59
+ %z = call %Pos @c_buffer_show_Int(%Int ${value})
60
+ ret %Pos %z
61
+ """
62
+
63
+ def show(value: Unit): String = "()"
64
+
65
+ extern pure def show(value: Double): String =
66
+ js "'' + ${value}"
67
+ chez "(show-number ${value})"
68
+ llvm """
69
+ %z = call %Pos @c_buffer_show_Double(%Double ${value})
70
+ ret %Pos %z
71
+ """
72
+
73
+ def show(value: String): String =
74
+ value
75
+
76
+ def show(value: Bool): String =
77
+ if (value) "true" else "false"
78
+
79
+ extern pure def show(value: Char): String =
80
+ js "String.fromCodePoint(${value})"
81
+ chez "(string (integer->char ${value}))"
82
+ llvm """
83
+ %z = call %Pos @c_buffer_show_Char(%Int ${value})
84
+ ret %Pos %z
85
+ """
86
+
87
+ extern pure def show(value: Byte): String =
88
+ llvm """
89
+ %z = call %Pos @c_buffer_show_Byte(i8 ${value})
90
+ ret %Pos %z
91
+ """
92
+
93
+ extern pure def genericShow[R](value: R): String =
94
+ js "$effekt.show(${value})"
95
+ chez "(show_impl ${value})"
96
+
97
+ extern io def inspect[R](value: R): Unit =
98
+ js { println(genericShow(value)) }
99
+ chez { println(genericShow(value)) }
100
+
101
+
102
+ // Strings
103
+ // =======
104
+ extern pure def infixConcat(s1: String, s2: String): String =
105
+ js "((${s1}) + (${s2}))"
106
+ chez "(string-append ${s1} ${s2})"
107
+ llvm """
108
+ %spz = call %Pos @c_buffer_concatenate(%Pos ${s1}, %Pos ${s2})
109
+ ret %Pos %spz
110
+ """
111
+
112
+ extern pure def length(str: String): Int =
113
+ js "${str}.length"
114
+ chez "(string-length ${str})"
115
+ llvm """
116
+ %x = call %Int @c_buffer_length(%Pos ${str})
117
+ call void @erasePositive(%Pos ${str})
118
+ ret %Int %x
119
+ """
120
+
121
+ extern pure def unsafeSubstring(str: String, from: Int, to: Int): String =
122
+ js "${str}.substring(${from}, ${to})"
123
+ chez "(substring ${str} ${from} ${to})" // potentially raises: "Exception in substring: ..."
124
+ llvm """
125
+ %x = call %Pos @c_buffer_substring(%Pos ${str}, i64 ${from}, i64 ${to})
126
+ ret %Pos %x
127
+ """
128
+
129
+
130
+ // Side effecting ops
131
+ // ==================
132
+
133
+ extern io def random(): Double =
134
+ js "Math.random()"
135
+ chez "(random 1.0)"
136
+
137
+ // References and state
138
+ // ====================
139
+ // the following type is defined in builtins.scala
140
+ // interface Ref[T] { def get(): T; def put(t: T): Unit }
141
+ // extern io def freshIn[T](t: T) {r: Region}: Ref[T] at {r} = js "r.fresh(${t})"
142
+ // extern io def freshGlobal[T](t: T): Ref[T] at {global} = js "$effekt.fresh(${t})"
143
+
144
+
145
+ // Equality
146
+ // ========
147
+ /**
148
+ * Result of comparison between two objects according to some order:
149
+ *
150
+ * - `Less()` means that the first object is *before* the first in the order,
151
+ * - `Equal()` means that the two objects are the same in the order,
152
+ * - and `Greater()` means that the second object is *before* the first in the order.
153
+ */
154
+ type Ordering {
155
+ Less();
156
+ Equal();
157
+ Greater()
158
+ }
159
+
160
+ extern pure def genericCompareImpl[R](x: R, y: R): Int =
161
+ js "$effekt.compare(${x}, ${y})"
162
+
163
+ // Compares two values of the same type, returning an `Ordering`.
164
+ def genericCompare[R](x: R, y: R): Ordering = {
165
+ genericCompareImpl(x, y) match {
166
+ case -1 => Less()
167
+ case 0 => Equal()
168
+ case 1 => Greater()
169
+ case _ => <{ "Impossible: JS comparison returned invalid value!" }>
170
+ }
171
+ }
172
+
173
+ def show(o: Ordering): String = o match {
174
+ case Less() => "Less()"
175
+ case Equal() => "Equal()"
176
+ case Greater() => "Greater()"
177
+ }
178
+
179
+ def println(o: Ordering): Unit = println(o.show)
180
+
181
+
182
+ // Comparison ops
183
+ // ==============
184
+
185
+ /**
186
+ * Structural equality: Not available in the LLVM backend
187
+ */
188
+ extern pure def equals[R](x: R, y: R): Bool =
189
+ js "$effekt.equals(${x}, ${y})"
190
+ chez "(equal? ${x} ${y})"
191
+
192
+ def differsFrom[R](x: R, y: R): Bool =
193
+ not(equals(x, y))
194
+
195
+ // TODO fix this in the pattern matching compiler
196
+ extern pure def infixEq(x: Unit, y: Unit): Bool =
197
+ js "true"
198
+ chez "#t"
199
+
200
+ extern pure def infixEq(x: Int, y: Int): Bool =
201
+ js "${x} === ${y}"
202
+ chez "(equal? ${x} ${y})"
203
+ llvm """
204
+ %z = icmp eq %Int ${x}, ${y}
205
+ %fat_z = zext i1 %z to i64
206
+ %adt_boolean = insertvalue %Pos zeroinitializer, i64 %fat_z, 0
207
+ ret %Pos %adt_boolean
208
+ """
209
+
210
+ extern pure def infixNeq(x: Int, y: Int): Bool =
211
+ js "${x} !== ${y}"
212
+ chez "(not (equal? ${x} ${y}))"
213
+ llvm """
214
+ %z = icmp ne %Int ${x}, ${y}
215
+ %fat_z = zext i1 %z to i64
216
+ %adt_boolean = insertvalue %Pos zeroinitializer, i64 %fat_z, 0
217
+ ret %Pos %adt_boolean
218
+ """
219
+
220
+ extern pure def infixEq(x: Char, y: Char): Bool =
221
+ js "${x} === ${y}"
222
+ chez "(equal? ${x} ${y})"
223
+ llvm """
224
+ %z = icmp eq %Int ${x}, ${y}
225
+ %fat_z = zext i1 %z to i64
226
+ %adt_boolean = insertvalue %Pos zeroinitializer, i64 %fat_z, 0
227
+ ret %Pos %adt_boolean
228
+ """
229
+
230
+ extern pure def infixNeq(x: Char, y: Char): Bool =
231
+ js "${x} !== ${y}"
232
+ chez "(not (equal? ${x} ${y}))"
233
+ llvm """
234
+ %z = icmp ne %Int ${x}, ${y}
235
+ %fat_z = zext i1 %z to i64
236
+ %adt_boolean = insertvalue %Pos zeroinitializer, i64 %fat_z, 0
237
+ ret %Pos %adt_boolean
238
+ """
239
+
240
+ extern pure def infixEq(x: String, y: String): Bool =
241
+ js "${x} === ${y}"
242
+ chez "(equal? ${x} ${y})"
243
+ llvm """
244
+ %res = call %Pos @c_buffer_eq(%Pos ${x}, %Pos ${y})
245
+ ret %Pos %res
246
+ """
247
+
248
+ def infixNeq(x: String, y: String): Bool = not(x == y)
249
+
250
+ extern pure def infixEq(x: Bool, y: Bool): Bool =
251
+ js "${x} === ${y}"
252
+ chez "(equal? ${x} ${y})"
253
+ llvm """
254
+ %slim_x = extractvalue %Pos ${x}, 0
255
+ %slim_y = extractvalue %Pos ${y}, 0
256
+ %slim_z = icmp eq i64 %slim_x, %slim_y
257
+ %fat_z = zext i1 %slim_z to i64
258
+ %adt_boolean = insertvalue %Pos zeroinitializer, i64 %fat_z, 0
259
+ ret %Pos %adt_boolean
260
+ """
261
+
262
+ extern pure def infixNeq(x: Bool, y: Bool): Bool =
263
+ js "${x} !== ${y}"
264
+ chez "(not (equal? ${x} ${y}))"
265
+ llvm """
266
+ %slim_x = extractvalue %Pos ${x}, 0
267
+ %slim_y = extractvalue %Pos ${y}, 0
268
+ %slim_z = icmp ne i64 %slim_x, %slim_y
269
+ %fat_z = zext i1 %slim_z to i64
270
+ %adt_boolean = insertvalue %Pos zeroinitializer, i64 %fat_z, 0
271
+ ret %Pos %adt_boolean
272
+ """
273
+
274
+
275
+ // Math ops
276
+ // ========
277
+ extern pure def infixAdd(x: Int, y: Int): Int =
278
+ js "(${x} + ${y})"
279
+ chez "(+ ${x} ${y})"
280
+ llvm "%z = add %Int ${x}, ${y} ret %Int %z"
281
+
282
+ extern pure def infixMul(x: Int, y: Int): Int =
283
+ js "(${x} * ${y})"
284
+ chez "(* ${x} ${y})"
285
+ llvm "%z = mul %Int ${x}, ${y} ret %Int %z"
286
+
287
+ extern pure def infixDiv(x: Int, y: Int): Int =
288
+ js "Math.floor(${x} / ${y})"
289
+ chez "(floor (/ ${x} ${y}))"
290
+ llvm "%z = sdiv %Int ${x}, ${y} ret %Int %z"
291
+
292
+ extern pure def infixSub(x: Int, y: Int): Int =
293
+ js "(${x} - ${y})"
294
+ chez "(- ${x} ${y})"
295
+ llvm "%z = sub %Int ${x}, ${y} ret %Int %z"
296
+
297
+ extern pure def mod(x: Int, y: Int): Int =
298
+ js "(${x} % ${y})"
299
+ chez "(modulo ${x} ${y})"
300
+ llvm "%z = srem %Int ${x}, ${y} ret %Int %z"
301
+
302
+ extern pure def infixAdd(x: Double, y: Double): Double =
303
+ js "(${x} + ${y})"
304
+ chez "(+ ${x} ${y})"
305
+ llvm "%z = fadd %Double ${x}, ${y} ret %Double %z"
306
+
307
+ extern pure def infixMul(x: Double, y: Double): Double =
308
+ js "(${x} * ${y})"
309
+ chez "(* ${x} ${y})"
310
+ llvm "%z = fmul %Double ${x}, ${y} ret %Double %z"
311
+
312
+ extern pure def infixSub(x: Double, y: Double): Double =
313
+ js "(${x} - ${y})"
314
+ chez "(- ${x} ${y})"
315
+ llvm "%z = fsub %Double ${x}, ${y} ret %Double %z"
316
+
317
+ extern pure def infixDiv(x: Double, y: Double): Double =
318
+ js "(${x} / ${y})"
319
+ chez "(/ ${x} ${y})"
320
+ llvm "%z = fdiv %Double ${x}, ${y} ret %Double %z"
321
+
322
+ extern pure def cos(x: Double): Double =
323
+ js "Math.cos(${x})"
324
+ chez "(cos ${x})"
325
+
326
+ extern pure def sin(x: Double): Double =
327
+ js "Math.sin(${x})"
328
+ chez "(sin ${x})"
329
+
330
+ extern pure def atan(x: Double): Double =
331
+ js "Math.atan(${x})"
332
+ chez "(atan ${x})"
333
+
334
+ extern pure def tan(x: Double): Double =
335
+ js "Math.tan(${x})"
336
+ chez "(tan ${x})"
337
+
338
+ extern pure def sqrt(x: Double): Double =
339
+ js "Math.sqrt(${x})"
340
+ chez "(sqrt ${x})"
341
+ llvm "%z = call %Double @llvm.sqrt.f64(double ${x}) ret %Double %z"
342
+
343
+ def square(x: Double): Double = x * x
344
+
345
+ def neg(n: Double): Double =
346
+ 0.0 - n
347
+
348
+ def max(n: Double, m: Double): Double =
349
+ if (n > m) n else m
350
+
351
+ def abs(n: Double): Double =
352
+ max(n, neg(n))
353
+
354
+ extern pure def log(x: Double): Double =
355
+ js "Math.log(${x})"
356
+ chez "(log ${x})"
357
+
358
+ extern pure def log1p(x: Double): Double =
359
+ js "Math.log1p(${x})"
360
+ chez "(log (+ ${x} 1))"
361
+
362
+ extern pure def exp(x: Double): Double =
363
+ js "Math.exp(${x})"
364
+ chez "(exp ${x})"
365
+
366
+ def pow(base: Double, exponent: Int): Double = {
367
+ def loop(base: Double, exponent: Int, acc: Double): Double = {
368
+ if (exponent == 0) acc
369
+ else if (exponent.mod(2) == 0) loop(base * base, exponent / 2, acc) // even exponent
370
+ else loop(base, exponent - 1, acc * base) // odd exponent
371
+ }
372
+ loop(base, exponent, 1.0)
373
+ }
374
+
375
+ extern pure def pow(base: Double, exponent: Double): Double =
376
+ js "Math.pow(${base}, ${exponent})"
377
+ chez "(expt ${base} ${exponent})"
378
+
379
+ // since we do not have "extern val", yet
380
+ extern pure def _pi(): Double =
381
+ js "Math.PI"
382
+ chez "(* 4 (atan 1))"
383
+
384
+ val PI: Double = _pi()
385
+
386
+ extern pure def toInt(d: Double): Int =
387
+ js "Math.trunc(${d})"
388
+ chez "(flonum->fixnum ${d})"
389
+ llvm "%z = fptosi double ${d} to %Int ret %Int %z"
390
+
391
+ extern pure def toDouble(d: Int): Double =
392
+ js "${d}"
393
+ chez "${d}"
394
+ llvm "%z = sitofp i64 ${d} to double ret double %z"
395
+
396
+ extern pure def round(d: Double): Int =
397
+ js "Math.round(${d})"
398
+ chez "(round ${d})"
399
+ llvm """
400
+ %i = call %Double @llvm.round.f64(double ${d})
401
+ %z = fptosi double %i to %Int ret %Int %z
402
+ """
403
+
404
+ def round(d: Double, digits: Int): Double = {
405
+ val factor = pow(10.0, digits)
406
+ round(d * factor).toDouble / factor
407
+ }
408
+
409
+ extern pure def floor(d: Double): Int =
410
+ js "Math.floor(${d})"
411
+ chez "(flonum->fixnum (floor ${d}))"
412
+ llvm """
413
+ %i = call %Double @llvm.floor.f64(double ${d})
414
+ %z = fptosi double %i to %Int ret %Int %z
415
+ """
416
+
417
+ extern pure def ceil(d: Double): Int =
418
+ js "Math.ceil(${d})"
419
+ chez "(flonum->fixnum (ceiling ${d}))"
420
+ llvm """
421
+ %i = call %Double @llvm.ceil.f64(double ${d})
422
+ %z = fptosi double %i to %Int ret %Int %z
423
+ """
424
+
425
+ def min(n: Int, m: Int): Int =
426
+ if (n < m) n else m
427
+
428
+ def max(n: Int, m: Int): Int =
429
+ if (n > m) n else m
430
+
431
+ def neg(n: Int): Int =
432
+ 0 - n
433
+
434
+ def abs(n: Int): Int =
435
+ max(n, neg(n))
436
+
437
+
438
+ extern pure def infixLt(x: Int, y: Int): Bool =
439
+ js "(${x} < ${y})"
440
+ chez "(< ${x} ${y})"
441
+ llvm """
442
+ %z = icmp slt %Int ${x}, ${y}
443
+ %fat_z = zext i1 %z to i64
444
+ %adt_boolean = insertvalue %Pos zeroinitializer, i64 %fat_z, 0
445
+ ret %Pos %adt_boolean
446
+ """
447
+
448
+ extern pure def infixLte(x: Int, y: Int): Bool =
449
+ js "(${x} <= ${y})"
450
+ chez "(<= ${x} ${y})"
451
+ llvm """
452
+ %z = icmp sle %Int ${x}, ${y}
453
+ %fat_z = zext i1 %z to i64
454
+ %adt_boolean = insertvalue %Pos zeroinitializer, i64 %fat_z, 0
455
+ ret %Pos %adt_boolean
456
+ """
457
+
458
+ extern pure def infixGt(x: Int, y: Int): Bool =
459
+ js "(${x} > ${y})"
460
+ chez "(> ${x} ${y})"
461
+ llvm """
462
+ %z = icmp sgt %Int ${x}, ${y}
463
+ %fat_z = zext i1 %z to i64
464
+ %adt_boolean = insertvalue %Pos zeroinitializer, i64 %fat_z, 0
465
+ ret %Pos %adt_boolean
466
+ """
467
+
468
+ extern pure def infixGte(x: Int, y: Int): Bool =
469
+ js "(${x} >= ${y})"
470
+ chez "(>= ${x} ${y})"
471
+ llvm """
472
+ %z = icmp sge %Int ${x}, ${y}
473
+ %fat_z = zext i1 %z to i64
474
+ %adt_boolean = insertvalue %Pos zeroinitializer, i64 %fat_z, 0
475
+ ret %Pos %adt_boolean
476
+ """
477
+
478
+ extern pure def infixEq(x: Double, y: Double): Bool =
479
+ js "${x} === ${y}"
480
+ chez "(= ${x} ${y})"
481
+
482
+ extern pure def infixNeq(x: Double, y: Double): Bool =
483
+ js "${x} !== ${y}"
484
+ chez "(not (= ${x} ${y}))"
485
+
486
+ extern pure def infixLt(x: Double, y: Double): Bool =
487
+ js "(${x} < ${y})"
488
+ chez "(< ${x} ${y})"
489
+ llvm """
490
+ %z = fcmp olt %Double ${x}, ${y}
491
+ %fat_z = zext i1 %z to i64
492
+ %adt_boolean = insertvalue %Pos zeroinitializer, i64 %fat_z, 0
493
+ ret %Pos %adt_boolean
494
+ """
495
+
496
+ extern pure def infixLte(x: Double, y: Double): Bool =
497
+ js "(${x} <= ${y})"
498
+ chez "(<= ${x} ${y})"
499
+
500
+ extern pure def infixGt(x: Double, y: Double): Bool =
501
+ js "(${x} > ${y})"
502
+ chez "(> ${x} ${y})"
503
+ llvm """
504
+ %z = fcmp ogt %Double ${x}, ${y}
505
+ %fat_z = zext i1 %z to i64
506
+ %adt_boolean = insertvalue %Pos zeroinitializer, i64 %fat_z, 0
507
+ ret %Pos %adt_boolean
508
+ """
509
+
510
+ extern pure def infixGte(x: Double, y: Double): Bool =
511
+ js "(${x} >= ${y})"
512
+ chez "(>= ${x} ${y})"
513
+
514
+ // TODO do we really need those? if yes, move to string.effekt
515
+ extern pure def infixLt(x: String, y: String): Bool =
516
+ js "(${x} < ${y})"
517
+ chez "(< ${x} ${y})"
518
+
519
+ extern pure def infixLte(x: String, y: String): Bool =
520
+ js "(${x} <= ${y})"
521
+ chez "(<= ${x} ${y})"
522
+
523
+ extern pure def infixGt(x: String, y: String): Bool =
524
+ js "(${x} > ${y})"
525
+ chez "(> ${x} ${y})"
526
+
527
+ extern pure def infixGte(x: String, y: String): Bool =
528
+ js "(${x} >= ${y})"
529
+ chez "(>= ${x} ${y})"
530
+
531
+
532
+ // Boolean operations
533
+ // ==================
534
+ extern pure def not(b: Bool): Bool =
535
+ js "!${b}"
536
+ chez "(not ${b})"
537
+ llvm """
538
+ %p = extractvalue %Pos ${b}, 0
539
+ %q = xor i64 1, %p
540
+ %adt_q = insertvalue %Pos zeroinitializer, i64 %q, 0
541
+ ret %Pos %adt_q
542
+ """
543
+
544
+ def infixOr { first: => Bool } { second: => Bool }: Bool =
545
+ if (first()) true else second()
546
+
547
+ def infixAnd { first: => Bool } { second: => Bool }: Bool =
548
+ if (first()) second() else false
549
+
550
+
551
+ // Bitwise operations
552
+ // ==================
553
+ extern pure def bitwiseShl(x: Int, y: Int): Int =
554
+ js "(${x} << ${y})"
555
+ chez "(ash ${x} ${y})"
556
+ llvm "%z = shl %Int ${x}, ${y} ret %Int %z"
557
+
558
+ extern pure def bitwiseAnd(x: Int, y: Int): Int =
559
+ js "(${x} & ${y})"
560
+ chez "(logand ${x} ${y})"
561
+ llvm "%z = and %Int ${x}, ${y} ret %Int %z"
562
+
563
+ extern pure def bitwiseXor(x: Int, y: Int): Int =
564
+ js "(${x} ^ ${y})"
565
+ chez "(logxor ${x} ${y})"
566
+ llvm "%z = xor %Int ${x}, ${y} ret %Int %z"
567
+
568
+
569
+ // Byte operations
570
+ // ===============
571
+ extern pure def toByte(n: Int): Byte =
572
+ js "${n}"
573
+ llvm "%z = trunc %Int ${n} to %Byte ret %Byte %z"
574
+
575
+ extern pure def toInt(n: Byte): Int =
576
+ js "${n}"
577
+ llvm "%z = zext %Byte ${n} to %Int ret %Int %z"
578
+
579
+
580
+ // Undefined and Null
581
+ // ==================
582
+ // Should only be used for interop with FFI, since values in Effekt
583
+ // should not be undefined.
584
+ //
585
+ // js: undefined || null
586
+ // chez: #f
587
+ // llvm: null?
588
+
589
+ /**
590
+ * The value used by the FFI to represent undefined values
591
+ */
592
+ extern pure def undefined[A](): A =
593
+ js "undefined"
594
+ chez "#f"
595
+
596
+ /**
597
+ * Is an FFI value undefined?
598
+ */
599
+ extern pure def isUndefined[A](value: A): Bool =
600
+ js "(${value} === undefined || ${value} === null)"
601
+ chez "(eq? ${value} #f)"
602
+
603
+
604
+ // Tuples
605
+ // ======
606
+ record Tuple2[A, B](first: A, second: B)
607
+ record Tuple3[A, B, C](first: A, second: B, third: C)
608
+ record Tuple4[A, B, C, D](first: A, second: B, third: C, fourth: D)
609
+ record Tuple5[A, B, C, D, E](first: A, second: B, third: C, fourth: D, fifth: E)
610
+ record Tuple6[A, B, C, D, E, F](first: A, second: B, third: C, fourth: D, fifth: E, sixth: F)
611
+
612
+
613
+ // Control Flow
614
+ // ============
615
+ interface Control {
616
+ def break(): Unit
617
+ def continue(): Unit
618
+ }
619
+
620
+ def loop { f: () => Unit }: Unit = {
621
+ def go(): Unit = { f(); go() }
622
+ go()
623
+ }
624
+
625
+ def loop { f: {Control} => Unit }: Unit = try {
626
+ def go(): Unit = { f {label}; go() }
627
+ go()
628
+ } with label: Control {
629
+ def break() = ()
630
+ def continue() = loop { f }
631
+ }
632
+
633
+ /**
634
+ * Calls provided action repeatedly. `start` is inclusive, `end` is not.
635
+ */
636
+ def each(start: Int, end: Int) { action: (Int) => Unit } = {
637
+ def loop(i: Int): Unit =
638
+ if (i < end) { action(i); loop(i + 1) }
639
+
640
+ loop(start)
641
+ }
642
+
643
+ /**
644
+ * Calls provided action repeatedly with support for breaking. `start` is inclusive, `end` is not.
645
+ */
646
+ def each(start: Int, end: Int) { action: (Int) {Control} => Unit } = {
647
+ var i = start;
648
+ loop { {l} =>
649
+ if (i < end) { val el = i; i = i + 1; action(el){l} }
650
+ else { l.break() }
651
+ }
652
+ }
653
+
654
+ def repeat(n: Int) { action: () => Unit } = each(0, n) { n => action() }
655
+
656
+ def repeat(n: Int) { action: () {Control} => Unit } = each(0, n) { (n) {l} => action() {l} }
657
+
658
+ namespace internal {
659
+ namespace boxing {
660
+ // For boxing polymorphic values
661
+ extern type BoxedUnit
662
+ extern pure def boxUnit(u: Unit): Unit =
663
+ extern pure def unboxUnit(u: Unit): Unit =
664
+
665
+ extern type BoxedInt
666
+ extern pure def boxInt(n: Int): BoxedInt =
667
+ llvm """
668
+ %boxed1 = insertvalue %Pos zeroinitializer, i64 ${n}, 0
669
+ %boxed2 = insertvalue %Pos %boxed1, %Object null, 1
670
+ ret %Pos %boxed2
671
+ """
672
+ extern pure def unboxInt(b: BoxedInt): Int =
673
+ llvm """
674
+ %unboxed = extractvalue %Pos ${b}, 0
675
+ ret %Int %unboxed
676
+ """
677
+
678
+ extern type BoxedByte
679
+ extern pure def boxByte(n: Byte): BoxedByte =
680
+ llvm """
681
+ %extended = sext i8 ${n} to i64
682
+ %boxed1 = insertvalue %Pos zeroinitializer, i64 %extended, 0
683
+ %boxed2 = insertvalue %Pos %boxed1, %Object null, 1
684
+ ret %Pos %boxed2
685
+ """
686
+ extern pure def unboxByte(b: BoxedByte): Byte =
687
+ llvm """
688
+ %unboxed = extractvalue %Pos ${b}, 0
689
+ %truncated = trunc i64 %unboxed to i8
690
+ ret i8 %truncated
691
+ """
692
+
693
+ extern type BoxedChar
694
+ extern pure def boxChar(c: Char): BoxedChar =
695
+ llvm """
696
+ %boxed1 = insertvalue %Pos zeroinitializer, i64 ${c}, 0
697
+ %boxed2 = insertvalue %Pos %boxed1, %Object null, 1
698
+ ret %Pos %boxed2
699
+ """
700
+ extern pure def unboxChar(b: BoxedChar): Char =
701
+ llvm """
702
+ %unboxed = extractvalue %Pos ${b}, 0
703
+ ret %Int %unboxed
704
+ """
705
+
706
+ extern type BoxedBool
707
+ extern pure def boxBool(b: Bool): BoxedBool =
708
+ extern pure def unboxBool(b: BoxedBool): Bool =
709
+
710
+ extern type BoxedDouble
711
+ extern pure def boxDouble(d: Double): BoxedDouble =
712
+ llvm """
713
+ %n = bitcast double ${d} to i64
714
+ %boxed1 = insertvalue %Pos zeroinitializer, i64 %n, 0
715
+ %boxed2 = insertvalue %Pos %boxed1, %Object null, 1
716
+ ret %Pos %boxed2
717
+ """
718
+ extern pure def unboxDouble(b: BoxedDouble): Double =
719
+ llvm """
720
+ %unboxed = extractvalue %Pos ${b}, 0
721
+ %d = bitcast i64 %unboxed to double
722
+ ret %Double %d
723
+ """
724
+ }
725
+ }