@effekt-lang/effekt 0.65.0 → 0.67.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 (33) hide show
  1. package/bin/effekt +0 -0
  2. package/libraries/chez/cps/effekt.ss +5 -11
  3. package/libraries/common/args.effekt +2 -2
  4. package/libraries/common/array.effekt +26 -8
  5. package/libraries/common/bytearray.effekt +18 -10
  6. package/libraries/common/bytestream.effekt +4 -4
  7. package/libraries/common/char.effekt +10 -10
  8. package/libraries/common/dictionary.effekt +44 -43
  9. package/libraries/common/effekt.effekt +16 -5
  10. package/libraries/common/io/channel.effekt +29 -22
  11. package/libraries/common/io/console.effekt +2 -1
  12. package/libraries/common/io/filesystem.effekt +5 -5
  13. package/libraries/common/io/network.effekt +2 -2
  14. package/libraries/common/io/promise.effekt +2 -2
  15. package/libraries/common/io/signal.effekt +86 -22
  16. package/libraries/common/json.effekt +16 -42
  17. package/libraries/common/list.effekt +4 -4
  18. package/libraries/common/process.effekt +6 -2
  19. package/libraries/common/random.effekt +29 -7
  20. package/libraries/common/ref.effekt +4 -1
  21. package/libraries/common/regex.effekt +6 -4
  22. package/libraries/common/resizable_array.effekt +4 -4
  23. package/libraries/common/scanner.effekt +36 -41
  24. package/libraries/common/stream.effekt +76 -36
  25. package/libraries/common/string.effekt +14 -10
  26. package/libraries/common/test.effekt +2 -2
  27. package/libraries/js/effekt_runtime.js +55 -43
  28. package/libraries/llvm/io.c +0 -55
  29. package/licenses/eclipse public license, version 2.0 - epl-2.0.html +4 -4
  30. package/licenses/mit license - mit-license.html +33 -31
  31. package/licenses/the bsd license - bsd-license.html +33 -31
  32. package/licenses/the mit license - mit.html +34 -30
  33. package/package.json +1 -1
package/bin/effekt CHANGED
Binary file
@@ -65,7 +65,7 @@
65
65
  (store-generation-set! store (+ (snap-generation snap) 1))))
66
66
 
67
67
  ; Cont a = a, MetaCont -> #
68
- ; Prompt = Int
68
+ ; Prompt = Symbol
69
69
 
70
70
  ; MetaCont = Cont * Prompt * Store | Snapshot * MetaCont?
71
71
  ; Holds a "copy" of k, as well as its prompt and store
@@ -104,14 +104,8 @@
104
104
  ; Ref | MetaCont -> void
105
105
  (define (deallocate _) (void))
106
106
 
107
- (define _prompt 1)
108
- (define (new-prompt)
109
- (let ([prompt _prompt])
110
- (set! _prompt (+ prompt 1))
111
- prompt))
112
-
113
107
  (define (top-level-k x _) x)
