@effekt-lang/effekt 0.66.0 → 0.68.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.
@@ -46,7 +46,6 @@ extern def print(value: String): Unit =
46
46
  call void @c_io_print(%Pos ${value})
47
47
  ret %Pos zeroinitializer ; Unit
48
48
  """
49
- vm "effekt::print(String)"
50
49
 
51
50
  extern def println(value: String): Unit =
52
51
  js "$effekt.println(${value})"
@@ -55,7 +54,6 @@ extern def println(value: String): Unit =
55
54
  call void @c_io_println(%Pos ${value})
56
55
  ret %Pos zeroinitializer ; Unit
57
56
  """
58
- vm "effekt::println(String)"
59
57
 
60
58
  extern jsNode """
61
59
  $effekt.readln = function readln$impl(callback) {
@@ -83,6 +81,7 @@ def println(value: Unit): Unit = println(value.show)
83
81
  def println(value: Double): Unit = println(value.show)
84
82
  def println(value: Bool): Unit = println(value.show)
85
83
  def println(value: Byte): Unit = println(value.show)
84
+ def println(value: Char): Unit = println(value.show)
86
85
 
87
86
  extern def showBuiltin(value: Int) at {}: String =
88
87
  js "'' + ${value}"
@@ -91,7 +90,6 @@ extern def showBuiltin(value: Int) at {}: String =
91
90
  %z = call %Pos @c_bytearray_show_Int(%Int ${value})
92
91
  ret %Pos %z
93
92
  """
94
- vm "effekt::show(Int)"
95
93
 
96
94
  extern def showBuiltin(value: Double) at {}: String =
97
95
  js "'' + ${value}"
@@ -100,7 +98,6 @@ extern def showBuiltin(value: Double) at {}: String =
100
98
  %z = call %Pos @c_bytearray_show_Double(%Double ${value})
101
99
  ret %Pos %z
102
100
  """
103
- vm "effekt::show(Double)"
104
101
 
105
102
  extern def showBuiltin(value: Char) at {}: String =
106
103
  js "String.fromCodePoint(${value})"
@@ -109,7 +106,6 @@ extern def showBuiltin(value: Char) at {}: String =
109
106
  %z = call %Pos @c_bytearray_show_Char(%Int ${value})
110
107
  ret %Pos %z
111
108
  """
112
- vm "effekt::show(Char)"
113
109
 
114
110
  extern def showBuiltin(value: Byte) at {}: String =
115
111
  js "'0x' + ${value}.toString(16).toUpperCase().padStart(2, '0')"
@@ -118,11 +114,9 @@ extern def showBuiltin(value: Byte) at {}: String =
118
114
  %z = call %Pos @c_bytearray_show_Byte(%Byte ${value})
119
115
  ret %Pos %z
120
116
  """
121
- vm "effekt::show(Byte)"
122
117
 
123
118
  extern def inspect[R](value: R) at io: Unit =
124
119
  default { println(show(value)) }
125
- vm "effekt::inspect(Any)"
126
120
 
127
121
  /// A fatal runtime error that cannot be caught
128
122
  extern def panic(msg: String) at io: Nothing =
@@ -135,8 +129,8 @@ extern def panic(msg: String) at io: Nothing =
135
129
  """
136
130
 
137
131
  extern def show[R](value: R) at {}: String =
138
- js "$effekt.show(${value})"
139
- chez "(show_impl ${value})"
132
+ js "undefined"
133
+ chez "(void)"
140
134
  llvm "ret %Pos poison"
141
135
 
142
136
  extern def genericShow[R](value: R) at {}: String =
@@ -152,7 +146,6 @@ extern def infixPlusPlus(s1: String, s2: String) at {}: String =
152
146
  %spz = call %Pos @c_bytearray_concatenate(%Pos ${s1}, %Pos ${s2})
153
147
  ret %Pos %spz
154
148
  """
155
- vm "effekt::infixPlusPlus(String, String)"
156
149
 
157
150
  extern def length(str: String) at {}: Int =
158
151
  js "${str}.length"
@@ -161,7 +154,6 @@ extern def length(str: String) at {}: Int =
161
154
  %x = call %Int @c_bytearray_size(%Pos ${str})
162
155
  ret %Int %x
163
156
  """
164
- vm "effekt::length(String)"
165
157
 
166
158
  extern def unsafeSubstring(str: String, from: Int, to: Int) at {}: String =
