@effekt-lang/effekt 0.78.0 → 0.80.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/common/array.effekt +1 -1
- package/libraries/common/bytearray.effekt +1 -1
- package/libraries/common/dictionary.effekt +243 -53
- package/libraries/common/effekt.effekt +1 -1
- package/libraries/common/io/filesystem.effekt +7 -7
- package/libraries/common/io/network.effekt +6 -6
- package/libraries/common/io/signal.effekt +10 -10
- package/libraries/common/io/time.effekt +1 -1
- package/libraries/common/io.effekt +4 -4
- package/libraries/common/map.effekt +194 -100
- package/libraries/common/process.effekt +6 -5
- package/libraries/common/random.effekt +14 -1
- package/libraries/common/set.effekt +9 -19
- package/libraries/common/sourcepos.effekt +75 -0
- package/libraries/common/test.effekt +57 -56
- package/libraries/js/effekt_runtime.js +19 -3
- package/libraries/llvm/bytearray.c +1 -1
- package/libraries/llvm/io.c +17 -17
- package/libraries/llvm/rts.ll +30 -29
- package/libraries/llvm/types.c +3 -3
- package/licenses/mit license - mit-license.html +28 -28
- package/licenses/the bsd license - bsd-license.html +27 -27
- package/licenses/the mit license - mit.html +27 -27
- package/package.json +1 -1
package/bin/effekt
CHANGED
|
Binary file
|
|
@@ -108,7 +108,7 @@ define void @assertInbounds(i64 %index, %Pos %arr) alwaysinline {
|
|
|
108
108
|
%in_bounds = icmp ult i64 %index, %size
|
|
109
109
|
br i1 %in_bounds, label %ok, label %out
|
|
110
110
|
out:
|
|
111
|
-
call void @exit(
|
|
111
|
+
call void @exit(i32 1)
|
|
112
112
|
unreachable
|
|
113
113
|
ok:
|
|
114
114
|
ret void
|
|
@@ -6,14 +6,40 @@ import bytearray
|
|
|
6
6
|
import stream
|
|
7
7
|
|
|
8
8
|
/// Internal trie node type.
|
|
9
|
+
///
|
|
10
|
+
/// Nodes with at most four children are `Branch1` ... `Branch4`, holding their
|
|
11
|
+
/// children behind `Ref`s so that descending along an existing path can
|
|
12
|
+
/// update in place without rebuilding the spine. A fifth child promotes the
|
|
13
|
+
/// node to the dense representation (`Branch256` / `Node256`), a full 256-slot
|
|
14
|
+
/// array indexed by the byte, whose cells are mutable themselves.
|
|
15
|
+
///
|
|
16
|
+
/// Invariant: in the sparse representations, `byte1 < byte2 < byte3 < byte4`
|
|
17
|
+
/// (bytes are unsigned), so iteration is in key order in every representation.
|
|
18
|
+
///
|
|
19
|
+
/// `Leaf`, `Node1` ... `Node4` and `Node256` carry a value at this
|
|
20
|
+
/// position; `Branch1` ... `Branch4` and `Branch256` do not.
|
|
21
|
+
///
|
|
22
|
+
/// No `Trie` value is ever shared between two live positions: insertion
|
|
23
|
+
/// mutates through `Ref`s and array cells, so aliasing a subtree would be
|
|
24
|
+
/// unsound.
|
|
9
25
|
type Trie[A] {
|
|
10
26
|
Empty()
|
|
11
27
|
Leaf(value: A)
|
|
12
|
-
|
|
13
|
-
|
|
28
|
+
Branch1(byte: Byte, child: Ref[Trie[A]])
|
|
29
|
+
Node1(value: A, byte: Byte, child: Ref[Trie[A]])
|
|
30
|
+
Branch2(byte1: Byte, child1: Ref[Trie[A]], byte2: Byte, child2: Ref[Trie[A]])
|
|
31
|
+
Node2(value: A, byte1: Byte, child1: Ref[Trie[A]], byte2: Byte, child2: Ref[Trie[A]])
|
|
32
|
+
Branch3(byte1: Byte, child1: Ref[Trie[A]], byte2: Byte, child2: Ref[Trie[A]], byte3: Byte, child3: Ref[Trie[A]])
|
|
33
|
+
Node3(value: A, byte1: Byte, child1: Ref[Trie[A]], byte2: Byte, child2: Ref[Trie[A]], byte3: Byte, child3: Ref[Trie[A]])
|
|
34
|
+
Branch4(byte1: Byte, child1: Ref[Trie[A]], byte2: Byte, child2: Ref[Trie[A]], byte3: Byte, child3: Ref[Trie[A]], byte4: Byte, child4: Ref[Trie[A]])
|
|
35
|
+
Node4(value: A, byte1: Byte, child1: Ref[Trie[A]], byte2: Byte, child2: Ref[Trie[A]], byte3: Byte, child3: Ref[Trie[A]], byte4: Byte, child4: Ref[Trie[A]])
|
|
36
|
+
Branch256(children: Array[Trie[A]])
|
|
37
|
+
Node256(value: A, children: Array[Trie[A]])
|
|
14
38
|
}
|
|
15
39
|
|
|
16
40
|
/// A mutable trie-based dictionary for efficient key-value storage with bytearray keys.
|
|
41
|
+
///
|
|
42
|
+
/// Mutating the dictionary while iterating it (`each`, `eachTagged`) is undefined.
|
|
17
43
|
type Dictionary[A] = Ref[Trie[A]]
|
|
18
44
|
|
|
19
45
|
/// A record pairing a key with a value for use in streams.
|
|
@@ -27,34 +53,104 @@ def insert[A](dictionary: Dictionary[A], key: String, value: A): Unit =
|
|
|
27
53
|
|
|
28
54
|
/// Insert a key-value pair into the dictionary with a ByteArray key.
|
|
29
55
|
def insert[A](dictionary: Dictionary[A], key: ByteArray, value: A): Unit = {
|
|
56
|
+
val n = key.size
|
|
57
|
+
|
|
58
|
+
// The rest of the key from position `i` on, as a chain of `Branch1`s
|
|
59
|
+
// ending in a `Leaf`.
|
|
60
|
+
def chain(i: Int): Trie[A] =
|
|
61
|
+
if (i < n) Branch1(key.get(i), ref(chain(i + 1)))
|
|
62
|
+
else Leaf(value)
|
|
63
|
+
|
|
64
|
+
// The four children of a `Branch4`, plus the rest of the key at `b`,
|
|
65
|
+
// as a full 256-slot array.
|
|
66
|
+
def densified(byte1: Byte, child1: Ref[Trie[A]], byte2: Byte, child2: Ref[Trie[A]], byte3: Byte, child3: Ref[Trie[A]], byte4: Byte, child4: Ref[Trie[A]], b: Byte, i: Int): Array[Trie[A]] = {
|
|
67
|
+
val children = array[Trie[A]](256, Empty())
|
|
68
|
+
children.set(byte1.toInt, child1.get)
|
|
69
|
+
children.set(byte2.toInt, child2.get)
|
|
70
|
+
children.set(byte3.toInt, child3.get)
|
|
71
|
+
children.set(byte4.toInt, child4.get)
|
|
72
|
+
children.set(b.toInt, chain(i + 1))
|
|
73
|
+
children
|
|
74
|
+
}
|
|
75
|
+
|
|
30
76
|
def go(trie: Trie[A], i: Int): Trie[A] =
|
|
31
|
-
if (i <
|
|
77
|
+
if (i < n) {
|
|
78
|
+
val b = key.get(i)
|
|
32
79
|
trie match {
|
|
33
|
-
case Empty() =>
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
80
|
+
case Empty() => chain(i)
|
|
81
|
+
case Leaf(existing) => Node1(existing, b, ref(chain(i + 1)))
|
|
82
|
+
|
|
83
|
+
case Branch1(byte1, child1) =>
|
|
84
|
+
if (b == byte1) { child1.set(go(child1.get, i + 1)); trie }
|
|
85
|
+
else if (b.toInt < byte1.toInt) Branch2(b, ref(chain(i + 1)), byte1, child1)
|
|
86
|
+
else Branch2(byte1, child1, b, ref(chain(i + 1)))
|
|
87
|
+
case Node1(existing, byte1, child1) =>
|
|
88
|
+
if (b == byte1) { child1.set(go(child1.get, i + 1)); trie }
|
|
89
|
+
else if (b.toInt < byte1.toInt) Node2(existing, b, ref(chain(i + 1)), byte1, child1)
|
|
90
|
+
else Node2(existing, byte1, child1, b, ref(chain(i + 1)))
|
|
91
|
+
|
|
92
|
+
case Branch2(byte1, child1, byte2, child2) =>
|
|
93
|
+
if (b == byte1) { child1.set(go(child1.get, i + 1)); trie }
|
|
94
|
+
else if (b == byte2) { child2.set(go(child2.get, i + 1)); trie }
|
|
95
|
+
else if (b.toInt < byte1.toInt) Branch3(b, ref(chain(i + 1)), byte1, child1, byte2, child2)
|
|
96
|
+
else if (b.toInt < byte2.toInt) Branch3(byte1, child1, b, ref(chain(i + 1)), byte2, child2)
|
|
97
|
+
else Branch3(byte1, child1, byte2, child2, b, ref(chain(i + 1)))
|
|
98
|
+
case Node2(existing, byte1, child1, byte2, child2) =>
|
|
99
|
+
if (b == byte1) { child1.set(go(child1.get, i + 1)); trie }
|
|
100
|
+
else if (b == byte2) { child2.set(go(child2.get, i + 1)); trie }
|
|
101
|
+
else if (b.toInt < byte1.toInt) Node3(existing, b, ref(chain(i + 1)), byte1, child1, byte2, child2)
|
|
102
|
+
else if (b.toInt < byte2.toInt) Node3(existing, byte1, child1, b, ref(chain(i + 1)), byte2, child2)
|
|
103
|
+
else Node3(existing, byte1, child1, byte2, child2, b, ref(chain(i + 1)))
|
|
104
|
+
|
|
105
|
+
case Branch3(byte1, child1, byte2, child2, byte3, child3) =>
|
|
106
|
+
if (b == byte1) { child1.set(go(child1.get, i + 1)); trie }
|
|
107
|
+
else if (b == byte2) { child2.set(go(child2.get, i + 1)); trie }
|
|
108
|
+
else if (b == byte3) { child3.set(go(child3.get, i + 1)); trie }
|
|
109
|
+
else if (b.toInt < byte1.toInt) Branch4(b, ref(chain(i + 1)), byte1, child1, byte2, child2, byte3, child3)
|
|
110
|
+
else if (b.toInt < byte2.toInt) Branch4(byte1, child1, b, ref(chain(i + 1)), byte2, child2, byte3, child3)
|
|
111
|
+
else if (b.toInt < byte3.toInt) Branch4(byte1, child1, byte2, child2, b, ref(chain(i + 1)), byte3, child3)
|
|
112
|
+
else Branch4(byte1, child1, byte2, child2, byte3, child3, b, ref(chain(i + 1)))
|
|
113
|
+
case Node3(existing, byte1, child1, byte2, child2, byte3, child3) =>
|
|
114
|
+
if (b == byte1) { child1.set(go(child1.get, i + 1)); trie }
|
|
115
|
+
else if (b == byte2) { child2.set(go(child2.get, i + 1)); trie }
|
|
116
|
+
else if (b == byte3) { child3.set(go(child3.get, i + 1)); trie }
|
|
117
|
+
else if (b.toInt < byte1.toInt) Node4(existing, b, ref(chain(i + 1)), byte1, child1, byte2, child2, byte3, child3)
|
|
118
|
+
else if (b.toInt < byte2.toInt) Node4(existing, byte1, child1, b, ref(chain(i + 1)), byte2, child2, byte3, child3)
|
|
119
|
+
else if (b.toInt < byte3.toInt) Node4(existing, byte1, child1, byte2, child2, b, ref(chain(i + 1)), byte3, child3)
|
|
120
|
+
else Node4(existing, byte1, child1, byte2, child2, byte3, child3, b, ref(chain(i + 1)))
|
|
121
|
+
|
|
122
|
+
case Branch4(byte1, child1, byte2, child2, byte3, child3, byte4, child4) =>
|
|
123
|
+
if (b == byte1) { child1.set(go(child1.get, i + 1)); trie }
|
|
124
|
+
else if (b == byte2) { child2.set(go(child2.get, i + 1)); trie }
|
|
125
|
+
else if (b == byte3) { child3.set(go(child3.get, i + 1)); trie }
|
|
126
|
+
else if (b == byte4) { child4.set(go(child4.get, i + 1)); trie }
|
|
127
|
+
else Branch256(densified(byte1, child1, byte2, child2, byte3, child3, byte4, child4, b, i))
|
|
128
|
+
case Node4(existing, byte1, child1, byte2, child2, byte3, child3, byte4, child4) =>
|
|
129
|
+
if (b == byte1) { child1.set(go(child1.get, i + 1)); trie }
|
|
130
|
+
else if (b == byte2) { child2.set(go(child2.get, i + 1)); trie }
|
|
131
|
+
else if (b == byte3) { child3.set(go(child3.get, i + 1)); trie }
|
|
132
|
+
else if (b == byte4) { child4.set(go(child4.get, i + 1)); trie }
|
|
133
|
+
else Node256(existing, densified(byte1, child1, byte2, child2, byte3, child3, byte4, child4, b, i))
|
|
134
|
+
|
|
135
|
+
case Branch256(children) =>
|
|
136
|
+
children.set(b.toInt, go(children.get(b.toInt), i + 1)); trie
|
|
137
|
+
case Node256(_, children) =>
|
|
138
|
+
children.set(b.toInt, go(children.get(b.toInt), i + 1)); trie
|
|
51
139
|
}
|
|
52
140
|
} else {
|
|
53
141
|
trie match {
|
|
54
142
|
case Empty() => Leaf(value)
|
|
55
143
|
case Leaf(_) => Leaf(value)
|
|
56
|
-
case
|
|
57
|
-
case
|
|
144
|
+
case Branch1(byte1, child1) => Node1(value, byte1, child1)
|
|
145
|
+
case Node1(_, byte1, child1) => Node1(value, byte1, child1)
|
|
146
|
+
case Branch2(byte1, child1, byte2, child2) => Node2(value, byte1, child1, byte2, child2)
|
|
147
|
+
case Node2(_, byte1, child1, byte2, child2) => Node2(value, byte1, child1, byte2, child2)
|
|
148
|
+
case Branch3(byte1, child1, byte2, child2, byte3, child3) => Node3(value, byte1, child1, byte2, child2, byte3, child3)
|
|
149
|
+
case Node3(_, byte1, child1, byte2, child2, byte3, child3) => Node3(value, byte1, child1, byte2, child2, byte3, child3)
|
|
150
|
+
case Branch4(byte1, child1, byte2, child2, byte3, child3, byte4, child4) => Node4(value, byte1, child1, byte2, child2, byte3, child3, byte4, child4)
|
|
151
|
+
case Node4(_, byte1, child1, byte2, child2, byte3, child3, byte4, child4) => Node4(value, byte1, child1, byte2, child2, byte3, child3, byte4, child4)
|
|
152
|
+
case Branch256(children) => Node256(value, children)
|
|
153
|
+
case Node256(_, children) => Node256(value, children)
|
|
58
154
|
}
|
|
59
155
|
}
|
|
60
156
|
dictionary.set(go(dictionary.get, 0))
|
|
@@ -68,18 +164,56 @@ def lookup[A](dictionary: Dictionary[A], key: String): Option[A] =
|
|
|
68
164
|
def lookup[A](dictionary: Dictionary[A], key: ByteArray): Option[A] = {
|
|
69
165
|
def go(trie: Trie[A], i: Int): Option[A] =
|
|
70
166
|
if (i < key.size) {
|
|
167
|
+
val b = key.get(i)
|
|
71
168
|
trie match {
|
|
72
169
|
case Empty() => None()
|
|
73
170
|
case Leaf(_) => None()
|
|
74
|
-
case
|
|
75
|
-
|
|
171
|
+
case Branch1(byte1, child1) =>
|
|
172
|
+
if (b == byte1) go(child1.get, i + 1) else None()
|
|
173
|
+
case Node1(_, byte1, child1) =>
|
|
174
|
+
if (b == byte1) go(child1.get, i + 1) else None()
|
|
175
|
+
case Branch2(byte1, child1, byte2, child2) =>
|
|
176
|
+
if (b == byte1) go(child1.get, i + 1)
|
|
177
|
+
else if (b == byte2) go(child2.get, i + 1)
|
|
178
|
+
else None()
|
|
179
|
+
case Node2(_, byte1, child1, byte2, child2) =>
|
|
180
|
+
if (b == byte1) go(child1.get, i + 1)
|
|
181
|
+
else if (b == byte2) go(child2.get, i + 1)
|
|
182
|
+
else None()
|
|
183
|
+
case Branch3(byte1, child1, byte2, child2, byte3, child3) =>
|
|
184
|
+
if (b == byte1) go(child1.get, i + 1)
|
|
185
|
+
else if (b == byte2) go(child2.get, i + 1)
|
|
186
|
+
else if (b == byte3) go(child3.get, i + 1)
|
|
187
|
+
else None()
|
|
188
|
+
case Node3(_, byte1, child1, byte2, child2, byte3, child3) =>
|
|
189
|
+
if (b == byte1) go(child1.get, i + 1)
|
|
190
|
+
else if (b == byte2) go(child2.get, i + 1)
|
|
191
|
+
else if (b == byte3) go(child3.get, i + 1)
|
|
192
|
+
else None()
|
|
193
|
+
case Branch4(byte1, child1, byte2, child2, byte3, child3, byte4, child4) =>
|
|
194
|
+
if (b == byte1) go(child1.get, i + 1)
|
|
195
|
+
else if (b == byte2) go(child2.get, i + 1)
|
|
196
|
+
else if (b == byte3) go(child3.get, i + 1)
|
|
197
|
+
else if (b == byte4) go(child4.get, i + 1)
|
|
198
|
+
else None()
|
|
199
|
+
case Node4(_, byte1, child1, byte2, child2, byte3, child3, byte4, child4) =>
|
|
200
|
+
if (b == byte1) go(child1.get, i + 1)
|
|
201
|
+
else if (b == byte2) go(child2.get, i + 1)
|
|
202
|
+
else if (b == byte3) go(child3.get, i + 1)
|
|
203
|
+
else if (b == byte4) go(child4.get, i + 1)
|
|
204
|
+
else None()
|
|
205
|
+
case Branch256(children) => go(children.get(b.toInt), i + 1)
|
|
206
|
+
case Node256(_, children) => go(children.get(b.toInt), i + 1)
|
|
76
207
|
}
|
|
77
208
|
} else {
|
|
78
209
|
trie match {
|
|
79
|
-
case Empty() => None()
|
|
80
210
|
case Leaf(value) => Some(value)
|
|
81
|
-
case
|
|
82
|
-
case
|
|
211
|
+
case Node1(value, _, _) => Some(value)
|
|
212
|
+
case Node2(value, _, _, _, _) => Some(value)
|
|
213
|
+
case Node3(value, _, _, _, _, _, _) => Some(value)
|
|
214
|
+
case Node4(value, _, _, _, _, _, _, _, _) => Some(value)
|
|
215
|
+
case Node256(value, _) => Some(value)
|
|
216
|
+
case _ => None()
|
|
83
217
|
}
|
|
84
218
|
}
|
|
85
219
|
go(dictionary.get, 0)
|
|
@@ -87,48 +221,104 @@ def lookup[A](dictionary: Dictionary[A], key: ByteArray): Option[A] = {
|
|
|
87
221
|
|
|
88
222
|
/// Collect key-value pairs from a stream of Tagged elements into a fresh Dictionary.
|
|
89
223
|
def collect[A] { stream: () => Unit / emit[Tagged[A]] }: Dictionary[A] = {
|
|
90
|
-
val dictionary =
|
|
224
|
+
val dictionary = empty[A]()
|
|
91
225
|
for[Tagged[A]] { stream() } { case Tagged(bytes, value) =>
|
|
92
226
|
dictionary.insert(bytes, value)
|
|
93
227
|
}
|
|
94
|
-
|
|
228
|
+
dictionary
|
|
95
229
|
}
|
|
96
230
|
|
|
97
|
-
/// Emit all values stored in the dictionary as a push stream
|
|
231
|
+
/// Emit all values stored in the dictionary as a push stream,
|
|
232
|
+
/// in lexicographic key order (a key before its extensions).
|
|
98
233
|
def each[A](dictionary: Dictionary[A]): Unit / emit[A] = {
|
|
99
234
|
def go(trie: Trie[A]): Unit / emit[A] =
|
|
100
235
|
trie match {
|
|
101
236
|
case Empty() => ()
|
|
102
237
|
case Leaf(value) => do emit(value)
|
|
103
|
-
case
|
|
104
|
-
|
|
105
|
-
|
|
238
|
+
case Branch1(_, child1) => go(child1.get)
|
|
239
|
+
case Node1(value, _, child1) =>
|
|
240
|
+
do emit(value); go(child1.get)
|
|
241
|
+
case Branch2(_, child1, _, child2) =>
|
|
242
|
+
go(child1.get); go(child2.get)
|
|
243
|
+
case Node2(value, _, child1, _, child2) =>
|
|
244
|
+
do emit(value); go(child1.get); go(child2.get)
|
|
245
|
+
case Branch3(_, child1, _, child2, _, child3) =>
|
|
246
|
+
go(child1.get); go(child2.get); go(child3.get)
|
|
247
|
+
case Node3(value, _, child1, _, child2, _, child3) =>
|
|
248
|
+
do emit(value); go(child1.get); go(child2.get); go(child3.get)
|
|
249
|
+
case Branch4(_, child1, _, child2, _, child3, _, child4) =>
|
|
250
|
+
go(child1.get); go(child2.get); go(child3.get); go(child4.get)
|
|
251
|
+
case Node4(value, _, child1, _, child2, _, child3, _, child4) =>
|
|
252
|
+
do emit(value); go(child1.get); go(child2.get); go(child3.get); go(child4.get)
|
|
253
|
+
case Branch256(children) =>
|
|
254
|
+
each(0, 256) { i => go(children.get(i)) }
|
|
255
|
+
case Node256(value, children) =>
|
|
106
256
|
do emit(value)
|
|
107
|
-
each(0,
|
|
257
|
+
each(0, 256) { i => go(children.get(i)) }
|
|
108
258
|
}
|
|
109
259
|
go(dictionary.get)
|
|
110
260
|
}
|
|
111
261
|
|
|
112
|
-
/// Emit all key-value pairs stored in the dictionary as a push stream of
|
|
262
|
+
/// Emit all key-value pairs stored in the dictionary as a push stream of
|
|
263
|
+
/// Tagged elements, in lexicographic key order (a key before its extensions).
|
|
113
264
|
def eachTagged[A](dictionary: Dictionary[A]): Unit / emit[Tagged[A]] = {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
265
|
+
var buffer = bytearray::allocate(32)
|
|
266
|
+
// `depth` grows by exactly one per level, so `depth <= buffer.size` always
|
|
267
|
+
// holds and a single doubling suffices.
|
|
268
|
+
def push(depth: Int, b: Byte): Unit = {
|
|
269
|
+
if (depth >= buffer.size) {
|
|
270
|
+
buffer = buffer.resize(buffer.size * 2)
|
|
271
|
+
}
|
|
272
|
+
buffer.set(depth, b)
|
|
118
273
|
}
|
|
119
|
-
def
|
|
274
|
+
def emitAt(depth: Int, value: A): Unit = {
|
|
275
|
+
val key = bytearray::allocate(depth)
|
|
276
|
+
// safe: `key` has exactly `depth` bytes, and `depth` is within `buffer`'s capacity.
|
|
277
|
+
bytearray::unsafeCopy(buffer, 0, key, 0, depth)
|
|
278
|
+
do emit(Tagged(key, value))
|
|
279
|
+
}
|
|
280
|
+
def go(trie: Trie[A], depth: Int): Unit =
|
|
120
281
|
trie match {
|
|
121
282
|
case Empty() => ()
|
|
122
|
-
case Leaf(value) =>
|
|
123
|
-
case
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
283
|
+
case Leaf(value) => emitAt(depth, value)
|
|
284
|
+
case Branch1(byte1, child1) =>
|
|
285
|
+
push(depth, byte1); go(child1.get, depth + 1)
|
|
286
|
+
case Node1(value, byte1, child1) =>
|
|
287
|
+
emitAt(depth, value)
|
|
288
|
+
push(depth, byte1); go(child1.get, depth + 1)
|
|
289
|
+
case Branch2(byte1, child1, byte2, child2) =>
|
|
290
|
+
push(depth, byte1); go(child1.get, depth + 1)
|
|
291
|
+
push(depth, byte2); go(child2.get, depth + 1)
|
|
292
|
+
case Node2(value, byte1, child1, byte2, child2) =>
|
|
293
|
+
emitAt(depth, value)
|
|
294
|
+
push(depth, byte1); go(child1.get, depth + 1)
|
|
295
|
+
push(depth, byte2); go(child2.get, depth + 1)
|
|
296
|
+
case Branch3(byte1, child1, byte2, child2, byte3, child3) =>
|
|
297
|
+
push(depth, byte1); go(child1.get, depth + 1)
|
|
298
|
+
push(depth, byte2); go(child2.get, depth + 1)
|
|
299
|
+
push(depth, byte3); go(child3.get, depth + 1)
|
|
300
|
+
case Node3(value, byte1, child1, byte2, child2, byte3, child3) =>
|
|
301
|
+
emitAt(depth, value)
|
|
302
|
+
push(depth, byte1); go(child1.get, depth + 1)
|
|
303
|
+
push(depth, byte2); go(child2.get, depth + 1)
|
|
304
|
+
push(depth, byte3); go(child3.get, depth + 1)
|
|
305
|
+
case Branch4(byte1, child1, byte2, child2, byte3, child3, byte4, child4) =>
|
|
306
|
+
push(depth, byte1); go(child1.get, depth + 1)
|
|
307
|
+
push(depth, byte2); go(child2.get, depth + 1)
|
|
308
|
+
push(depth, byte3); go(child3.get, depth + 1)
|
|
309
|
+
push(depth, byte4); go(child4.get, depth + 1)
|
|
310
|
+
case Node4(value, byte1, child1, byte2, child2, byte3, child3, byte4, child4) =>
|
|
311
|
+
emitAt(depth, value)
|
|
312
|
+
push(depth, byte1); go(child1.get, depth + 1)
|
|
313
|
+
push(depth, byte2); go(child2.get, depth + 1)
|
|
314
|
+
push(depth, byte3); go(child3.get, depth + 1)
|
|
315
|
+
push(depth, byte4); go(child4.get, depth + 1)
|
|
316
|
+
case Branch256(children) =>
|
|
317
|
+
each(0, 256) { i => push(depth, i.toByte); go(children.get(i), depth + 1) }
|
|
318
|
+
case Node256(value, children) =>
|
|
319
|
+
emitAt(depth, value)
|
|
320
|
+
each(0, 256) { i => push(depth, i.toByte); go(children.get(i), depth + 1) }
|
|
132
321
|
}
|
|
133
|
-
go(dictionary.get,
|
|
134
|
-
}
|
|
322
|
+
go(dictionary.get, 0)
|
|
323
|
+
}
|
|
324
|
+
|
|
@@ -72,7 +72,7 @@ extern def readln() at async: String =
|
|
|
72
72
|
jsNode "$effekt.capture(callback => $effekt.readln(callback))"
|
|
73
73
|
llvm """
|
|
74
74
|
%result = call %Pos @c_io_readln()
|
|
75
|
-
|
|
75
|
+
notail call void @resume_Pos(%Stack %stack, %Pos %result)
|
|
76
76
|
ret void
|
|
77
77
|
"""
|
|
78
78
|
|
|
@@ -245,49 +245,49 @@ namespace internal {
|
|
|
245
245
|
extern def openForReading(path: String) at async: Int =
|
|
246
246
|
jsNode "$effekt.capture(callback => open(${path}, 'r', callback))"
|
|
247
247
|
llvm """
|
|
248
|
-
call void @c_fs_open_reading(%Pos ${path}, %Stack %stack)
|
|
248
|
+
notail call void @c_fs_open_reading(%Pos ${path}, %Stack %stack)
|
|
249
249
|
ret void
|
|
250
250
|
"""
|
|
251
251
|
|
|
252
252
|
extern def openForWriting(path: String) at async: Int =
|
|
253
253
|
jsNode "$effekt.capture(callback => open(${path}, 'w', callback))"
|
|
254
254
|
llvm """
|
|
255
|
-
call void @c_fs_open_writing(%Pos ${path}, %Stack %stack)
|
|
255
|
+
notail call void @c_fs_open_writing(%Pos ${path}, %Stack %stack)
|
|
256
256
|
ret void
|
|
257
257
|
"""
|
|
258
258
|
|
|
259
259
|
extern def openForAppending(path: String) at async: Int =
|
|
260
260
|
jsNode "$effekt.capture(callback => open(${path}, 'a', callback))"
|
|
261
261
|
llvm """
|
|
262
|
-
call void @c_fs_open_appending(%Pos ${path}, %Stack %stack)
|
|
262
|
+
notail call void @c_fs_open_appending(%Pos ${path}, %Stack %stack)
|
|
263
263
|
ret void
|
|
264
264
|
"""
|
|
265
265
|
|
|
266
266
|
extern def read(file: Int, buffer: ByteArray, offset: Int, size: Int, position: Int) at async: Int =
|
|
267
267
|
jsNode "$effekt.capture(callback => read(${file}, ${buffer}, ${offset}, ${size}, ${position}, callback))"
|
|
268
268
|
llvm """
|
|
269
|
-
call void @c_fs_read(%Int ${file}, %Pos ${buffer}, %Int ${offset}, %Int ${size}, %Int ${position}, %Stack %stack)
|
|
269
|
+
notail call void @c_fs_read(%Int ${file}, %Pos ${buffer}, %Int ${offset}, %Int ${size}, %Int ${position}, %Stack %stack)
|
|
270
270
|
ret void
|
|
271
271
|
"""
|
|
272
272
|
|
|
273
273
|
extern def write(file: Int, buffer: ByteArray, offset: Int, size: Int, position: Int) at async: Int =
|
|
274
274
|
jsNode "$effekt.capture(callback => write(${file}, ${buffer}, ${offset}, ${size}, ${position}, callback))"
|
|
275
275
|
llvm """
|
|
276
|
-
call void @c_fs_write(%Int ${file}, %Pos ${buffer}, %Int ${offset}, %Int ${size}, %Int ${position}, %Stack %stack)
|
|
276
|
+
notail call void @c_fs_write(%Int ${file}, %Pos ${buffer}, %Int ${offset}, %Int ${size}, %Int ${position}, %Stack %stack)
|
|
277
277
|
ret void
|
|
278
278
|
"""
|
|
279
279
|
|
|
280
280
|
extern def close(file: Int) at async: Int =
|
|
281
281
|
jsNode "$effekt.capture(callback => close(${file}, callback))"
|
|
282
282
|
llvm """
|
|
283
|
-
call void @c_fs_close(%Int ${file}, %Stack %stack)
|
|
283
|
+
notail call void @c_fs_close(%Int ${file}, %Stack %stack)
|
|
284
284
|
ret void
|
|
285
285
|
"""
|
|
286
286
|
|
|
287
287
|
extern def mkdir(path: String) at async: Int =
|
|
288
288
|
jsNode "$effekt.capture(callback => mkdir(${path}, callback))"
|
|
289
289
|
llvm """
|
|
290
|
-
call void @c_fs_mkdir(%Pos ${path}, %Stack %stack)
|
|
290
|
+
notail call void @c_fs_mkdir(%Pos ${path}, %Stack %stack)
|
|
291
291
|
ret void
|
|
292
292
|
"""
|
|
293
293
|
|
|
@@ -147,28 +147,28 @@ namespace internal {
|
|
|
147
147
|
extern def connect(host: String, port: Int) at async: Int =
|
|
148
148
|
jsNode "$effekt.capture(k => tcp$connect(${host}, ${port}, k))"
|
|
149
149
|
llvm """
|
|
150
|
-
call void @c_tcp_connect(%Pos ${host}, %Int ${port}, %Stack %stack)
|
|
150
|
+
notail call void @c_tcp_connect(%Pos ${host}, %Int ${port}, %Stack %stack)
|
|
151
151
|
ret void
|
|
152
152
|
"""
|
|
153
153
|
|
|
154
154
|
extern def read(handle: Int, buffer: ByteArray, offset: Int, size: Int) at async: Int =
|
|
155
155
|
jsNode "$effekt.capture(k => tcp$read(${handle}, ${buffer}, ${offset}, ${size}, k))"
|
|
156
156
|
llvm """
|
|
157
|
-
call void @c_tcp_read(%Int ${handle}, %Pos ${buffer}, %Int ${offset}, %Int ${size}, %Stack %stack)
|
|
157
|
+
notail call void @c_tcp_read(%Int ${handle}, %Pos ${buffer}, %Int ${offset}, %Int ${size}, %Stack %stack)
|
|
158
158
|
ret void
|
|
159
159
|
"""
|
|
160
160
|
|
|
161
161
|
extern def write(handle: Int, buffer: ByteArray, offset: Int, size: Int) at async: Int =
|
|
162
162
|
jsNode "$effekt.capture(k => tcp$write(${handle}, ${buffer}, ${offset}, ${size}, k))"
|
|
163
163
|
llvm """
|
|
164
|
-
call void @c_tcp_write(%Int ${handle}, %Pos ${buffer}, %Int ${offset}, %Int ${size}, %Stack %stack)
|
|
164
|
+
notail call void @c_tcp_write(%Int ${handle}, %Pos ${buffer}, %Int ${offset}, %Int ${size}, %Stack %stack)
|
|
165
165
|
ret void
|
|
166
166
|
"""
|
|
167
167
|
|
|
168
168
|
extern def close(handle: Int) at async: Unit =
|
|
169
169
|
jsNode "$effekt.capture(k => tcp$close(${handle}, k))"
|
|
170
170
|
llvm """
|
|
171
|
-
call void @c_tcp_close(%Int ${handle}, %Stack %stack)
|
|
171
|
+
notail call void @c_tcp_close(%Int ${handle}, %Stack %stack)
|
|
172
172
|
ret void
|
|
173
173
|
"""
|
|
174
174
|
|
|
@@ -182,14 +182,14 @@ namespace internal {
|
|
|
182
182
|
extern def listen(listener: Int, handler: Connection => Unit at {io, async, global}) at async: Int =
|
|
183
183
|
jsNode "$effekt.capture(k => tcp$listen(${listener}, ${handler}, k))"
|
|
184
184
|
llvm """
|
|
185
|
-
call void @c_tcp_listen(%Int ${listener}, %
|
|
185
|
+
notail call void @c_tcp_listen(%Int ${listener}, %Neg ${handler}, %Stack %stack)
|
|
186
186
|
ret void
|
|
187
187
|
"""
|
|
188
188
|
|
|
189
189
|
extern def shutdown(handle: Int) at async: Unit =
|
|
190
190
|
jsNode "$effekt.capture(k => tcp$shutdown(${handle}, k))"
|
|
191
191
|
llvm """
|
|
192
|
-
call void @c_tcp_shutdown(%Int ${handle}, %Stack %stack)
|
|
192
|
+
notail call void @c_tcp_shutdown(%Int ${handle}, %Stack %stack)
|
|
193
193
|
ret void
|
|
194
194
|
"""
|
|
195
195
|
|
|
@@ -74,18 +74,18 @@ extern def fire[A, B](signal: Signal[A, B], value: A) at async: B =
|
|
|
74
74
|
store i64 2, ptr %statePtr
|
|
75
75
|
store %Stack %stack, ptr %stackPtr
|
|
76
76
|
store %Pos ${value}, ptr %valuePtr
|
|
77
|
-
call void @erasePositive(%Pos ${signal})
|
|
77
|
+
notail call void @erasePositive(%Pos ${signal})
|
|
78
78
|
ret void
|
|
79
79
|
fire:
|
|
80
80
|
%otherStack = load %Stack, ptr %stackPtr
|
|
81
81
|
%otherValue = load %Pos, ptr %valuePtr
|
|
82
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)
|
|
83
|
+
notail call void @erasePositive(%Pos ${signal})
|
|
84
|
+
notail call void @resume_Pos(%Stack %otherStack, %Pos ${value})
|
|
85
|
+
notail call void @resume_Pos(%Stack %stack, %Pos %otherValue)
|
|
86
86
|
ret void
|
|
87
87
|
panic:
|
|
88
|
-
call void @exit(
|
|
88
|
+
notail call void @exit(i32 1)
|
|
89
89
|
ret void
|
|
90
90
|
"""
|
|
91
91
|
|
|
@@ -102,18 +102,18 @@ extern def wait[A, B](signal: Signal[A, B], value: B) at async: A =
|
|
|
102
102
|
store i64 1, ptr %statePtr
|
|
103
103
|
store %Stack %stack, ptr %stackPtr
|
|
104
104
|
store %Pos ${value}, ptr %valuePtr
|
|
105
|
-
call void @erasePositive(%Pos ${signal})
|
|
105
|
+
notail call void @erasePositive(%Pos ${signal})
|
|
106
106
|
ret void
|
|
107
107
|
wait:
|
|
108
108
|
%otherStack = load %Stack, ptr %stackPtr
|
|
109
109
|
%otherValue = load %Pos, ptr %valuePtr
|
|
110
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)
|
|
111
|
+
notail call void @erasePositive(%Pos ${signal})
|
|
112
|
+
notail call void @resume_Pos(%Stack %otherStack, %Pos ${value})
|
|
113
|
+
notail call void @resume_Pos(%Stack %stack, %Pos %otherValue)
|
|
114
114
|
ret void
|
|
115
115
|
panic:
|
|
116
|
-
call void @exit(
|
|
116
|
+
notail call void @exit(i32 1)
|
|
117
117
|
ret void
|
|
118
118
|
"""
|
|
119
119
|
|
|
@@ -7,6 +7,6 @@ extern llvm """
|
|
|
7
7
|
extern def sleep(millis: Int) at async: Unit =
|
|
8
8
|
js "$effekt.capture(k => setTimeout(() => k($effekt.unit), ${millis}))"
|
|
9
9
|
llvm """
|
|
10
|
-
call void @c_timer_start(%Int ${millis}, %Stack %stack)
|
|
10
|
+
notail call void @c_timer_start(%Int ${millis}, %Stack %stack)
|
|
11
11
|
ret void
|
|
12
12
|
"""
|
|
@@ -11,22 +11,22 @@ extern llvm """
|
|
|
11
11
|
extern def spawn[T](task: () => T at {io, async, global}) at async: Unit =
|
|
12
12
|
js "$effekt.capture(k => { setTimeout(() => k($effekt.unit), 0); return $effekt.run(${task}) })"
|
|
13
13
|
llvm """
|
|
14
|
-
call void @c_yield(%Stack %stack)
|
|
15
|
-
call void @run(%
|
|
14
|
+
notail call void @c_yield(%Stack %stack)
|
|
15
|
+
notail call void @run(%Neg ${task})
|
|
16
16
|
ret void
|
|
17
17
|
"""
|
|
18
18
|
|
|
19
19
|
extern def yield() at async: Unit =
|
|
20
20
|
js "$effekt.capture(k => setTimeout(() => k($effekt.unit), 0))"
|
|
21
21
|
llvm """
|
|
22
|
-
call void @c_yield(%Stack %stack)
|
|
22
|
+
notail call void @c_yield(%Stack %stack)
|
|
23
23
|
ret void
|
|
24
24
|
"""
|
|
25
25
|
|
|
26
26
|
extern def abort() at async: Nothing =
|
|
27
27
|
js "$effekt.capture(k => undefined)"
|
|
28
28
|
llvm """
|
|
29
|
-
call void @eraseStack(%Stack %stack)
|
|
29
|
+
notail call void @eraseStack(%Stack %stack)
|
|
30
30
|
ret void
|
|
31
31
|
"""
|
|
32
32
|
|