@effekt-lang/effekt 0.66.0 → 0.68.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 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 // = Array[String]
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 // = CSList[String]
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:
@@ -57,7 +60,6 @@ extern def unsafeAllocate[T](size: Int) at global: Array[T] =
57
60
  %ret_pos = insertvalue %Pos { i64 0, ptr poison }, ptr %calloc, 1
58
61
  ret %Pos %ret_pos
59
62
  """
60
- vm "array::unsafeAllocate(Int)"
61
63
 
62
64
  /// Fills a given array in-place.
63
65
  def fill[T](arr: Array[T], filler: T): Unit = {
@@ -96,7 +98,6 @@ extern def size[T](arr: Array[T]) at {}: Int =
96
98
  tail call void @erasePositive(%Pos ${arr})
97
99
  ret i64 %size
98
100
  """
99
- vm "array::size[T](Array[T])"
100
101
 
101
102
  extern llvm """
102
103
  define void @assertInbounds(i64 %index, %Pos %arr) alwaysinline {
@@ -138,7 +139,6 @@ extern def get[T](arr: Array[T], index: Int) at global: T =
138
139
  tail call void @erasePositive(%Pos ${arr})
139
140
  ret %Pos %element
140
141
  """
141
- vm "array::get[T](Array[T], Int)"
142
142
 
143
143
  extern js """
144
144
  function array$set(arr, index, value) {
@@ -165,7 +165,6 @@ extern def set[T](arr: Array[T], index: Int, value: T) at global: Unit =
165
165
  tail call void @erasePositive(%Pos ${arr})
166
166
  ret %Pos zeroinitializer
167
167
  """
168
- vm "array::set[T](Array[T], Int, T)"
169
168
 
170
169
  // Derived operations:
171
170
 
@@ -659,12 +658,12 @@ def each[T](array: Array[T]): Unit / emit[T] = {
659
658
  go(0)
660
659
  }
661
660
 
