@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.
- package/bin/effekt +0 -0
- package/libraries/chez/cps/effekt.ss +5 -11
- package/libraries/common/args.effekt +2 -2
- package/libraries/common/array.effekt +26 -8
- package/libraries/common/bytearray.effekt +18 -10
- package/libraries/common/bytestream.effekt +4 -4
- package/libraries/common/char.effekt +10 -10
- package/libraries/common/dictionary.effekt +44 -43
- package/libraries/common/effekt.effekt +16 -5
- package/libraries/common/io/channel.effekt +29 -22
- package/libraries/common/io/console.effekt +2 -1
- package/libraries/common/io/filesystem.effekt +5 -5
- package/libraries/common/io/network.effekt +2 -2
- package/libraries/common/io/promise.effekt +2 -2
- package/libraries/common/io/signal.effekt +86 -22
- package/libraries/common/json.effekt +16 -42
- package/libraries/common/list.effekt +4 -4
- package/libraries/common/process.effekt +6 -2
- package/libraries/common/random.effekt +29 -7
- package/libraries/common/ref.effekt +4 -1
- package/libraries/common/regex.effekt +6 -4
- package/libraries/common/resizable_array.effekt +4 -4
- package/libraries/common/scanner.effekt +36 -41
- package/libraries/common/stream.effekt +76 -36
- package/libraries/common/string.effekt +14 -10
- package/libraries/common/test.effekt +2 -2
- package/libraries/js/effekt_runtime.js +55 -43
- package/libraries/llvm/io.c +0 -55
- package/licenses/eclipse public license, version 2.0 - epl-2.0.html +4 -4
- package/licenses/mit license - mit-license.html +33 -31
- package/licenses/the bsd license - bsd-license.html +33 -31
- package/licenses/the mit license - mit.html +34 -30
- 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 =
|
|
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
|
|
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 (
|
|
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 (
|
|
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
|
|
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
|
|
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 `
|
|
663
|
-
def feed[T, R](array: Array[T]) {
|
|
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
|
-
|
|
667
|
-
} with
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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) {
|
|
286
|
+
def feed[R](bytes: ByteArray) { driver: () => R / next[Byte] }: R = {
|
|
287
287
|
var i = 0
|
|
288
288
|
try {
|
|
289
|
-
|
|
290
|
-
} with
|
|
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
|
-
|
|
307
|
+
collect(4){stream}
|
|
305
308
|
|
|
306
309
|
namespace returning {
|
|
307
|
-
|
|
310
|
+
|
|
311
|
+
def collect[R](capacity: Int) { stream: () => R / emit[Byte] }: (R, ByteArray) = {
|
|
308
312
|
var i = 0
|
|
309
|
-
var a = allocate(
|
|
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
|
|
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
|
|
119
|
-
val lower: Int = hexDigitValue(do
|
|
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
|
|
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 / {
|
|
179
|
-
val b = do
|
|
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
|
|
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
|
|
189
|
-
val part3 = bitwiseAnd(do
|
|
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
|
|
194
|
-
val part3 = bitwiseShl(bitwiseAnd(do
|
|
195
|
-
val part4 = bitwiseAnd(do
|
|
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 /
|
|
219
|
+
def decodeUTF8[R] { reader: () => R / next[Char] }: R / next[Byte] =
|
|
220
220
|
try {
|
|
221
221
|
reader()
|
|
222
|
-
} with
|
|
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
|
-
|
|
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[
|
|
14
|
-
Node(value: A, children: Array[
|
|
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](
|
|
19
|
-
insert(
|
|
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](
|
|
23
|
-
def go(trie:
|
|
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(
|
|
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](
|
|
58
|
-
lookup(
|
|
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](
|
|
62
|
-
def go(trie:
|
|
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(
|
|
85
|
+
go(dictionary.get, 0)
|
|
79
86
|
}
|
|
80
87
|
|
|
81
|
-
///
|
|
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
|
-
|
|
90
|
+
val dictionary = ref(Empty())
|
|
87
91
|
for[Tagged[A]] { stream() } { case Tagged(bytes, value) =>
|
|
88
|
-
|
|
92
|
+
dictionary.insert(bytes, value)
|
|
89
93
|
}
|
|
90
|
-
return
|
|
94
|
+
return dictionary
|
|
91
95
|
}
|
|
92
96
|
|
|
93
97
|
/// Emit all values stored in the dictionary as a push stream.
|
|
94
|
-
def each[A](
|
|
95
|
-
trie
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
each(children.get(i))
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
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](
|
|
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:
|
|
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(
|
|
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
|
|
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
|
-
|
|
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 =
|
|
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
|
|
21
|
-
rest.get() match {
|
|
22
|
-
case
|
|
23
|
-
val
|
|
24
|
-
rest
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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.
|
|
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
|
|
37
|
-
rest.get() match {
|
|
38
|
-
case
|
|
39
|
-
val
|
|
40
|
-
rest
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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.
|
|
54
|
+
this.wait(value)
|
|
48
55
|
}
|
|
49
56
|
|
|
50
57
|
// TODO streaming
|
|
@@ -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) {
|
|
78
|
-
readFile(path) { decodeUTF8 {
|
|
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) {
|
|
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
|
-
|
|
132
|
-
} with
|
|
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 / {
|
|
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
|
|
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.
|
|
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 =>
|
|
51
|
+
signals.reverse.foreach { signal => fire(signal, value) }
|
|
52
52
|
}
|
|
53
53
|
|