167
159
  js "${str}.substring(${from}, ${to})"
@@ -170,7 +162,6 @@ extern def unsafeSubstring(str: String, from: Int, to: Int) at {}: String =
170
162
  %x = call %Pos @c_bytearray_substring(%Pos ${str}, i64 ${from}, i64 ${to})
171
163
  ret %Pos %x
172
164
  """
173
- vm "effekt::substring(String, Int, Int)"
174
165
 
175
166
 
176
167
  // Side effecting ops
@@ -183,7 +174,6 @@ extern def random() at io: Double =
183
174
  %r = call double @c_io_random()
184
175
  ret double %r
185
176
  """
186
- vm "effekt::random()"
187
177
 
188
178
  // References and state
189
179
  // ====================
@@ -252,7 +242,6 @@ extern def infixEq(x: Int, y: Int) at {}: Bool =
252
242
  %adt_boolean = insertvalue %Pos zeroinitializer, i64 %fat_z, 0
253
243
  ret %Pos %adt_boolean
254
244
  """
255
- vm "effekt::infixEq(Int, Int)"
256
245
 
257
246
  extern def infixNeq(x: Int, y: Int) at {}: Bool =
258
247
  js "${x} !== ${y}"
@@ -263,7 +252,6 @@ extern def infixNeq(x: Int, y: Int) at {}: Bool =
263
252
  %adt_boolean = insertvalue %Pos zeroinitializer, i64 %fat_z, 0
264
253
  ret %Pos %adt_boolean
265
254
  """
266
- vm "effekt::infixNeq(Int, Int)"
267
255
 
268
256
  extern def infixEq(x: Char, y: Char) at {}: Bool =
269
257
  js "${x} === ${y}"
@@ -274,7 +262,6 @@ extern def infixEq(x: Char, y: Char) at {}: Bool =
274
262
  %adt_boolean = insertvalue %Pos zeroinitializer, i64 %fat_z, 0
275
263
  ret %Pos %adt_boolean
276
264
  """
277
- vm "effekt::infixEq(Char, Char)"
278
265
 
279
266
  extern def infixNeq(x: Char, y: Char) at {}: Bool =
280
267
  js "${x} !== ${y}"
@@ -293,7 +280,6 @@ extern def infixEq(x: String, y: String) at {}: Bool =
293
280
  %res = call %Pos @c_bytearray_equal(%Pos ${x}, %Pos ${y})
294
281
  ret %Pos %res
295
282
  """
296
- vm "effekt::infixEq(String, String)"
297
283
 
298
284
  def infixNeq(x: String, y: String): Bool = not(x == y)
299
285
 
@@ -308,7 +294,6 @@ extern def infixEq(x: Bool, y: Bool) at {}: Bool =
308
294
  %adt_boolean = insertvalue %Pos zeroinitializer, i64 %fat_z, 0
309
295
  ret %Pos %adt_boolean
310
296
  """
311
- vm "effekt::infixEq(Bool, Bool)"
312
297
 
313
298
  extern def infixNeq(x: Bool, y: Bool) at {}: Bool =
314
299
  js "${x} !== ${y}"
@@ -331,7 +316,6 @@ extern def infixEq(x: Byte, y: Byte) at {}: Bool =
331
316
  %adt_boolean = insertvalue %Pos zeroinitializer, i64 %fat_z, 0
332
317
  ret %Pos %adt_boolean
333
318
  """
334
- vm "effekt::infixEq(Byte, Byte)"
335
319
 
336
320
  extern def infixNeq(x: Byte, y: Byte) at {}: Bool =
337
321
  js "${x} !== ${y}"
@@ -342,7 +326,6 @@ extern def infixNeq(x: Byte, y: Byte) at {}: Bool =
342
326
  %adt_boolean = insertvalue %Pos zeroinitializer, i64 %fat_z, 0
343
327
  ret %Pos %adt_boolean
