@effekt-lang/effekt 0.3.0 → 0.5.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 (44) 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 +34 -63
  5. package/libraries/common/bench.effekt +40 -22
  6. package/libraries/common/buffer.effekt +8 -20
  7. package/libraries/common/bytes.effekt +5 -15
  8. package/libraries/common/dequeue.effekt +5 -5
  9. package/libraries/common/effekt.effekt +51 -92
  10. package/libraries/common/exception.effekt +0 -1
  11. package/libraries/common/io/console.effekt +30 -36
  12. package/libraries/common/io/error.effekt +131 -30
  13. package/libraries/common/io/filesystem.effekt +262 -0
  14. package/libraries/common/io/network.effekt +30 -54
  15. package/libraries/common/io/time.effekt +9 -12
  16. package/libraries/common/io.effekt +54 -124
  17. package/libraries/common/list.effekt +345 -327
  18. package/libraries/common/process.effekt +0 -1
  19. package/libraries/common/queue.effekt +1 -3
  20. package/libraries/common/ref.effekt +11 -24
  21. package/libraries/common/result.effekt +6 -14
  22. package/libraries/common/seq.effekt +28 -49
  23. package/libraries/common/string/tty.effekt +66 -0
  24. package/libraries/common/string.effekt +7 -49
  25. package/libraries/common/test.effekt +96 -34
  26. package/libraries/js/unsafe/cont.effekt +1 -1
  27. package/libraries/llvm/io.c +258 -378
  28. package/libraries/llvm/main.c +3 -0
  29. package/libraries/llvm/rts.ll +57 -38
  30. package/libraries/llvm/types.c +10 -1
  31. package/licenses/eclipse public license, version 2.0 - epl-2.0.html +4 -4
  32. package/licenses/mit license - mit-license.html +21 -20
  33. package/licenses/the bsd license - bsd-license.html +20 -21
  34. package/licenses/the mit license - mit.html +22 -21
  35. package/package.json +1 -1
  36. package/libraries/chez/lift/effekt.ss +0 -118
  37. package/libraries/common/io/files.effekt +0 -282
  38. package/libraries/js/io.js +0 -143
  39. package/libraries/llvm/io.ll +0 -19
  40. package/libraries/ml/effekt.sml +0 -65
  41. package/libraries/ml/internal/mllist.effekt +0 -9
  42. package/libraries/ml/internal/mloption.effekt +0 -18
  43. package/libraries/ml/random.effekt +0 -85
  44. package/libraries/ml/text/regex.effekt +0 -102
@@ -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
  // ====================
@@ -159,13 +144,12 @@ extern io def random(): Double =
159
144
 
160
145
  // Equality
