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