@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
|
@@ -974,12 +974,12 @@ def tails[A](list: List[A]): Unit / emit[List[A]] =
|
|
|
974
974
|
case Cons(head, tail) => do emit(list); tails(tail)
|
|
975
975
|
}
|
|
976
976
|
|
|
977
|
-
/// Connects `list` as a producer to a given pull stream `
|
|
978
|
-
def feed[T, R](list: List[T]) {
|
|
977
|
+
/// Connects `list` as a producer to a given pull stream `driver` acting as a consumer.
|
|
978
|
+
def feed[T, R](list: List[T]) { driver: () => R / next[T] }: R = {
|
|
979
979
|
var l = list
|
|
980
980
|
try {
|
|
981
|
-
|
|
982
|
-
} with
|
|
981
|
+
driver()
|
|
982
|
+
} with next[T] {
|
|
983
983
|
resume {
|
|
984
984
|
l match {
|
|
985
985
|
case Nil() => do stop()
|
|
@@ -25,7 +25,9 @@ extern llvm """
|
|
|
25
25
|
declare %Pos @c_spawn(%Pos, %Pos, %Pos)
|
|
26
26
|
"""
|
|
27
27
|
|
|
28
|
-
extern type SpawnOptions
|
|
28
|
+
extern type SpawnOptions =
|
|
29
|
+
jsNode "{ stdio: list[int], onSpawn: fn => {} }"
|
|
30
|
+
llvm "%Pos"
|
|
29
31
|
extern def default() at {}: SpawnOptions =
|
|
30
32
|
jsNode """{ stdio: [0,1,2], onSpawn: (p) => {} }"""
|
|
31
33
|
llvm """
|
|
@@ -64,7 +66,9 @@ extern def onStderr(opts: SpawnOptions, callback: String => Unit at {io, global}
|
|
|
64
66
|
%opts = call %Pos @c_spawn_options_on_stderr(%Pos ${opts}, %Pos ${callback})
|
|
65
67
|
ret %Pos %opts
|
|
66
68
|
"""
|
|
67
|
-
extern type WritableStream
|
|
69
|
+
extern type WritableStream =
|
|
70
|
+
jsNode "stream.Writable"
|
|
71
|
+
llvm "%Pos"
|
|
68
72
|
extern def withStdin(opts: SpawnOptions, callback: WritableStream => Unit at {io, global}) at {}: SpawnOptions =
|
|
69
73
|
jsNode """(function () {
|
|
70
74
|
let old = ${opts};
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
module random
|
|
2
2
|
|
|
3
3
|
import stream
|
|
4
|
+
import array
|
|
5
|
+
import option
|
|
6
|
+
import exception
|
|
4
7
|
import io/filesystem
|
|
5
8
|
import io/error
|
|
6
9
|
|
|
@@ -38,7 +41,7 @@ def minstd(seed: Int): Unit / emit[Byte] = {
|
|
|
38
41
|
if (result < 0) result + m else result
|
|
39
42
|
}
|
|
40
43
|
|
|
41
|
-
|
|
44
|
+
forever {
|
|
42
45
|
state = nextInt()
|
|
43
46
|
val b = state.mod(256).toByte
|
|
44
47
|
do emit(b)
|
|
@@ -73,7 +76,7 @@ def devurandom { randomnessReader: () => Unit / random }: Unit / Exception[IOErr
|
|
|
73
76
|
try {
|
|
74
77
|
with readFile("/dev/urandom")
|
|
75
78
|
try randomnessReader() with random {
|
|
76
|
-
resume(do
|
|
79
|
+
resume(do next())
|
|
77
80
|
}
|
|
78
81
|
} with stop {
|
|
79
82
|
do raise(io::error::EOF(), "Unexpected EOF when reading /dev/urandom!")
|
|
@@ -88,14 +91,14 @@ def devurandom { randomnessReader: () => Unit / random }: Unit / Exception[IOErr
|
|
|
88
91
|
|
|
89
92
|
def randomByte(): Byte / random = do random()
|
|
90
93
|
def randomBytes(): Unit / {emit[Byte], random} =
|
|
91
|
-
|
|
94
|
+
forever { do emit(do random()) }
|
|
92
95
|
|
|
93
96
|
def randomBool(): Bool / random = {
|
|
94
97
|
val b = do random()
|
|
95
98
|
b.toInt.mod(2) == 1
|
|
96
99
|
}
|
|
97
100
|
def randomBools(): Unit / {emit[Bool], random} =
|
|
98
|
-
|
|
101
|
+
forever { do emit(randomBool()) }
|
|
99
102
|
|
|
100
103
|
def randomInt32(): Int / random = {
|
|
101
104
|
var result = 0
|
|
@@ -107,7 +110,7 @@ def randomInt32(): Int / random = {
|
|
|
107
110
|
result.mod(1.bitwiseShl(31)).abs * if (signBit) 1 else -1
|
|
108
111
|
}
|
|
109
112
|
def randomInt32s(): Unit / {emit[Int], random} =
|
|
110
|
-
|
|
113
|
+
forever { do emit(randomInt32()) }
|
|
111
114
|
|
|
112
115
|
/// `max` is _inclusive_!
|
|
113
116
|
def randomInt(min: Int, max: Int): Int / random = {
|
|
@@ -126,9 +129,10 @@ def randomInt(min: Int, max: Int): Int / random = {
|
|
|
126
129
|
min + (abs(result).mod(range))
|
|
127
130
|
}
|
|
128
131
|
}
|
|
132
|
+
|
|
129
133
|
/// `max` is _inclusive_!
|
|
130
134
|
def randomInts(min: Int, max: Int): Unit / {emit[Int], random} =
|
|
131
|
-
|
|
135
|
+
forever { do emit(randomInt(min, max)) }
|
|
132
136
|
|
|
133
137
|
|
|
134
138
|
/// Random double between 0.0 and 1.0
|
|
@@ -136,7 +140,25 @@ def randomDouble(): Double / random =
|
|
|
136
140
|
(randomInt32().toDouble / 1.bitwiseShl(31).toDouble).abs
|
|
137
141
|
// This is not perfect, but it will do for now.
|
|
138
142
|
def randomDoubles(): Unit / {emit[Double], random} =
|
|
139
|
-
|
|
143
|
+
forever { do emit(randomDouble()) }
|
|
144
|
+
|
|
145
|
+
/// Shuffle an array in-place using the Fisher-Yates algorithm.
|
|
146
|
+
def shuffle[A](arr: Array[A]): Unit / random = {
|
|
147
|
+
val n = arr.size
|
|
148
|
+
each(0, n - 1) { i =>
|
|
149
|
+
arr.swap(i, randomInt(i, n - 1))
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/// Pick a random element from an array.
|
|
154
|
+
///
|
|
155
|
+
/// Panics when called on an empty array.
|
|
156
|
+
def pick[A](arr: Array[A]): A / random =
|
|
157
|
+
if (arr.size == 0) {
|
|
158
|
+
panic("Pick from an empty array")
|
|
159
|
+
} else {
|
|
160
|
+
arr.get(randomInt(0, arr.size - 1))
|
|
161
|
+
}
|
|
140
162
|
|
|
141
163
|
|
|
142
164
|
namespace examples {
|
|
@@ -18,7 +18,10 @@ define void @c_ref_erase_field(ptr %0) {
|
|
|
18
18
|
"""
|
|
19
19
|
|
|
20
20
|
/// Global, mutable references
|
|
21
|
-
extern type Ref[T]
|
|
21
|
+
extern type Ref[T] =
|
|
22
|
+
js "{ value: T }"
|
|
23
|
+
chez "box"
|
|
24
|
+
llvm "%Pos"
|
|
22
25
|
|
|
23
26
|
/** We represent references like positive types in LLVM
|
|
24
27
|
* The tag is 0 and the obj points to memory with the following layout:
|
|
@@ -4,7 +4,9 @@ import string
|
|
|
4
4
|
|
|
5
5
|
extern include chez "text/pregexp.scm"
|
|
6
6
|
|
|
7
|
-
extern type Regex
|
|
7
|
+
extern type Regex =
|
|
8
|
+
js "RegExp"
|
|
9
|
+
chez "pregexp"
|
|
8
10
|
|
|
9
11
|
record Match(matched: String, index: Int)
|
|
10
12
|
|
|
@@ -25,9 +27,9 @@ namespace internal {
|
|
|
25
27
|
|
|
26
28
|
/// The type RegexMatch is used internally to represent platform
|
|
27
29
|
/// dependent results of matching a regex.
|
|
28
|
-
extern type RegexMatch
|
|
29
|
-
|
|
30
|
-
|
|
30
|
+
extern type RegexMatch =
|
|
31
|
+
js "{ matched: String, index: Int } | undefined"
|
|
32
|
+
vm "scala.util.matching.Regex.Match | null"
|
|
31
33
|
|
|
32
34
|
extern def matched(r: RegexMatch) at {}: String =
|
|
33
35
|
js "${r}.matched"
|
|
@@ -224,12 +224,12 @@ def each[T](arr: ResizableArray[T]): Unit / emit[T] =
|
|
|
224
224
|
do emit(arr.rawContentPtr.get.get(i))
|
|
225
225
|
}
|
|
226
226
|
|
|
227
|
-
/// Connects `arr` as a producer to a given pull stream `
|
|
228
|
-
def feed[R, T](arr: ResizableArray[T]) {
|
|
227
|
+
/// Connects `arr` as a producer to a given pull stream `driver` acting as a consumer.
|
|
228
|
+
def feed[R, T](arr: ResizableArray[T]) { driver: () => R / next[T] }: R = {
|
|
229
229
|
var i = 0
|
|
230
230
|
try {
|
|
231
|
-
|
|
232
|
-
} with
|
|
231
|
+
driver()
|
|
232
|
+
} with next[T] {
|
|
233
233
|
resume {
|
|
234
234
|
if (i < arr.size) {
|
|
235
235
|
val v = arr.rawContentPtr.get.get(i)
|
|
@@ -3,19 +3,10 @@ module scanner
|
|
|
3
3
|
import stream
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
/// That is, this does not change what any future calls on the Scanner return.
|
|
8
|
-
effect peek[A](): A / stop
|
|
9
|
-
|
|
10
|
-
effect Scan[A] = {read[A], peek[A]}
|
|
6
|
+
effect Scan[A] = {next[A], peek[A]}
|
|
11
7
|
|
|
12
8
|
/// Advance the pull stream to the next element, discarding the current element.
|
|
13
|
-
def skip[A](): Unit / {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
/// Run a scanner by reading from an input stream, discarding its output.
|
|
17
|
-
def scanner[A] { scanner: () => Unit / Scan[A] }: Unit / read[A] =
|
|
18
|
-
returning::scanner[A, Unit]{scanner}
|
|
9
|
+
def skip[A](): Unit / {next[A], stop} = { do next(); () }
|
|
19
10
|
|
|
20
11
|
def expect(message: String) { scanner: () => Unit / fail }: Unit / Exception[WrongFormat] =
|
|
21
12
|
returning::expect[Unit](message){scanner}
|
|
@@ -23,7 +14,7 @@ def expect(message: String) { scanner: () => Unit / fail }: Unit / Exception[Wro
|
|
|
23
14
|
/// If conversion is successful read the next token, otherwise stop.
|
|
24
15
|
def readWhen[A, B] { convert: A => B / fail }: B / { Scan[A], stop } = {
|
|
25
16
|
val t = attempt { convert(do peek()) } { do stop() };
|
|
26
|
-
do
|
|
17
|
+
do next()
|
|
27
18
|
return t
|
|
28
19
|
}
|
|
29
20
|
|
|
@@ -31,7 +22,7 @@ def readWhen[A, B] { convert: A => B / fail }: B / { Scan[A], stop } = {
|
|
|
31
22
|
def readIf[A] { predicate: A => Bool }: A / { Scan[A], stop } = {
|
|
32
23
|
val t = do peek()
|
|
33
24
|
if (predicate(t)) {
|
|
34
|
-
do
|
|
25
|
+
do next()
|
|
35
26
|
return t
|
|
36
27
|
} else {
|
|
37
28
|
do stop()
|
|
@@ -92,10 +83,10 @@ def until[A, R] { predicate: A => Bool } { scanner: () => R / Scan[A] }: R / { S
|
|
|
92
83
|
resume {
|
|
93
84
|
if (stopped) { do stop() } else { do peek() }
|
|
94
85
|
}
|
|
95
|
-
} with
|
|
86
|
+
} with next[A] {
|
|
96
87
|
resume {
|
|
97
88
|
if (stopped) { do stop() } else {
|
|
98
|
-
val t = do
|
|
89
|
+
val t = do next()
|
|
99
90
|
boundary {
|
|
100
91
|
if (predicate(do peek())) { stopped = true; skip() }
|
|
101
92
|
}
|
|
@@ -166,38 +157,42 @@ def readInteger(): Int / { Scan[Char], fail } =
|
|
|
166
157
|
case _ => do fail()
|
|
167
158
|
}
|
|
168
159
|
|
|
169
|
-
namespace returning {
|
|
170
160
|
|
|
171
|
-
///
|
|
172
|
-
def
|
|
173
|
-
def
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
}
|
|
161
|
+
/// Read a decimal floating-point number with optional fraction and exponent.
|
|
162
|
+
def readDouble(): Double / { Scan[Char], fail} = {
|
|
163
|
+
def exponent(pre: Double): Double / fail = {
|
|
164
|
+
try {
|
|
165
|
+
if(do peek() == 'e' || do peek() == 'E') {
|
|
166
|
+
skip[Char]()
|
|
167
|
+
val e = do peek[Char]() match {
|
|
168
|
+
case '+' => skip[Char](); readDecimal()
|
|
169
|
+
case '-' => skip[Char](); neg(readDecimal())
|
|
170
|
+
case _ => readDecimal()
|
|
171
|
+
}
|
|
172
|
+
pre * pow(10.0, e)
|
|
173
|
+
} else { pre }
|
|
174
|
+
} with stop {
|
|
175
|
+
pre
|
|
187
176
|
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
177
|
+
}
|
|
178
|
+
def fraction(pre: Int): Double / fail = {
|
|
179
|
+
if (succeeds { must { readIf('.') } }) {
|
|
180
|
+
var b = if (pre >= 0) 0.1 else -0.1
|
|
181
|
+
var r = pre.toDouble
|
|
182
|
+
while (optionally[Int] { must { readDigit() } } is Some(d)) {
|
|
183
|
+
r = r + b * d.toDouble
|
|
184
|
+
b = b * 0.1
|
|
196
185
|
}
|
|
186
|
+
exponent(r)
|
|
187
|
+
} else {
|
|
188
|
+
exponent(pre.toDouble)
|
|
197
189
|
}
|
|
198
190
|
}
|
|
191
|
+
fraction(readInteger())
|
|
199
192
|
}
|
|
200
193
|
|
|
194
|
+
namespace returning {
|
|
195
|
+
|
|
201
196
|
def expect[R](message: String) { scanner: () => R / fail }: R / Exception[WrongFormat] =
|
|
202
197
|
try { scanner() } with fail { wrongFormat(message) }
|
|
203
198
|
|
|
@@ -217,7 +212,7 @@ namespace test {
|
|
|
217
212
|
with on[WrongFormat].panic
|
|
218
213
|
with expect("this grammar")
|
|
219
214
|
with feed(input)
|
|
220
|
-
with
|
|
215
|
+
with peeking[Char]
|
|
221
216
|
|
|
222
217
|
skipWhitespace()
|
|
223
218
|
println(readInteger().show)
|
|
@@ -7,13 +7,13 @@ import partial
|
|
|
7
7
|
// Effects
|
|
8
8
|
// -------
|
|
9
9
|
|
|
10
|
-
///
|
|
11
|
-
effect emit[A](
|
|
10
|
+
/// The effect for emitting an item of type `A` in a push stream.
|
|
11
|
+
effect emit[A](item: A): Unit
|
|
12
12
|
|
|
13
|
-
///
|
|
13
|
+
/// The effect for getting the next item of type `A` from a pull stream.
|
|
14
14
|
///
|
|
15
|
-
///
|
|
16
|
-
effect
|
|
15
|
+
/// Uses the `stop` effect to signal the end of the stream.
|
|
16
|
+
effect next[A](): A / stop
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
/// Like `for[A, R]`, but ignores the result of the stream, and consequently
|
|
@@ -30,11 +30,11 @@ def for[A] { stream: () => Unit / emit[A] } { action: A => Unit }: Unit =
|
|
|
30
30
|
def map[A, B] { function: A => B } { stream: () => Unit / emit[A] }: Unit / emit[B] =
|
|
31
31
|
returning::map[A, B, Unit]{function}{stream}
|
|
32
32
|
|
|
33
|
-
/// Runs the given action whenever the given
|
|
33
|
+
/// Runs the given action whenever the given driver reads an element.
|
|
34
34
|
///
|
|
35
|
-
/// e.g. var i = -1; with tap { i = i + 1; i };
|
|
36
|
-
def tap[A] { action: () => A / stop } {
|
|
37
|
-
returning::tap[A, Unit]{action}{
|
|
35
|
+
/// e.g. var i = -1; with tap { i = i + 1; i }; driver()
|
|
36
|
+
def tap[A] { action: () => A / stop } { driver: () => Unit / next[A] }: Unit =
|
|
37
|
+
returning::tap[A, Unit]{action}{driver}
|
|
38
38
|
|
|
39
39
|
/// Runs the stream as a message queue,
|
|
40
40
|
/// handling each of its elements that can produce new elements ("messages"),
|
|
@@ -42,8 +42,8 @@ def tap[A] { action: () => A / stop } { reader: () => Unit / read[A] }: Unit =
|
|
|
42
42
|
def fix[T] { one: T => Unit / emit[T] } { stream: => Unit / emit[T] }: Unit =
|
|
43
43
|
try {
|
|
44
44
|
stream()
|
|
45
|
-
} with emit[T] {
|
|
46
|
-
fix {one} { one(
|
|
45
|
+
} with emit[T] { item =>
|
|
46
|
+
fix {one} { one(item) }
|
|
47
47
|
resume(())
|
|
48
48
|
}
|
|
49
49
|
|
|
@@ -58,7 +58,7 @@ def some[A] { action: () => A / stop }: Unit / { emit[A], fail } = {
|
|
|
58
58
|
|
|
59
59
|
|
|
60
60
|
/// In Effekt lower bounds are inclusive and upper bounds are exclusive
|
|
61
|
-
record Indexed[A](index: Int,
|
|
61
|
+
record Indexed[A](index: Int, item: A)
|
|
62
62
|
|
|
63
63
|
def range(lower: Int, upper: Int): Unit / emit[Int] =
|
|
64
64
|
if (lower < upper) {
|
|
@@ -116,7 +116,7 @@ def iterate[A](initial: A) { step: A => A }: Unit / emit[A] = {
|
|
|
116
116
|
/// ```
|
|
117
117
|
def takeWhile[A] { predicate: A => Bool } { stream: () => Unit / emit[A] }: Unit / emit[A] =
|
|
118
118
|
try { stream() } with emit[A] {
|
|
119
|
-
case
|
|
119
|
+
case item and predicate(item) => do emit(item); resume(())
|
|
120
120
|
case _ => () // end the stream
|
|
121
121
|
}
|
|
122
122
|
|
|
@@ -146,7 +146,7 @@ def product { stream: () => Unit / emit[Int] }: Int =
|
|
|
146
146
|
/// ```
|
|
147
147
|
def all[A] { cond: A => Bool } { stream: => Unit / emit[A] }: Bool =
|
|
148
148
|
try { stream(); true } with emit[A] {
|
|
149
|
-
case
|
|
149
|
+
case item and not(cond(item)) => false
|
|
150
150
|
case _ => resume(())
|
|
151
151
|
}
|
|
152
152
|
|
|
@@ -169,7 +169,7 @@ def all[A] { cond: A => Bool } { stream: => Unit / emit[A] }: Bool =
|
|
|
169
169
|
/// ```
|
|
170
170
|
def any[A] { cond: A => Bool } { stream: => Unit / emit[A] }: Bool =
|
|
171
171
|
try { stream(); false } with emit[A] {
|
|
172
|
-
case
|
|
172
|
+
case item and cond(item) => true
|
|
173
173
|
case _ => resume(())
|
|
174
174
|
}
|
|
175
175
|
|
|
@@ -196,8 +196,8 @@ def countIf[A] { shouldCount: A => Bool } { stream: () => Unit / emit[A] }: Int
|
|
|
196
196
|
def count[A] { stream: () => Unit / emit[A] }: Int =
|
|
197
197
|
countIf[A] { _ => true } {stream}
|
|
198
198
|
|
|
199
|
-
def source[A] { stream: () => Unit / emit[A] } {
|
|
200
|
-
returning::source[A, Unit]{stream}{
|
|
199
|
+
def source[A] { stream: () => Unit / emit[A] } { driver: () => Unit / next[A] }: Unit =
|
|
200
|
+
returning::source[A, Unit]{stream}{driver}
|
|
201
201
|
|
|
202
202
|
/// Combines two streams together calling action on pairs in lockstep.
|
|
203
203
|
/// Terminates when either of them terminates.
|
|
@@ -206,7 +206,7 @@ def zip[A, B] { stream1: () => Unit / emit[A] } { stream2: () => Unit / emit[B]
|
|
|
206
206
|
with source[B] { stream2 }
|
|
207
207
|
|
|
208
208
|
loop {
|
|
209
|
-
action(do
|
|
209
|
+
action(do next[A](), do next[B]())
|
|
210
210
|
}
|
|
211
211
|
}
|
|
212
212
|
|
|
@@ -218,15 +218,15 @@ def zipLongest[A, B] { stream1: () => Unit / emit[A] } { stream2: () => Unit / e
|
|
|
218
218
|
|
|
219
219
|
loop {
|
|
220
220
|
try {
|
|
221
|
-
val a = do
|
|
221
|
+
val a = do next[A]()
|
|
222
222
|
try {
|
|
223
|
-
val b = do
|
|
223
|
+
val b = do next[B]()
|
|
224
224
|
action(Both(a, b))
|
|
225
225
|
} with stop { () =>
|
|
226
226
|
action(This(a))
|
|
227
227
|
}
|
|
228
228
|
} with stop{ () =>
|
|
229
|
-
val b = do
|
|
229
|
+
val b = do next[B]()
|
|
230
230
|
action(That(b))
|
|
231
231
|
}
|
|
232
232
|
}
|
|
@@ -328,8 +328,8 @@ def tee[A]{ cons1: { => Unit / emit[A] } => Unit }{ cons2: { => Unit / emit[A] }
|
|
|
328
328
|
/// ```
|
|
329
329
|
def first[A] { stream: () => Unit / emit[A] }: A / fail = {
|
|
330
330
|
try {
|
|
331
|
-
|
|
332
|
-
|
|
331
|
+
stream()
|
|
332
|
+
do fail().absurd
|
|
333
333
|
} with emit[A] { a => a }
|
|
334
334
|
}
|
|
335
335
|
|
|
@@ -338,8 +338,8 @@ def first[A] { stream: () => Unit / emit[A] }: A / fail = {
|
|
|
338
338
|
def nth[A](n: Int){ stream: () => Unit / emit[A] }: A / fail = {
|
|
339
339
|
var m = n
|
|
340
340
|
try {
|
|
341
|
-
|
|
342
|
-
|
|
341
|
+
stream()
|
|
342
|
+
do fail().absurd
|
|
343
343
|
} with emit[A] { a =>
|
|
344
344
|
if (m == 0) {
|
|
345
345
|
return a
|
|
@@ -350,6 +350,16 @@ def nth[A](n: Int){ stream: () => Unit / emit[A] }: A / fail = {
|
|
|
350
350
|
}
|
|
351
351
|
}
|
|
352
352
|
|
|
353
|
+
// Peeking
|
|
354
|
+
// -------
|
|
355
|
+
|
|
356
|
+
/// Return the next item without advancing.
|
|
357
|
+
effect peek[A](): A / stop
|
|
358
|
+
|
|
359
|
+
/// Provide the ability to peek when consuming a stream.
|
|
360
|
+
def peeking[A] { peeker: () => Unit / {next[A], peek[A]} }: Unit / next[A] =
|
|
361
|
+
returning::peeking[A, Unit]{peeker}
|
|
362
|
+
|
|
353
363
|
// Counting and padding
|
|
354
364
|
// --------------------
|
|
355
365
|
|
|
@@ -380,25 +390,25 @@ def tracking[A]{ body: => Unit / { emit[A], getPos } }: Unit / emit[A] =
|
|
|
380
390
|
namespace returning {
|
|
381
391
|
|
|
382
392
|
/// Canonical handler of push streams that performs `action` for every
|
|
383
|
-
///
|
|
393
|
+
/// item emitted by `stream`.
|
|
384
394
|
def for[A, R] { stream: () => R / emit[A] } { action: A => Unit }: R =
|
|
385
395
|
try {
|
|
386
396
|
stream()
|
|
387
|
-
} with emit[A] {
|
|
388
|
-
resume(action(
|
|
397
|
+
} with emit[A] { item =>
|
|
398
|
+
resume(action(item))
|
|
389
399
|
}
|
|
390
400
|
|
|
391
401
|
def map[A, B, R] { function: A => B } { stream: () => R / emit[A] }: R / emit[B] =
|
|
392
402
|
try {
|
|
393
403
|
stream()
|
|
394
|
-
} with emit[A] {
|
|
395
|
-
resume(do emit(function(
|
|
404
|
+
} with emit[A] { item =>
|
|
405
|
+
resume(do emit(function(item)))
|
|
396
406
|
}
|
|
397
407
|
|
|
398
|
-
def tap[A, R] { action: () => A / stop } {
|
|
408
|
+
def tap[A, R] { action: () => A / stop } { driver: () => R / next[A] }: R =
|
|
399
409
|
try {
|
|
400
|
-
|
|
401
|
-
} with
|
|
410
|
+
driver()
|
|
411
|
+
} with next[A] { () =>
|
|
402
412
|
resume { action() }
|
|
403
413
|
}
|
|
404
414
|
|
|
@@ -460,7 +470,7 @@ def product[R] { stream: () => R / emit[Int] }: (R, Int) = {
|
|
|
460
470
|
}
|
|
461
471
|
}
|
|
462
472
|
|
|
463
|
-
def source[A, R] { stream: () => Unit / emit[A] } {
|
|
473
|
+
def source[A, R] { stream: () => Unit / emit[A] } { driver: () => R / next[A] }: R = {
|
|
464
474
|
var next = box { None() }
|
|
465
475
|
next = box {
|
|
466
476
|
try {
|
|
@@ -473,12 +483,42 @@ def source[A, R] { stream: () => Unit / emit[A] } { reader: () => R / read[A] }:
|
|
|
473
483
|
}
|
|
474
484
|
}
|
|
475
485
|
try {
|
|
476
|
-
|
|
477
|
-
} with
|
|
486
|
+
driver()
|
|
487
|
+
} with next[A] {
|
|
478
488
|
resume {
|
|
479
489
|
next().getOrElse { do stop() }
|
|
480
490
|
}
|
|
481
491
|
}
|
|
482
492
|
}
|
|
483
493
|
|
|
494
|
+
/// Provide the ability to peek when consuming a stream.
|
|
495
|
+
def peeking[A, R] { peeker: () => R / {next[A], peek[A]} }: R / next[A] = {
|
|
496
|
+
def upstream(): A / stop = do next()
|
|
497
|
+
var last = None()
|
|
498
|
+
try {
|
|
499
|
+
peeker()
|
|
500
|
+
} with peek[A] { () =>
|
|
501
|
+
resume {
|
|
502
|
+
last match {
|
|
503
|
+
case None() =>
|
|
504
|
+
val t = upstream()
|
|
505
|
+
last = Some(t)
|
|
506
|
+
return t
|
|
507
|
+
case Some(t) =>
|
|
508
|
+
return t
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
} with next[A] {
|
|
512
|
+
resume {
|
|
513
|
+
last match {
|
|
514
|
+
case None() =>
|
|
515
|
+
upstream()
|
|
516
|
+
case Some(t) =>
|
|
517
|
+
last = None()
|
|
518
|
+
return t
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
|
|
484
524
|
}
|
|
@@ -237,17 +237,13 @@ extern def unsafeCharAt(str: String, n: Int) at {}: Char =
|
|
|
237
237
|
// Streaming
|
|
238
238
|
// ---------
|
|
239
239
|
|
|
240
|
-
def feed[R](string: String) {
|
|
241
|
-
feed(string.fromString) {
|
|
242
|
-
decodeUTF8 {
|
|
243
|
-
reader()
|
|
244
|
-
}
|
|
245
|
-
}
|
|
240
|
+
def feed[R](string: String) { driver: () => R / next[Char] } =
|
|
241
|
+
feed(string.fromString) { decodeUTF8 { driver() } }
|
|
246
242
|
|
|
247
243
|
def each(string: String): Unit / emit[Char] =
|
|
248
244
|
feed(string) {
|
|
249
245
|
loop {
|
|
250
|
-
do emit(do
|
|
246
|
+
do emit(do next())
|
|
251
247
|
}
|
|
252
248
|
}
|
|
253
249
|
|
package/libraries/llvm/io.c
CHANGED
|
@@ -576,61 +576,6 @@ void c_yield(Stack stack) {
|
|
|
576
576
|
c_timer_start(0, stack);
|
|
577
577
|
}
|
|
578
578
|
|
|
579
|
-
// Signals
|
|
580
|
-
// --------
|
|
581
|
-
|
|
582
|
-
typedef enum { INITIAL, NOTIFIED } signal_state_t;
|
|
583
|
-
|
|
584
|
-
typedef struct {
|
|
585
|
-
uint64_t rc;
|
|
586
|
-
void* eraser;
|
|
587
|
-
signal_state_t state;
|
|
588
|
-
struct Pos value;
|
|
589
|
-
Stack stack;
|
|
590
|
-
} Signal;
|
|
591
|
-
|
|
592
|
-
void c_signal_erase(void *envPtr) {
|
|
593
|
-
// envPtr points to a Signal _after_ the eraser, so let's adjust it to point to the beginning.
|
|
594
|
-
Signal *signal = (Signal*) (envPtr - offsetof(Signal, state));
|
|
595
|
-
erasePositive(signal->value);
|
|
596
|
-
if (signal->stack != NULL) { eraseStack(signal->stack); }
|
|
597
|
-
}
|
|
598
|
-
|
|
599
|
-
struct Pos c_signal_make() {
|
|
600
|
-
Signal* f = (Signal*)malloc(sizeof(Signal));
|
|
601
|
-
|
|
602
|
-
f->rc = 0;
|
|
603
|
-
f->eraser = c_signal_erase;
|
|
604
|
-
f->state = INITIAL;
|
|
605
|
-
f->value = (struct Pos) { .tag = 0, .obj = NULL, };
|
|
606
|
-
f->stack = NULL;
|
|
607
|
-
|
|
608
|
-
return (struct Pos) { .tag = 0, .obj = f, };
|
|
609
|
-
}
|
|
610
|
-
|
|
611
|
-
void c_signal_notify(struct Pos signal, struct Pos value, Stack stack) {
|
|
612
|
-
Signal* f = (Signal*)signal.obj;
|
|
613
|
-
switch (f->state) {
|
|
614
|
-
case INITIAL: {
|
|
615
|
-
f->state = NOTIFIED;
|
|
616
|
-
f->value = value;
|
|
617
|
-
f->stack = stack;
|
|
618
|
-
erasePositive(signal);
|
|
619
|
-
break;
|
|
620
|
-
}
|
|
621
|
-
case NOTIFIED: {
|
|
622
|
-
struct Pos other_value = f->value;
|
|
623
|
-
f->value = (struct Pos) { .tag = 0, .obj = NULL, };
|
|
624
|
-
Stack other_stack = f->stack;
|
|
625
|
-
f->stack = NULL;
|
|
626
|
-
erasePositive(signal);
|
|
627
|
-
resume_Pos(other_stack, value);
|
|
628
|
-
resume_Pos(stack, other_value);
|
|
629
|
-
break;
|
|
630
|
-
}
|
|
631
|
-
}
|
|
632
|
-
}
|
|
633
|
-
|
|
634
579
|
// Subprocesses
|
|
635
580
|
// ------------
|
|
636
581
|
|