344
328
  """
345
- vm "effekt::infixNeq(Byte, Byte)"
346
329
 
347
330
  // Math ops
348
331
  // ========
@@ -350,85 +333,71 @@ extern def infixPlus(x: Int, y: Int) at {}: Int =
350
333
  js "(${x} + ${y})"
351
334
  chez "(+ ${x} ${y})"
352
335
  llvm "%z = add %Int ${x}, ${y} ret %Int %z"
353
- vm "effekt::infixPlus(Int, Int)"
354
336
 
355
337
  extern def infixStar(x: Int, y: Int) at {}: Int =
356
338
  js "(${x} * ${y})"
357
339
  chez "(* ${x} ${y})"
358
340
  llvm "%z = mul %Int ${x}, ${y} ret %Int %z"
359
- vm "effekt::infixStar(Int, Int)"
360
341
 
361
342
  extern def infixSlash(x: Int, y: Int) at {}: Int =
362
343
  js "Math.floor(${x} / ${y})"
363
344
  chez "(floor (/ ${x} ${y}))"
364
345
  llvm "%z = sdiv %Int ${x}, ${y} ret %Int %z"
365
- vm "effekt::infixSlash(Int, Int)"
366
346
 
367
347
  extern def infixMinus(x: Int, y: Int) at {}: Int =
368
348
  js "(${x} - ${y})"
369
349
  chez "(- ${x} ${y})"
370
350
  llvm "%z = sub %Int ${x}, ${y} ret %Int %z"
371
- vm "effekt::infixMinus(Int, Int)"
372
351
 
373
352
  extern def mod(x: Int, y: Int) at {}: Int =
374
353
  js "(${x} % ${y})"
375
354
  chez "(modulo ${x} ${y})"
376
355
  llvm "%z = srem %Int ${x}, ${y} ret %Int %z"
377
- vm "effekt::mod(Int, Int)"
378
356
 
379
357
  extern def infixPlus(x: Double, y: Double) at {}: Double =
380
358
  js "(${x} + ${y})"
381
359
  chez "(+ ${x} ${y})"
382
360
  llvm "%z = fadd %Double ${x}, ${y} ret %Double %z"
383
- vm "effekt::infixPlus(Double, Double)"
384
361
 
385
362
  extern def infixStar(x: Double, y: Double) at {}: Double =
386
363
  js "(${x} * ${y})"
387
364
  chez "(* ${x} ${y})"
388
365
  llvm "%z = fmul %Double ${x}, ${y} ret %Double %z"
389
- vm "effekt::infixStar(Double, Double)"
390
366
 
391
367
  extern def infixMinus(x: Double, y: Double) at {}: Double =
392
368
  js "(${x} - ${y})"
393
369
  chez "(- ${x} ${y})"
394
370
  llvm "%z = fsub %Double ${x}, ${y} ret %Double %z"
395
- vm "effekt::infixMinus(Double, Double)"
396
371
 
397
372
  extern def infixSlash(x: Double, y: Double) at {}: Double =
398
373
  js "(${x} / ${y})"
399
374
  chez "(fl/ ${x} ${y})"
400
375
  llvm "%z = fdiv %Double ${x}, ${y} ret %Double %z"
401
- vm "effekt::infixSlash(Double, Double)"
402
376
 
403
377
  extern def cos(x: Double) at {}: Double =
404
378
  js "Math.cos(${x})"
405
379
  chez "(cos ${x})"
406
- vm "effekt::cos(Double)"
407
380
  llvm "%z = call %Double @llvm.cos.f64(double ${x}) ret %Double %z"
408
381
 
409
382
  extern def sin(x: Double) at {}: Double =
410
383
  js "Math.sin(${x})"
411
384
  chez "(sin ${x})"
412
- vm "effekt::sin(Double)"
413
385
  llvm "%z = call %Double @llvm.sin.f64(double ${x}) ret %Double %z"
414
386
 
415
387
  extern def atan(x: Double) at {}: Double =
416
388
  js "Math.atan(${x})"
417
389
  chez "(atan ${x})"
418
- vm "effekt::atan(Double)"
419
390
  llvm "%z = call %Double @atan(double ${x}) ret %Double %z"
420
391
 
421
392
  extern def tan(x: Double) at {}: Double =
422
393
  js "Math.tan(${x})"
423
394
  chez "(tan ${x})"
424
- vm "effekt::tan(Double)"
425
395
  llvm "%z = call %Double @tan(double ${x}) ret %Double %z"
426
396
 
427
397
  extern def sqrt(x: Double) at {}: Double =
428
398
  js "Math.sqrt(${x})"
429
399
  chez "(sqrt ${x})"
430
400
  llvm "%z = call %Double @llvm.sqrt.f64(double ${x}) ret %Double %z"
431
- vm "effekt::sqrt(Double)"
432
401
 
433
402
  def square(x: Double): Double = x * x
434
403
 
@@ -447,7 +416,6 @@ def abs(n: Double): Double =
447
416
  extern def log(x: Double) at {}: Double =
448
417
  js "Math.log(${x})"
449
418
  chez "(log ${x})"
450
- vm "effekt::log(Double)"
451
419
  llvm "%z = call %Double @llvm.log.f64(double ${x}) ret %Double %z"
452
420
 
453
421
  extern def log1p(x: Double) at {}: Double =
@@ -458,7 +426,6 @@ extern def log1p(x: Double) at {}: Double =
458
426
  extern def exp(x: Double) at {}: Double =
459
427
  js "Math.exp(${x})"
460
428
  chez "(exp ${x})"
461
- vm "effekt::exp(Double)"
462
429
  llvm "%z = call %Double @llvm.exp.f64(double ${x}) ret %Double %z"
463
430
 
464
431
  def pow(base: Double, exponent: Int): Double = {
@@ -477,14 +444,12 @@ def pow(base: Double, exponent: Int): Double = {
477
444
  extern def pow(base: Double, exponent: Double) at {}: Double =
478
445
  js "Math.pow(${base}, ${exponent})"
479
446
  chez "(expt ${base} ${exponent})"
480
- vm "effekt::pow(Double, Double)"
481
447
  llvm "%z = call %Double @llvm.pow.f64(double ${base}, double ${exponent}) ret %Double %z"
482
448
 
483
449
  // since we do not have "extern val", yet
484
450
  extern def _pi() at {}: Double =
485
451
  js "Math.PI"
486
452
  chez "(* 4 (atan 1))"
487
- vm "effekt::pi()"
488
453
  llvm "ret double 3.14159265358979323846264338327950288419716939937510582097494459"
489
454
 
490
455
  val PI: Double = _pi()
@@ -493,13 +458,11 @@ extern def toInt(d: Double) at {}: Int =
493
458
  js "Math.trunc(${d})"
494
459
  chez "(flonum->fixnum ${d})"
495
460
  llvm "%z = fptosi double ${d} to %Int ret %Int %z"
496
- vm "effekt::toInt(Double)"
497
461
 
498
462
  extern def toDouble(d: Int) at {}: Double =
499
463
  js "${d}"
500
464
  chez "(fixnum->flonum ${d})"
501
465
  llvm "%z = sitofp i64 ${d} to double ret double %z"
502
- vm "effekt::toDouble(Int)"
503
466
 
504
467
 
505
468
  extern def round(d: Double) at {}: Int =
@@ -509,7 +472,6 @@ extern def round(d: Double) at {}: Int =
509
472
  %i = call %Double @llvm.round.f64(double ${d})
510
473
  %z = fptosi double %i to %Int ret %Int %z
511
474
  """
