@effekt-lang/effekt 0.66.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/common/args.effekt +2 -2
- package/libraries/common/array.effekt +8 -5
- package/libraries/common/bytearray.effekt +7 -7
- 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 +12 -2
- package/libraries/common/io/channel.effekt +2 -2
- 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 +3 -7
- package/libraries/llvm/io.c +0 -55
- package/licenses/eclipse public license, version 2.0 - epl-2.0.html +2 -2
- package/licenses/mit license - mit-license.html +33 -31
- package/licenses/the bsd license - bsd-license.html +32 -30
- package/licenses/the mit license - mit.html +33 -31
- package/package.json +1 -1
package/bin/effekt
CHANGED
|
Binary file
|
|
@@ -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
|
|
@@ -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
|
|
@@ -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,8 +136,8 @@ extern def panic(msg: String) at io: Nothing =
|
|
|
135
136
|
"""
|
|
136
137
|
|
|
137
138
|
extern def show[R](value: R) at {}: String =
|
|
138
|
-
js "
|
|
139
|
-
chez "(
|
|
139
|
+
js "undefined"
|
|
140
|
+
chez "(void)"
|
|
140
141
|
llvm "ret %Pos poison"
|
|
141
142
|
|
|
142
143
|
extern def genericShow[R](value: R) at {}: String =
|
|
@@ -746,6 +747,15 @@ extern def isUndefined[A](value: A) at {}: Bool =
|
|
|
746
747
|
chez "(eq? ${value} #f)"
|
|
747
748
|
vm "effekt::isUndefined[A](A)"
|
|
748
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 {}
|
|
749
759
|
|
|
750
760
|
// Tuples
|
|
751
761
|
// ======
|
|
@@ -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.
|
|
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.
|
|
54
|
+
this.wait(value)
|
|
55
55
|
}
|
|
56
56
|
|
|
57
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
|
|
|
@@ -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
|
|
11
|
-
|
|
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
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
+
|
|
@@ -90,40 +90,6 @@ def encodeJson[R]{ body: => R / JsonBuilder }: R / emit[String] = {
|
|
|
90
90
|
// --------------------------------------------------------------------------------
|
|
91
91
|
|
|
92
92
|
|
|
93
|
-
/// Read a double value, in the common format (TODO document)
|
|
94
|
-
def readDouble(): Double / { Scan[Char], Exception[WrongFormat]} = {
|
|
95
|
-
def exponent(pre: Double): Double / fail = {
|
|
96
|
-
try {
|
|
97
|
-
if(do peek() == 'e' || do peek() == 'E') {
|
|
98
|
-
skip[Char]()
|
|
99
|
-
val e = do peek[Char]() match {
|
|
100
|
-
case '+' => skip[Char](); readDecimal()
|
|
101
|
-
case '-' => skip[Char](); neg(readDecimal())
|
|
102
|
-
case _ => readDecimal()
|
|
103
|
-
}
|
|
104
|
-
pre * pow(10.0, e)
|
|
105
|
-
} else { pre }
|
|
106
|
-
} with stop {
|
|
107
|
-
pre
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
def fraction(pre: Int): Double / fail = {
|
|
111
|
-
if (succeeds { must { readIf('.') } }) {
|
|
112
|
-
var b = 0.1
|
|
113
|
-
var r = pre.toDouble
|
|
114
|
-
while (optionally[Int] { must { readDigit() } } is Some(d)) {
|
|
115
|
-
r = r + b * d.toDouble
|
|
116
|
-
b = b * 0.1
|
|
117
|
-
}
|
|
118
|
-
exponent(r)
|
|
119
|
-
} else {
|
|
120
|
-
pre.toDouble
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
with returning::expect("Expected double")
|
|
124
|
-
fraction(readInteger())
|
|
125
|
-
}
|
|
126
|
-
|
|
127
93
|
def expectString(string: String): Unit / { Scan[Char], Exception[WrongFormat] } =
|
|
128
94
|
expect("Expected " ++ string) { readString(string) }
|
|
129
95
|
|
|
@@ -133,9 +99,9 @@ def readQuotedString(): Unit / { Scan[Char], emit[Char], Exception[WrongFormat]
|
|
|
133
99
|
with expect("Unexpected end of input while reading a string")
|
|
134
100
|
skipWhitespace()
|
|
135
101
|
expect("Expected \"") { must { readIf('"') } }
|
|
136
|
-
while(must { do
|
|
102
|
+
while(must { do next[Char]() } is c and c != '"') {
|
|
137
103
|
c match {
|
|
138
|
-
case '\\' => must { do
|
|
104
|
+
case '\\' => must { do next[Char]() } match {
|
|
139
105
|
case '"' => do emit('\"')
|
|
140
106
|
case '\\' => do emit('\\')
|
|
141
107
|
case '/' => do emit('/')
|
|
@@ -159,8 +125,8 @@ def decodeJson(): Unit / {Scan[Char], JsonBuilder, Exception[WrongFormat]} = {
|
|
|
159
125
|
case 'n' => expectString("null"); do null()
|
|
160
126
|
case 't' => expectString("true"); do bool(true)
|
|
161
127
|
case 'f' => expectString("false"); do bool(false)
|
|
162
|
-
case '-' => do number(readDouble())
|
|
163
|
-
case d and d.isDigit => do number(readDouble())
|
|
128
|
+
case '-' => do number(returning::expect("Expected double") { readDouble() })
|
|
129
|
+
case d and d.isDigit => do number(returning::expect("Expected double") { readDouble() })
|
|
164
130
|
case '"' => do string(collect { readQuotedString() })
|
|
165
131
|
case '{' => do dict{ decodeJsonObject() }
|
|
166
132
|
case '[' => do list{ decodeJsonList() }
|
|
@@ -310,15 +276,23 @@ namespace test {
|
|
|
310
276
|
|
|
311
277
|
// Read quoted string
|
|
312
278
|
feed("\"\ta\n\ra\"") {
|
|
313
|
-
with
|
|
279
|
+
with peeking[Char]
|
|
314
280
|
println(string::collect { readQuotedString() })
|
|
315
281
|
}
|
|
316
282
|
|
|
317
283
|
println("")
|
|
318
284
|
|
|
285
|
+
feed("-1.5") {
|
|
286
|
+
with peeking[Char]
|
|
287
|
+
with on[WrongFormat].report
|
|
288
|
+
println(returning::expect("Expected double") { readDouble() })
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
println("")
|
|
292
|
+
|
|
319
293
|
// Parse example
|
|
320
294
|
feed("""{ "a": null, "b": [true,false,false,true], "f": 12.532 }"""){
|
|
321
|
-
with
|
|
295
|
+
with peeking[Char]
|
|
322
296
|
|
|
323
297
|
def k = new JsonObjectBuilder {
|
|
324
298
|
def field[T](k){v} = { println(k); ignore{v} }
|
|
@@ -362,7 +336,7 @@ namespace test {
|
|
|
362
336
|
"a": null,
|
|
363
337
|
"b": [true, false, false, true], "f": 12.532
|
|
364
338
|
} """){
|
|
365
|
-
with returning::
|
|
339
|
+
with returning::peeking[Char, JsonValue]
|
|
366
340
|
build {
|
|
367
341
|
decodeJson()
|
|
368
342
|
}.second
|
|
@@ -379,7 +353,7 @@ namespace test {
|
|
|
379
353
|
"a": null,
|
|
380
354
|
"b": [true, false, false, true], "f": 12.532
|
|
381
355
|
} """){
|
|
382
|
-
with
|
|
356
|
+
with peeking[Char]
|
|
383
357
|
decodeJson()
|
|
384
358
|
}
|
|
385
359
|
}
|