@effekt-lang/effekt 0.46.0 → 0.48.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/common/immutable/cslist.effekt +6 -6
- package/libraries/chez/common/mutable/dict.effekt +7 -7
- package/libraries/common/args.effekt +10 -10
- package/libraries/common/array.effekt +57 -4
- package/libraries/common/bench.effekt +2 -2
- package/libraries/common/buffer.effekt +5 -5
- package/libraries/common/bytearray.effekt +69 -7
- package/libraries/common/char.effekt +95 -8
- package/libraries/common/effekt.effekt +74 -71
- package/libraries/common/exception.effekt +1 -1
- package/libraries/common/io/console.effekt +4 -4
- package/libraries/common/io/error.effekt +12 -1
- package/libraries/common/io/filesystem.effekt +78 -16
- package/libraries/common/io/network.effekt +97 -65
- package/libraries/common/io/time.effekt +1 -1
- package/libraries/common/io.effekt +7 -8
- package/libraries/common/json.effekt +5 -5
- package/libraries/common/list.effekt +154 -18
- package/libraries/common/map.effekt +35 -1
- package/libraries/common/process.effekt +1 -1
- package/libraries/common/queue.effekt +3 -3
- package/libraries/common/random.effekt +1 -0
- package/libraries/common/ref.effekt +8 -4
- package/libraries/common/regex.effekt +4 -4
- package/libraries/common/seq.effekt +1 -1
- package/libraries/common/set.effekt +24 -1
- package/libraries/common/stream.effekt +2 -360
- package/libraries/common/string.effekt +35 -5
- package/libraries/common/stringbuffer.effekt +1 -0
- package/libraries/js/mutable/map.effekt +5 -5
- package/libraries/js/web/dom.effekt +11 -11
- package/libraries/llvm/io.c +281 -8
- package/libraries/llvm/main.c +1 -2
- package/libraries/llvm/rts.ll +14 -7
- package/libraries/llvm/types.c +3 -3
- package/licenses/eclipse public license, version 2.0 - epl-2.0.html +2 -2
- package/licenses/mit license - mit-license.html +48 -48
- package/licenses/the bsd license - bsd-license.html +50 -50
- package/licenses/the mit license - mit.html +48 -48
- package/package.json +1 -1
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
module map
|
|
2
2
|
|
|
3
|
+
import stream
|
|
4
|
+
|
|
3
5
|
/// Ordered finite immutable map, backed by balanced binary trees of logarithmic depth.
|
|
4
6
|
record Map[K, V](tree: internal::Tree[K, V], compare: (K, K) => Ordering at {})
|
|
5
7
|
|
|
@@ -989,4 +991,36 @@ namespace internal {
|
|
|
989
991
|
|
|
990
992
|
"[" ++ res ++ "]"
|
|
991
993
|
}
|
|
992
|
-
}
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
|
|
997
|
+
// Streaming
|
|
998
|
+
// ---------
|
|
999
|
+
|
|
1000
|
+
/// Turns a `map` into a producer of a push stream
|
|
1001
|
+
/// of `(key, value)` pairs by emitting each contained *in order*.
|
|
1002
|
+
def each[K, V](map: Map[K, V]): Unit / emit[(K, V)] =
|
|
1003
|
+
map.foreach { (k, v) => do emit((k, v)) }
|
|
1004
|
+
|
|
1005
|
+
/// Turns a `map` into a producer of a push stream
|
|
1006
|
+
/// of its keys by emitting each contained *in order*.
|
|
1007
|
+
def eachKey[K, V](map: Map[K, V]): Unit / emit[K] =
|
|
1008
|
+
map.foreach { (k, _v) => do emit(k) }
|
|
1009
|
+
|
|
1010
|
+
/// Turns a `map` into a producer of a push stream
|
|
1011
|
+
/// of its values by emitting each contained.
|
|
1012
|
+
def eachValue[K, V](map: Map[K, V]): Unit / emit[V] =
|
|
1013
|
+
map.foreach { (_k, v) => do emit(v) }
|
|
1014
|
+
|
|
1015
|
+
def collect[K, V](compare: (K, K) => Ordering at {}) { stream: () => Unit / emit[(K, V)] }: Map[K, V] =
|
|
1016
|
+
returning::collect[K, V, Unit](compare){stream}.second
|
|
1017
|
+
|
|
1018
|
+
namespace returning {
|
|
1019
|
+
def collect[K, V, R](compare: (K, K) => Ordering at {}) { stream: () => R / emit[(K, V)] }: (R, Map[K, V]) =
|
|
1020
|
+
try {
|
|
1021
|
+
(stream(), empty(compare))
|
|
1022
|
+
} with emit[(K, V)] { case (k, v) =>
|
|
1023
|
+
val (r, map) = resume(());
|
|
1024
|
+
(r, map.put(k, v))
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
@@ -20,10 +20,10 @@ interface Queue[T] {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
|
|
23
|
-
def emptyQueue[T](): Queue[T] at
|
|
23
|
+
def emptyQueue[T](): Queue[T] at global =
|
|
24
24
|
emptyQueue[T](64)
|
|
25
25
|
|
|
26
|
-
def emptyQueue[T](initialCapacity: Int): Queue[T] at
|
|
26
|
+
def emptyQueue[T](initialCapacity: Int): Queue[T] at global = {
|
|
27
27
|
|
|
28
28
|
val contents = ref(array[Option[T]](initialCapacity, None()))
|
|
29
29
|
val head = ref(0)
|
|
@@ -103,7 +103,7 @@ def emptyQueue[T](initialCapacity: Int): Queue[T] at {global} = {
|
|
|
103
103
|
tail.set(mod(tail.get + 1, capacity.get))
|
|
104
104
|
}
|
|
105
105
|
}
|
|
106
|
-
queue
|
|
106
|
+
box queue
|
|
107
107
|
}
|
|
108
108
|
|
|
109
109
|
namespace examples {
|
|
@@ -30,7 +30,7 @@ extern type Ref[T]
|
|
|
30
30
|
|
|
31
31
|
/// Allocates a new reference, keeping its value _undefined_.
|
|
32
32
|
/// Prefer using `ref` constructor instead to ensure that the value is defined.
|
|
33
|
-
extern
|
|
33
|
+
extern def allocate[T]() at global: Ref[T] =
|
|
34
34
|
js "{ value: undefined }"
|
|
35
35
|
chez "(box #f)"
|
|
36
36
|
llvm """
|
|
@@ -50,7 +50,7 @@ extern global def allocate[T](): Ref[T] =
|
|
|
50
50
|
"""
|
|
51
51
|
|
|
52
52
|
/// Creates a new reference with the initial value `init`.
|
|
53
|
-
extern
|
|
53
|
+
extern def ref[T](init: T) at global: Ref[T] =
|
|
54
54
|
js "{ value: ${init} }"
|
|
55
55
|
chez "(box ${init})"
|
|
56
56
|
llvm """
|
|
@@ -72,7 +72,7 @@ extern global def ref[T](init: T): Ref[T] =
|
|
|
72
72
|
vm "ref::ref[T](T)"
|
|
73
73
|
|
|
74
74
|
/// Gets the referenced element of the `ref` in constant time.
|
|
75
|
-
extern
|
|
75
|
+
extern def get[T](ref: Ref[T]) at global: T =
|
|
76
76
|
js "${ref}.value"
|
|
77
77
|
chez "(unbox ${ref})"
|
|
78
78
|
llvm """
|
|
@@ -88,7 +88,7 @@ llvm """
|
|
|
88
88
|
vm "ref::get[T](Ref[T])"
|
|
89
89
|
|
|
90
90
|
/// Sets the referenced element of the `ref` to `value` in constant time.
|
|
91
|
-
extern
|
|
91
|
+
extern def set[T](ref: Ref[T], value: T) at global: Unit =
|
|
92
92
|
js "set$impl(${ref}, ${value})"
|
|
93
93
|
chez "(set-box! ${ref} ${value})"
|
|
94
94
|
llvm """
|
|
@@ -104,3 +104,7 @@ extern global def set[T](ref: Ref[T], value: T): Unit =
|
|
|
104
104
|
ret %Pos zeroinitializer
|
|
105
105
|
"""
|
|
106
106
|
vm "ref::set[T](Ref[T], T)"
|
|
107
|
+
|
|
108
|
+
/// Modifies the inner contents of the `ref` with a function `f`
|
|
109
|
+
def map[T](ref: Ref[T]) { f: T => T }: Unit =
|
|
110
|
+
ref.set(f(ref.get))
|
|
@@ -8,7 +8,7 @@ extern type Regex
|
|
|
8
8
|
|
|
9
9
|
record Match(matched: String, index: Int)
|
|
10
10
|
|
|
11
|
-
extern
|
|
11
|
+
extern def regex(str: String) at {}: Regex =
|
|
12
12
|
js "new RegExp(${str})"
|
|
13
13
|
chez "(pregexp ${str})"
|
|
14
14
|
vm "regex::regex(String)"
|
|
@@ -29,12 +29,12 @@ namespace internal {
|
|
|
29
29
|
// js: { matched: String, index: Int } | undefined
|
|
30
30
|
// vm: scala.util.matching.Regex.Match | null
|
|
31
31
|
|
|
32
|
-
extern
|
|
32
|
+
extern def matched(r: RegexMatch) at {}: String =
|
|
33
33
|
js "${r}.matched"
|
|
34
34
|
chez "(vector-ref ${r} 0)"
|
|
35
35
|
vm "regex::matched(RegexMatch)"
|
|
36
36
|
|
|
37
|
-
extern
|
|
37
|
+
extern def index(r: RegexMatch) at {}: Int =
|
|
38
38
|
js "${r}.index"
|
|
39
39
|
chez "(vector-ref ${r} 1)"
|
|
40
40
|
vm "regex::index(RegexMatch)"
|
|
@@ -57,7 +57,7 @@ namespace internal {
|
|
|
57
57
|
#f))))
|
|
58
58
|
"""
|
|
59
59
|
|
|
60
|
-
extern
|
|
60
|
+
extern def exec(reg: Regex, str: String) at io: RegexMatch =
|
|
61
61
|
js "regex$exec(${reg}, ${str})"
|
|
62
62
|
chez "(regex-exec ${reg} ${str})"
|
|
63
63
|
vm "regex::exec(Regex, String)"
|
|
@@ -875,7 +875,7 @@ def map[A, B](seq: Seq[A]) { f: (A) {Control} => B }: Seq[B] = {
|
|
|
875
875
|
|
|
876
876
|
// def iterate[A, R](seq: Seq[A]) { prog: {Iterator[A]} => R }: R = {
|
|
877
877
|
|
|
878
|
-
// var k: Unit => Unit at {} =
|
|
878
|
+
// var k: Unit => Unit at {} = box { () => () }
|
|
879
879
|
// var v: Option[A] = None()
|
|
880
880
|
|
|
881
881
|
// try { seq.each { el => do yield(el) } } with Generator[A] {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
module set
|
|
2
2
|
|
|
3
3
|
import map
|
|
4
|
+
import stream
|
|
4
5
|
|
|
5
6
|
/// Ordered finite immutable set, backed by balanced binary trees of logarithmic depth.
|
|
6
7
|
record Set[A](tree: internal::Tree[A, Unit], compare: (A, A) => Ordering at {})
|
|
@@ -231,4 +232,26 @@ def intersection[A](s1: Set[A], s2: Set[A], compare: (A, A) => Ordering at {}):
|
|
|
231
232
|
///
|
|
232
233
|
/// O(???)
|
|
233
234
|
def intersection[A](s1: Set[A], s2: Set[A]): Set[A] =
|
|
234
|
-
s1.intersection(s2, s1.compare)
|
|
235
|
+
s1.intersection(s2, s1.compare)
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
// Streaming
|
|
239
|
+
// ---------
|
|
240
|
+
|
|
241
|
+
/// Turns a `set` into a producer of a push stream
|
|
242
|
+
/// by emitting each contained *in order*.
|
|
243
|
+
def each[A](set: Set[A]): Unit / emit[A] =
|
|
244
|
+
set.foreach { x => do emit(x) }
|
|
245
|
+
|
|
246
|
+
def collect[A](compare: (A, A) => Ordering at {}) { stream: () => Unit / emit[A] }: Set[A] =
|
|
247
|
+
returning::collect[A, Unit](compare){stream}.second
|
|
248
|
+
|
|
249
|
+
namespace returning {
|
|
250
|
+
def collect[A, R](compare: (A, A) => Ordering at {}) { stream: () => R / emit[A] }: (R, Set[A]) =
|
|
251
|
+
try {
|
|
252
|
+
(stream(), empty(compare))
|
|
253
|
+
} with emit[A] { (v) =>
|
|
254
|
+
val (r, set) = resume(());
|
|
255
|
+
(r, set.insert(v))
|
|
256
|
+
}
|
|
257
|
+
}
|
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
module stream
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import map
|
|
6
|
-
import set
|
|
7
|
-
|
|
8
|
-
import io/filesystem
|
|
9
|
-
import io/error
|
|
3
|
+
import effekt
|
|
4
|
+
import option
|
|
10
5
|
|
|
11
6
|
// Effects
|
|
12
7
|
// -------
|
|
@@ -53,68 +48,6 @@ def fix[T] { one: T => Unit / emit[T] } { stream: => Unit / emit[T] }: Unit =
|
|
|
53
48
|
resume(())
|
|
54
49
|
}
|
|
55
50
|
|
|
56
|
-
/// Turns a `list` into a producer of a push stream
|
|
57
|
-
/// by emitting each contained value left-to-right.
|
|
58
|
-
def each[A](list: List[A]): Unit / emit[A] =
|
|
59
|
-
list match {
|
|
60
|
-
case Nil() => ()
|
|
61
|
-
case Cons(head, tail) =>
|
|
62
|
-
do emit(head)
|
|
63
|
-
each(tail)
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/// Turns an `array` into a producer of a push stream
|
|
67
|
-
/// by emitting each contained value from 0 to length - 1.
|
|
68
|
-
def each[T](array: Array[T]): Unit / emit[T] = {
|
|
69
|
-
val n = array.size
|
|
70
|
-
def go(i: Int): Unit = {
|
|
71
|
-
if (i < n) {
|
|
72
|
-
do emit(array.unsafeGet(i))
|
|
73
|
-
go(i + 1)
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
go(0)
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/// Turns `bytes` into a producer of a push stream
|
|
80
|
-
/// by emitting each contained value from 0 to length - 1.
|
|
81
|
-
def each(bytes: ByteArray): Unit / emit[Byte] = {
|
|
82
|
-
val n = bytes.size
|
|
83
|
-
def go(i: Int): Unit = {
|
|
84
|
-
if (i < n) {
|
|
85
|
-
do emit(bytes.unsafeGet(i))
|
|
86
|
-
go(i + 1)
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
go(0)
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/// Turns a `map` into a producer of a push stream
|
|
93
|
-
/// of `(key, value)` pairs by emitting each contained *in order*.
|
|
94
|
-
def each[K, V](map: Map[K, V]): Unit / emit[(K, V)] =
|
|
95
|
-
map.foreach { (k, v) => do emit((k, v)) }
|
|
96
|
-
|
|
97
|
-
/// Turns a `map` into a producer of a push stream
|
|
98
|
-
/// of its keys by emitting each contained *in order*.
|
|
99
|
-
def eachKey[K, V](map: Map[K, V]): Unit / emit[K] =
|
|
100
|
-
map.foreach { (k, _v) => do emit(k) }
|
|
101
|
-
|
|
102
|
-
/// Turns a `map` into a producer of a push stream
|
|
103
|
-
/// of its values by emitting each contained.
|
|
104
|
-
def eachValue[K, V](map: Map[K, V]): Unit / emit[V] =
|
|
105
|
-
map.foreach { (_k, v) => do emit(v) }
|
|
106
|
-
|
|
107
|
-
/// Turns a `set` into a producer of a push stream
|
|
108
|
-
/// by emitting each contained *in order*.
|
|
109
|
-
def each[A](set: Set[A]): Unit / emit[A] =
|
|
110
|
-
set.foreach { x => do emit(x) }
|
|
111
|
-
|
|
112
|
-
// not option
|
|
113
|
-
// not dequeue
|
|
114
|
-
// not queue
|
|
115
|
-
// not result
|
|
116
|
-
// not seq
|
|
117
|
-
|
|
118
51
|
|
|
119
52
|
def boundary { program: () => Unit / stop }: Unit = {
|
|
120
53
|
returning::boundary[Unit]{program}
|
|
@@ -202,87 +135,6 @@ def sum { stream: () => Unit / emit[Int] }: Int =
|
|
|
202
135
|
def product { stream: () => Unit / emit[Int] }: Int =
|
|
203
136
|
returning::product[Unit]{stream}.second
|
|
204
137
|
|
|
205
|
-
def collectList[A] { stream: () => Unit / emit[A] }: List[A] =
|
|
206
|
-
returning::collectList[A, Unit]{stream}.second
|
|
207
|
-
|
|
208
|
-
def collectArray[A] { stream: () => Unit / emit[A] }: Array[A] =
|
|
209
|
-
returning::collectArray[A, Unit]{stream}.second
|
|
210
|
-
|
|
211
|
-
def collectBytes { stream: () => Unit / emit[Byte] }: ByteArray =
|
|
212
|
-
returning::collectBytes[Unit]{stream}.second
|
|
213
|
-
|
|
214
|
-
def feed[T, R](list: List[T]) { reader: () => R / read[T] }: R = {
|
|
215
|
-
var l = list
|
|
216
|
-
try {
|
|
217
|
-
reader()
|
|
218
|
-
} with read[T] {
|
|
219
|
-
resume {
|
|
220
|
-
l match {
|
|
221
|
-
case Nil() => do stop()
|
|
222
|
-
case Cons(value, rest) =>
|
|
223
|
-
l = rest
|
|
224
|
-
return value
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
def collectMap[K, V, R](compare: (K, K) => Ordering at {}) { stream: () => R / emit[(K, V)] }: (R, Map[K, V]) =
|
|
231
|
-
try {
|
|
232
|
-
(stream(), map::empty(compare))
|
|
233
|
-
} with emit[(K, V)] { case (k, v) =>
|
|
234
|
-
val (r, map) = resume(());
|
|
235
|
-
(r, map.put(k, v))
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
def collectMap[K, V](compare: (K, K) => Ordering at {}) { stream: () => Any / emit[(K, V)] }: Map[K, V] =
|
|
239
|
-
collectMap[K, V, Any](compare){stream}.second
|
|
240
|
-
|
|
241
|
-
def collectSet[A, R](compare: (A, A) => Ordering at {}) { stream: () => R / emit[A] }: (R, Set[A]) =
|
|
242
|
-
try {
|
|
243
|
-
(stream(), set::empty(compare))
|
|
244
|
-
} with emit[A] { (v) =>
|
|
245
|
-
val (r, set) = resume(());
|
|
246
|
-
(r, set.insert(v))
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
def collectSet[A](compare: (A, A) => Ordering at {}) { stream: () => Any / emit[A] }: Set[A] =
|
|
250
|
-
collectSet[A, Any](compare){stream}.second
|
|
251
|
-
|
|
252
|
-
def feed[T, R](array: Array[T]) { reader: () => R / read[T] }: R = {
|
|
253
|
-
var i = 0
|
|
254
|
-
try {
|
|
255
|
-
reader()
|
|
256
|
-
} with read[T] {
|
|
257
|
-
resume {
|
|
258
|
-
if (i < array.size) {
|
|
259
|
-
val c = i
|
|
260
|
-
i = c + 1
|
|
261
|
-
array.unsafeGet(c)
|
|
262
|
-
} else {
|
|
263
|
-
do stop()
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
def feed[R](bytes: ByteArray) { reader: () => R / read[Byte] }: R = {
|
|
270
|
-
var i = 0
|
|
271
|
-
try {
|
|
272
|
-
reader()
|
|
273
|
-
} with read[Byte] {
|
|
274
|
-
resume {
|
|
275
|
-
if (i < bytes.size) {
|
|
276
|
-
val c = i
|
|
277
|
-
i = c + 1
|
|
278
|
-
bytes.unsafeGet(c)
|
|
279
|
-
} else {
|
|
280
|
-
do stop()
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
|
|
286
138
|
def source[A] { stream: () => Unit / emit[A] } { reader: () => Unit / read[A] }: Unit =
|
|
287
139
|
returning::source[A, Unit]{stream}{reader}
|
|
288
140
|
|
|
@@ -319,155 +171,6 @@ def zipLongest[A, B] { stream1: () => Unit / emit[A] } { stream2: () => Unit / e
|
|
|
319
171
|
}
|
|
320
172
|
}
|
|
321
173
|
|
|
322
|
-
def writeFile[R](path: String) { stream: () => R / emit[Byte] }: R / Exception[IOError] = {
|
|
323
|
-
|
|
324
|
-
val file = openForWriting(path);
|
|
325
|
-
with on[IOError].finalize { close(file) }
|
|
326
|
-
|
|
327
|
-
val chunkSize = 1048576 // 1MB
|
|
328
|
-
val buffer = bytearray::allocate(chunkSize)
|
|
329
|
-
var offset = 0
|
|
330
|
-
|
|
331
|
-
def push(i: Int, n: Int): Unit = {
|
|
332
|
-
val r = write(file, buffer, i, n, -1)
|
|
333
|
-
if (r < n) {
|
|
334
|
-
push(i + r, n - r)
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
try {
|
|
339
|
-
val r = stream()
|
|
340
|
-
push(0, offset)
|
|
341
|
-
return r
|
|
342
|
-
} with emit[Byte] { (byte) =>
|
|
343
|
-
if (offset >= buffer.size) {
|
|
344
|
-
push(0, buffer.size)
|
|
345
|
-
offset = 0
|
|
346
|
-
}
|
|
347
|
-
buffer.unsafeSet(offset, byte)
|
|
348
|
-
offset = offset + 1
|
|
349
|
-
resume(())
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
def readFile[R](path: String) { reader: () => R / read[Byte] }: R / Exception[IOError] = {
|
|
354
|
-
|
|
355
|
-
val file = openForReading(path);
|
|
356
|
-
with on[IOError].finalize { close(file) }
|
|
357
|
-
|
|
358
|
-
val chunkSize = 1048576 // 1MB
|
|
359
|
-
val buffer = bytearray::allocate(chunkSize)
|
|
360
|
-
var offset = 0
|
|
361
|
-
var length = 0
|
|
362
|
-
|
|
363
|
-
def pull(): Unit / stop = {
|
|
364
|
-
read(file, buffer, 0, chunkSize, -1) match {
|
|
365
|
-
case 0 =>
|
|
366
|
-
do stop()
|
|
367
|
-
case n =>
|
|
368
|
-
length = n
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
try {
|
|
373
|
-
reader()
|
|
374
|
-
} with read[Byte] {
|
|
375
|
-
resume {
|
|
376
|
-
if (offset >= length) {
|
|
377
|
-
pull()
|
|
378
|
-
offset = 0
|
|
379
|
-
}
|
|
380
|
-
val byte = buffer.unsafeGet(offset)
|
|
381
|
-
offset = offset + 1
|
|
382
|
-
return byte
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
def decodeChar(): Char / {read[Byte], stop} = {
|
|
388
|
-
val b = do read().toInt
|
|
389
|
-
if (b < 128) {
|
|
390
|
-
b.toChar
|
|
391
|
-
} else if (b < 224) {
|
|
392
|
-
val part1 = bitwiseShl(bitwiseAnd(b, 31), 6)
|
|
393
|
-
val part2 = bitwiseAnd(do read().toInt, 63)
|
|
394
|
-
bitwiseOr(part1, part2).toChar
|
|
395
|
-
} else if (b < 240) {
|
|
396
|
-
val part1 = bitwiseShl(bitwiseAnd(b, 15), 12)
|
|
397
|
-
val part2 = bitwiseShl(bitwiseAnd(do read().toInt, 63), 6)
|
|
398
|
-
val part3 = bitwiseAnd(do read().toInt, 63)
|
|
399
|
-
bitwiseOr(bitwiseOr(part1, part2), part3).toChar
|
|
400
|
-
} else {
|
|
401
|
-
val part1 = bitwiseShl(bitwiseAnd(b, 7), 18)
|
|
402
|
-
val part2 = bitwiseShl(bitwiseAnd(do read().toInt, 63), 12)
|
|
403
|
-
val part3 = bitwiseShl(bitwiseAnd(do read().toInt, 63), 6)
|
|
404
|
-
val part4 = bitwiseAnd(do read().toInt, 63)
|
|
405
|
-
bitwiseOr(bitwiseOr(bitwiseOr(part1, part2), part3), part4).toChar
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
def encodeChar(char: Char): Unit / emit[Byte] = {
|
|
410
|
-
val code = char.toInt
|
|
411
|
-
if (code < 128) {
|
|
412
|
-
do emit(code.toByte)
|
|
413
|
-
} else if (code < 2048) {
|
|
414
|
-
do emit(bitwiseOr(192, bitwiseShr(code, 6)).toByte)
|
|
415
|
-
do emit(bitwiseOr(128, bitwiseAnd(code, 63)).toByte)
|
|
416
|
-
} else if (code < 65536) {
|
|
417
|
-
do emit(bitwiseOr(224, bitwiseShr(code, 12)).toByte)
|
|
418
|
-
do emit(bitwiseOr(128, bitwiseAnd(bitwiseShr(code, 6), 63)).toByte)
|
|
419
|
-
do emit(bitwiseOr(128, bitwiseAnd(code, 63)).toByte)
|
|
420
|
-
} else {
|
|
421
|
-
do emit(bitwiseOr(240, bitwiseShr(code, 18)).toByte)
|
|
422
|
-
do emit(bitwiseOr(128, bitwiseAnd(bitwiseShr(code, 12), 63)).toByte)
|
|
423
|
-
do emit(bitwiseOr(128, bitwiseAnd(bitwiseShr(code, 6), 63)).toByte)
|
|
424
|
-
do emit(bitwiseOr(128, bitwiseAnd(code, 63)).toByte)
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
def decodeUTF8[R] { reader: () => R / read[Char] }: R / read[Byte] =
|
|
429
|
-
try {
|
|
430
|
-
reader()
|
|
431
|
-
} with read[Char] {
|
|
432
|
-
resume { decodeChar() }
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
def encodeUTF8[R] { stream: () => R / emit[Char] }: R / emit[Byte] =
|
|
436
|
-
try {
|
|
437
|
-
stream()
|
|
438
|
-
} with emit[Char] { char =>
|
|
439
|
-
resume(encodeChar(char))
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
def writeFileUTF8[R](path: String) { stream: () => R / emit[Char] }: R / Exception[IOError] =
|
|
443
|
-
writeFile(path) { encodeUTF8 { stream() } }
|
|
444
|
-
|
|
445
|
-
def readFileUTF8[R](path: String) { reader: () => R / read[Char] }: R / Exception[IOError] =
|
|
446
|
-
readFile(path) { decodeUTF8 { reader() } }
|
|
447
|
-
|
|
448
|
-
def feed[R](string: String) { reader: () => R / read[Char] } =
|
|
449
|
-
feed(string.fromString) {
|
|
450
|
-
decodeUTF8 {
|
|
451
|
-
reader()
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
def each(string: String): Unit / emit[Char] =
|
|
456
|
-
feed(string) {
|
|
457
|
-
exhaustively {
|
|
458
|
-
do emit[Char](do read[Char]())
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
def collectString { stream: () => Unit / emit[Char] }: String =
|
|
463
|
-
returning::collectString[Unit]{stream}.second
|
|
464
|
-
|
|
465
|
-
def writeLine { body: () => Unit / emit[Char] }: Unit / emit[Char] =
|
|
466
|
-
returning::writeLine[Unit]{body}
|
|
467
|
-
|
|
468
|
-
def readLine { body: () => Unit / read[Char] }: Unit / {read[Char], stop} =
|
|
469
|
-
returning::readLine[Unit]{body}
|
|
470
|
-
|
|
471
174
|
namespace internal {
|
|
472
175
|
effect snapshot(): Unit
|
|
473
176
|
}
|
|
@@ -640,67 +343,6 @@ def product[R] { stream: () => R / emit[Int] }: (R, Int) = {
|
|
|
640
343
|
}
|
|
641
344
|
}
|
|
642
345
|
|
|
643
|
-
def collectList[A, R] { stream: () => R / emit[A] }: (R, List[A]) =
|
|
644
|
-
try {
|
|
645
|
-
(stream(), Nil())
|
|
646
|
-
} with emit[A] { (v) =>
|
|
647
|
-
val (r, vs) = resume(());
|
|
648
|
-
(r, Cons(v, vs))
|
|
649
|
-
}
|
|
650
|
-
|
|
651
|
-
def collectArray[A, R] { stream: () => R / emit[A] }: (R, Array[A]) = {
|
|
652
|
-
var i = 0
|
|
653
|
-
var a = array::allocate(1)
|
|
654
|
-
try {
|
|
655
|
-
(stream(), a.resize(i))
|
|
656
|
-
} with emit[A] { (v) =>
|
|
657
|
-
if (i >= a.size) { a = a.resize(2 * a.size) }
|
|
658
|
-
a.unsafeSet(i, v)
|
|
659
|
-
i = i + 1
|
|
660
|
-
resume(())
|
|
661
|
-
}
|
|
662
|
-
}
|
|
663
|
-
|
|
664
|
-
def collectBytes[R] { stream: () => R / emit[Byte] }: (R, ByteArray) = {
|
|
665
|
-
var i = 0
|
|
666
|
-
var a = bytearray::allocate(1)
|
|
667
|
-
try {
|
|
668
|
-
(stream(), a.resize(i))
|
|
669
|
-
} with emit[Byte] { (v) =>
|
|
670
|
-
if (i >= a.size) { a = a.resize(2 * a.size) }
|
|
671
|
-
a.unsafeSet(i, v)
|
|
672
|
-
i = i + 1
|
|
673
|
-
resume(())
|
|
674
|
-
}
|
|
675
|
-
}
|
|
676
|
-
|
|
677
|
-
def collectString[R] { stream: () => R / emit[Char] }: (R, String) = {
|
|
678
|
-
val (result, bytes) = collectBytes[R] { encodeUTF8 { stream } }
|
|
679
|
-
(result, bytes.toString)
|
|
680
|
-
}
|
|
681
|
-
|
|
682
|
-
def writeLine[R] { body: () => R / emit[Char] }: R / emit[Char] = {
|
|
683
|
-
val result = body()
|
|
684
|
-
do emit('\n')
|
|
685
|
-
return result
|
|
686
|
-
}
|
|
687
|
-
|
|
688
|
-
def readLine[R] { body: () => R / read[Char] }: R / {read[Char], stop} = {
|
|
689
|
-
var stopped = false
|
|
690
|
-
try {
|
|
691
|
-
body()
|
|
692
|
-
} with read[Char] {
|
|
693
|
-
if(stopped){
|
|
694
|
-
resume { do stop() }
|
|
695
|
-
} else {
|
|
696
|
-
do read[Char] match {
|
|
697
|
-
case '\n' => stopped = true; resume { do stop() }
|
|
698
|
-
case char => resume { return char }
|
|
699
|
-
}
|
|
700
|
-
}
|
|
701
|
-
}
|
|
702
|
-
}
|
|
703
|
-
|
|
704
346
|
def source[A, R] { stream: () => Unit / emit[A] } { reader: () => R / read[A] }: R = {
|
|
705
347
|
var next = box { None() }
|
|
706
348
|
next = box {
|
|
@@ -2,10 +2,12 @@ module string
|
|
|
2
2
|
|
|
3
3
|
import effekt
|
|
4
4
|
import option
|
|
5
|
+
import stream
|
|
5
6
|
import list
|
|
6
7
|
import exception
|
|
7
8
|
import result
|
|
8
9
|
import char
|
|
10
|
+
import bytearray
|
|
9
11
|
|
|
10
12
|
// TODO
|
|
11
13
|
// - [ ] handle unicode codepoints (that can span two indices) correctly
|
|
@@ -111,7 +113,7 @@ def join(strings: List[String], sep: String): String = {
|
|
|
111
113
|
}
|
|
112
114
|
}
|
|
113
115
|
|
|
114
|
-
extern
|
|
116
|
+
extern def trim(str: String) at {}: String =
|
|
115
117
|
js "${str}.trim()"
|
|
116
118
|
|
|
117
119
|
// Parsing
|
|
@@ -169,7 +171,7 @@ def toInt(str: String, base: Int): Int / Exception[WrongFormat] = {
|
|
|
169
171
|
}
|
|
170
172
|
|
|
171
173
|
/// Native versions of toInt (unused right now)
|
|
172
|
-
extern
|
|
174
|
+
extern def unsafeToInt(str: String) at {}: Int =
|
|
173
175
|
js "(Number.isNaN(parseInt(${str})) ? undefined : parseInt(${str}))"
|
|
174
176
|
chez "(string->number ${str})"
|
|
175
177
|
|
|
@@ -203,7 +205,7 @@ def lastIndexOf(str: String, sub: String, from: Int): Option[Int] = {
|
|
|
203
205
|
|
|
204
206
|
// TODO more efficient (native) implementations could be integrated as follows
|
|
205
207
|
|
|
206
|
-
// extern
|
|
208
|
+
// extern def indexOf(str: String, sub: String) at {}: Option[Int] =
|
|
207
209
|
// //js { nativeIndexOf(str, sub) }
|
|
208
210
|
// default { indexOf(str, sub, 0) }
|
|
209
211
|
|
|
@@ -212,7 +214,7 @@ def lastIndexOf(str: String, sub: String, from: Int): Option[Int] = {
|
|
|
212
214
|
// if (index < 0) { None() } else { Some(index) }
|
|
213
215
|
// }
|
|
214
216
|
|
|
215
|
-
// extern
|
|
217
|
+
// extern def unsafeIndexOf(str: String, sub: String) at {}: Int =
|
|
216
218
|
// js "${str}.indexOf(${sub})"
|
|
217
219
|
|
|
218
220
|
def charAt(str: String, index: Int): Char / Exception[OutOfBounds] =
|
|
@@ -221,7 +223,7 @@ def charAt(str: String, index: Int): Char / Exception[OutOfBounds] =
|
|
|
221
223
|
else
|
|
222
224
|
unsafeCharAt(str, index)
|
|
223
225
|
|
|
224
|
-
extern
|
|
226
|
+
extern def unsafeCharAt(str: String, n: Int) at {}: Char =
|
|
225
227
|
js "${str}.codePointAt(${n})"
|
|
226
228
|
chez "(char->integer (string-ref ${str} ${n}))"
|
|
227
229
|
llvm """
|
|
@@ -229,3 +231,31 @@ extern pure def unsafeCharAt(str: String, n: Int): Char =
|
|
|
229
231
|
ret %Int %x
|
|
230
232
|
"""
|
|
231
233
|
vm "string::unsafeCharAt(String, Int)"
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
// Streaming
|
|
237
|
+
// ---------
|
|
238
|
+
|
|
239
|
+
def feed[R](string: String) { reader: () => R / read[Char] } =
|
|
240
|
+
feed(string.fromString) {
|
|
241
|
+
decodeUTF8 {
|
|
242
|
+
reader()
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
def each(string: String): Unit / emit[Char] =
|
|
247
|
+
feed(string) {
|
|
248
|
+
exhaustively {
|
|
249
|
+
do emit[Char](do read[Char]())
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
def collect { stream: () => Unit / emit[Char] }: String =
|
|
254
|
+
returning::collect[Unit]{stream}.second
|
|
255
|
+
|
|
256
|
+
namespace returning {
|
|
257
|
+
def collect[R] { stream: () => R / emit[Char] }: (R, String) = {
|
|
258
|
+
val (result, bytes) = bytearray::returning::collect[R] { encodeUTF8 { stream } }
|
|
259
|
+
(result, bytes.toString)
|
|
260
|
+
}
|
|
261
|
+
}
|