@effekt-lang/effekt 0.3.0 → 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 (38) hide show
  1. package/README.md +6 -18
  2. package/bin/effekt +0 -0
  3. package/libraries/common/args.effekt +0 -27
  4. package/libraries/common/array.effekt +11 -16
  5. package/libraries/common/bench.effekt +32 -6
  6. package/libraries/common/effekt.effekt +30 -69
  7. package/libraries/common/exception.effekt +0 -1
  8. package/libraries/common/io/console.effekt +32 -36
  9. package/libraries/common/io/error.effekt +111 -2
  10. package/libraries/common/io/filesystem.effekt +274 -0
  11. package/libraries/common/io/network.effekt +30 -54
  12. package/libraries/common/io/time.effekt +9 -12
  13. package/libraries/common/io.effekt +54 -124
  14. package/libraries/common/list.effekt +18 -0
  15. package/libraries/common/process.effekt +0 -1
  16. package/libraries/common/ref.effekt +4 -7
  17. package/libraries/common/string/tty.effekt +66 -0
  18. package/libraries/common/string.effekt +0 -34
  19. package/libraries/common/test.effekt +96 -34
  20. package/libraries/js/unsafe/cont.effekt +1 -1
  21. package/libraries/llvm/io.c +258 -378
  22. package/libraries/llvm/main.c +3 -0
  23. package/libraries/llvm/rts.ll +57 -38
  24. package/libraries/llvm/types.c +10 -1
  25. package/licenses/eclipse public license, version 2.0 - epl-2.0.html +4 -4
  26. package/licenses/mit license - mit-license.html +19 -19
  27. package/licenses/the bsd license - bsd-license.html +19 -19
  28. package/licenses/the mit license - mit.html +20 -20
  29. package/package.json +1 -1
  30. package/libraries/chez/lift/effekt.ss +0 -118
  31. package/libraries/common/io/files.effekt +0 -282
  32. package/libraries/js/io.js +0 -143
  33. package/libraries/llvm/io.ll +0 -19
  34. package/libraries/ml/effekt.sml +0 -65
  35. package/libraries/ml/internal/mllist.effekt +0 -9
  36. package/libraries/ml/internal/mloption.effekt +0 -18
  37. package/libraries/ml/random.effekt +0 -85
  38. package/libraries/ml/text/regex.effekt +0 -102
package/README.md CHANGED
@@ -11,26 +11,14 @@ aims to be significantly more lightweight in its concepts.
11
11
  Also, Effekt comes with no warranty and there are (probably) many bugs -- If this does not discourage you, feel free to
12
12
  play with it and give us your feedback :)
13
13
 
14
- ## Installation
15
-
16
- You need to have Java (>= 11) and Node (>= 12) and npm installed.
17
-
18
- The recommended way of installing Effekt is by running:
14
+ ## Examples
19
15
 