161
146
  // ========
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
- */
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.
169
153
  type Ordering {
170
154
  Less();
171
155
  Equal();
@@ -175,7 +159,8 @@ type Ordering {
175
159
  extern pure def genericCompareImpl[R](x: R, y: R): Int =
176
160
  js "$effekt.compare(${x}, ${y})"
177
161
 
178
- // Compares two values of the same type, returning an `Ordering`.
162
+ /// Compares two values of the same type, returning an `Ordering`.
163
+ /// Only available on the JavaScript backend.
179
164
  def genericCompare[R](x: R, y: R): Ordering = {
180
165
  genericCompareImpl(x, y) match {
181
166
  case -1 => Less()
@@ -197,13 +182,10 @@ def println(o: Ordering): Unit = println(o.show)
197
182
  // Comparison ops
198
183
  // ==============
199
184
 
200
- /**
201
- * Structural equality: Not available in the LLVM backend
202
- */
185
+ /// Structural equality: Not available in the LLVM backend
203
186
  extern pure def equals[R](x: R, y: R): Bool =
204
187
  js "$effekt.equals(${x}, ${y})"
205
188
  chez "(equal? ${x} ${y})"
206
- ml "${x} = ${y}"
207
189
 
208
190
  def differsFrom[R](x: R, y: R): Bool =
209
191
  not(equals(x, y))
@@ -212,12 +194,10 @@ def differsFrom[R](x: R, y: R): Bool =
212
194
  extern pure def infixEq(x: Unit, y: Unit): Bool =
213
195
  js "true"
214
196
  chez "#t"
215
- ml "true"
216
197
 
217
198
  extern pure def infixEq(x: Int, y: Int): Bool =
218
199
  js "${x} === ${y}"
219
200
  chez "(equal? ${x} ${y})"
220
- ml "${x} = ${y}"
221
201
  llvm """
222
202
  %z = icmp eq %Int ${x}, ${y}
223
203
  %fat_z = zext i1 %z to i64
@@ -228,7 +208,6 @@ extern pure def infixEq(x: Int, y: Int): Bool =
228
208
  extern pure def infixNeq(x: Int, y: Int): Bool =
229
209
  js "${x} !== ${y}"
230
210
  chez "(not (equal? ${x} ${y}))"
231
- ml "${x} <> ${y}"
232
211
  llvm """
233
212
  %z = icmp ne %Int ${x}, ${y}
234
213
  %fat_z = zext i1 %z to i64
@@ -239,7 +218,6 @@ extern pure def infixNeq(x: Int, y: Int): Bool =
239
218
  extern pure def infixEq(x: Char, y: Char): Bool =
240
219
  js "${x} === ${y}"
241
220
  chez "(equal? ${x} ${y})"
242
- ml "${x} = ${y}"
243
221
  llvm """
244
222
  %z = icmp eq %Int ${x}, ${y}
245
223
  %fat_z = zext i1 %z to i64
@@ -250,7 +228,6 @@ extern pure def infixEq(x: Char, y: Char): Bool =
250
228
  extern pure def infixNeq(x: Char, y: Char): Bool =
251
229
  js "${x} !== ${y}"
252
230
  chez "(not (equal? ${x} ${y}))"
253
- ml "${x} <> ${y}"
254
231
  llvm """
255
232
  %z = icmp ne %Int ${x}, ${y}
256
233
  %fat_z = zext i1 %z to i64
@@ -261,7 +238,6 @@ extern pure def infixNeq(x: Char, y: Char): Bool =
261
238
  extern pure def infixEq(x: String, y: String): Bool =
262
239
  js "${x} === ${y}"
263
240
  chez "(equal? ${x} ${y})"
264
- ml "${x} = ${y}"
265
241
  llvm """
266
242
  %res = call %Pos @c_buffer_eq(%Pos ${x}, %Pos ${y})
267
243
  ret %Pos %res
@@ -272,7 +248,6 @@ def infixNeq(x: String, y: String): Bool = not(x == y)
272
248
  extern pure def infixEq(x: Bool, y: Bool): Bool =
273
249
  js "${x} === ${y}"
274
250
  chez "(equal? ${x} ${y})"
275
- ml "${x} = ${y}"
276
251
  llvm """
277
252
  %slim_x = extractvalue %Pos ${x}, 0
278
253
  %slim_y = extractvalue %Pos ${y}, 0
@@ -285,7 +260,6 @@ extern pure def infixEq(x: Bool, y: Bool): Bool =
285
260
  extern pure def infixNeq(x: Bool, y: Bool): Bool =
286
261
  js "${x} !== ${y}"
287
262
  chez "(not (equal? ${x} ${y}))"
288
- ml "${x} <> ${y}"
289
263
  llvm """
290
264
  %slim_x = extractvalue %Pos ${x}, 0
291
265
  %slim_y = extractvalue %Pos ${y}, 0
@@ -301,87 +275,69 @@ extern pure def infixNeq(x: Bool, y: Bool): Bool =
301
275
  extern pure def infixAdd(x: Int, y: Int): Int =
302
276
  js "(${x} + ${y})"
303
277
  chez "(+ ${x} ${y})"
304
- ml "(${x}: int) + ${y}"
305
278
  llvm "%z = add %Int ${x}, ${y} ret %Int %z"
306
279
 
307
280
  extern pure def infixMul(x: Int, y: Int): Int =
308
281
  js "(${x} * ${y})"
309
282
  chez "(* ${x} ${y})"
310
- ml "(${x}: int) * ${y}"
311
283
  llvm "%z = mul %Int ${x}, ${y} ret %Int %z"
312
284
 
313
285
  extern pure def infixDiv(x: Int, y: Int): Int =
314
286
  js "Math.floor(${x} / ${y})"
315
287
  chez "(floor (/ ${x} ${y}))"
316
- ml "(${x}: int) div ${y}"
317
288
  llvm "%z = sdiv %Int ${x}, ${y} ret %Int %z"
318
289
 
319
290
  extern pure def infixSub(x: Int, y: Int): Int =
320
291
  js "(${x} - ${y})"
321
292
  chez "(- ${x} ${y})"
322
- ml "(${x}: int) - ${y}"
323
293
  llvm "%z = sub %Int ${x}, ${y} ret %Int %z"
324
294
 
325
295
  extern pure def mod(x: Int, y: Int): Int =
326
296
  js "(${x} % ${y})"
327
297
  chez "(modulo ${x} ${y})"
328
- ml "(${x}: int) mod ${y}"
329
298
  llvm "%z = srem %Int ${x}, ${y} ret %Int %z"
330
299
 
331
300
  extern pure def infixAdd(x: Double, y: Double): Double =
332
301
  js "(${x} + ${y})"
333
302
  chez "(+ ${x} ${y})"
334
- ml "(${x}: real) + ${y}"
335
303
  llvm "%z = fadd %Double ${x}, ${y} ret %Double %z"
336
304
 
337
305
  extern pure def infixMul(x: Double, y: Double): Double =
338
306
  js "(${x} * ${y})"
339
307
  chez "(* ${x} ${y})"
340
- ml "(${x}: real) * ${y}"
341
308
  llvm "%z = fmul %Double ${x}, ${y} ret %Double %z"
342
309
 
343
310
  extern pure def infixSub(x: Double, y: Double): Double =
344
311
  js "(${x} - ${y})"
345
312
  chez "(- ${x} ${y})"
346
- ml "(${x}: real) - ${y}"
347
313
  llvm "%z = fsub %Double ${x}, ${y} ret %Double %z"
348
314
 
349
315
  extern pure def infixDiv(x: Double, y: Double): Double =
350
316
  js "(${x} / ${y})"
351
317
  chez "(/ ${x} ${y})"
352
- ml "(${x}: real) / ${y}"
353
318
  llvm "%z = fdiv %Double ${x}, ${y} ret %Double %z"
354
319
 
355
320
  extern pure def cos(x: Double): Double =
356
321
  js "Math.cos(${x})"
357
322
  chez "(cos ${x})"
358
- ml "Math.cos ${x}"
359
323
 
360
324
  extern pure def sin(x: Double): Double =
361
325
  js "Math.sin(${x})"
362
326
  chez "(sin ${x})"
363
- ml "Math.sin ${x}"
364
327
 
365
328
  extern pure def atan(x: Double): Double =
366
329
  js "Math.atan(${x})"
367
330
  chez "(atan ${x})"
368
- ml "Math.atan ${x}"
369
331
 
370
332
  extern pure def tan(x: Double): Double =
371
333
  js "Math.tan(${x})"
372
334
  chez "(tan ${x})"
373
- ml "Math.tan ${x}"
374
335
 
375
336
  extern pure def sqrt(x: Double): Double =
376
337
  js "Math.sqrt(${x})"
377
338
  chez "(sqrt ${x})"
378
- ml "Math.sqrt ${x}"
379
339
  llvm "%z = call %Double @llvm.sqrt.f64(double ${x}) ret %Double %z"
380
340
 
381
- extern llvm """
382
- declare double @llvm.sqrt.f64(double %x)
383
- """
384
-
385
341
  def square(x: Double): Double = x * x
386
342
 
387
343
  def neg(n: Double): Double =
@@ -396,52 +352,73 @@ def abs(n: Double): Double =
396
352
  extern pure def log(x: Double): Double =
397
353
  js "Math.log(${x})"
398
354
  chez "(log ${x})"
399
- ml "Math.ln ${x}"
400
355
 
401
356
  extern pure def log1p(x: Double): Double =
402
357
  js "Math.log1p(${x})"
403
358
  chez "(log (+ ${x} 1))"
404
- ml "Math.ln (${x} + 1.0)"
405
359
 
406
360
  extern pure def exp(x: Double): Double =
407
361
  js "Math.exp(${x})"
408
362
  chez "(exp ${x})"
409
- ml "Math.exp ${x}"
363
+
364
+ def pow(base: Double, exponent: Int): Double = {
365
+ def loop(base: Double, exponent: Int, acc: Double): Double = {
366
+ if (exponent == 0) acc
367
+ else if (exponent.mod(2) == 0) loop(base * base, exponent / 2, acc) // even exponent
368
+ else loop(base, exponent - 1, acc * base) // odd exponent
369
+ }
370
+ loop(base, exponent, 1.0)
371
+ }
372
+
373
+ extern pure def pow(base: Double, exponent: Double): Double =
374
+ js "Math.pow(${base}, ${exponent})"
375
+ chez "(expt ${base} ${exponent})"
410
376
 
411
377
  // since we do not have "extern val", yet
412
378
  extern pure def _pi(): Double =
413
379
  js "Math.PI"
414
380
  chez "(* 4 (atan 1))"
415
- ml "Math.pi"
416
381
 
417
382
  val PI: Double = _pi()
418
383
 
419
384
  extern pure def toInt(d: Double): Int =
420
385
  js "Math.trunc(${d})"
421
386
  chez "(flonum->fixnum ${d})"
422
- ml "Real.trunc ${d}"
423
387
  llvm "%z = fptosi double ${d} to %Int ret %Int %z"
424
388
 
425
389
  extern pure def toDouble(d: Int): Double =
426
390
  js "${d}"
427
391
  chez "${d}"
428
- ml "Real.fromInt ${d}"
429
392
  llvm "%z = sitofp i64 ${d} to double ret double %z"
430
393
 
431
394
  extern pure def round(d: Double): Int =
432
395
  js "Math.round(${d})"
433
396
  chez "(round ${d})"
434
- ml "Real.round ${d}"
397
+ llvm """
398
+ %i = call %Double @llvm.round.f64(double ${d})
399
+ %z = fptosi double %i to %Int ret %Int %z
400
+ """
401
+
402
+ def round(d: Double, digits: Int): Double = {
403
+ val factor = pow(10.0, digits)
404
+ round(d * factor).toDouble / factor
405
+ }
435
406
 
436
407
  extern pure def floor(d: Double): Int =
437
408
  js "Math.floor(${d})"
438
409
  chez "(flonum->fixnum (floor ${d}))"
439
- ml "Real.floor ${d}"
410
+ llvm """
411
+ %i = call %Double @llvm.floor.f64(double ${d})
412
+ %z = fptosi double %i to %Int ret %Int %z
413
+ """
440
414
 
441
415
  extern pure def ceil(d: Double): Int =
442
416
  js "Math.ceil(${d})"
443
417
  chez "(flonum->fixnum (ceiling ${d}))"
444
- ml "Real.ceil ${d}"
418
+ llvm """
419
+ %i = call %Double @llvm.ceil.f64(double ${d})
420
+ %z = fptosi double %i to %Int ret %Int %z
421
+ """
445
422
 
446
423
  def min(n: Int, m: Int): Int =
447
424
  if (n < m) n else m
@@ -459,7 +436,6 @@ def abs(n: Int): Int =
459
436
  extern pure def infixLt(x: Int, y: Int): Bool =
460
437
  js "(${x} < ${y})"
461
438
  chez "(< ${x} ${y})"
462
- ml "(${x}: int) < ${y}"
463
439
  llvm """
464
440
  %z = icmp slt %Int ${x}, ${y}
465
441
  %fat_z = zext i1 %z to i64
@@ -470,7 +446,6 @@ extern pure def infixLt(x: Int, y: Int): Bool =
470
446
  extern pure def infixLte(x: Int, y: Int): Bool =
471
447
  js "(${x} <= ${y})"
472
448
  chez "(<= ${x} ${y})"
473
- ml "(${x}: int) <= ${y}"
474
449
  llvm """
475
450
  %z = icmp sle %Int ${x}, ${y}
476
451
  %fat_z = zext i1 %z to i64
@@ -481,7 +456,6 @@ extern pure def infixLte(x: Int, y: Int): Bool =
481
456
  extern pure def infixGt(x: Int, y: Int): Bool =
482
457
  js "(${x} > ${y})"
483
458
  chez "(> ${x} ${y})"
484
- ml "(${x}: int) > ${y}"
485
459
  llvm """
486
460
  %z = icmp sgt %Int ${x}, ${y}
487
461
  %fat_z = zext i1 %z to i64
@@ -492,7 +466,6 @@ extern pure def infixGt(x: Int, y: Int): Bool =
492
466
  extern pure def infixGte(x: Int, y: Int): Bool =
493
467
  js "(${x} >= ${y})"
494
468
  chez "(>= ${x} ${y})"
495
- ml "(${x}: int) >= ${y}"
496
469
  llvm """
497
470
  %z = icmp sge %Int ${x}, ${y}
498
471
  %fat_z = zext i1 %z to i64
@@ -503,17 +476,14 @@ extern pure def infixGte(x: Int, y: Int): Bool =
503
476
  extern pure def infixEq(x: Double, y: Double): Bool =
504
477
  js "${x} === ${y}"
505
478
  chez "(= ${x} ${y})"
506
- ml "(${x}: real) = ${y}"
507
479
 
508
480
  extern pure def infixNeq(x: Double, y: Double): Bool =
509
481
  js "${x} !== ${y}"
510
482
  chez "(not (= ${x} ${y}))"
511
- ml "(${x}: real) <> ${y}"
512
483
 
513
484
  extern pure def infixLt(x: Double, y: Double): Bool =
514
485
  js "(${x} < ${y})"
515
486
  chez "(< ${x} ${y})"
516
- ml "(${x}: real) < ${y}"
517
487
  llvm """
518
488
  %z = fcmp olt %Double ${x}, ${y}
519
489
  %fat_z = zext i1 %z to i64
@@ -524,12 +494,10 @@ extern pure def infixLt(x: Double, y: Double): Bool =
524
494
  extern pure def infixLte(x: Double, y: Double): Bool =
525
495
  js "(${x} <= ${y})"
526
496
  chez "(<= ${x} ${y})"
527
- ml "(${x}: real) <= ${y}"
528
497
 
529
498
  extern pure def infixGt(x: Double, y: Double): Bool =
530
499
  js "(${x} > ${y})"
531
500
  chez "(> ${x} ${y})"
532
- ml "(${x}: real) > ${y}"
533
501
  llvm """
534
502
  %z = fcmp ogt %Double ${x}, ${y}
535
503
  %fat_z = zext i1 %z to i64
@@ -540,28 +508,23 @@ extern pure def infixGt(x: Double, y: Double): Bool =
540
508
  extern pure def infixGte(x: Double, y: Double): Bool =
541
509
  js "(${x} >= ${y})"
542
510
  chez "(>= ${x} ${y})"
543
- ml "(${x}: real) >= ${y}"
544
511
 
545
512
  // TODO do we really need those? if yes, move to string.effekt
546
513
  extern pure def infixLt(x: String, y: String): Bool =
547
514
  js "(${x} < ${y})"
548
515
  chez "(< ${x} ${y})"
549
- ml "(${x}: string) < ${y}"
550
516
 
551
517
  extern pure def infixLte(x: String, y: String): Bool =
552
518
  js "(${x} <= ${y})"
553
519
  chez "(<= ${x} ${y})"
554
- ml "(${x}: string) <= ${y}"
555
520
 
556
521
  extern pure def infixGt(x: String, y: String): Bool =
557
522
  js "(${x} > ${y})"
558
523
  chez "(> ${x} ${y})"
559
- ml "(${x}: string) > ${y}"
560
524
 
561
525
  extern pure def infixGte(x: String, y: String): Bool =
562
526
  js "(${x} >= ${y})"
563
527
  chez "(>= ${x} ${y})"
564
- ml "(${x}: string) >= ${y}"
565
528
 
566
529
 
567
530
  // Boolean operations
@@ -569,7 +532,6 @@ extern pure def infixGte(x: String, y: String): Bool =
569
532
  extern pure def not(b: Bool): Bool =
570
533
  js "!${b}"
571
534
  chez "(not ${b})"
572
- ml "not ${b}"
573
535
  llvm """
574
536
  %p = extractvalue %Pos ${b}, 0
575
537
  %q = xor i64 1, %p
@@ -586,11 +548,19 @@ def infixAnd { first: => Bool } { second: => Bool }: Bool =
586
548
 
587
549
  // Bitwise operations
588
550
  // ==================
551
+
552
+ /// Arithmetic left shift
589
553
  extern pure def bitwiseShl(x: Int, y: Int): Int =
590
554
  js "(${x} << ${y})"
591
555
  chez "(ash ${x} ${y})"
592
556
  llvm "%z = shl %Int ${x}, ${y} ret %Int %z"
593
557
 
558
+ /// Arithmetic right shift
559
+ extern pure def bitwiseShr(x: Int, y: Int): Int =
560
+ js "(${x} >> ${y})"
561
+ chez "(ash ${x} (- ${y}))"
562
+ llvm "%z = ashr %Int ${x}, ${y} ret %Int %z"
563
+
594
564
  extern pure def bitwiseAnd(x: Int, y: Int): Int =
595
565
  js "(${x} & ${y})"
596
566
  chez "(logand ${x} ${y})"
@@ -620,24 +590,17 @@ extern pure def toInt(n: Byte): Int =
620
590
  //
621
591
  // js: undefined || null
622
592
  // chez: #f
623
- // ml: NONE (of option 'a)
624
593
  // llvm: null?
625
594
 
626
- /**
627
- * The value used by the FFI to represent undefined values
628
- */
595
+ /// The value used by the FFI to represent undefined values
629
596
  extern pure def undefined[A](): A =
630
597
  js "undefined"
631
598
  chez "#f"
632
- ml "NONE"
633
599
 
634
- /**
635
- * Is an FFI value undefined?
636
- */
600
+ /// Is an FFI value undefined?
637
601
  extern pure def isUndefined[A](value: A): Bool =
638
602
  js "(${value} === undefined || ${value} === null)"
639
603
  chez "(eq? ${value} #f)"
640
- ml "Option.isSome ${value}"
641
604
 
642
605
 
643
606
  // Tuples
@@ -669,9 +632,7 @@ def loop { f: {Control} => Unit }: Unit = try {
669
632
  def continue() = loop { f }
670
633
  }
671
634
 
672
- /**
673
- * Calls provided action repeatedly. `start` is inclusive, `end` is not.
674
- */
635
+ /// Calls provided action repeatedly. `start` is inclusive, `end` is not.
675
636
  def each(start: Int, end: Int) { action: (Int) => Unit } = {
676
637
  def loop(i: Int): Unit =
677
638
  if (i < end) { action(i); loop(i + 1) }
@@ -679,9 +640,7 @@ def each(start: Int, end: Int) { action: (Int) => Unit } = {
679
640
  loop(start)
680
641
  }
681
642
 
682
- /**
683
- * Calls provided action repeatedly with support for breaking. `start` is inclusive, `end` is not.
684
- */
643
+ /// Calls provided action repeatedly with support for breaking. `start` is inclusive, `end` is not.
685
644
  def each(start: Int, end: Int) { action: (Int) {Control} => Unit } = {
686
645
  var i = start;
687
646
  loop { {l} =>
@@ -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)
@@ -1,53 +1,47 @@
1
1
  module io/console
2
2
 
3
3
  import io
4
- import io/time // just for testing
5
-
6
- extern js """
7
- const readline = require('node:readline');
8
- """
9
4
 
10
5
  interface Console {
11
6
  def readLine(): String
12
7
  def writeLine(content: String): Unit
13
8
  }
14
9
 
10
+ /// Handler for the console effect, using the Console available in js
11
+ def console[R] { program: () => R / Console }: R = {
12
+ val c = js::newConsole()
13
+ try {
14
+ val r = program()
15
+ js::close(c)
16
+ return r
17
+ } with Console {
18
+ def readLine() = resume(js::readLine(c))
19
+ def writeLine(message) = resume(js::writeLine(c, message))
20
+ }
21
+ }
22
+
15
23
  namespace js {
24
+
25
+ extern jsNode """
26
+ const readline = require('node:readline');
27
+ """
28
+
16
29
  extern type JSConsole
17
- extern {io} def newConsole(): JSConsole =
18
- js """readline.createInterface({
30
+
31
+ extern io def newConsole(): JSConsole =
32
+ jsNode """readline.createInterface({
19
33
  input: process.stdin,
20
34
  output: process.stdout,
21
35
  })"""
22
- extern {io} def close(console: JSConsole): Unit =
23
- js "${console}.close()"
24
36
 
25
- extern {io} def readline(console: JSConsole, k: String => Unit at {io, global}): Unit =
26
- js "${console}.question('', input => (${k})(input).run())"
27
- }
37
+ extern io def close(console: JSConsole): Unit =
38
+ jsNode "${console}.close()"
28
39
 
29
- /**
30
- * Handler for the console effect, using the Console available in js
31
- */
32
- def console[R] { prog: => R / Console }: R / AsyncIO = {
33
- val c = js::newConsole()
34
- try { val res = prog(); js::close(c); res } with Console {
35
- def readLine() = {
36
- resume(do performIO[String](box { write =>
37
- js::readline(c, write)
38
- }))
39
- }
40
- def writeLine(content) = resume(println(content))
41
- }
42
- }
40
+ extern async def readLine(console: JSConsole): String =
41
+ jsNode "$effekt.callcc(callback => ${console}.once('line', callback))"
43
42
 
44
- // TODO we could also use stdin and out to implement the Console effect:
45
- namespace alternative {
46
- extern {io} def writeStdoutCallback(message: String, k: () => Unit at {io, global}): Unit =
47
- js "process.stdout.write(${message}, 'utf-8', () => (${k})().run())"
48
-
49
- def write(message: String): Unit / IO =
50
- do performIO[Unit](box { write => writeStdoutCallback(message, box { write(()) })})
43
+ extern io def writeLine(console: JSConsole, message: String): Unit =
44
+ jsNode "${console}.output.write(${message} + '\\n')"
51
45
  }
52
46
 
53
47
  namespace examples {
@@ -58,9 +52,9 @@ namespace examples {
58
52
  do writeLine("Hi " ++ name ++ ", nice to meet you!")
59
53
  }
60
54
 
61
- def main() = eventloop(box {
55
+ def main() = {
62
56
  with console;
63
57
  greeter()
64
- })
58
+ }
65
59
 
66
- }
60
+ }