@effekt-lang/effekt 0.8.0 → 0.10.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/README.md CHANGED
@@ -17,7 +17,7 @@ If you are looking for examples of the Effekt language, we invite you to look at
17
17
 
18
18
  ## Installation
19
19
 
20
- Please navigate to the [getting-started guide](https://effekt-lang.org/docs/getting-started#installing-effekt) on our [website](https://effekt-lang.org) for detailed instructions of how to install Effekt.
20
+ Please navigate to the [getting-started guide](https://effekt-lang.org/docs) on our [website](https://effekt-lang.org) for detailed instructions of how to install Effekt.
21
21
 
22
22
  ## Contributing
23
23
 
package/bin/effekt CHANGED
Binary file
@@ -1,28 +1,15 @@
1
+ (define (reset body)
2
+ (let ([p (newPrompt)])
3
+ (pushPrompt p (body p))))
1
4
 
2
- ; ;; EXAMPLE
3
- ; ; (handle ([Fail_22 (Fail_109 () resume_120 (Nil_74))])
4
- ; ; (let ((tmp86_121 ((Fail_109 Fail_22))))
5
- ; ; (Cons_73 tmp86_121 (Nil_74))))
6
- ; (define-syntax handle
7
- ; (syntax-rules ()
8
- ; [(_ ((cap1 (op1 (arg1 ...) k exp ...) ...) ...) body ...)
9
- ; (let ([P (newPrompt)])
10
- ; (pushPrompt P
11
- ; (let ([cap1 (cap1 (define-effect-op P (arg1 ...) k exp ...) ...)] ...)
12
- ; body ...)))]))
5
+ (define (shift p body)
6
+ (shift0-at p k (body k)))
13
7
 
14
- (define-syntax handle
15
- (syntax-rules ()
16
- [(_ ((cap1 (op1 (arg1 ...) k exp ...) ...) ...) body)
17
- (let ([P (newPrompt)])
18
- (pushPrompt P
19
- (body (cap1 (define-effect-op P (arg1 ...) k exp ...) ...) ...)))]))
20
-
21
- (define-syntax define-effect-op
22
- (syntax-rules ()
23
- [(_ P (arg1 ...) k exp ...)
24
- (lambda (arg1 ...)
25
- (shift0-at P k exp ...))]))
8
+ ;(define-syntax define-effect-op
9
+ ; (syntax-rules ()
10
+ ; [(_ P (arg1 ...) k exp ...)
11
+ ; (lambda (arg1 ...)
12
+ ; (shift0-at P k exp ...))]))
26
13
 
27
14
  ; state(init) { cell => ... }
28
15
  (define (state init body)
@@ -29,10 +29,11 @@
29
29
  (if (null? frames) (underflow v rest)
30
30
  (values ((car frames) v) (cons (make-Stack (cdr frames) arena prompt) rest))))))
31
31
 