20
- ```
21
- npm install -g https://github.com/effekt-lang/effekt/releases/latest/download/effekt.tgz
22
- ```
16
+ If you are looking for examples of the Effekt language, we invite you to look at the [casestudies](https://github.com/effekt-lang/effekt/tree/master/examples/casestudies) and the [language tour](https://effekt-lang.org/tour).
23
17
 
24
- Alternatively, you can download the `effekt.tgz` file from [another release](https://github.com/effekt-lang/effekt/releases) and then run
25
-
26
- ```
27
- npm install -g effekt.tgz
28
- ```
18
+ ## Installation
29
19
 
30
- This will make the `effekt` command globally available. You can start the Effekt REPL by entering:
20
+ Please navigate to the [getting-started guide](https://effekt-lang.org/docs/getting-started#installing-effekt) on our [website](https://effekt-lang.org) for detailed instructions of how to install Effekt.
31
21
 
32
- ```
33
- > effekt
34
- ```
22
+ ## Contributing
35
23
 
36
- You can find more information about the Effekt language and how to use it on the website (<https://effekt-lang.org>).
24
+ Thanks for considering to contribute to the Effekt compiler! For setting up your local environment, please check out our [contributing guide](https://effekt-lang.org/contributing.html) on the [website](https://effekt-lang.org).
package/bin/effekt CHANGED
Binary file
@@ -3,7 +3,6 @@ module args
3
3
  extern io def commandLineArgs(): List[String] =
4
4
  js { js::commandLineArgs() }
5
5
  chez { chez::commandLineArgs() }
6
- ml { ml::commandLineArgs() }
7
6
  llvm { llvm::commandLineArgs() }
8
7
 
9
8
  namespace js {
@@ -46,32 +45,6 @@ namespace chez {
46
45
  def commandLineArgs(): List[String] = nativeArgs().toList
47
46
  }
48
47
 
49
- namespace ml {
50
-
51
- // MLList[String]
52
- // we inline these from mllist to not have a dependency
53
- extern type Args
54
-
55
- extern io def nativeArgs(): Args =
56
- ml "CommandLine.arguments ()"
57
-
58
- extern pure def isEmpty(args: Args): Bool =
59
- ml "null ${args}"
60
-
61
- extern io def first(a: Args): String =
62
- ml "hd ${a}"
63
-
64
- extern io def rest(a: Args): Args =
65
- ml "tl ${a}"
66
-
67
-
68
- def commandLineArgs(): List[String] = {
69
- def toList(args: Args): List[String] =
70
- if (args.isEmpty) Nil() else Cons(args.first, args.rest.toList)
71
- nativeArgs().toList
72
- }
73
- }
74
-
75
48
  namespace llvm {
76
49
  extern io def argCount(): Int =
77
50
  llvm """
@@ -24,15 +24,13 @@ extern global def allocate[T](size: Int): Array[T] =
24
24
  /**
25
25
  * Creates a new Array of size `size` filled with the value `init`
26
26
  */
27
- extern global def array[T](size: Int, init: T): Array[T] =
28
- ml "Array.array (${size}, ${init})"
29
- default {
30
- val arr = allocate[T](size);
31
- each(0, size) { i =>
32
- unsafeSet(arr, i, init)
33
- };
34
- arr
35
- }
27
+ def array[T](size: Int, init: T): Array[T] = {
28
+ val arr = allocate[T](size);
29
+ each(0, size) { i =>
30
+ unsafeSet(arr, i, init)
31
+ };
32
+ arr
33
+ }
36
34
 
37
35
  /**
38
36
  * Converts a List `list` to an Array
@@ -53,7 +51,6 @@ def fromList[T](list: List[T]): Array[T] = {
53
51
  extern pure def size[T](arr: Array[T]): Int =
54
52
  js "${arr}.length"
55
53
  chez "(vector-length ${arr})"
56
- ml "Array.length ${arr}"
57
54
  llvm """
58
55
  %z = call %Int @c_array_size(%Pos ${arr})
59
56
  ret %Int %z
@@ -68,17 +65,16 @@ extern pure def size[T](arr: Array[T]): Int =
68
65
  extern global def unsafeGet[T](arr: Array[T], index: Int): T =
69
66
  js "${arr}[${index}]"
70
67
  chez "(vector-ref ${arr} ${index})"
71
- ml "Array.sub (${arr}, ${index})"
72
68
  llvm """
73
69
  %z = call %Pos @c_array_get(%Pos ${arr}, %Int ${index})
74
70
  ret %Pos %z
75
71
  """
76
72
 
77
73
  extern js """
78
- function array$set(arr, index, value) {
79
- arr[index] = value;
80
- return $effekt.unit
81
- }
74
+ function array$set(arr, index, value) {
75
+ arr[index] = value;
76
+ return $effekt.unit
77
+ }
82
78
  """
83
79
 
84
80
  /**
@@ -90,7 +86,6 @@ function array$set(arr, index, value) {
90
86
  extern global def unsafeSet[T](arr: Array[T], index: Int, value: T): Unit =
91
87
  js "array$set(${arr}, ${index}, ${value})"
92
88
  chez "(begin (vector-set! ${arr} ${index} ${value}) #f)"
93
- ml "Array.update (${arr}, ${index}, ${value})"
94
89
  llvm """
95
90
  %z = call %Pos @c_array_set(%Pos ${arr}, %Int ${index}, %Pos ${value})
96
91
  ret %Pos %z
@@ -1,17 +1,17 @@
1
1
  module bench
2
2
 
3
+ type Nanos = Int
4
+
3
5
  /**
4
6
  * The current time (since UNIX Epoch) in nanoseconds.
5
7
  *
6
8
  * The actual precision varies across the different backends.
7
9
  * - js: Milliseconds
8
10
  * - chez: Microseconds
9
- * - ml: Microseconds
10
11
  */
11
- extern io def timestamp(): Int =
12
+ extern io def timestamp(): Nanos =
12
13
  js "Date.now() * 1000000"
13
14
  chez "(timestamp)"
14
- ml "IntInf.toInt (Time.toNanoseconds (Time.now ()))"
15
15
  llvm """
16
16
  %time_ptr = alloca { i64, i64 }
17
17
  call i32 @clock_gettime(i32 0, ptr %time_ptr)
@@ -27,24 +27,35 @@ extern llvm """
27
27
  declare i32 @clock_gettime(i32, ptr)
28
28
  """
29
29
 
30
+ // This should not be needed when using NodeJS 16.x or newer.
31
+ extern jsNode """
32
+ const { performance } = require('node:perf_hooks');
33
+ """
34
+
30
35
  /**
31
36
  * High-precision timestamp in nanoseconds that should be for measurements.
32
37
  *
33
38
  * This timestamp should only be used for **relative** measurements,
34
39
  * as gives no guarantees on the absolute time (unlike a UNIX timestamp).
35
40
  */
36
- extern io def relativeTimestamp(): Int =
41
+ extern io def relativeTimestamp(): Nanos =
37
42
  js "Math.round(performance.now() * 1000000)"
38
43
  default { timestamp() }
39
44
 
45
+ type Duration = Int
46
+
47
+ namespace Duration {
48
+ def diff(fromNanos: Nanos, toNanos: Nanos): Duration = toNanos - fromNanos
49
+ }
50
+
40
51
  /**
41
52
  * Runs the block and returns the time in nanoseconds
42
53
  */
43
- def timed { block: => Unit }: Int = {
54
+ def timed { block: => Unit }: Duration = {
44
55
  val before = relativeTimestamp()
45
56
  block()
46
57
  val after = relativeTimestamp()
47
- after - before
58
+ Duration::diff(before, after)
48
59
  }
49
60
 
50
61
  def measure(warmup: Int, iterations: Int) { block: => Unit }: Unit = {
@@ -58,3 +69,18 @@ def measure(warmup: Int, iterations: Int) { block: => Unit }: Unit = {
58
69
  run(warmup, false)
59
70
  run(iterations, true)
60
71
  }
72
+
73
+ /**
74
+ * Takes a duration in nanoseconds and formats it in milliseconds with precision of two decimal digits.
75
+ */
76
+ def formatMs(nanos: Nanos): String = {
77
+ val micros = nanos / 1000000
78
+ val sub = (nanos.mod(1000000).toDouble / 10000.0).round
79
+
80
+ if (sub == 100) {
81
+ // overflow because of rounding
82
+ (micros + 1).show ++ ".0ms"
83
+ } else {
84
+ micros.show ++ "." ++ sub.show ++ "ms"
85
+ }
86
+ }
@@ -30,10 +30,6 @@ namespace chez {
30
30
  extern include chezMonadic "../chez/monadic/effekt.ss"
31
31
  }
32
32
 
33
- namespace ml {
34
- extern include ml "../ml/effekt.sml"
35
- }
36
-
37
33
  namespace llvm {
38
34
  extern include llvm "../llvm/rts.ll"
39
35
  extern include llvm "../llvm/forward-declare-c.ll"
@@ -49,10 +45,6 @@ extern def println(value: String): Unit =
49
45
  call void @c_io_println_String(%Pos ${value})
50
46
  ret %Pos zeroinitializer ; Unit
51
47
  """
52
- ml { print(value); print("\n") }
53
-
54
- extern io def print(value: String): Unit =
55
- ml "print ${value}"
56
48
 
57
49
  def println(value: Int): Unit = println(value.show)
58
50
  def println(value: Unit): Unit = println(value.show)
@@ -63,7 +55,6 @@ def println(value: Byte): Unit = println(value.show)
63
55
  extern pure def show(value: Int): String =
64
56
  js "'' + ${value}"
65
57
  chez "(show-number ${value})"
66
- ml "show'int ${value}"
67
58
  llvm """
68
59
  %z = call %Pos @c_buffer_show_Int(%Int ${value})
69
60
  ret %Pos %z
@@ -74,7 +65,6 @@ def show(value: Unit): String = "()"
74
65
  extern pure def show(value: Double): String =
75
66
  js "'' + ${value}"
76
67
  chez "(show-number ${value})"
77
- ml "show'real ${value}"
78
68
  llvm """
79
69
  %z = call %Pos @c_buffer_show_Double(%Double ${value})
80
70
  ret %Pos %z
@@ -89,7 +79,6 @@ def show(value: Bool): String =
89
79
  extern pure def show(value: Char): String =
90
80
  js "String.fromCodePoint(${value})"
91
81
  chez "(string (integer->char ${value}))"
92
- ml "str (chr ${value})"
93
82
  llvm """
94
83
  %z = call %Pos @c_buffer_show_Char(%Int ${value})
95
84
  ret %Pos %z
@@ -115,7 +104,6 @@ extern io def inspect[R](value: R): Unit =
115
104
  extern pure def infixConcat(s1: String, s2: String): String =
116
105
  js "((${s1}) + (${s2}))"
117
106
  chez "(string-append ${s1} ${s2})"
118
- ml "${s1} ^ ${s2}"
119
107
  llvm """
120
108
  %spz = call %Pos @c_buffer_concatenate(%Pos ${s1}, %Pos ${s2})
121
109
  ret %Pos %spz
@@ -124,7 +112,6 @@ extern pure def infixConcat(s1: String, s2: String): String =
124
112
  extern pure def length(str: String): Int =
125
113
  js "${str}.length"
126
114
  chez "(string-length ${str})"
127
- ml "String.size ${str}"
128
115
  llvm """
129
116
  %x = call %Int @c_buffer_length(%Pos ${str})
130
117
  call void @erasePositive(%Pos ${str})
@@ -134,7 +121,6 @@ extern pure def length(str: String): Int =
134
121
  extern pure def unsafeSubstring(str: String, from: Int, to: Int): String =
135
122
  js "${str}.substring(${from}, ${to})"
136
123
  chez "(substring ${str} ${from} ${to})" // potentially raises: "Exception in substring: ..."
137
- ml "String.extract (${str}, ${from}, SOME (${to} - ${from}))"
138
124
  llvm """
139
125
  %x = call %Pos @c_buffer_substring(%Pos ${str}, i64 ${from}, i64 ${to})
140
126
  ret %Pos %x
@@ -147,7 +133,6 @@ extern pure def unsafeSubstring(str: String, from: Int, to: Int): String =
147
133
  extern io def random(): Double =
148
134
  js "Math.random()"
149
135
  chez "(random 1.0)"
150
- ml "mlRandomReal ()"
151
136
 
152
137
  // References and state
153
138
  // ====================
@@ -203,7 +188,6 @@ def println(o: Ordering): Unit = println(o.show)
203
188
  extern pure def equals[R](x: R, y: R): Bool =
204
189
  js "$effekt.equals(${x}, ${y})"
205
190
  chez "(equal? ${x} ${y})"
206
- ml "${x} = ${y}"
207
191
 
208
192
  def differsFrom[R](x: R, y: R): Bool =
209
193
  not(equals(x, y))
@@ -212,12 +196,10 @@ def differsFrom[R](x: R, y: R): Bool =
212
196
  extern pure def infixEq(x: Unit, y: Unit): Bool =
213
197
  js "true"
214
198
  chez "#t"
215
- ml "true"
216
199
 
217
200
  extern pure def infixEq(x: Int, y: Int): Bool =
218
201
  js "${x} === ${y}"
219
202
  chez "(equal? ${x} ${y})"
220
- ml "${x} = ${y}"
221
203
  llvm """
222
204
  %z = icmp eq %Int ${x}, ${y}
223
205
  %fat_z = zext i1 %z to i64
@@ -228,7 +210,6 @@ extern pure def infixEq(x: Int, y: Int): Bool =
228
210
  extern pure def infixNeq(x: Int, y: Int): Bool =
229
211
  js "${x} !== ${y}"
230
212
  chez "(not (equal? ${x} ${y}))"
231
- ml "${x} <> ${y}"
232
213
  llvm """
233
214
  %z = icmp ne %Int ${x}, ${y}
234
215
  %fat_z = zext i1 %z to i64
@@ -239,7 +220,6 @@ extern pure def infixNeq(x: Int, y: Int): Bool =
239
220
  extern pure def infixEq(x: Char, y: Char): Bool =
240
221
  js "${x} === ${y}"
241
222
  chez "(equal? ${x} ${y})"
242
- ml "${x} = ${y}"
243
223
  llvm """
244
224
  %z = icmp eq %Int ${x}, ${y}
245
225
  %fat_z = zext i1 %z to i64
@@ -250,7 +230,6 @@ extern pure def infixEq(x: Char, y: Char): Bool =
250
230
  extern pure def infixNeq(x: Char, y: Char): Bool =
251
231
  js "${x} !== ${y}"
252
232
  chez "(not (equal? ${x} ${y}))"
253
- ml "${x} <> ${y}"
254
233
  llvm """
255
234
  %z = icmp ne %Int ${x}, ${y}
256
235
  %fat_z = zext i1 %z to i64
@@ -261,7 +240,6 @@ extern pure def infixNeq(x: Char, y: Char): Bool =
261
240
  extern pure def infixEq(x: String, y: String): Bool =
262
241
  js "${x} === ${y}"
263
242
  chez "(equal? ${x} ${y})"
264
- ml "${x} = ${y}"
265
243
  llvm """
266
244
  %res = call %Pos @c_buffer_eq(%Pos ${x}, %Pos ${y})
267
245
  ret %Pos %res
@@ -272,7 +250,6 @@ def infixNeq(x: String, y: String): Bool = not(x == y)
272
250
  extern pure def infixEq(x: Bool, y: Bool): Bool =
273
251
  js "${x} === ${y}"
274
252
  chez "(equal? ${x} ${y})"
275
- ml "${x} = ${y}"
276
253
  llvm """
277
254
  %slim_x = extractvalue %Pos ${x}, 0
278
255
  %slim_y = extractvalue %Pos ${y}, 0
@@ -285,7 +262,6 @@ extern pure def infixEq(x: Bool, y: Bool): Bool =
285
262
  extern pure def infixNeq(x: Bool, y: Bool): Bool =
286
263
  js "${x} !== ${y}"
287
264
  chez "(not (equal? ${x} ${y}))"
288
- ml "${x} <> ${y}"
289
265
  llvm """
290
266
  %slim_x = extractvalue %Pos ${x}, 0
291
267
  %slim_y = extractvalue %Pos ${y}, 0
@@ -301,87 +277,69 @@ extern pure def infixNeq(x: Bool, y: Bool): Bool =
301
277
  extern pure def infixAdd(x: Int, y: Int): Int =
302
278
  js "(${x} + ${y})"
303
279
  chez "(+ ${x} ${y})"
304
- ml "(${x}: int) + ${y}"
305
280
  llvm "%z = add %Int ${x}, ${y} ret %Int %z"
306
281
 
307
282
  extern pure def infixMul(x: Int, y: Int): Int =
308
283
  js "(${x} * ${y})"
309
284
  chez "(* ${x} ${y})"
310
- ml "(${x}: int) * ${y}"
311
285
  llvm "%z = mul %Int ${x}, ${y} ret %Int %z"
312
286
 
313
287
  extern pure def infixDiv(x: Int, y: Int): Int =
314
288
  js "Math.floor(${x} / ${y})"
315
289
  chez "(floor (/ ${x} ${y}))"
316
- ml "(${x}: int) div ${y}"
317
290
  llvm "%z = sdiv %Int ${x}, ${y} ret %Int %z"
318
291
 
319
292
  extern pure def infixSub(x: Int, y: Int): Int =
320
293
  js "(${x} - ${y})"
321
294
  chez "(- ${x} ${y})"
322
- ml "(${x}: int) - ${y}"
323
295
  llvm "%z = sub %Int ${x}, ${y} ret %Int %z"
324
296
 
325
297
  extern pure def mod(x: Int, y: Int): Int =
326
298
  js "(${x} % ${y})"
327
299
  chez "(modulo ${x} ${y})"
328
- ml "(${x}: int) mod ${y}"
329
300
  llvm "%z = srem %Int ${x}, ${y} ret %Int %z"
330
301
 
331
302
  extern pure def infixAdd(x: Double, y: Double): Double =
332
303
  js "(${x} + ${y})"
333
304
  chez "(+ ${x} ${y})"
334
- ml "(${x}: real) + ${y}"
335
305
  llvm "%z = fadd %Double ${x}, ${y} ret %Double %z"
336
306
 
337
307
  extern pure def infixMul(x: Double, y: Double): Double =
338
308
  js "(${x} * ${y})"
339
309
  chez "(* ${x} ${y})"
340
- ml "(${x}: real) * ${y}"
341
310
  llvm "%z = fmul %Double ${x}, ${y} ret %Double %z"
342
311
 
343
312
  extern pure def infixSub(x: Double, y: Double): Double =
344
313
  js "(${x} - ${y})"
345
314
  chez "(- ${x} ${y})"
346
- ml "(${x}: real) - ${y}"
347
315
  llvm "%z = fsub %Double ${x}, ${y} ret %Double %z"
348
316
 
349
317
  extern pure def infixDiv(x: Double, y: Double): Double =
350
318
  js "(${x} / ${y})"
351
319
  chez "(/ ${x} ${y})"
352
- ml "(${x}: real) / ${y}"
353
320
  llvm "%z = fdiv %Double ${x}, ${y} ret %Double %z"
354
321
 
355
322
  extern pure def cos(x: Double): Double =
356
323
  js "Math.cos(${x})"
357
324
  chez "(cos ${x})"
358
- ml "Math.cos ${x}"
359
325
 
360
326
  extern pure def sin(x: Double): Double =
361
327
  js "Math.sin(${x})"
362
328
  chez "(sin ${x})"
363
- ml "Math.sin ${x}"
364
329
 
365
330
  extern pure def atan(x: Double): Double =
366
331
  js "Math.atan(${x})"
367
332
  chez "(atan ${x})"
368
- ml "Math.atan ${x}"
369
333
 
370
334
  extern pure def tan(x: Double): Double =
371
335
  js "Math.tan(${x})"
372
336
  chez "(tan ${x})"
373
- ml "Math.tan ${x}"
374
337
 
375
338
  extern pure def sqrt(x: Double): Double =
376
339
  js "Math.sqrt(${x})"
377
340
  chez "(sqrt ${x})"
378
- ml "Math.sqrt ${x}"
379
341
  llvm "%z = call %Double @llvm.sqrt.f64(double ${x}) ret %Double %z"
380
342
 
381
- extern llvm """
382
- declare double @llvm.sqrt.f64(double %x)
383
- """
384
-
385
343
  def square(x: Double): Double = x * x
386
344
 
387
345
  def neg(n: Double): Double =
@@ -396,52 +354,73 @@ def abs(n: Double): Double =
396
354
  extern pure def log(x: Double): Double =
397
355
  js "Math.log(${x})"
398
356
  chez "(log ${x})"
399
- ml "Math.ln ${x}"
400
357
 
401
358
  extern pure def log1p(x: Double): Double =
402
359
  js "Math.log1p(${x})"
403
360
  chez "(log (+ ${x} 1))"
404
- ml "Math.ln (${x} + 1.0)"
405
361
 
406
362
  extern pure def exp(x: Double): Double =
407
363
  js "Math.exp(${x})"
408
364
  chez "(exp ${x})"
409
- ml "Math.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})"
410
378
 
411
379
  // since we do not have "extern val", yet
412
380
  extern pure def _pi(): Double =
413
381
  js "Math.PI"
414
382
  chez "(* 4 (atan 1))"
415
- ml "Math.pi"
416
383
 
417
384
  val PI: Double = _pi()
418
385
 
419
386
  extern pure def toInt(d: Double): Int =
420
387
  js "Math.trunc(${d})"
421
388
  chez "(flonum->fixnum ${d})"
422
- ml "Real.trunc ${d}"
423
389
  llvm "%z = fptosi double ${d} to %Int ret %Int %z"
424
390
 
425
391
  extern pure def toDouble(d: Int): Double =
426
392
  js "${d}"
427
393
  chez "${d}"
428
- ml "Real.fromInt ${d}"
429
394
  llvm "%z = sitofp i64 ${d} to double ret double %z"
430
395
 
431
396
  extern pure def round(d: Double): Int =
432
397
  js "Math.round(${d})"
433
398
  chez "(round ${d})"
434
- ml "Real.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
+ }
435
408
 
436
409
  extern pure def floor(d: Double): Int =
437
410
  js "Math.floor(${d})"
438
411
  chez "(flonum->fixnum (floor ${d}))"
439
- ml "Real.floor ${d}"
412
+ llvm """
413
+ %i = call %Double @llvm.floor.f64(double ${d})
414
+ %z = fptosi double %i to %Int ret %Int %z
415
+ """
440
416
 
441
417
  extern pure def ceil(d: Double): Int =
442
418
  js "Math.ceil(${d})"
443
419
  chez "(flonum->fixnum (ceiling ${d}))"
444
- ml "Real.ceil ${d}"
420
+ llvm """
421
+ %i = call %Double @llvm.ceil.f64(double ${d})
422
+ %z = fptosi double %i to %Int ret %Int %z
423
+ """
445
424
 
446
425
  def min(n: Int, m: Int): Int =
447
426
  if (n < m) n else m
@@ -459,7 +438,6 @@ def abs(n: Int): Int =
459
438
  extern pure def infixLt(x: Int, y: Int): Bool =
460
439
  js "(${x} < ${y})"
461
440
  chez "(< ${x} ${y})"
462
- ml "(${x}: int) < ${y}"
463
441
  llvm """
464
442
  %z = icmp slt %Int ${x}, ${y}
465
443
  %fat_z = zext i1 %z to i64
@@ -470,7 +448,6 @@ extern pure def infixLt(x: Int, y: Int): Bool =
470
448
  extern pure def infixLte(x: Int, y: Int): Bool =
471
449
  js "(${x} <= ${y})"
472
450
  chez "(<= ${x} ${y})"
473
- ml "(${x}: int) <= ${y}"
474
451
  llvm """
475
452
  %z = icmp sle %Int ${x}, ${y}
476
453
  %fat_z = zext i1 %z to i64
@@ -481,7 +458,6 @@ extern pure def infixLte(x: Int, y: Int): Bool =
481
458
  extern pure def infixGt(x: Int, y: Int): Bool =
482
459
  js "(${x} > ${y})"
483
460
  chez "(> ${x} ${y})"
484
- ml "(${x}: int) > ${y}"
485
461
  llvm """
486
462
  %z = icmp sgt %Int ${x}, ${y}
487
463
  %fat_z = zext i1 %z to i64
@@ -492,7 +468,6 @@ extern pure def infixGt(x: Int, y: Int): Bool =
492
468
  extern pure def infixGte(x: Int, y: Int): Bool =
493
469
  js "(${x} >= ${y})"
494
470
  chez "(>= ${x} ${y})"
495
- ml "(${x}: int) >= ${y}"
496
471
  llvm """
497
472
  %z = icmp sge %Int ${x}, ${y}
498
473
  %fat_z = zext i1 %z to i64
@@ -503,17 +478,14 @@ extern pure def infixGte(x: Int, y: Int): Bool =
503
478
  extern pure def infixEq(x: Double, y: Double): Bool =
504
479
  js "${x} === ${y}"
505
480
  chez "(= ${x} ${y})"
506
- ml "(${x}: real) = ${y}"
507
481
 
508
482
  extern pure def infixNeq(x: Double, y: Double): Bool =
509
483
  js "${x} !== ${y}"
510
484
  chez "(not (= ${x} ${y}))"
511
- ml "(${x}: real) <> ${y}"
512
485
 
513
486
  extern pure def infixLt(x: Double, y: Double): Bool =
514
487
  js "(${x} < ${y})"
515
488
  chez "(< ${x} ${y})"
516
- ml "(${x}: real) < ${y}"
517
489
  llvm """
518
490
  %z = fcmp olt %Double ${x}, ${y}
519
491
  %fat_z = zext i1 %z to i64
@@ -524,12 +496,10 @@ extern pure def infixLt(x: Double, y: Double): Bool =
524
496
  extern pure def infixLte(x: Double, y: Double): Bool =
525
497
  js "(${x} <= ${y})"
526
498
  chez "(<= ${x} ${y})"
527
- ml "(${x}: real) <= ${y}"
528
499
 
529
500
  extern pure def infixGt(x: Double, y: Double): Bool =
530
501
  js "(${x} > ${y})"
531
502
  chez "(> ${x} ${y})"
532
- ml "(${x}: real) > ${y}"
533
503
  llvm """
534
504
  %z = fcmp ogt %Double ${x}, ${y}
535
505
  %fat_z = zext i1 %z to i64
@@ -540,28 +510,23 @@ extern pure def infixGt(x: Double, y: Double): Bool =
540
510
  extern pure def infixGte(x: Double, y: Double): Bool =
541
511
  js "(${x} >= ${y})"
542
512
  chez "(>= ${x} ${y})"
543
- ml "(${x}: real) >= ${y}"
544
513
 
545
514
  // TODO do we really need those? if yes, move to string.effekt
546
515
  extern pure def infixLt(x: String, y: String): Bool =
547
516
  js "(${x} < ${y})"
548
517
  chez "(< ${x} ${y})"
549
- ml "(${x}: string) < ${y}"
550
518
 
551
519
  extern pure def infixLte(x: String, y: String): Bool =
552
520
  js "(${x} <= ${y})"
553
521
  chez "(<= ${x} ${y})"
554
- ml "(${x}: string) <= ${y}"
555
522
 
556
523
  extern pure def infixGt(x: String, y: String): Bool =
557
524
  js "(${x} > ${y})"
558
525
  chez "(> ${x} ${y})"
559
- ml "(${x}: string) > ${y}"
560
526
 
561
527
  extern pure def infixGte(x: String, y: String): Bool =
562
528
  js "(${x} >= ${y})"
563
529
  chez "(>= ${x} ${y})"
564
- ml "(${x}: string) >= ${y}"
565
530
 
566
531
 
567
532
  // Boolean operations
@@ -569,7 +534,6 @@ extern pure def infixGte(x: String, y: String): Bool =
569
534
  extern pure def not(b: Bool): Bool =
570
535
  js "!${b}"
571
536
  chez "(not ${b})"
572
- ml "not ${b}"
573
537
  llvm """
574
538
  %p = extractvalue %Pos ${b}, 0
575
539
  %q = xor i64 1, %p
@@ -620,7 +584,6 @@ extern pure def toInt(n: Byte): Int =
620
584
  //
621
585
  // js: undefined || null
622
586
  // chez: #f
623
- // ml: NONE (of option 'a)
624
587
  // llvm: null?
625
588
 
626
589
  /**
@@ -629,7 +592,6 @@ extern pure def toInt(n: Byte): Int =
629
592
  extern pure def undefined[A](): A =
630
593
  js "undefined"
631
594
  chez "#f"
632
- ml "NONE"
633
595
 
634
596
  /**
635
597
  * Is an FFI value undefined?
@@ -637,7 +599,6 @@ extern pure def undefined[A](): A =
637
599
  extern pure def isUndefined[A](value: A): Bool =
638
600
  js "(${value} === undefined || ${value} === null)"
639
601
  chez "(eq? ${value} #f)"
640
- ml "Option.isSome ${value}"
641
602
 
642
603
 
643
604
  // Tuples
@@ -53,7 +53,6 @@ def wrongFormat(msg: String): Nothing / Exception[WrongFormat] =
53
53
  extern io def panic[R](msg: String): R =
54
54
  js "(function() { throw ${msg} })()"
55
55
  chez "(raise ${msg})"
56
- ml "raise Fail ${msg}"
57
56
  llvm """
58
57
  call void @c_io_println_String(%Pos ${msg})
59
58
  call void @exit(i32 1)