512
- vm "effekt::round(Double)"
513
475
 
514
476
  def round(d: Double, digits: Int): Double = {
515
477
  val factor = pow(10.0, digits)
@@ -554,7 +516,6 @@ extern def infixLt(x: Int, y: Int) at {}: Bool =
554
516
  %adt_boolean = insertvalue %Pos zeroinitializer, i64 %fat_z, 0
555
517
  ret %Pos %adt_boolean
556
518
  """
557
- vm "effekt::infixLt(Int, Int)"
558
519
 
559
520
  extern def infixLte(x: Int, y: Int) at {}: Bool =
560
521
  js "(${x} <= ${y})"
@@ -565,7 +526,6 @@ extern def infixLte(x: Int, y: Int) at {}: Bool =
565
526
  %adt_boolean = insertvalue %Pos zeroinitializer, i64 %fat_z, 0
566
527
  ret %Pos %adt_boolean
567
528
  """
568
- vm "effekt::infixLte(Int, Int)"
569
529
 
570
530
  extern def infixGt(x: Int, y: Int) at {}: Bool =
571
531
  js "(${x} > ${y})"
@@ -576,7 +536,6 @@ extern def infixGt(x: Int, y: Int) at {}: Bool =
576
536
  %adt_boolean = insertvalue %Pos zeroinitializer, i64 %fat_z, 0
577
537
  ret %Pos %adt_boolean
578
538
  """
579
- vm "effekt::infixGt(Int, Int)"
580
539
 
581
540
  extern def infixGte(x: Int, y: Int) at {}: Bool =
582
541
  js "(${x} >= ${y})"
@@ -587,17 +546,14 @@ extern def infixGte(x: Int, y: Int) at {}: Bool =
587
546
  %adt_boolean = insertvalue %Pos zeroinitializer, i64 %fat_z, 0
588
547
  ret %Pos %adt_boolean
589
548
  """
590
- vm "effekt::infixGte(Int, Int)"
591
549
 
592
550
  extern def infixEq(x: Double, y: Double) at {}: Bool =
593
551
  js "${x} === ${y}"
594
552
  chez "(= ${x} ${y})"
595
- vm "effekt::infixEq(Double, Double)"
596
553
 
597
554
  extern def infixNeq(x: Double, y: Double) at {}: Bool =
598
555
  js "${x} !== ${y}"
599
556
  chez "(not (= ${x} ${y}))"
600
- vm "effekt::infixNeq(Double, Double)"
601
557
 
602
558
  extern def infixLt(x: Double, y: Double) at {}: Bool =
603
559
  js "(${x} < ${y})"
@@ -608,12 +564,10 @@ extern def infixLt(x: Double, y: Double) at {}: Bool =
608
564
  %adt_boolean = insertvalue %Pos zeroinitializer, i64 %fat_z, 0
609
565
  ret %Pos %adt_boolean
610
566
  """
611
- vm "effekt::infixLt(Double, Double)"
612
567
 
613
568
  extern def infixLte(x: Double, y: Double) at {}: Bool =
614
569
  js "(${x} <= ${y})"
615
570
  chez "(<= ${x} ${y})"
616
- vm "effekt::infixLte(Double, Double)"
617
571
 
618
572
  extern def infixGt(x: Double, y: Double) at {}: Bool =
619
573
  js "(${x} > ${y})"
@@ -624,12 +578,10 @@ extern def infixGt(x: Double, y: Double) at {}: Bool =
624
578
  %adt_boolean = insertvalue %Pos zeroinitializer, i64 %fat_z, 0
625
579
  ret %Pos %adt_boolean
626
580
  """
627
- vm "effekt::infixGt(Double, Double)"
628
581
 
629
582
  extern def infixGte(x: Double, y: Double) at {}: Bool =
630
583
  js "(${x} >= ${y})"
631
584
  chez "(>= ${x} ${y})"
632
- vm "effekt::infixGte(Double, Double)"
633
585
 
634
586
  // TODO do we really need those? if yes, move to string.effekt
635
587
  extern def infixLt(x: String, y: String) at {}: Bool =
@@ -660,7 +612,6 @@ extern def not(b: Bool) at {}: Bool =
660
612
  %adt_q = insertvalue %Pos zeroinitializer, i64 %q, 0
661
613
  ret %Pos %adt_q
662
614
  """
663
- vm "effekt::not(Bool)"
664
615
 
665
616
  def infixBarBar { first: => Bool } { second: => Bool }: Bool =
666
617
  if (first()) true else second()
@@ -677,38 +628,32 @@ extern def bitwiseShl(x: Int, y: Int) at {}: Int =
677
628
  js "(${x} << ${y})"
678
629
  chez "(ash ${x} ${y})"
679
630
  llvm "%z = shl %Int ${x}, ${y} ret %Int %z"
680
- vm "effekt::bitwiseShl(Int, Int)"
681
631
 
682
632
  /// Arithmetic right shift
683
633
  extern def bitwiseShr(x: Int, y: Int) at {}: Int =
684
634
  js "(${x} >> ${y})"
685
635
  chez "(ash ${x} (- ${y}))"
686
636
  llvm "%z = ashr %Int ${x}, ${y} ret %Int %z"
687
- vm "effekt::bitwiseShr(Int, Int)"
688
637
 
689
638
  extern def bitwiseAnd(x: Int, y: Int) at {}: Int =
690
639
  js "(${x} & ${y})"
691
640
  chez "(logand ${x} ${y})"
692
641
  llvm "%z = and %Int ${x}, ${y} ret %Int %z"
693
- vm "effekt::bitwiseAnd(Int, Int)"
694
642
 
695
643
  extern def bitwiseOr(x: Int, y: Int) at {}: Int =
696
644
  js "(${x} | ${y})"
697
645
  chez "(logior ${x} ${y})"
698
646
  llvm "%z = or %Int ${x}, ${y} ret %Int %z"
699
- vm "effekt::bitwiseOr(Int, Int)"
700
647
 
701
648
  extern def bitwiseXor(x: Int, y: Int) at {}: Int =
702
649
  js "(${x} ^ ${y})"
703
650
  chez "(logxor ${x} ${y})"
704
651
  llvm "%z = xor %Int ${x}, ${y} ret %Int %z"
705
- vm "effekt::bitwiseXor(Int, Int)"
706
652
 
707
653
  extern def bitwiseNot(x: Int) at {}: Int =
708
654
  js "(~${x})"
709
655
  chez "(lognot ${x})"
710
656
  llvm "%z = xor %Int ${x}, -1 ret %Int %z"
711
- vm "effekt::bitwiseNot(Int)"
712
657
 
713
658
 
714
659
  // Byte operations
@@ -721,7 +666,6 @@ extern def toByte(n: Int) at {}: Byte =
721
666
  extern def toInt(n: Byte) at {}: Int =
722
667
  js "${n}"
723
668
  llvm "%z = zext %Byte ${n} to %Int ret %Int %z"
724
- vm "effekt::toInt(Byte)"
725
669
  chez "${n}"
726
670
 
727
671
 
@@ -738,14 +682,21 @@ extern def toInt(n: Byte) at {}: Int =
738
682
  extern def undefined[A]() at {}: A =
739
683
  js "undefined"
740
684
  chez "#f"
741
- vm "effekt::undefined()"
742
685
 
743
686
  /// Is an FFI value undefined?
744
687
  extern def isUndefined[A](value: A) at {}: Bool =
745
688
  js "(${value} === undefined || ${value} === null)"
746
689
  chez "(eq? ${value} #f)"
747
- vm "effekt::isUndefined[A](A)"
748
690
 
691
+ // Ascription
692
+ // ==========
693
+
694
+ /// Ascribe a type, for example `f().as[Int]`.
695
+ def as[A](x: A): A = x
696
+
697
+ /// Witness absurdity, for example `f().absurd`.
698
+ /// Very often the type argument is inferred.
699
+ def absurd[A](x: Nothing): A = x match {}
749
700
 
750
701
  // Tuples
751
702
  // ======
@@ -832,4 +783,10 @@ effect write(s: String): Unit
832
783
 
833
784
  effect splice[A](x: A): Unit
834
785
 
786
+ // Source positions
787
+ // ================
788
+ //
789
+ // When adding an implicit value argument ?sourcePosition of this type, will have the information
790
+ // of the call site unless passed explicitly.
835
791
 
792
+ record SourcePosition(file: String, startLine: Int, startColumn: Int, endLine: Int, endColumn: Int)
@@ -33,7 +33,7 @@ def send[A, B](sender: Sender[A, B], value: A): B = {
33
33
  sender.set(rest)
34
34
  // TODO avoid yield
35
35
  yield()
36
- this.unsafeFire(value)
36
+ this.fire(value)
37
37
  }
38
38
 
39
39
  /// Receives a value from a channel and blocks until a sender arrives.
@@ -51,7 +51,7 @@ def receive[A, B](receiver: Receiver[A, B], value: B): A = {
51
51
  receiver.set(rest)
52
52
  // TODO avoid yield
53
53
  yield()
54
- this.unsafeWait(value)
54
+ this.wait(value)
55
55
  }
56
56
 
57
57
  // TODO streaming
@@ -26,7 +26,8 @@ namespace js {
26
26
  const readline = require('node:readline');
27
27
  """
28
28
 
29
- extern type JSConsole
29
+ extern type JSConsole =
30
+ js "readline.createInterface return type"
30
31
 
31
32
  extern def newConsole() at io: JSConsole =
32
33
  jsNode """readline.createInterface({
@@ -74,8 +74,8 @@ def appendFile(path: String, contents: String): Unit / Exception[IOError] = {
74
74
  def writeFileUTF8[R](path: String) { stream: () => R / emit[Char] }: R / Exception[IOError] =
75
75
  writeFile(path) { encodeUTF8 { stream() } }
76
76
 
77
- def readFileUTF8[R](path: String) { reader: () => R / read[Char] }: R / Exception[IOError] =
78
- readFile(path) { decodeUTF8 { reader() } }
77
+ def readFileUTF8[R](path: String) { driver: () => R / next[Char] }: R / Exception[IOError] =
78
+ readFile(path) { decodeUTF8 { driver() } }
79
79
 
80
80
  def writeFile[R](path: String) { stream: () => R / emit[Byte] }: R / Exception[IOError] = {
81
81
 
@@ -108,7 +108,7 @@ def writeFile[R](path: String) { stream: () => R / emit[Byte] }: R / Exception[I
108
108
  }
109
109
  }
110
110
 
111
- def readFile[R](path: String) { reader: () => R / read[Byte] }: R / Exception[IOError] = {
111
+ def readFile[R](path: String) { driver: () => R / next[Byte] }: R / Exception[IOError] = {
112
112
 
113
113
  val file = openForReading(path);
114
114
  with on[IOError].finalize { close(file) }
@@ -128,8 +128,8 @@ def readFile[R](path: String) { reader: () => R / read[Byte] }: R / Exception[IO
128
128
  }
129
129
 
130
130
  try {
131
- reader()
132
- } with read[Byte] {
131
+ driver()
132
+ } with next[Byte] {
133
133
  resume {
134
134
  if (offset >= length) {
135
135
  pull()
@@ -42,13 +42,13 @@ def listen(listener: Listener, handler: Connection => Unit at {io, async, global
42
42
  def shutdown(listener: Listener): Unit =
43
43
  internal::shutdown(listener)
44
44
 
45
- def streaming[R](connection: Connection) { program: () => R / {read[ByteArray], emit[ByteArray]} }: R / Exception[IOError] =
45
+ def streaming[R](connection: Connection) { program: () => R / {next[ByteArray], emit[ByteArray]} }: R / Exception[IOError] =
46
46
  try {
47
47
  program()
48
48
  } with emit[ByteArray] { bytes =>
49
49
  write(connection, bytes, 0, bytes.size)
50
50
  resume(())
51
- } with read[ByteArray] { () =>
51
+ } with next[ByteArray] { () =>
52
52
  val bytes = bytearray::allocate(4096)
53
53
  read(connection, bytes, 0, bytes.size) match {
54
54
  case r and r == bytes.size => resume { return bytes }
@@ -37,7 +37,7 @@ def await[T](promise: Promise[T]): T =
37
37
  val signal = signal()
38
38
  promise.set(Pending(Cons(signal, signals)))
39
39
  // TODO perhaps yield to avoid stack overflow
40
- signal.unsafeWait(())
40
+ signal.wait(())
41
41
  }
42
42
 
43
43
  /// Resolves the given promise, unblocking all awaiting tasks.
@@ -48,6 +48,6 @@ def resolve[T](promise: Promise[T], value: T): Unit =
48
48
  case Pending(signals) =>
49
49
  promise.set(Resolved(value))
50
50
  // TODO perhaps yield to avoid stack overflow
51
- signals.reverse.foreach { signal => unsafeFire(signal, value) }
51
+ signals.reverse.foreach { signal => fire(signal, value) }
52
52
  }
53
53
 
@@ -5,32 +5,29 @@ module io/signal
5
5
 
6
6
  /// Must be fired exactly once with an A receiving a B,
7
7
  /// and must be waited for exactly once with a B receiving an A.
8
- extern type Signal[A, B]
8
+ extern type Signal[A, B] =
9
+ js "{ state: int, value, stack }"
10
+ llvm "%Pos"
9
11
 
10
- extern def signal[A, B]() at global: Signal[A, B] =
11
- js "signal$make()"
12
- llvm """
13
- %signal = call %Pos @c_signal_make()
14
- ret %Pos %signal
15
- """
12
+ extern llvm """
13
+ %Signal = type { %Header, i64, ptr, %Pos }
16
14
 
17
- extern def unsafeFire[A, B](signal: Signal[A, B], value: A) at async: B =
18
- js "$effekt.capture(callback => signal$notify(${signal}, ${value}, callback))"
19
- llvm """
20
- call void @c_signal_notify(%Pos ${signal}, %Pos ${value}, %Stack %stack)
15
+ define void @signal_erase(ptr %envPtr) {
16
+ %base = getelementptr %Header, ptr %envPtr, i64 -1
17
+ %statePtr = getelementptr %Signal, ptr %base, i64 0, i32 1
18
+ %stackPtr = getelementptr %Signal, ptr %base, i64 0, i32 2
19
+ %valuePtr = getelementptr %Signal, ptr %base, i64 0, i32 3
20
+ %state = load i64, ptr %statePtr
21
+ switch i64 %state, label %none [i64 0, label %free i64 1, label %free i64 2, label %free]
22
+ free:
23
+ %stack = load %Stack, ptr %stackPtr
24
+ %value = load %Pos, ptr %valuePtr
25
+ call void @erasePositive(%Pos %value)
26
+ call void @eraseStack(%Stack %stack)
21
27
  ret void
22
- """
23
-
24
- extern def unsafeWait[A, B](signal: Signal[A, B], value: B) at async: A =
25
- js "$effekt.capture(callback => signal$notify(${signal}, ${value}, callback))"
26
- llvm """
27
- call void @c_signal_notify(%Pos ${signal}, %Pos ${value}, %Stack %stack)
28
+ none:
28
29
  ret void
29
- """
30
-
31
- extern llvm """
32
- declare %Pos @c_signal_make()
33
- declare void @c_signal_notify(%Pos, %Pos, %Stack)
30
+ }
34
31
  """
35
32
 
36
33
  extern js """
@@ -53,3 +50,70 @@ extern js """
53
50
  }