32
- ; Control, Prompt -> Control
33
- (define (reset p c)
34
- (lambda (mk)
35
- (c (cons (make-Stack '() (make-arena) p) mk))))
32
+ ; Control -> Control
33
+ (define (reset c)
34
+ (let ([p (newPrompt)])
35
+ (lambda (mk)
36
+ ((c p) (cons (make-Stack '() (make-arena) p) mk)))))
36
37
 
37
38
  ; Prompt, Body -> Control
38
39
  (define (shift p f)
@@ -64,15 +65,6 @@
64
65
 
65
66
  (define newPrompt (lambda () (string #\p)))
66
67
 
67
- (define-syntax handle
68
- (syntax-rules ()
69
- [(_ ((cap1 (op1 (arg1 ...) kid exp) ...) ...) body)
70
- (let ([p (newPrompt)])
71
- (reset p (body
72
- (cap1 (define-effect-op p (arg1 ...) kid exp) ...)
73
- ...)))]))
74
-
75
-
76
68
  (define-syntax define-effect-op
77
69
  (syntax-rules ()
78
70
  [(_ p (arg1 ...) kid exp ...)
@@ -77,30 +77,7 @@ extern global def unsafeSet[T](arr: Array[T], index: Int, value: T): Unit =
77
77
  ret %Pos %z
78
78
  """
79
79
 
80
- /// Creates a copy of `arr`
81
- def copy[T](arr: Array[T]): Array[T] = {
82
- with on[OutOfBounds].default { <> }; // should not happen
83
- val len = arr.size;
84
- val newArray = allocate[T](len);
85
- copy[T](arr, 0, newArray, 0, len);
86
- newArray
87
- }
88
80
 
89
- /// Copies `length`-many elements from `from` to `to`
90
- /// starting at `start` (in `from`) and `offset` (in `to`)
91
- def copy[T](from: Array[T], start: Int, to: Array[T], offset: Int, length: Int): Unit / Exception[OutOfBounds] = {
92
- val startValid = start >= 0 && start + length <= from.size
93
- val offsetValid = offset >= 0 && offset + length <= to.size
94
-
95
- def go(i: Int, j: Int, length: Int): Unit =
96
- if (length > 0) {
97
- to.unsafeSet(j, from.unsafeGet(i))
98
- go(i + 1, j + 1, length - 1)
99
- }
100
-
101
- if (startValid && offsetValid) go(start, offset, length)
102
- else do raise(OutOfBounds(), "Array index out of bounds, when copying")
103
- }
104
81
 
105
82
  // Derived operations:
106
83
 
@@ -126,6 +103,44 @@ def build[T](size: Int) { index: Int => T }: Array[T] = {
126
103
  arr
127
104
  }
128
105
 
106
+ def resize[T](source: Array[T], size: Int): Array[T] = {
107
+ val target = allocate(size)
108
+ val n = min(source.size, target.size)
109
+ def go(i: Int): Array[T] =
110
+ if (i < n) {
111
+ target.unsafeSet(i, source.unsafeGet(i))
112
+ go(i + 1)
113
+ } else {
114
+ target
115
+ }
116
+ go(0)
117
+ }
118
+
119
+ /**
120
+ * Creates a copy of `arr`
121
+ */
122
+ def copy[T](array: Array[T]): Array[T] =
123
+ array.resize(array.size)
124
+
125
+ /**
126
+ * Copies `length`-many elements from `from` to `to`
127
+ * starting at `start` (in `from`) and `offset` (in `to`)
128
+ */
129
+ def copy[T](from: Array[T], start: Int, to: Array[T], offset: Int, length: Int): Unit / Exception[OutOfBounds] = {
130
+ val startValid = start >= 0 && start + length <= from.size
131
+ val offsetValid = offset >= 0 && offset + length <= to.size
132
+
133
+ def go(i: Int, j: Int, length: Int): Unit =
134
+ if (length > 0) {
135
+ to.unsafeSet(j, from.unsafeGet(i))
136
+ go(i + 1, j + 1, length - 1)
137
+ }
138
+
139
+ if (startValid && offsetValid) go(start, offset, length)
140
+ else do raise(OutOfBounds(), "Array index out of bounds, when copying")
141
+ }
142
+
143
+
129
144
  // Utility functions:
130
145
 
131
146
  def toList[T](arr: Array[T]): List[T] = {
@@ -140,26 +155,22 @@ def toList[T](arr: Array[T]): List[T] = {
140
155
 
141
156
  def foreach[T](arr: Array[T]){ action: T => Unit }: Unit =
142
157
  each(0, arr.size) { i =>
143
- val x: T = arr.unsafeGet(i)
144
- action(x)
158
+ action(arr.unsafeGet(i))
145
159
  }
146
160
 
147
161
  def foreach[T](arr: Array[T]){ action: (T) {Control} => Unit }: Unit =
148
162
  each(0, arr.size) { (i) {label} =>
149
- val x: T = arr.unsafeGet(i)
150
- action(x) {label}
163
+ action(arr.unsafeGet(i)) {label}
151
164
  }
152
165
 
153
166
  def foreachIndex[T](arr: Array[T]){ action: (Int, T) => Unit }: Unit =
154
167
  each(0, arr.size) { i =>
155
- val x: T = arr.unsafeGet(i)
156
- action(i, x)
168
+ action(i, arr.unsafeGet(i))
157
169
  }
158
170
 
159
171
  def foreachIndex[T](arr: Array[T]){ action: (Int, T) {Control} => Unit }: Unit =
160
172
  each(0, arr.size) { (i) {label} =>
161
- val x: T = arr.unsafeGet(i)
162
- action(i, x) {label}
173
+ action(i, arr.unsafeGet(i)) {label}
163
174
  }
164
175
 
165
176
  def sum(list: Array[Int]): Int = {
@@ -50,13 +50,33 @@ def resize(source: ByteArray, size: Int): ByteArray = {
50
50
  go(0)
51
51
  }
52
52
 
53
- extern pure def fromUTF8(str: String): ByteArray =
53
+ def foreach(arr: ByteArray){ action: Byte => Unit }: Unit =
54
+ each(0, arr.size) { i =>
55
+ action(arr.unsafeGet(i))
56
+ }
57
+
58
+ def foreach(arr: ByteArray){ action: (Byte) {Control} => Unit }: Unit =
59
+ each(0, arr.size) { (i) {label} =>
60
+ action(arr.unsafeGet(i)) {label}
61
+ }
62
+
63
+ def foreachIndex(arr: ByteArray){ action: (Int, Byte) => Unit }: Unit =
64
+ each(0, arr.size) { i =>
65
+ action(i, arr.unsafeGet(i))
66
+ }
67
+
68
+ def foreachIndex(arr: ByteArray){ action: (Int, Byte) {Control} => Unit }: Unit =
69
+ each(0, arr.size) { (i) {label} =>
70
+ action(i, arr.unsafeGet(i)) {label}
71
+ }
72
+
73
+ extern pure def fromString(str: String): ByteArray =
54
74
  js "(new TextEncoder().encode(${str}))"
55
75
  llvm """
56
76
  ret %Pos ${str}
57
77
  """
58
78
 
59
- extern pure def toUTF8(arr: ByteArray): String =
79
+ extern pure def toString(arr: ByteArray): String =
60
80
  js "(new TextDecoder('utf-8').decode(${arr}))"
61
81
  // assuming the buffer is already in UTF-8
62
82
  llvm """
@@ -0,0 +1,58 @@
1
+ /// Warning: This library currently only works with ASCII characters, **not** unicode!
2
+ module char
3
+
4
+ import exception
5
+
6
+
7
+ /// Checks if the given character is an ASCII whitespace
8
+ def isWhitespace(c: Char): Bool = c match {
9
+ case ' ' => true
10
+ case '\n' => true
11
+ case '\r' => true
12
+ case '\t' => true
13
+ case '\u0B' => true // vertical tab
14
+ case '\u0C' => true // form feed
15
+ case _ => false
16
+ }
17
+
18
+ /// Checks if the given character is an ASCII digit in base 10
19
+ /// Use `digitValue(c: Char)` to get the numeric value out.
20
+ def isDigit(c: Char): Bool = { c >= '0' && c <= '9' }
21
+
22
+ /// Checks if the given character is an ASCII digit in the given base
23
+ /// Use `digitValue(c: Char, base: Int)` to get the numeric value out.
24
+ def isDigit(c: Char, base: Int): Bool = {
25
+ with on[WrongFormat].default { false }
26
+ val _ = digitValue(c, base)
27
+ true
28
+ }
29
+
30
+ /// Gets the value of a given ASCII digit in base 10
31
+ def digitValue(c: Char): Int / Exception[WrongFormat] =
32
+ digitValue(c, 10)
33
+
34
+ /// Gets the value of a given ASCII digit in the given base
35
+ def digitValue(c: Char, base: Int): Int / Exception[WrongFormat] = {
36
+ val v = c match {
37
+ case c and c >= '0' && c <= '9' => (c.toInt - '0'.toInt)
38
+ case c and c >= 'a' && c <= 'z' => (c.toInt - 'a'.toInt) + 10
39
+ case c and c >= 'A' && c <= 'Z' => (c.toInt - 'A'.toInt) + 10
40
+ case _ => wrongFormat("'" ++ c.toString ++ "' is not a digit")
41
+ }
42
+ if (v >= base) { wrongFormat(c.toString ++ " is not a valid digit in base " ++ base.show) } else { v }
43
+ }
44
+
45
+ /// Checks if a given character is a 7-bit ASCII character
46
+ def isASCII(c: Char): Bool = { c.toInt < 128 }
47
+
48
+ /// Checks if a given character is an ASCII lower alphabetic character
49
+ def isLower(c: Char): Bool = { c >= 'a' && c <= 'z' }
50
+
51
+ /// Checks if a given character is an ASCII upper alphabetic character
52
+ def isUpper(c: Char): Bool = { c >= 'A' && c <= 'Z' }
53
+
54
+ /// Checks if a given character is an ASCII alphabetic or numeric character
55
+ def isAlphanumeric(c: Char): Bool = isDigit(c) || isLower(c) || isUpper(c)
56
+
57
+ /// Checks if a given character is an ASCII alphabetic character
58
+ def isAlphabetic(c: Char): Bool = isLower(c) || isUpper(c)
@@ -566,6 +566,11 @@ extern pure def bitwiseAnd(x: Int, y: Int): Int =
566
566
  chez "(logand ${x} ${y})"
567
567
  llvm "%z = and %Int ${x}, ${y} ret %Int %z"
568
568
 
569
+ extern pure def bitwiseOr(x: Int, y: Int): Int =
570
+ js "(${x} | ${y})"
571
+ chez "(logior ${x} ${y})"
572
+ llvm "%z = or %Int ${x}, ${y} ret %Int %z"
573
+
569
574
  extern pure def bitwiseXor(x: Int, y: Int): Int =
570
575
  js "(${x} ^ ${y})"
571
576
  chez "(logxor ${x} ${y})"
@@ -44,7 +44,7 @@ def readFile(path: String): String / Exception[IOError] = {
44
44
  def go(): String = {
45
45
  read(file, buffer, offset, chunkSize, -1) match {
46
46
  case 0 =>
47
- buffer.resize(offset).toUTF8
47
+ buffer.resize(offset).toString
48
48
  case n =>
49
49
  offset = offset + n
50
50
  if (offset + chunkSize > buffer.size) {
@@ -63,7 +63,7 @@ def writeFile(path: String, contents: String): Unit / Exception[IOError] = {
63
63
  with on[IOError].finalize { close(file) }
64
64
 
65
65
  val chunkSize = 1048576 // 1MB
66
- val buffer = contents.fromUTF8
66
+ val buffer = contents.fromString
67
67
  var offset = 0;
68
68
 
69
69
  def go(): Unit = {
@@ -0,0 +1,419 @@
1
+ module stream
2
+
3
+ import array
4
+ import bytearray
5
+ import io/filesystem
6
+ import io/error
7
+
8
+ // Effects
9
+ // -------
10
+
11
+ /// Describes push streams by emitting values of type `A`.
12
+ effect emit[A](value: A): Unit
13
+
14
+ /// Describes pull streams by requiring values of type `A`.
15
+ ///
16
+ /// The producer can decide to `stop` emitting values.
17
+ effect read[A](): A / stop
18
+
19
+ /// Signal from a producer to a consumer that there are no further values.
20
+ effect stop(): Nothing
21
+
22
+ /// Canonical handler of push streams that performs `action` for every
23
+ /// value emitted by `stream`.
24
+ def for[A, R] { stream: () => R / emit[A] } { action: A => Unit }: R =
25
+ try {
26
+ stream()
27
+ } with emit[A] { value =>
28
+ resume(action(value))
29
+ }
30
+
31
+ /// Like `for[A, R]`, but fixes the result of producing computation to the
32
+ /// common type `Unit`. This simplifies annotating the type of stream
33
+ /// elements `A` without having to also annotate `R`.
34
+ ///
35
+ /// e.g. for[Int] { prog() } { el => println(el) }
36
+ def for[A] { stream: () => Unit / emit[A] } { action: A => Unit }: Unit =
37
+ for[A, Unit]{stream}{action}
38
+
39
+ def continually[A] { action: () => A }: Nothing / emit[A] = {
40
+ def go(): Nothing = {
41
+ do emit(action())
42
+ go()
43
+ }
44
+ go()
45
+ }
46
+
47
+ /// Turns a `list` into a producer of a push stream
48
+ /// by emitting each contained value left-to-right.
49
+ def each[A](list: List[A]): Unit / emit[A] =
50
+ list match {
51
+ case Nil() => ()
52
+ case Cons(head, tail) =>
53
+ do emit(head)
54
+ each(tail)
55
+ }
56
+
57
+ /// Turns an `array` into a producer of a push stream
58
+ /// by emitting each contained value from 0 to length - 1.
59
+ def each[T](array: Array[T]): Unit / emit[T] = {
60
+ val n = array.size
61
+ def go(i: Int): Unit = {
62
+ if (i < n) {
63
+ do emit(array.unsafeGet(i))
64
+ go(i + 1)
65
+ }
66
+ }
67
+ go(0)
68
+ }
69
+
70
+ /// Turns `bytes` into a producer of a push stream
71
+ /// by emitting each contained value from 0 to length - 1.
72
+ def each(bytes: ByteArray): Unit / emit[Byte] = {
73
+ val n = bytes.size
74
+ def go(i: Int): Unit = {
75
+ if (i < n) {
76
+ do emit(bytes.unsafeGet(i))
77
+ go(i + 1)
78
+ }
79
+ }
80
+ go(0)
81
+ }
82
+
83
+ // not option
84
+ // not dequeue
85
+ // not queue
86
+ // not result
87
+ // not seq
88
+
89
+
90
+ def boundary[R] { program: () => R / stop }: Option[R] =
91
+ try {
92
+ Some(program())
93
+ } with stop {
94
+ def stop() = None()
95
+ }
96
+
97
+ def exhaustively[A] { program: () => A / stop } { action: A => Unit }: Unit =
98
+ try {
99
+ def go(): Unit = {
100
+ action(program())
101
+ go()
102
+ }
103
+ go()
104
+ } with stop {
105
+ def stop() = ()
106
+ }
107
+
108
+
109
+ // In Effekt lower bounds are inclusive and upper bounds are exclusive
110
+
111
+ record Indexed[A](index: Int, value: A)
112
+
113
+ def range(lower: Int, upper: Int): Unit / emit[Int] =
114
+ if (lower < upper) {
115
+ do emit(lower)
116
+ range(lower + 1, upper)
117
+ }
118
+
119
+ def rangeTo(upper: Int): Unit / emit[Int] =
120
+ range(0, upper)
121
+
122
+ def rangeFrom(lower: Int): Unit / emit[Int] = {
123
+ do emit(lower)
124
+ rangeFrom(lower + 1)
125
+ }
126
+
127
+
128
+ def index[A, R] { stream: () => R / emit[A] }: R / emit[Indexed[A]] = {
129
+ var i = 0;
130
+ try {
131
+ stream()
132
+ } with emit[A] { v =>
133
+ val c = i;
134
+ i = c + 1;
135
+ resume(do emit(Indexed(c, v)))
136
+ }
137
+ }
138
+
139
+ /// If `number` is zero or negative it does nothing
140
+ def take[A, R](number: Int) { stream: () => R / emit[A] }: R / { emit[A], stop } = {
141
+ if (number <= 0) do stop();
142
+ var i = 1;
143
+ try {
144
+ stream()
145
+ } with emit[A] { v =>
146
+ if (i < number) {
147
+ i = i + 1;
148
+ resume(do emit(v))
149
+ } else {
150
+ do stop()
151
+ }
152
+ }
153
+ }
154
+
155
+ /// If `number` is zero or negative it does nothing
156
+ def replicate[A](number: Int) { action: () => A }: Unit / emit[A] =
157
+ if (number > 0) {
158
+ do emit(action())
159
+ replicate(number - 1) {action}
160
+ }
161
+
162
+
163
+ def sum[R] { stream : () => R / emit[Int] }: (R, Int) = {
164
+ var s = 0;
165
+ try {
166
+ (stream(), s)
167
+ } with emit[Int] { v =>
168
+ s = s + v;
169
+ resume(())
170
+ }
171
+ }
172
+
173
+ def sum { stream : () => Unit / emit[Int] }: Int =
174
+ sum[Unit]{stream}.second
175
+
176
+ def collectList[A, R] { stream: () => R / emit[A] }: (R, List[A]) =
177
+ try {
178
+ (stream(), Nil())
179
+ } with emit[A] { (v) =>
180
+ val (r, vs) = resume(());
181
+ (r, Cons(v, vs))
182
+ }
183
+
184
+ def collectList[A] { stream: () => Unit / emit[A] }: List[A] =
185
+ collectList[A, Unit]{stream}.second
186
+
187
+ def collectArray[A, R] { stream: () => R / emit[A] }: (R, Array[A]) = {
188
+ var i = 0
189
+ var a = array::allocate(1)
190
+ try {
191
+ (stream(), a.resize(i))
192
+ } with emit[A] { (v) =>
193
+ if (i >= a.size) { a = a.resize(2 * a.size) }
194
+ a.unsafeSet(i, v)
195
+ i = i + 1
196
+ resume(())
197
+ }
198
+ }
199
+
200
+ def collectArray[A] { stream: () => Unit / emit[A] }: Array[A] =
201
+ collectArray[A, Unit]{stream}.second
202
+
203
+ def collectBytes[R] { stream: () => R / emit[Byte] }: (R, ByteArray) = {
204
+ var i = 0
205
+ var a = bytearray::allocate(1)
206
+ try {
207
+ (stream(), a.resize(i))
208
+ } with emit[Byte] { (v) =>
209
+ if (i >= a.size) { a = a.resize(2 * a.size) }
210
+ a.unsafeSet(i, v)
211
+ i = i + 1
212
+ resume(())
213
+ }
214
+ }
215
+
216
+ def collectBytes { stream: () => Unit / emit[Byte] }: ByteArray =
217
+ collectBytes[Unit]{stream}.second
218
+
219
+ def feed[T](list: List[T]) { reader: () => Unit / read[T] } = {
220
+ var l = list
221
+ try {
222
+ reader()
223
+ } with read[T] {
224
+ resume {
225
+ l match {
226
+ case Nil() => do stop()
227
+ case Cons(value, rest) =>
228
+ l = rest
229
+ return value
230
+ }
231
+ }
232
+ }
233
+ }
234
+
235
+ def feed[T](array: Array[T]) { reader: () => Unit / read[T] } = {
236
+ var i = 0
237
+ try {
238
+ reader()
239
+ } with read[T] {
240
+ resume {
241
+ if (i < array.size) {
242
+ array.unsafeGet(i)
243
+ } else {
244
+ do stop()
245
+ }
246
+ }
247
+ }
248
+ }
249
+
250
+ def feed(bytes: ByteArray) { reader: () => Unit / read[Byte] } = {
251
+ var i = 0
252
+ try {
253
+ reader()
254
+ } with read[Byte] {
255
+ resume {
256
+ if (i < bytes.size) {
257
+ bytes.unsafeGet(i)
258
+ } else {
259
+ do stop()
260
+ }
261
+ }
262
+ }
263
+ }
264
+
265
+ def source[A, R] { stream: () => Unit / emit[A] } { reader: () => R / read[A] }: R = {
266
+ var next = box { None() }
267
+ next = box {
268
+ try {
269
+ stream()
270
+ None()
271
+ } with emit[A] { (v) =>
272
+ next = box { resume(()) }
273
+ Some(v)
274
+ }
275
+ }
276
+ try {
277
+ reader()
278
+ } with read[A] {
279
+ resume {
280
+ next().getOrElse { do stop() }
281
+ }
282
+ }
283
+ }
284
+
285
+
286
+ def writeFile[R](path: String) { stream: () => R / emit[Byte] }: R / Exception[IOError] = {
287
+
288
+ val file = open(path, WriteOnly());
289
+ with on[IOError].finalize { close(file) }
290
+
291
+ val chunkSize = 1048576 // 1MB
292
+ val buffer = bytearray::allocate(chunkSize)
293
+ var offset = 0
294
+
295
+ def push(i: Int, n: Int): Unit = {
296
+ val r = write(file, buffer, i, n, -1)
297
+ if (r < n) {
298
+ push(i + r, n - r)
299
+ }
300
+ }
301
+
302
+ try {
303
+ val r = stream()
304
+ push(0, offset)
305
+ return r
306
+ } with emit[Byte] { (byte) =>
307
+ if (offset >= buffer.size) { push(0, buffer.size) }
308
+ buffer.unsafeSet(offset, byte)
309
+ offset = offset + 1
310
+ resume(())
311
+ }
312
+ }
313
+
314
+ def readFile[R](path: String) { reader: () => R / read[Byte] }: R / Exception[IOError] = {
315
+
316
+ val file = open(path, ReadOnly());
317
+ with on[IOError].finalize { close(file) }
318
+
319
+ val chunkSize = 1048576 // 1MB
320
+ val buffer = bytearray::allocate(chunkSize)
321
+ var offset = 0
322
+ var length = 0
323
+
324
+ def pull(): Unit / stop = {
325
+ read(file, buffer, 0, chunkSize, -1) match {
326
+ case 0 =>
327
+ do stop()
328
+ case n =>
329
+ offset = 0
330
+ length = n
331
+ }
332
+ }
333
+
334
+ try {
335
+ reader()
336
+ } with read[Byte] {
337
+ resume {
338
+ if (offset >= length) { pull() }
339
+ val byte = buffer.unsafeGet(offset)
340
+ offset = offset + 1
341
+ return byte
342
+ }
343
+ }
344
+ }
345
+
346
+ def decodeChar(): Char / {read[Byte], stop} = {
347
+ val b = do read().toInt
348
+ if (b < 128) {
349
+ b.toChar
350
+ } else if (b < 224) {
351
+ val part1 = bitwiseShl(bitwiseAnd(b, 31), 6)
352
+ val part2 = bitwiseAnd(do read().toInt, 63)
353
+ bitwiseOr(part1, part2).toChar
354
+ } else if (b < 240) {
355
+ val part1 = bitwiseShl(bitwiseAnd(b, 15), 12)
356
+ val part2 = bitwiseShl(bitwiseAnd(do read().toInt, 63), 6)
357
+ val part3 = bitwiseAnd(do read().toInt, 63)
358
+ bitwiseOr(bitwiseOr(part1, part2), part3).toChar
359
+ } else {
360
+ val part1 = bitwiseShl(bitwiseAnd(b, 7), 18)
361
+ val part2 = bitwiseShl(bitwiseAnd(do read().toInt, 63), 12)
362
+ val part3 = bitwiseShl(bitwiseAnd(do read().toInt, 63), 6)
363
+ val part4 = bitwiseAnd(do read().toInt, 63)
364
+ bitwiseOr(bitwiseOr(bitwiseOr(part1, part2), part3), part4).toChar
365
+ }
366
+ }
367
+
368
+ def encodeChar(char: Char): Unit / emit[Byte] = {
369
+ val code = char.toInt
370
+ if (code < 128) {
371
+ do emit(code.toByte)
372
+ } else if (code < 2048) {
373
+ do emit(bitwiseOr(192, bitwiseShr(code, 6)).toByte)
374
+ do emit(bitwiseOr(128, bitwiseAnd(code, 63)).toByte)
375
+ } else if (code < 65536) {
376
+ do emit(bitwiseOr(224, bitwiseShr(code, 12)).toByte)
377
+ do emit(bitwiseOr(128, bitwiseAnd(bitwiseShr(code, 6), 63)).toByte)
378
+ do emit(bitwiseOr(128, bitwiseAnd(code, 63)).toByte)
379
+ } else {
380
+ do emit(bitwiseOr(240, bitwiseShr(code, 18)).toByte)
381
+ do emit(bitwiseOr(128, bitwiseAnd(bitwiseShr(code, 12), 63)).toByte)
382
+ do emit(bitwiseOr(128, bitwiseAnd(bitwiseShr(code, 6), 63)).toByte)
383
+ do emit(bitwiseOr(128, bitwiseAnd(code, 63)).toByte)
384
+ }
385
+ }
386
+
387
+ def decodeUTF8[R] { reader: () => R / read[Char] }: R / read[Byte] =
388
+ try {
389
+ reader()
390
+ } with read[Char] {
391
+ resume { decodeChar() }
392
+ }
393
+
394
+ def encodeUTF8[R] { stream: () => R / emit[Char] }: R / emit[Byte] =
395
+ try {
396
+ stream()
397
+ } with emit[Char] { char =>
398
+ resume(encodeChar(char))
399
+ }
400
+
401
+ def feed(string: String) { reader: () => Unit / read[Char] } =
402
+ feed(string.fromString) {
403
+ decodeUTF8 {
404
+ reader()
405
+ }
406
+ }
407
+
408
+ def each(string: String): Unit / emit[Char] =
409
+ feed(string) {
410
+ exhaustively[Char] { do read() } { char => do emit(char) }
411
+ }
412
+
413
+ def collectString[R] { stream: () => R / emit[Char] }: (R, String) = {
414
+ val (result, bytes) = collectBytes { encodeUTF8 { stream } }
415
+ (result, bytes.toString)
416
+ }
417
+
418
+ def collectString { stream: () => Unit / emit[Char] }: String =
419
+ collectString[Unit]{stream}.second
@@ -222,15 +222,6 @@ def lastIndexOf(str: String, sub: String, from: Int): Option[Int] = {
222
222
  // extern pure def unsafeIndexOf(str: String, sub: String): Int =
223
223
  // js "${str}.indexOf(${sub})"
224
224
 
225
- interface Stream {
226
- def emit(string: Char): Unit
227
- }
228
-
229
- def string[T] { prog: => T / Stream }: (T, String) = <>
230
-
231
- // TODO implement after concurrent IO (we need to stub `process.stdout` in JS for browsers).
232
- def printing[T] { prog: => T / Stream }: T = <>
233
-
234
225
 
235
226
  // Characters
236
227
  // ----------
@@ -299,10 +290,6 @@ extern pure def infixGte(x: Char, y: Char): Bool =
299
290
  ret %Pos %adt_boolean
300
291
  """
301
292
 
302
- // TODO iterator over codepoints (maybe use the JS primitive feature???)
303
-
304
- extern type StringIterator
305
-
306
293
 
307
294
  /**
308
295
  * Determines the number of bytes needed by a codepoint
@@ -23,7 +23,7 @@ function Arena(_region) {
23
23
  fresh: function(init) {
24
24
  const cell = Cell(init);
25
25
  // region keeps track what to backup, but we do not need to backup unreachable cells
26
- region.push(new WeakRef(cell))
26
+ region.push(cell) // new WeakRef(cell))
27
27
  return cell;
28
28
  },
29
29
  region: _region,
@@ -31,15 +31,14 @@ function Arena(_region) {
31
31
  // a region aggregates weak references
32
32
  const nested = Arena([])
33
33
  // this doesn't work yet, since Arena.backup doesn't return a thunk
34
- region.push(new WeakRef(nested))
34
+ region.push(nested) //new WeakRef(nested))
35
35
  return nested;
36
36
  },
37
37
  backup: function() {
38
38
  const _backup = []
39
39
  let nextIndex = 0;
40
40
  for (const ref of region) {
41
- // console.log(ref)
42
- const cell = ref.deref()
41
+ const cell = ref //.deref()
43
42
  // only backup live cells
44
43
  if (cell) {
45
44
  _backup[nextIndex] = cell.backup()
@@ -50,7 +49,7 @@ function Arena(_region) {
50
49
  const region = []
51
50
  let nextIndex = 0;
52
51
  for (const restoreCell of _backup) {
53
- region[nextIndex] = new WeakRef(restoreCell())
52
+ region[nextIndex] = restoreCell() // new WeakRef(restoreCell())
54
53
  nextIndex++
55
54
  }
56
55
  return Arena(region)
@@ -114,11 +113,7 @@ function SHIFT(p, body, ks, k) {
114
113
  cont = { stack: meta.stack, prompt: meta.prompt, backup: meta.arena.backup(), rest: cont }
115
114
  meta = meta.rest
116
115
 
117
- function resumeValue(a, ks, k) {
118
- return resumeComp((ks, k) => k(a, ks), ks, k)
119
- }
120
116
  function resumeComp(c, ks, k) {
121
- //console.log("Resuming", ks.arena)
122
117
  let meta = { stack: k, prompt: ks.prompt, arena: ks.arena, rest: ks.rest }
123
118
  let toRewind = cont
124
119
  while (!!toRewind) {
@@ -133,7 +128,7 @@ function SHIFT(p, body, ks, k) {
133
128
 
134
129
  let k1 = meta.stack
135
130
  meta.stack = null
136
- return body(resumeValue, resumeComp, meta, k1)
131
+ return body(resumeComp, meta, k1)
137
132
  }
138
133
 
139
134
  function RUN_TOPLEVEL(comp) {
@@ -81,7 +81,7 @@ char* c_bytearray_into_nullterminated_string(const struct Pos arr) {
81
81
  // TODO do this in Effekt
82
82
  struct Pos c_bytearray_show_Int(const Int n) {
83
83
  char str[24];
84
- sprintf(str, "%" PRId64, n);
84
+ snprintf(str, sizeof(str), "%" PRId64, n);
85
85
  return c_bytearray_from_nullterminated_string(str);
86
86
  }
87
87
 
@@ -112,14 +112,14 @@ struct Pos c_bytearray_show_Char(const uint64_t n) {
112
112
  // TODO do this in Effekt
113
113
  struct Pos c_bytearray_show_Byte(const Byte n) {
114
114
  char str[4]; // Byte values range from 0 to 255, 3 characters + null terminator
115
- sprintf(str, "%" PRIu8, n);
115
+ snprintf(str, sizeof(str), "%" PRIu8, n);
116
116
  return c_bytearray_from_nullterminated_string(str);
117
117
  }
118
118
 
119
119
  // TODO do this in Effekt
120
120
  struct Pos c_bytearray_show_Double(const Double x) {
121
- char str[64]; // TODO is this large enough? Possibly use snprintf first
122
- sprintf(str, "%g", x);
121
+ char str[64]; // TODO is this large enough?
122
+ snprintf(str, sizeof(str), "%g", x);
123
123
  return c_bytearray_from_nullterminated_string(str);
124
124
  }
125
125
 
@@ -58,14 +58,6 @@
58
58
  ; Pointers for a heap allocated stack
59
59
  %Memory = type { %StackPointer, %Base, %Limit }
60
60
 
61
- ; The garbage collector differentiates three groups of types:
62
- ; - Values (Integer, Double)
63
- ; - Objects (Positive, Negative)
64
- ; - Strings
65
- ; For each group we have an arena where mutable state is allocated.
66
- ;
67
- %Region = type [ 3 x %Memory ]
68
-
69
61
  ; Unique address for each handler.
70
62
  %Prompt = type ptr
71
63
 
@@ -82,7 +74,7 @@
82
74
  ; This is used for two purposes:
83
75
  ; - a refied first-class list of stacks (cyclic linked-list)
84
76
  ; - as part of an intrusive linked-list of stacks (meta stack)
85
- %StackValue = type { %ReferenceCount, %Memory, %Region, %Prompt, i1, %Stack }
77
+ %StackValue = type { %ReferenceCount, %Memory, %Prompt, i1, %Stack }
86
78
 
87
79
 
88
80
 
@@ -124,7 +116,7 @@ declare void @exit(i64)
124
116
  ; Prompts
125
117
 
126
118
  define private %Prompt @currentPrompt(%Stack %stack) {
127
- %prompt_pointer = getelementptr %StackValue, ptr %stack, i64 0, i32 3
119
+ %prompt_pointer = getelementptr %StackValue, ptr %stack, i64 0, i32 2
128
120
  %prompt = load %Prompt, ptr %prompt_pointer
129
121
  ret %Prompt %prompt
130
122
  }
@@ -222,77 +214,6 @@ define void @eraseNegative(%Neg %val) alwaysinline {
222
214
 
223
215
 
224
216
  ; Arena management
225
- define private ptr @getRegionPointer(%Prompt %prompt) {
226
- %stack_pointer = getelementptr %PromptValue, %Prompt %prompt, i64 0, i32 1
227
- %stack = load %Stack, ptr %stack_pointer
228
- %region_pointer = getelementptr %StackValue, %Stack %stack, i64 0, i32 2
229
- ret ptr %region_pointer
230
- }
231
-
232
- define private { ptr, %Reference } @alloc(i64 %index, %Prompt %prompt) alwaysinline {
233
- %region_pointer = call ptr @getRegionPointer(%Prompt %prompt)
234
-
235
- %stackPointer_pointer = getelementptr %Region, ptr %region_pointer, i64 0, i64 %index, i32 0
236
- %base_pointer = getelementptr %Region, ptr %region_pointer, i64 0, i64 %index, i32 1
237
- %limit_pointer = getelementptr %Region, ptr %region_pointer, i64 0, i64 %index, i32 2
238
-
239
- %stackPointer = load %StackPointer, ptr %stackPointer_pointer
240
- %base = load %Base, ptr %base_pointer
241
- %limit = load %Limit, ptr %limit_pointer
242
-
243
- %object = icmp ne i64 %index, 0
244
- %size = select i1 %object, i64 16, i64 8
245
-
246
- %nextStackPointer = getelementptr i8, %StackPointer %stackPointer, i64 %size
247
-
248
- %cmp = icmp ule %StackPointer %nextStackPointer, %limit
249
- br i1 %cmp, label %continue, label %realloc
250
-
251
- continue:
252
- store %StackPointer %nextStackPointer, ptr %stackPointer_pointer
253
- %intBase = ptrtoint %Base %base to i64
254
- %intStackPointer = ptrtoint %StackPointer %stackPointer to i64
255
- %offset = sub i64 %intStackPointer, %intBase
256
-
257
- %ret.0 = insertvalue { ptr, %Reference } undef, %StackPointer %stackPointer, 0
258
- %ret.1 = insertvalue { ptr, %Reference } %ret.0, %Prompt %prompt, 1, 0
259
- %ret.2 = insertvalue { ptr, %Reference } %ret.1, i64 %offset, 1, 1
260
- ret { ptr, %Reference } %ret.2
261
-
262
- realloc:
263
- %intBase_2 = ptrtoint %Base %base to i64
264
- %intLimit = ptrtoint %Limit %limit to i64
265
- %arenaSize = sub i64 %intLimit, %intBase_2
266
- %empty = icmp eq i64 %arenaSize, 0
267
- %double = mul i64 %arenaSize, 2
268
- %newArenaSize = select i1 %empty, i64 1024, i64 %double
269
-
270
- %newBase = call ptr @realloc(ptr %base, i64 %newArenaSize)
271
- %newlimit = getelementptr i8, %Base %newBase, i64 %newArenaSize
272
- %newStackPointer = getelementptr i8, %Base %newBase, i64 %arenaSize
273
- %newNextStackPointer = getelementptr i8, %StackPointer %newStackPointer, i64 %size
274
-
275
- store %Base %newBase, ptr %base_pointer
276
- store %Limit %newlimit, ptr %limit_pointer
277
- store %StackPointer %newNextStackPointer, ptr %stackPointer_pointer
278
-
279
- %ret..0 = insertvalue { ptr, %Reference } undef, %StackPointer %newStackPointer, 0
280
- %ret..1 = insertvalue { ptr, %Reference } %ret..0, %Prompt %prompt, 1, 0
281
- %ret..2 = insertvalue { ptr, %Reference } %ret..1, i64 %arenaSize, 1, 1
282
- ret { ptr, %Reference } %ret..2
283
- }
284
-
285
-
286
- define private ptr @getPointer(%Reference %reference, i64 %index, %Stack %stack) {
287
- %prompt = extractvalue %Reference %reference, 0
288
- %offset = extractvalue %Reference %reference, 1
289
-
290
- %region_pointer = call ptr @getRegionPointer(%Prompt %prompt)
291
- %base_pointer = getelementptr %Region, ptr %region_pointer, i64 0, i64 %index, i32 1
292
- %base = load %Base, ptr %base_pointer
293
- %pointer = getelementptr i8, ptr %base, i64 %offset
294
- ret ptr %pointer
295
- }
296
217
 
297
218
  define private %Stack @getStack(%Prompt %prompt) {
298
219
  %stack_pointer = getelementptr %PromptValue, %Prompt %prompt, i64 0, i32 1
@@ -414,8 +335,8 @@ define private %Stack @reset(%Stack %oldStack) {
414
335
  %stackMemory = call %Memory @newMemory()
415
336
 
416
337
  %stack.0 = insertvalue %StackValue zeroinitializer, %Memory %stackMemory, 1
417
- %stack.1 = insertvalue %StackValue %stack.0, %Prompt %prompt, 3
418
- %stack.2 = insertvalue %StackValue %stack.1, %Stack %oldStack, 5
338
+ %stack.1 = insertvalue %StackValue %stack.0, %Prompt %prompt, 2
339
+ %stack.2 = insertvalue %StackValue %stack.1, %Stack %oldStack, 4
419
340
 
420
341
  store %StackValue %stack.2, %Stack %stack
421
342
 
@@ -426,7 +347,7 @@ define private %Stack @reset(%Stack %oldStack) {
426
347
  }
427
348
 
428
349
  define private void @updatePrompts(%Stack %stack) {
429
- %dirtyBit_pointer = getelementptr %StackValue, %Stack %stack, i64 0, i32 4
350
+ %dirtyBit_pointer = getelementptr %StackValue, %Stack %stack, i64 0, i32 3
430
351
  %dirtyBit = load i1, ptr %dirtyBit_pointer
431
352
  br i1 %dirtyBit, label %continue, label %done
432
353
 
@@ -434,7 +355,7 @@ done:
434
355
  ret void
435
356
 
436
357
  continue:
437
- %prompt_pointer = getelementptr %StackValue, %Stack %stack, i64 0, i32 3
358
+ %prompt_pointer = getelementptr %StackValue, %Stack %stack, i64 0, i32 2
438
359
  %prompt = load %Prompt, ptr %prompt_pointer
439
360
  %stack_pointer = getelementptr %PromptValue, %Prompt %prompt, i64 0, i32 1
440
361
  %promptStack = load %Stack, ptr %stack_pointer
@@ -449,16 +370,16 @@ update:
449
370
  store %Stack %stack, ptr %stack_pointer
450
371
  store i1 0, ptr %dirtyBit_pointer
451
372
 
452
- %next_pointer = getelementptr %StackValue, %Stack %stack, i64 0, i32 5
373
+ %next_pointer = getelementptr %StackValue, %Stack %stack, i64 0, i32 4
453
374
  %next = load %Stack, ptr %next_pointer
454
375
  tail call void @updatePrompts(%Stack %next)
455
376
  ret void
456
377
  }
457
378
 
458
379
  define void @displace(%Stack %stack) {
459
- %prompt_pointer = getelementptr %StackValue, %Stack %stack, i64 0, i32 3
460
- %next_pointer = getelementptr %StackValue, %Stack %stack, i64 0, i32 5
461
- %dirtyBit_pointer = getelementptr %StackValue, %Stack %stack, i64 0, i32 4
380
+ %prompt_pointer = getelementptr %StackValue, %Stack %stack, i64 0, i32 2
381
+ %next_pointer = getelementptr %StackValue, %Stack %stack, i64 0, i32 4
382
+ %dirtyBit_pointer = getelementptr %StackValue, %Stack %stack, i64 0, i32 3
462
383
  %dirtyBit = load i1, ptr %dirtyBit_pointer
463
384
  br i1 %dirtyBit, label %done, label %continue
464
385
 
@@ -478,7 +399,7 @@ continue:
478
399
 
479
400
  define %Stack @resume(%Resumption %resumption, %Stack %oldStack) {
480
401
  %uniqueResumption = call %Resumption @uniqueStack(%Resumption %resumption)
481
- %rest_pointer = getelementptr %StackValue, %Resumption %uniqueResumption, i64 0, i32 5
402
+ %rest_pointer = getelementptr %StackValue, %Resumption %uniqueResumption, i64 0, i32 4
482
403
  %start = load %Stack, ptr %rest_pointer
483
404
  call void @updatePrompts(%Stack %start)
484
405
 
@@ -490,7 +411,7 @@ define %Stack @resume(%Resumption %resumption, %Stack %oldStack) {
490
411
  define private {%Resumption, %Stack} @shift(%Stack %stack, %Prompt %prompt) {
491
412
  %resumpion_pointer = getelementptr %PromptValue, %Prompt %prompt, i64 0, i32 1
492
413
  %resumption = load %Stack, ptr %resumpion_pointer
493
- %next_pointer = getelementptr %StackValue, %Stack %resumption, i64 0, i32 5
414
+ %next_pointer = getelementptr %StackValue, %Stack %resumption, i64 0, i32 4
494
415
  %next = load %Stack, ptr %next_pointer
495
416
 
496
417
  store %Stack %stack, ptr %next_pointer
@@ -522,23 +443,6 @@ return:
522
443
  ret void
523
444
  }
524
445
 
525
- define private void @eraseRegion(%Region %region) alwaysinline {
526
- %valuesBase = extractvalue %Region %region, 0, 1
527
- call void @free(%Base %valuesBase)
528
-
529
- %objectsBase = extractvalue %Region %region, 1, 1
530
- %objectsStackPointer = extractvalue %Region %region, 1, 0
531
- call void @forEachObject(%Base %objectsBase, %StackPointer %objectsStackPointer, %Eraser @erasePositive)
532
- call void @free(%Base %objectsBase)
533
-
534
- %stringsBase = extractvalue %Region %region, 2, 1
535
- %stringsStackPointer = extractvalue %Region %region, 2, 0
536
- call void @forEachObject(%Base %stringsBase, %StackPointer %stringsStackPointer, %Eraser @erasePositive)
537
- call void @free(%Base %stringsBase)
538
-
539
- ret void
540
- }
541
-
542
446
  define void @erasePrompt(%Prompt %prompt, i1 %dirtyBit) alwaysinline {
543
447
  br i1 %dirtyBit, label %continue, label %clearPrompt
544
448
 
@@ -572,25 +476,26 @@ define void @sharePrompt(%Prompt %prompt) alwaysinline {
572
476
 
573
477
  define private %Stack @underflowStack(%Stack %stack) {
574
478
  %stackMemory = getelementptr %StackValue, %Stack %stack, i64 0, i32 1
575
- %stackRegion = getelementptr %StackValue, %Stack %stack, i64 0, i32 2
576
- %stackPrompt = getelementptr %StackValue, %Stack %stack, i64 0, i32 3
577
- %stackDirtyBit = getelementptr %StackValue, %Stack %stack, i64 0, i32 4
578
- %stackRest = getelementptr %StackValue, %Stack %stack, i64 0, i32 5
479
+ %stackPrompt = getelementptr %StackValue, %Stack %stack, i64 0, i32 2
480
+ %stackDirtyBit = getelementptr %StackValue, %Stack %stack, i64 0, i32 3
481
+ %stackRest = getelementptr %StackValue, %Stack %stack, i64 0, i32 4
579
482
 
580
483
  %memory = load %Memory, ptr %stackMemory
581
- %region = load %Region, ptr %stackRegion
582
484
  %prompt = load %Prompt, ptr %stackPrompt
583
485
  %rest = load %Stack, ptr %stackRest
584
486
  %dirtyBit = load i1, ptr %stackDirtyBit
585
487
 
586
488
  call void @eraseMemory(%Memory %memory)
587
- call void @eraseRegion(%Region %region)
588
489
  call void @erasePrompt(%Prompt %prompt, i1 false)
589
490
  call void @free(%Stack %stack)
590
491
 
591
492
  ret %Stack %rest
592
493
  }
593
494
 
495
+ define private void @nop(%Stack %stack) {
496
+ ret void
497
+ }
498
+
594
499
  define private %Memory @copyMemory(%Memory %memory) alwaysinline {
595
500
  %stackPointer = extractvalue %Memory %memory, 0
596
501
  %base = extractvalue %Memory %memory, 1
@@ -618,29 +523,6 @@ define private %Memory @copyMemory(%Memory %memory) alwaysinline {
618
523
  ret %Memory %memory.2
619
524
  }
620
525
 
621
- define private %Region @copyRegion(%Region %region) alwaysinline {
622
- %memory.0 = extractvalue %Region %region, 0
623
- %memory.1 = extractvalue %Region %region, 1
624
- %memory.2 = extractvalue %Region %region, 2
625
-
626
- %objectsBase = extractvalue %Region %region, 1, 1
627
- %objectsStackPointer = extractvalue %Region %region, 1, 0
628
- call void @forEachObject(%Base %objectsBase, %StackPointer %objectsStackPointer, %Sharer @sharePositive)
629
-
630
- %stringsBase = extractvalue %Region %region, 2, 1
631
- %stringsStackPointer = extractvalue %Region %region, 2, 0
632
- call void @forEachObject(%Base %stringsBase, %StackPointer %stringsStackPointer, %Sharer @sharePositive)
633
-
634
- %newMemory.0 = call %Memory @copyMemory(%Memory %memory.0)
635
- %newMemory.1 = call %Memory @copyMemory(%Memory %memory.1)
636
- %newMemory.2 = call %Memory @copyMemory(%Memory %memory.2)
637
-
638
- %region.0 = insertvalue %Region undef, %Memory %newMemory.0, 0
639
- %region.1 = insertvalue %Region %region.0, %Memory %newMemory.1, 1
640
- %region.2 = insertvalue %Region %region.1, %Memory %newMemory.2, 2
641
-
642
- ret %Region %region.2
643
- }
644
526
 
645
527
  define private %Resumption @uniqueStack(%Resumption %resumption) alwaysinline {
646
528
 
@@ -655,7 +537,7 @@ done:
655
537
  copy:
656
538
  %newOldReferenceCount = sub %ReferenceCount %referenceCount, 1
657
539
  store %ReferenceCount %newOldReferenceCount, ptr %referenceCount_pointer
658
- %stack_pointer = getelementptr %StackValue, %Resumption %resumption, i64 0, i32 5
540
+ %stack_pointer = getelementptr %StackValue, %Resumption %resumption, i64 0, i32 4
659
541
  %stack = load %Stack, ptr %stack_pointer
660
542
 
661
543
  %size = ptrtoint ptr getelementptr (%StackValue, ptr null, i64 1) to i64
@@ -668,34 +550,28 @@ loop:
668
550
  %newStack = phi %Stack [%newHead, %copy], [%nextNew, %next]
669
551
 
670
552
  %stackMemory = getelementptr %StackValue, %Stack %old, i64 0, i32 1
671
- %stackRegion = getelementptr %StackValue, %Stack %old, i64 0, i32 2
672
- %stackPrompt = getelementptr %StackValue, %Stack %old, i64 0, i32 3
673
- %stackRest = getelementptr %StackValue, %Stack %old, i64 0, i32 5
553
+ %stackPrompt = getelementptr %StackValue, %Stack %old, i64 0, i32 2
554
+ %stackRest = getelementptr %StackValue, %Stack %old, i64 0, i32 4
674
555
 
675
556
  %memory = load %Memory, ptr %stackMemory
676
- %region = load %Region, ptr %stackRegion
677
557
  %prompt = load %Prompt, ptr %stackPrompt
678
558
  %rest = load %Stack, ptr %stackRest
679
559
 
680
560
  %newStackReferenceCounter = getelementptr %StackValue, %Stack %newStack, i64 0, i32 0
681
561
  %newStackMemory = getelementptr %StackValue, %Stack %newStack, i64 0, i32 1
682
- %newStackRegion = getelementptr %StackValue, %Stack %newStack, i64 0, i32 2
683
- %newStackPrompt = getelementptr %StackValue, %Stack %newStack, i64 0, i32 3
684
- %newStackDirtyBit = getelementptr %StackValue, %Stack %newStack, i64 0, i32 4
685
- %newStackRest = getelementptr %StackValue, %Stack %newStack, i64 0, i32 5
562
+ %newStackPrompt = getelementptr %StackValue, %Stack %newStack, i64 0, i32 2
563
+ %newStackDirtyBit = getelementptr %StackValue, %Stack %newStack, i64 0, i32 3
564
+ %newStackRest = getelementptr %StackValue, %Stack %newStack, i64 0, i32 4
686
565
 
687
566
  %newMemory = call %Memory @copyMemory(%Memory %memory)
688
567
 
689
568
  %newStackPointer = extractvalue %Memory %newMemory, 0
690
569
  call void @shareFrames(%StackPointer %newStackPointer)
691
570
 
692
- %newRegion = call %Region @copyRegion(%Region %region)
693
-
694
571
  call void @sharePrompt(%Prompt %prompt)
695
572
 
696
- store i64 0, ptr %newStackReferenceCounter
573
+ store %ReferenceCount 0, ptr %newStackReferenceCounter
697
574
  store %Memory %newMemory, ptr %newStackMemory
698
- store %Region %newRegion, ptr %newStackRegion
699
575
  store %Prompt %prompt, ptr %newStackPrompt
700
576
  store i1 1, ptr %newStackDirtyBit
701
577
 
@@ -731,7 +607,7 @@ define void @eraseResumption(%Resumption %resumption) alwaysinline {
731
607
  ret void
732
608
 
733
609
  free:
734
- %stack_pointer = getelementptr %StackValue, %Resumption %resumption, i64 0, i32 5
610
+ %stack_pointer = getelementptr %StackValue, %Resumption %resumption, i64 0, i32 4
735
611
  %stack = load %Stack, ptr %stack_pointer
736
612
  store %Stack null, ptr %stack_pointer
737
613
  call void @eraseStack(%Stack %stack)
@@ -740,20 +616,17 @@ define void @eraseResumption(%Resumption %resumption) alwaysinline {
740
616
 
741
617
  define void @eraseStack(%Stack %stack) alwaysinline {
742
618
  %stackPointer_pointer = getelementptr %StackValue, %Stack %stack, i64 0, i32 1, i32 0
743
- %region_pointer = getelementptr %StackValue, %Stack %stack, i64 0, i32 2
744
- %prompt_pointer = getelementptr %StackValue, %Stack %stack, i64 0, i32 3
745
- %dirtyBit_pointer = getelementptr %StackValue, %Stack %stack, i64 0, i32 4
746
- %rest_pointer = getelementptr %StackValue, %Stack %stack, i64 0, i32 5
619
+ %prompt_pointer = getelementptr %StackValue, %Stack %stack, i64 0, i32 2
620
+ %dirtyBit_pointer = getelementptr %StackValue, %Stack %stack, i64 0, i32 3
621
+ %rest_pointer = getelementptr %StackValue, %Stack %stack, i64 0, i32 4
747
622
 
748
623
  %stackPointer = load %StackPointer, ptr %stackPointer_pointer
749
- %region = load %Region, ptr %region_pointer
750
624
  %prompt = load %Stack, ptr %prompt_pointer
751
625
  %dirtyBit = load i1, ptr %dirtyBit_pointer
752
626
  %rest = load %Stack, ptr %rest_pointer
753
627
 
754
628
  call void @free(%Stack %stack)
755
629
  call void @eraseFrames(%StackPointer %stackPointer)
756
- call void @eraseRegion(%Region %region)
757
630
  call void @erasePrompt(%Prompt %prompt, i1 %dirtyBit)
758
631
 
759
632
  %isNull = icmp eq %Stack %rest, null
@@ -787,7 +660,8 @@ define private void @eraseFrames(%StackPointer %stackPointer) alwaysinline {
787
660
 
788
661
  define private tailcc void @topLevel(%Pos %val, %Stack %stack) {
789
662
  %rest = call %Stack @underflowStack(%Stack %stack)
790
- ; assert %rest == null
663
+ ; rest holds global variables
664
+ call void @eraseStack(%Stack %rest)
791
665
  ret void
792
666
  }
793
667
 
@@ -804,7 +678,23 @@ define private void @topLevelEraser(%Environment %environment) {
804
678
  @global = private global { i64, %Stack } { i64 0, %Stack null }
805
679
 
806
680
  define private %Stack @withEmptyStack() {
807
- %stack = call %Stack @reset(%Stack null)
681
+ %globals = call %Stack @reset(%Stack null)
682
+
683
+ %globalsStackPointer_pointer = getelementptr %StackValue, %Stack %globals, i64 0, i32 1, i32 0
684
+ %globalsStackPointer = load %StackPointer, ptr %globalsStackPointer_pointer
685
+
686
+ %returnAddressPointer.0 = getelementptr %FrameHeader, %StackPointer %globalsStackPointer, i64 0, i32 0
687
+ %sharerPointer.0 = getelementptr %FrameHeader, %StackPointer %globalsStackPointer, i64 0, i32 1
688
+ %eraserPointer.0 = getelementptr %FrameHeader, %StackPointer %globalsStackPointer, i64 0, i32 2
689
+
690
+ store ptr @nop, ptr %returnAddressPointer.0
691
+ store ptr @nop, ptr %sharerPointer.0
692
+ store ptr @free, ptr %eraserPointer.0
693
+
694
+ %globalsStackPointer_2 = getelementptr %FrameHeader, %StackPointer %globalsStackPointer, i64 1
695
+ store %StackPointer %globalsStackPointer_2, ptr %globalsStackPointer_pointer
696
+
697
+ %stack = call %Stack @reset(%Stack %globals)
808
698
 
809
699
  %globalStack = getelementptr %PromptValue, %Prompt @global, i64 0, i32 1
810
700
  store %Stack %stack, ptr %globalStack
@@ -1,4 +1,4 @@
1
- <!doctype html><html lang=en><head><meta charset=utf-8><meta http-equiv=x-ua-compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1"><title>Eclipse Public License 2.0 (EPL) | The Eclipse Foundation</title><meta property="og:title" content="Eclipse Public License 2.0 (EPL) | The Eclipse Foundation"><meta name=twitter:title content="Eclipse Public License 2.0 (EPL) | The Eclipse Foundation"><meta name=description content="The Eclipse Foundation provides our global community of individuals and organisations with a mature, scalable, and business-friendly environment for open source …"><meta property="og:description" content="The Eclipse Foundation provides our global community of individuals and organisations with a mature, scalable, and business-friendly environment for open source …"><meta name=twitter:description content="The Eclipse Foundation provides our global community of individuals and organisations with a mature, scalable, and business-friendly environment for open source …"><meta name=author content="Wayne Beaton"><link href=/favicon.ico rel=icon type=image/x-icon><meta property="og:image" content="https://www.eclipse.org/images/logos/eclipse-foundation-400x400.png"><meta name=twitter:image content="https://www.eclipse.org/images/logos/eclipse-foundation-400x400.png"><meta name=twitter:card content="summary"><meta name=twitter:site content="@eclipsefdn"><meta name=twitter:creator content="@eclipsefdn"><meta property="og:url" content="https://www.eclipse.org/legal/epl-2.0/"><meta property="og:type" content="website"><meta property="og:site_name" content="Eclipse Foundation"><meta name=keywords content="epl,epl-2.0,legal,foundation,eclipse,eclipse public license,license,licenses"><meta name=generator content="Hugo 0.110.0"><link rel=canonical href=https://www.eclipse.org/legal/epl-2.0/><link rel=alternate href=/legal/epl-2.0/index.xml type=application/rss+xml title><link rel=stylesheet href="/public/css/styles.css?v=1730661366"><script>(function(e,t,n,s,o){e[s]=e[s]||[],e[s].push({"gtm.start":(new Date).getTime(),event:"gtm.js"});var a=t.getElementsByTagName(n)[0],i=t.createElement(n),r=s!="dataLayer"?"&l="+s:"";i.async=!0,i.src="https://www.googletagmanager.com/gtm.js?id="+o+r,a.parentNode.insertBefore(i,a)})(window,document,"script","dataLayer","GTM-5WLCZXC")</script><script>var tableClasses="table"</script><link href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap" rel=stylesheet type=text/css></head><body><noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-5WLCZXC" height=0 width=0 style=display:none;visibility:hidden></iframe></noscript><a class=sr-only href=#content>Skip to main content</a><header class="header-wrapper header-wrapper" id=header><div class=header-toolbar><div class=container><div class=header-toolbar-row><div class="toolbar-btn toolbar-search-btn dropdown"><button class=dropdown-toggle id=toolbar-search type=button data-toggle=dropdown tabindex=0 aria-label=Search>
1
+ <!doctype html><html lang=en><head><meta charset=utf-8><meta http-equiv=x-ua-compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1"><title>Eclipse Public License 2.0 (EPL) | The Eclipse Foundation</title><meta property="og:title" content="Eclipse Public License 2.0 (EPL) | The Eclipse Foundation"><meta name=twitter:title content="Eclipse Public License 2.0 (EPL) | The Eclipse Foundation"><meta name=description content="The Eclipse Foundation provides our global community of individuals and organisations with a mature, scalable, and business-friendly environment for open source …"><meta property="og:description" content="The Eclipse Foundation provides our global community of individuals and organisations with a mature, scalable, and business-friendly environment for open source …"><meta name=twitter:description content="The Eclipse Foundation provides our global community of individuals and organisations with a mature, scalable, and business-friendly environment for open source …"><meta name=author content="Wayne Beaton"><link href=/favicon.ico rel=icon type=image/x-icon><meta property="og:image" content="https://www.eclipse.org/images/logos/eclipse-foundation-400x400.png"><meta name=twitter:image content="https://www.eclipse.org/images/logos/eclipse-foundation-400x400.png"><meta name=twitter:card content="summary"><meta name=twitter:site content="@eclipsefdn"><meta name=twitter:creator content="@eclipsefdn"><meta property="og:url" content="https://www.eclipse.org/legal/epl-2.0/"><meta property="og:type" content="website"><meta property="og:site_name" content="Eclipse Foundation"><meta name=keywords content="epl,epl-2.0,legal,foundation,eclipse,eclipse public license,license,licenses"><meta name=generator content="Hugo 0.110.0"><link rel=canonical href=https://www.eclipse.org/legal/epl-2.0/><link rel=alternate href=/legal/epl-2.0/index.xml type=application/rss+xml title><link rel=stylesheet href="/public/css/styles.css?v=1731870966"><script>(function(e,t,n,s,o){e[s]=e[s]||[],e[s].push({"gtm.start":(new Date).getTime(),event:"gtm.js"});var a=t.getElementsByTagName(n)[0],i=t.createElement(n),r=s!="dataLayer"?"&l="+s:"";i.async=!0,i.src="https://www.googletagmanager.com/gtm.js?id="+o+r,a.parentNode.insertBefore(i,a)})(window,document,"script","dataLayer","GTM-5WLCZXC")</script><script>var tableClasses="table"</script><link href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap" rel=stylesheet type=text/css></head><body><noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-5WLCZXC" height=0 width=0 style=display:none;visibility:hidden></iframe></noscript><a class=sr-only href=#content>Skip to main content</a><header class="header-wrapper header-wrapper" id=header><div class=header-toolbar><div class=container><div class=header-toolbar-row><div class="toolbar-btn toolbar-search-btn dropdown"><button class=dropdown-toggle id=toolbar-search type=button data-toggle=dropdown tabindex=0 aria-label=Search>
2
2
  <i class="fa fa-search fa-lg" aria-role=none></i></button><div class="toolbar-search-bar-wrapper dropdown-menu dropdown-menu-right" aria-labelledby=toolbar-search><form action=https://www.eclipse.org/home/search method=get><div class=search-bar><input class=search-bar-input name=q placeholder=Search>
3
3
  <button>
4
4
  <i class="fa fa-search" type=submit></i></button></div></form></div></div><div class="toolbar-btn toolbar-user-menu-btn dropdown"><button class=dropdown-toggle id=toolbar-user-menu type=button data-toggle=dropdown tabindex=0 aria-label="User Menu">
@@ -57,5 +57,5 @@ open source software collaboration and innovation.</p></div><div class=mega-menu
57
57
  <i class="fa fa-linkedin fa-stack-1x fa-inverse" aria-hidden=true></i>
58
58
  <span class=sr-only>Linkedin account</span></span></a></li></ul></div></div><div class="footer-sections row equal-height-md font-bold"><div class=col-md-15><div class=row><section id=footer-eclipse-foundation class="footer-section col-sm-8"><div class=menu-heading>Eclipse Foundation</div><ul class=nav><li><a href=https://www.eclipse.org/org/>About</a></li><li><a href=https://projects.eclipse.org/>Projects</a></li><li><a href=https://www.eclipse.org/collaborations/>Collaborations</a></li><li><a href=https://www.eclipse.org/membership/>Membership</a></li><li><a href=https://www.eclipse.org/sponsor/>Sponsor</a></li></ul></section><section id=footer-legal class="footer-section col-sm-8"><div class=menu-heading>Legal</div><ul class=nav><li><a href=https://www.eclipse.org/legal/privacy/>Privacy Policy</a></li><li><a href=https://www.eclipse.org/legal/terms-of-use/>Terms of Use</a></li><li><a href=https://www.eclipse.org/legal/compliance/>Compliance</a></li><li><a href=https://www.eclipse.org/org/documents/Community_Code_of_Conduct.php>Code of Conduct</a></li><li><a href=https://www.eclipse.org/legal/>Legal Resources</a></li><li><a class=toolbar-manage-cookies href=# onclick=event.preventDefault()>Manage Cookies</a></li></ul></section><section id=footer-more class="footer-section col-sm-8"><div class=menu-heading>More</div><ul class=nav><li><a href=https://www.eclipse.org/security/>Report a Vulnerability</a></li><li><a href=https://status.eclipse.org/>Service Status</a></li><li><a href=https://www.eclipse.org/org/foundation/contact.php>Contact Us</a></li><li><a href=https://www.eclipse.org/projects/support/>Support</a></li></ul></section></div></div><div id=footer-end class="footer-section col-md-8 col-md-offset-1 col-sm-24"><div class=footer-end-newsletter><form id=mc-embedded-subscribe-form action=https://eclipsecon.us6.list-manage.com/subscribe/post method=post novalidate target=_blank><label class=footer-end-newsletter-label for=email>Subscribe to our Newsletter</label><div class=footer-end-newsletter-input-wrapper><input class=footer-end-newsletter-input type=email id=email name=EMAIL autocomplete=email placeholder="Enter your email address"><div><i class="fa fa-solid fa-envelope fa-lg" aria-hidden=true></i></div></div><input type=hidden name=u value=eaf9e1f06f194eadc66788a85>
59
59
  <input type=hidden name=id value=46e57eacf1>
60
- <input id=mc-embedded-subscribe type=submit name=subscribe hidden></form></div></div></div><div class="col-sm-24 margin-top-20"><div class=row><div id=copyright class=col-md-16><p id=copyright-text>Copyright &copy; Eclipse Foundation AISBL. All Rights Reserved.</p></div></div></div><a href=# class=scrollup>Back to the top</a></div></footer><div id=footer-js><script src="/public/js/main.js?v1.0?v=1730661366"></script>
60
+ <input id=mc-embedded-subscribe type=submit name=subscribe hidden></form></div></div></div><div class="col-sm-24 margin-top-20"><div class=row><div id=copyright class=col-md-16><p id=copyright-text>Copyright &copy; Eclipse Foundation AISBL. All Rights Reserved.</p></div></div></div><a href=# class=scrollup>Back to the top</a></div></footer><div id=footer-js><script src="/public/js/main.js?v1.0?v=1731870966"></script>
61
61
  <script>(function(){})(jQuery,document)</script></div></body></html>
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@effekt-lang/effekt",
3
3
  "author": "Jonathan Brachthäuser",
4
- "version": "0.8.0",
4
+ "version": "0.10.0",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/effekt-lang/effekt.git"