114
- (define top-level-ks (make-meta-cont top-level-k 0 (create-store) '()))
108
+ (define top-level-ks (make-meta-cont top-level-k (gensym "toplevel") (create-store) '()))
115
109
 
116
110
  ; a, MetaCont -> #
117
111
  (define (return x ks)
@@ -123,7 +117,7 @@
123
117
 
124
118
  ; Program Prompt b, MetaCont, Cont b -> #
125
119
  (define (reset prog ks k)
126
- (let ([prompt (new-prompt)])
120
+ (let ([prompt (gensym)])
127
121
  (meta-cont-cont-set! ks k)
128
122
  (prog prompt (make-meta-cont return prompt (create-store) ks) return)))
129
123
 
@@ -134,7 +128,7 @@
134
128
  [snap (snapshot (meta-cont-store below))])
135
129
  (meta-cont-store-set! below snap)
136
130
  (meta-cont-rest-set! below above)
137
- (if (= (meta-cont-prompt below) p)
131
+ (if (symbol=? (meta-cont-prompt below) p)
138
132
  (values below new-below)
139
133
  (worker below new-below))))
140
134
  (worker '() ks))
@@ -168,4 +162,4 @@
168
162
 
169
163
  ; Block b -> b
170
164
  (define (run-top-level p)
171
- (p top-level-ks top-level-k))
165
+ (p top-level-ks top-level-k))
@@ -7,7 +7,7 @@ extern def commandLineArgs() at io: List[String] =
7
7
  vm { Nil() }
8
8
 
9
9
  namespace js {
10
- extern type Args // = Array[String]
10
+ extern type Args = js "Array[String]"
11
11
 
12
12
  extern def nativeArgs() at io: Args = js "process.argv.slice(1)"
13
13
 
@@ -26,7 +26,7 @@ namespace js {
26
26
  }
27
27
 
28
28
  namespace chez {
29
- extern type Args // = CSList[String]
29
+ extern type Args = chez "CSList[String]"
30
30
 
31
31
  extern def nativeArgs() at io: Args =
32
32
  chez "(cdr (command-line))"
@@ -8,7 +8,10 @@ import list
8
8
  import exception
9
9
 
10
10
  /// A mutable 0-indexed fixed-sized array.
11
- extern type Array[T]
11
+ extern type Array[T] =
12
+ js "Array"
13
+ chez "vector"
14
+ llvm "%Pos"
12
15
 
13
16
  /// We represent arrays like positive types.
14
17
  /// The tag is 0 and the obj points to memory with the following layout:
@@ -659,12 +662,12 @@ def each[T](array: Array[T]): Unit / emit[T] = {
659
662
  go(0)
660
663
  }
661
664
 
662
- /// Connects `array` as a producer to a given pull stream `reader` acting as a consumer.
663
- def feed[T, R](array: Array[T]) { reader: () => R / read[T] }: R = {
665
+ /// Connects `array` as a producer to a given pull stream `driver` acting as a consumer.
666
+ def feed[T, R](array: Array[T]) { driver: () => R / next[T] }: R = {
664
667
  var i = 0
665
668
  try {
666
- reader()
667
- } with read[T] {
669
+ driver()
670
+ } with next[T] {
668
671
  resume {
669
672
  if (i < array.size) {
670
673
  val c = i
@@ -677,18 +680,27 @@ def feed[T, R](array: Array[T]) { reader: () => R / read[T] }: R = {
677
680
  }
678
681
  }
679
682
 
683
+ /// Collects elements emitted by a push stream producer `stream` into a new array,
684
+ /// discarding the result of the producer.
685
+ /// The provided capacity is a hint for the expected number of elements.
686
+ /// It must be strictly larger than zero.
687
+ def collect[A](capacity: Int) { stream: () => Unit / emit[A] }: Array[A] =
688
+ returning::collect[A, Unit](capacity){stream}.second
689
+
680
690
  /// Collects elements emitted by a push stream producer `stream` into a new array,
681
691
  /// discarding the result of the producer.
682
692
  def collect[A] { stream: () => Unit / emit[A] }: Array[A] =
683
- returning::collect[A, Unit]{stream}.second
693
+ collect[A](4){stream}
684
694
 
685
695
  namespace returning {
686
696
 
687
697
  /// Collects elements emitted by a push stream producer `stream` into a new array,
688
698
  /// returning the result of the producer as well as the collected array.
689
- def collect[A, R] { stream: () => R / emit[A] }: (R, Array[A]) = {
699
+ /// The provided capacity is a hint for the expected number of elements.
700
+ /// It must be strictly larger than zero.
701
+ def collect[A, R](capacity: Int) { stream: () => R / emit[A] }: (R, Array[A]) = {
690
702
  var i = 0
691
- var a = unsafeAllocate(1)
703
+ var a = unsafeAllocate(capacity)
692
704
  try {
693
705
  (stream(), a.resize(i))
694
706
  } with emit[A] { (v) =>
@@ -698,4 +710,10 @@ namespace returning {
698
710
  resume(())
699
711
  }
700
712
  }
713
+
714
+ /// Collects elements emitted by a push stream producer `stream` into a new array,
715
+ /// returning the result of the producer as well as the collected array.
716
+ def collect[A, R] { stream: () => R / emit[A] }: (R, Array[A]) =
717
+ returning::collect[A, R](4){stream}
718
+
701
719
  }
@@ -19,10 +19,10 @@ import array
19
19
  *
20
20
  * The eraser does nothing.
21
21
  */
22
- extern type ByteArray
23
- // = llvm "%Pos"
24
- // = js "Uint8Array"
25
- // = chez "bytevector"
22
+ extern type ByteArray =
23
+ llvm "%Pos"
24
+ js "Uint8Array"
25
+ chez "bytevector"
26
26
 
27
27
  /// Allocates a new bytearray with the given `size`, its values are zero bytes.
28
28
  extern def allocate(size: Int) at global: ByteArray =
@@ -283,11 +283,11 @@ def each(bytes: ByteArray): Unit / emit[Byte] = {
283
283
  go(0)
284
284
  }
285
285
 
286
- def feed[R](bytes: ByteArray) { reader: () => R / read[Byte] }: R = {
286
+ def feed[R](bytes: ByteArray) { driver: () => R / next[Byte] }: R = {
287
287
  var i = 0
288
288
  try {
289
- reader()
290
- } with read[Byte] {
289
+ driver()
290
+ } with next[Byte] {
291
291
  resume {
292
292
  if (i < bytes.size) {
293
293
  val c = i
@@ -300,13 +300,17 @@ def feed[R](bytes: ByteArray) { reader: () => R / read[Byte] }: R = {
300
300
  }
301
301
  }
302
302
 
303
+ def collect(capacity: Int) { stream: () => Unit / emit[Byte] }: ByteArray =
304
+ returning::collect[Unit](capacity){stream}.second
305
+
303
306
  def collect { stream: () => Unit / emit[Byte] }: ByteArray =
304
- returning::collect[Unit]{stream}.second
307
+ collect(4){stream}
305
308
 
306
309
  namespace returning {
307
- def collect[R] { stream: () => R / emit[Byte] }: (R, ByteArray) = {
310
+
311
+ def collect[R](capacity: Int) { stream: () => R / emit[Byte] }: (R, ByteArray) = {
308
312
  var i = 0
309
- var a = allocate(1)
313
+ var a = allocate(capacity)
310
314
  try {
311
315
  (stream(), a.resize(i))
312
316
  } with emit[Byte] { (v) =>
@@ -316,4 +320,8 @@ namespace returning {
316
320
  resume(())
317
321
  }
318
322
  }
323
+
324
+ def collect[R] { stream: () => R / emit[Byte] }: (R, ByteArray) =
325
+ returning::collect(4){stream}
326
+
319
327
  }
@@ -103,7 +103,7 @@ def hex{ body: => Unit / { write, HexSplices } }: Unit / emit[Byte] = {
103
103
  body()
104
104
  }
105
105
  with splice[String] { s =>
106
- feed(s){ loop { do splice[Char](do read[Char]()) } }
106
+ feed(s){ loop { do splice[Char](do next[Char]()) } }
107
107
  resume(())
108
108
  }
109
109
  with splice[ByteArray] { ba =>
@@ -115,8 +115,8 @@ def hex{ body: => Unit / { write, HexSplices } }: Unit / emit[Byte] = {
115
115
  feed(s){
116
116
  loop {
117
117
  attempt {
118
- val upper: Int = hexDigitValue(do read[Char]())
119
- val lower: Int = hexDigitValue(do read[Char]())
118
+ val upper: Int = hexDigitValue(do next[Char]())
119
+ val lower: Int = hexDigitValue(do next[Char]())
120
120
  do emit[Byte]((16 * upper + lower).toByte)
121
121
  } { () }
122
122
  }
@@ -296,7 +296,7 @@ def bit{ body: => Unit / { write, BitSplices } }: Unit / emit[Bit] = {
296
296
  with write { s =>
297
297
  feed(s){
298
298
  loop {
299
- do read[Char]() match {
299
+ do next[Char]() match {
300
300
  case '0' => do emit(B0())
301
301
  case '1' => do emit(B1())
302
302
  case _ => ()
@@ -175,24 +175,24 @@ extern def charWidth(c: Char) at {}: Int =
175
175
  js "(${c} > 0xffff) ? 2 : 1"
176
176
 
177
177
 
178
- def decodeChar(): Char / {read[Byte], stop} = {
179
- val b = do read().toInt
178
+ def decodeChar(): Char / {next[Byte], stop} = {
179
+ val b = do next().toInt
180
180
  if (b < 128) {
181
181
  b.toChar
182
182
  } else if (b < 224) {
183
183
  val part1 = bitwiseShl(bitwiseAnd(b, 31), 6)
184
- val part2 = bitwiseAnd(do read().toInt, 63)
184
+ val part2 = bitwiseAnd(do next().toInt, 63)
185
185
  bitwiseOr(part1, part2).toChar
186
186
  } else if (b < 240) {
187
187
  val part1 = bitwiseShl(bitwiseAnd(b, 15), 12)
188
- val part2 = bitwiseShl(bitwiseAnd(do read().toInt, 63), 6)
189
- val part3 = bitwiseAnd(do read().toInt, 63)
188
+ val part2 = bitwiseShl(bitwiseAnd(do next().toInt, 63), 6)
189
+ val part3 = bitwiseAnd(do next().toInt, 63)
190
190
  bitwiseOr(bitwiseOr(part1, part2), part3).toChar
191
191
  } else {
192
192
  val part1 = bitwiseShl(bitwiseAnd(b, 7), 18)
193
- val part2 = bitwiseShl(bitwiseAnd(do read().toInt, 63), 12)
194
- val part3 = bitwiseShl(bitwiseAnd(do read().toInt, 63), 6)
195
- val part4 = bitwiseAnd(do read().toInt, 63)
193
+ val part2 = bitwiseShl(bitwiseAnd(do next().toInt, 63), 12)
194
+ val part3 = bitwiseShl(bitwiseAnd(do next().toInt, 63), 6)
195
+ val part4 = bitwiseAnd(do next().toInt, 63)
196
196
  bitwiseOr(bitwiseOr(bitwiseOr(part1, part2), part3), part4).toChar
197
197
  }
198
198
  }
@@ -216,10 +216,10 @@ def encodeChar(char: Char): Unit / emit[Byte] = {
216
216
  }
217
217
  }
218
218
 
219
- def decodeUTF8[R] { reader: () => R / read[Char] }: R / read[Byte] =
219
+ def decodeUTF8[R] { reader: () => R / next[Char] }: R / next[Byte] =
220
220
  try {
221
221
  reader()
222
- } with read[Char] {
222
+ } with next[Char] {
223
223
  resume { decodeChar() }
224
224
  }
225
225
 
@@ -1,26 +1,33 @@
1
1
  module dictionary
2
2
 
3
+ import ref
3
4
  import array
4
5
  import bytearray
5
6
  import stream
6
7
 
7
-
8
- /// A trie-based dictionary for efficient key-value storage with bytearray keys.
9
- /// Supports String and ByteArray keys with fast lookup and insertion.
10
- type Dictionary[A] {
8
+ /// Internal trie node type.
9
+ type Trie[A] {
11
10
  Empty()
12
11
  Leaf(value: A)
13
- Branch(children: Array[Dictionary[A]])
14
- Node(value: A, children: Array[Dictionary[A]])
12
+ Branch(children: Array[Trie[A]])
13
+ Node(value: A, children: Array[Trie[A]])
15
14
  }
16
15
 
16
+ /// A mutable trie-based dictionary for efficient key-value storage with bytearray keys.
17
+ type Dictionary[A] = Ref[Trie[A]]
18
+
19
+ /// A record pairing a key with a value for use in streams.
20
+ record Tagged[A](key: ByteArray, value: A)
21
+
22
+ def empty[A](): Dictionary[A] = ref(Empty())
23
+
17
24
  /// Insert a value with a String key.
18
- def insert[A](trie: Dictionary[A], key: String, value: A): Dictionary[A] =
19
- insert(trie, key.fromString, value)
25
+ def insert[A](dictionary: Dictionary[A], key: String, value: A): Unit =
26
+ insert(dictionary, key.fromString, value)
20
27
 
21
28
  /// Insert a key-value pair into the dictionary with a ByteArray key.
22
- def insert[A](trie: Dictionary[A], key: ByteArray, value: A): Dictionary[A] = {
23
- def go(trie: Dictionary[A], i: Int): Dictionary[A] =
29
+ def insert[A](dictionary: Dictionary[A], key: ByteArray, value: A): Unit = {
30
+ def go(trie: Trie[A], i: Int): Trie[A] =
24
31
  if (i < key.size) {
25
32
  trie match {
26
33
  case Empty() =>
@@ -50,16 +57,16 @@ def insert[A](trie: Dictionary[A], key: ByteArray, value: A): Dictionary[A] = {
50
57
  case Branch(children) => Node(value, children)
51
58
  }
52
59
  }
53
- go(trie, 0)
60
+ dictionary.set(go(dictionary.get, 0))
54
61
  }
55
62
 
56
63
  /// Look up a value in the dictionary by string key.
57
- def lookup[A](trie: Dictionary[A], key: String): Option[A] =
58
- lookup(trie, key.fromString)
64
+ def lookup[A](dictionary: Dictionary[A], key: String): Option[A] =
65
+ lookup(dictionary, key.fromString)
59
66
 
60
67
  /// Look up a value in the dictionary by bytearray key.
61
- def lookup[A](trie: Dictionary[A], key: ByteArray): Option[A] = {
62
- def go(trie: Dictionary[A], i: Int): Option[A] =
68
+ def lookup[A](dictionary: Dictionary[A], key: ByteArray): Option[A] = {
69
+ def go(trie: Trie[A], i: Int): Option[A] =
63
70
  if (i < key.size) {
64
71
  trie match {
65
72
  case Empty() => None()
@@ -75,45 +82,41 @@ def lookup[A](trie: Dictionary[A], key: ByteArray): Option[A] = {
75
82
  case Node(value, _) => Some(value)
76
83
  }
77
84
  }
78
- go(trie, 0)
85
+ go(dictionary.get, 0)
79
86
  }
80
87
 
81
- /// A record pairing a key with a value for use in streams.
82
- record Tagged[A](key: ByteArray, value: A)
83
-
84
- /// Collect key-value pairs from a stream of Tagged elements into a Dictionary.
88
+ /// Collect key-value pairs from a stream of Tagged elements into a fresh Dictionary.
85
89
  def collect[A] { stream: () => Unit / emit[Tagged[A]] }: Dictionary[A] = {
86
- var trie = Empty()
90
+ val dictionary = ref(Empty())
87
91
  for[Tagged[A]] { stream() } { case Tagged(bytes, value) =>
88
- trie = trie.insert(bytes, value)
92
+ dictionary.insert(bytes, value)
89
93
  }
90
- return trie
94
+ return dictionary
91
95
  }
92
96
 
93
97
  /// Emit all values stored in the dictionary as a push stream.
94
- def each[A](trie: Dictionary[A]): Unit / emit[A] =
95
- trie match {
96
- case Empty() => ()
97
- case Leaf(value) => do emit(value)
98
- case Branch(children) =>
99
- each(0, children.size) { i =>
100
- each(children.get(i))
101
- }
102
- case Node(value, children) =>
103
- do emit(value)
104
- each(0, children.size) { i =>
105
- each(children.get(i))
106
- }
107
- }
98
+ def each[A](dictionary: Dictionary[A]): Unit / emit[A] = {
99
+ def go(trie: Trie[A]): Unit / emit[A] =
100
+ trie match {
101
+ case Empty() => ()
102
+ case Leaf(value) => do emit(value)
103
+ case Branch(children) =>
104
+ each(0, children.size) { i => go(children.get(i)) }
105
+ case Node(value, children) =>
106
+ do emit(value)
107
+ each(0, children.size) { i => go(children.get(i)) }
108
+ }
109
+ go(dictionary.get)
110
+ }
108
111
 
109
112
  /// Emit all key-value pairs stored in the dictionary as a push stream of Tagged elements.
110
- def eachTagged[A](trie: Dictionary[A]): Unit / emit[Tagged[A]] = {
113
+ def eachTagged[A](dictionary: Dictionary[A]): Unit / emit[Tagged[A]] = {
111
114
  def fromBytesReverse(bytes: List[Byte], n: Int): ByteArray = {
112
115
  val key = bytearray::allocate(n)
113
116
  foreachIndex(bytes) { (i, b) => key.set(n - 1 - i, b) }
114
117
  key
115
118
  }
116
- def go(trie: Dictionary[A], key: List[Byte], n: Int): Unit =
119
+ def go(trie: Trie[A], key: List[Byte], n: Int): Unit =
117
120
  trie match {
118
121
  case Empty() => ()
119
122
  case Leaf(value) => do emit(Tagged(fromBytesReverse(key, n), value))
@@ -127,7 +130,5 @@ def eachTagged[A](trie: Dictionary[A]): Unit / emit[Tagged[A]] = {
127
130
  go(children.get(i), Cons(i.toByte, key), n + 1)
128
131
  }
129
132
  }
130
- go(trie, Nil(), 0)
131
- }
132
-
133
-
133
+ go(dictionary.get, Nil(), 0)
134
+ }
@@ -83,6 +83,7 @@ def println(value: Unit): Unit = println(value.show)
83
83
  def println(value: Double): Unit = println(value.show)
84
84
  def println(value: Bool): Unit = println(value.show)
85
85
  def println(value: Byte): Unit = println(value.show)
86
+ def println(value: Char): Unit = println(value.show)
86
87
 
87
88
  extern def showBuiltin(value: Int) at {}: String =
88
89
  js "'' + ${value}"
@@ -135,9 +136,13 @@ extern def panic(msg: String) at io: Nothing =
135
136
  """
136
137
 
137
138
  extern def show[R](value: R) at {}: String =
139
+ js "undefined"
140
+ chez "(void)"
141
+ llvm "ret %Pos poison"
142
+
143
+ extern def genericShow[R](value: R) at {}: String =
138
144
  js "$effekt.show(${value})"
139
145
  chez "(show_impl ${value})"
140
- llvm "ret %Pos poison"
141
146
 
142
147
  // Strings
143
148
  // =======
@@ -231,13 +236,10 @@ def println(o: Ordering): Unit = println(o.show)
231
236
  // ==============
232
237
 
233
238
  /// Structural equality: Not available in the LLVM backend
234
- extern def equals[R](x: R, y: R) at {}: Bool =
239
+ extern def genericEquals[R](x: R, y: R) at {}: Bool =
235
240
  js "$effekt.equals(${x}, ${y})"
236
241
  chez "(equal_impl ${x} ${y})"
237
242
 
238
- def differsFrom[R](x: R, y: R): Bool =
239
- not(equals(x, y))
240
-
241
243
  // TODO fix this in the pattern matching compiler
242
244
  extern def infixEq(x: Unit, y: Unit) at {}: Bool =
243
245
  default { true }
@@ -745,6 +747,15 @@ extern def isUndefined[A](value: A) at {}: Bool =
745
747
  chez "(eq? ${value} #f)"
746
748
  vm "effekt::isUndefined[A](A)"
747
749
 
750
+ // Ascription
751
+ // ==========
752
+
753
+ /// Ascribe a type, for example `f().as[Int]`.
754
+ def as[A](x: A): A = x
755
+
756
+ /// Witness absurdity, for example `f().absurd`.
757
+ /// Very often the type argument is inferred.
758
+ def absurd[A](x: Nothing): A = x match {}
748
759
 
749
760
  // Tuples
750
761
  // ======
@@ -3,48 +3,55 @@ module io/channel
3
3
  import io
4
4
  import io/signal
5
5
 
6
- record Node[A, B](this: Signal[A, B], rest: Ref[Option[Node[A, B]]])
6
+ type Node[A, B] {
7
+ Nope()
8
+ Node(this: Signal[A, B], rest: Ref[Node[A, B]])
9
+ }
7
10
 
8
- type Sender[A, B] = Ref[Node[A, B]]
9
- type Receiver[A, B] = Ref[Node[A, B]]
11
+ type Sender[A, B] = Ref[Ref[Node[A, B]]]
12
+ type Receiver[A, B] = Ref[Ref[Node[A, B]]]
10
13
 
11
14
  /// Creates a new rendezvous channel and returns the receiving and the sending end.
12
15
  /// Every send must be matched by exactly one receive upon which two values are exchanged.
13
16
  def channel[A, B](): (Sender[A, B], Receiver[A, B]) = {
14
- val node = Node(signal(), ref(None()))
17
+ val node = ref(Nope())
15
18
  (ref(node), ref(node))
16
19
  }
17
20
 
18
21
  /// Sends a value to a channel and blocks until a receiver arrives.
19
22
  def send[A, B](sender: Sender[A, B], value: A): B = {
20
- val Node(this, rest) = sender.get()
21
- rest.get() match {
22
- case None() =>
23
- val node = Node(signal(), ref(None()))
24
- rest.set(Some(node))
25
- sender.set(node)
26
- case Some(node) =>
27
- sender.set(node)
23
+ val current = sender.get()
24
+ val (this, rest) = current.get() match {
25
+ case Nope() =>
26
+ val this = signal()
27
+ val rest = ref(Nope())
28
+ current.set(Node(this, rest))
29
+ (this, rest)
30
+ case Node(this, rest) =>
31
+ (this, rest)
28
32
  }
33
+ sender.set(rest)
29
34
  // TODO avoid yield
30
35
  yield()
31
- this.unsafeFire(value)
36
+ this.fire(value)
32
37
  }
33
38
 
34
39
  /// Receives a value from a channel and blocks until a sender arrives.
35
40
  def receive[A, B](receiver: Receiver[A, B], value: B): A = {
36
- val Node(this, rest) = receiver.get()
37
- rest.get() match {
38
- case None() =>
39
- val node = Node(signal(), ref(None()))
40
- rest.set(Some(node))
41
- receiver.set(node)
42
- case Some(node) =>
43
- receiver.set(node)
41
+ val current = receiver.get()
42
+ val (this, rest) = current.get() match {
43
+ case Nope() =>
44
+ val this = signal()
45
+ val rest = ref(Nope())
46
+ current.set(Node(this, rest))
47
+ (this, rest)
48
+ case Node(this, rest) =>
49
+ (this, rest)
44
50
  }
51
+ receiver.set(rest)
45
52
  // TODO avoid yield
46
53
  yield()
47
- this.unsafeWait(value)
54
+ this.wait(value)
48
55
  }
49
56
 
50
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