54
51
  }
55
52
  """
53
+
54
+ extern def signal[A, B]() at global: Signal[A, B] =
55
+ js "signal$make()"
56
+ llvm """
57
+ %base = call ptr @calloc(i64 1, i64 48)
58
+ %eraserPtr = getelementptr %Signal, ptr %base, i64 0, i32 0, i32 1
59
+ store ptr @signal_erase, ptr %eraserPtr
60
+ %result = insertvalue %Pos { i64 0, ptr poison }, ptr %base, 1
61
+ ret %Pos %result
62
+ """
63
+
64
+ extern def fire[A, B](signal: Signal[A, B], value: A) at async: B =
65
+ js "$effekt.capture(callback => signal$notify(${signal}, ${value}, callback))"
66
+ llvm """
67
+ %base = extractvalue %Pos ${signal}, 1
68
+ %statePtr = getelementptr %Signal, ptr %base, i64 0, i32 1
69
+ %stackPtr = getelementptr %Signal, ptr %base, i64 0, i32 2
70
+ %valuePtr = getelementptr %Signal, ptr %base, i64 0, i32 3
71
+ %state = load i64, ptr %statePtr
72
+ switch i64 %state, label %panic [i64 0, label %init i64 1, label %fire]
73
+ init:
74
+ store i64 2, ptr %statePtr
75
+ store %Stack %stack, ptr %stackPtr
76
+ store %Pos ${value}, ptr %valuePtr
77
+ call void @erasePositive(%Pos ${signal})
78
+ ret void
79
+ fire:
80
+ %otherStack = load %Stack, ptr %stackPtr
81
+ %otherValue = load %Pos, ptr %valuePtr
82
+ store i64 3, ptr %statePtr
83
+ call void @erasePositive(%Pos ${signal})
84
+ call void @resume_Pos(%Stack %otherStack, %Pos ${value})
85
+ call void @resume_Pos(%Stack %stack, %Pos %otherValue)
86
+ ret void
87
+ panic:
88
+ call void @exit(i64 1)
89
+ ret void
90
+ """
91
+
92
+ extern def wait[A, B](signal: Signal[A, B], value: B) at async: A =
93
+ js "$effekt.capture(callback => signal$notify(${signal}, ${value}, callback))"
94
+ llvm """
95
+ %base = extractvalue %Pos ${signal}, 1
96
+ %statePtr = getelementptr %Signal, ptr %base, i64 0, i32 1
97
+ %stackPtr = getelementptr %Signal, ptr %base, i64 0, i32 2
98
+ %valuePtr = getelementptr %Signal, ptr %base, i64 0, i32 3
99
+ %state = load i64, ptr %statePtr
100
+ switch i64 %state, label %panic [i64 0, label %init i64 2, label %wait]
101
+ init:
102
+ store i64 1, ptr %statePtr
103
+ store %Stack %stack, ptr %stackPtr
104
+ store %Pos ${value}, ptr %valuePtr
105
+ call void @erasePositive(%Pos ${signal})
106
+ ret void
107
+ wait:
108
+ %otherStack = load %Stack, ptr %stackPtr
109
+ %otherValue = load %Pos, ptr %valuePtr
110
+ store i64 3, ptr %statePtr
111
+ call void @erasePositive(%Pos ${signal})
112
+ call void @resume_Pos(%Stack %otherStack, %Pos ${value})
113
+ call void @resume_Pos(%Stack %stack, %Pos %otherValue)
114
+ ret void
115
+ panic:
116
+ call void @exit(i64 1)
117
+ ret void
118
+ """
119
+