662
- /// Connects `array` as a producer to a given pull stream `reader` acting as a consumer.
663
- def feed[T, R](array: Array[T]) { reader: () => R / read[T] }: R = {
661
+ /// Connects `array` as a producer to a given pull stream `driver` acting as a consumer.
662
+ def feed[T, R](array: Array[T]) { driver: () => R / next[T] }: R = {
664
663
  var i = 0
665
664
  try {
666
- reader()
667
- } with read[T] {
665
+ driver()
666
+ } with next[T] {
668
667
  resume {
669
668
  if (i < array.size) {
670
669
  val c = i
@@ -19,10 +19,10 @@ import array
19
19
  *
20
20
  * The eraser does nothing.
21
21
  */
22
- extern type ByteArray
23
- // = llvm "%Pos"
24
- // = js "Uint8Array"
25
- // = chez "bytevector"
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 =
@@ -38,7 +38,6 @@ extern def allocate(size: Int) at global: ByteArray =
38
38
  ret %Pos %ret_object2
39
39
  """
40
40
  chez "(make-bytevector ${size})"
41
- vm "bytearray::allocate(Int)"
42
41
 
43
42
  extern def size(arr: ByteArray) at {}: Int =
44
43
  js "${arr}.length"
@@ -48,7 +47,6 @@ extern def size(arr: ByteArray) at {}: Int =
48
47
  ret i64 %size
49
48
  """
50
49
  chez "(bytevector-length ${arr})"
51
- vm "bytearray::size(ByteArray)"
52
50
 
53
51
  extern js """
54
52
  function bytearray$get(arr, index) {
@@ -82,7 +80,6 @@ extern def get(arr: ByteArray, index: Int) at global: Byte =
82
80
  ret i8 %element
83
81
  """
84
82
  chez "(bytevector-u8-ref ${arr} ${index})"
85
- vm "bytearray::get(ByteArray, Int)"
86
83
 
87
84
  extern def set(arr: ByteArray, index: Int, value: Byte) at global: Unit =
88
85
  js "bytearray$set(${arr}, ${index}, ${value})"
@@ -96,7 +93,6 @@ extern def set(arr: ByteArray, index: Int, value: Byte) at global: Unit =
96
93
  ret %Pos zeroinitializer
97
94
  """
98
95
  chez "(bytevector-u8-set! ${arr} ${index} ${value})"
99
- vm "bytearray::set(ByteArray, Int, Byte)"
100
96
 
101
97
  /// Creates a new ByteArray of size `size` filled with the value `init`
102
98
  def bytearray(size: Int, init: Byte): ByteArray = {
@@ -184,7 +180,6 @@ extern def fromString(str: String) at {}: ByteArray =
184
180
  ret %Pos ${str}
185
181
  """
186
182
  chez "(string->utf8 ${str})"
187
- vm "bytearray::fromString(String)"
188
183
 
189
184
  extern def toString(arr: ByteArray) at {}: String =
190
185
  js "(new TextDecoder('utf-8').decode(${arr}))"
@@ -193,7 +188,6 @@ extern def toString(arr: ByteArray) at {}: String =
193
188
  ret %Pos ${arr}
194
189
  """
195
190
  chez "(utf8->string ${arr})"
196
- vm "bytearray::toString(ByteArray)"
197
191
 
198
192
  extern js """
199
193
  function bytearray$set(bytes, index, value) {
@@ -247,7 +241,6 @@ extern def compareByteArrayImpl(b1: ByteArray, b2: ByteArray) at {}: Int =
247
241
  ret %Int %x
248
242
  """
249
243
  chez "(bytearray$compare ${b1} ${b2})"
250
- vm "bytearray::compare(ByteArray, ByteArray)"
251
244
 
252
245
  def compareByteArray(b1: ByteArray, b2: ByteArray): Ordering = {
253
246
  val ret = compareByteArrayImpl(b1, b2)
@@ -283,11 +276,11 @@ def each(bytes: ByteArray): Unit / emit[Byte] = {
283
276
  go(0)
284
277
  }
285
278
 
286
- def feed[R](bytes: ByteArray) { reader: () => R / read[Byte] }: R = {
279
+ def feed[R](bytes: ByteArray) { driver: () => R / next[Byte] }: R = {
287
280
  var i = 0
288
281
  try {
289
- reader()
290
- } with read[Byte] {
282
+ driver()
283
+ } with next[Byte] {
291
284
  resume {
292
285
  if (i < bytes.size) {
293
286
  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 read[Char]()) } }
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 read[Char]())
119
- val lower: Int = hexDigitValue(do read[Char]())
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 read[Char]() match {
299
+ do next[Char]() match {
300
300
  case '0' => do emit(B0())
301
301
  case '1' => do emit(B1())
302
302
  case _ => ()
@@ -97,13 +97,11 @@ extern def toInt(ch: Char) at {}: Int =
97
97
  js "${ch}"
98
98
  chez "${ch}"
99
99
  llvm "ret %Int ${ch}"
100
- vm "string::toInt(Char)"
101
100
 
102
101
  extern def toChar(codepoint: Int) at {}: Char =
103
102
  js "${codepoint}"
104
103
  chez "${codepoint}"
105
104
  llvm "ret %Int ${codepoint}"
106
- vm "string::toChar(Int)"
107
105
 
108
106
 
109
107
  extern def infixLt(x: Char, y: Char) at {}: Bool =
@@ -115,7 +113,6 @@ extern def infixLt(x: Char, y: Char) at {}: Bool =
115
113
  %adt_boolean = insertvalue %Pos zeroinitializer, i64 %fat_z, 0
116
114
  ret %Pos %adt_boolean
117
115
  """
118
- vm "string::infixLt(Char, Char)"
119
116
 
120
117
  extern def infixLte(x: Char, y: Char) at {}: Bool =
121
118
  js "(${x} <= ${y})"
@@ -126,7 +123,6 @@ extern def infixLte(x: Char, y: Char) at {}: Bool =
126
123
  %adt_boolean = insertvalue %Pos zeroinitializer, i64 %fat_z, 0
127
124
  ret %Pos %adt_boolean
128
125
  """
129
- vm "string::infixLte(Char, Char)"
130
126
 
131
127
  extern def infixGt(x: Char, y: Char) at {}: Bool =
132
128
  js "(${x} > ${y})"
@@ -137,7 +133,6 @@ extern def infixGt(x: Char, y: Char) at {}: Bool =
137
133
  %adt_boolean = insertvalue %Pos zeroinitializer, i64 %fat_z, 0
138
134
  ret %Pos %adt_boolean
139
135
  """
140
- vm "string::infixGt(Char, Char)"
141
136
 
142
137
  extern def infixGte(x: Char, y: Char) at {}: Bool =
143
138
  js "(${x} >= ${y})"
@@ -148,7 +143,6 @@ extern def infixGte(x: Char, y: Char) at {}: Bool =
148
143
  %adt_boolean = insertvalue %Pos zeroinitializer, i64 %fat_z, 0
149
144
  ret %Pos %adt_boolean
150
145
  """
151
- vm "string::infixGte(Char, Char)"
152
146
 
153
147
 
154
148
  /**
@@ -175,24 +169,24 @@ extern def charWidth(c: Char) at {}: Int =
175
169
  js "(${c} > 0xffff) ? 2 : 1"
176
170
 
177
171
 
178
- def decodeChar(): Char / {read[Byte], stop} = {
179
- val b = do read().toInt
172
+ def decodeChar(): Char / {next[Byte], stop} = {
173
+ val b = do next().toInt
180
174
  if (b < 128) {
181
175
  b.toChar
182
176
  } else if (b < 224) {
183
177
  val part1 = bitwiseShl(bitwiseAnd(b, 31), 6)
184
- val part2 = bitwiseAnd(do read().toInt, 63)
178
+ val part2 = bitwiseAnd(do next().toInt, 63)
185
179
  bitwiseOr(part1, part2).toChar
186
180
  } else if (b < 240) {
187
181
  val part1 = bitwiseShl(bitwiseAnd(b, 15), 12)
188
- val part2 = bitwiseShl(bitwiseAnd(do read().toInt, 63), 6)
189
- val part3 = bitwiseAnd(do read().toInt, 63)
182
+ val part2 = bitwiseShl(bitwiseAnd(do next().toInt, 63), 6)
183
+ val part3 = bitwiseAnd(do next().toInt, 63)
190
184
  bitwiseOr(bitwiseOr(part1, part2), part3).toChar
191
185
  } else {
192
186
  val part1 = bitwiseShl(bitwiseAnd(b, 7), 18)
193
- val part2 = bitwiseShl(bitwiseAnd(do read().toInt, 63), 12)
194
- val part3 = bitwiseShl(bitwiseAnd(do read().toInt, 63), 6)
195
- val part4 = bitwiseAnd(do read().toInt, 63)
187
+ val part2 = bitwiseShl(bitwiseAnd(do next().toInt, 63), 12)
188
+ val part3 = bitwiseShl(bitwiseAnd(do next().toInt, 63), 6)
189
+ val part4 = bitwiseAnd(do next().toInt, 63)
196
190
  bitwiseOr(bitwiseOr(bitwiseOr(part1, part2), part3), part4).toChar
197
191
  }
198
192
  }
@@ -216,10 +210,10 @@ def encodeChar(char: Char): Unit / emit[Byte] = {
216
210
  }
217
211
  }
218
212
 
219
- def decodeUTF8[R] { reader: () => R / read[Char] }: R / read[Byte] =
213
+ def decodeUTF8[R] { reader: () => R / next[Char] }: R / next[Byte] =
220
214
  try {
221
215
  reader()
222
- } with read[Char] {
216
+ } with next[Char] {
223
217
  resume { decodeChar() }
224
218
  }
225
219
 
@@ -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
- /// A trie-based dictionary for efficient key-value storage with bytearray keys.
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[Dictionary[A]])
14
- Node(value: A, children: Array[Dictionary[A]])
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](trie: Dictionary[A], key: String, value: A): Dictionary[A] =
19
- insert(trie, key.fromString, value)
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](trie: Dictionary[A], key: ByteArray, value: A): Dictionary[A] = {
23
- def go(trie: Dictionary[A], i: Int): Dictionary[A] =
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(trie, 0)
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](trie: Dictionary[A], key: String): Option[A] =
58
- lookup(trie, key.fromString)
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](trie: Dictionary[A], key: ByteArray): Option[A] = {
62
- def go(trie: Dictionary[A], i: Int): Option[A] =
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(trie, 0)
85
+ go(dictionary.get, 0)
79
86
  }
80
87
 
81
- /// A record pairing a key with a value for use in streams.
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
- var trie = Empty()
90
+ val dictionary = ref(Empty())
87
91
  for[Tagged[A]] { stream() } { case Tagged(bytes, value) =>
88
- trie = trie.insert(bytes, value)
92
+ dictionary.insert(bytes, value)
89
93
  }
90
- return trie
94
+ return dictionary
91
95
  }
92
96
 
93
97
  /// Emit all values stored in the dictionary as a push stream.
94
- def each[A](trie: Dictionary[A]): Unit / emit[A] =
95
- trie match {
96
- case Empty() => ()
97
- case Leaf(value) => do emit(value)
98
- case Branch(children) =>
99
- each(0, children.size) { i =>
100
- each(children.get(i))
101
- }
102
- case Node(value, children) =>
103
- do emit(value)
104
- each(0, children.size) { i =>
105
- each(children.get(i))
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](trie: Dictionary[A]): Unit / emit[Tagged[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: Dictionary[A], key: List[Byte], n: Int): Unit =
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(trie, Nil(), 0)
131
- }
132
-
133
-
133
+ go(dictionary.get, Nil(), 0)
134
+ }