@effekt-lang/effekt 0.66.0 → 0.67.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/effekt 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:
@@ -659,12 +662,12 @@ def each[T](array: Array[T]): Unit / emit[T] = {
659
662
  go(0)
660
663
  }
661
664
 
662
- /// Connects `array` as a producer to a given pull stream `reader` acting as a consumer.
663
- def feed[T, R](array: Array[T]) { reader: () => R / read[T] }: R = {
665
+ /// Connects `array` as a producer to a given pull stream `driver` acting as a consumer.
666
+ def feed[T, R](array: Array[T]) { driver: () => R / next[T] }: R = {
664
667
  var i = 0
665
668
  try {
666
- reader()
667
- } with read[T] {
669
+ driver()
670
+ } with next[T] {
668
671
  resume {
669
672
  if (i < array.size) {
670
673
  val c = i
@@ -19,10 +19,10 @@ import array
19
19
  *
20
20
  * The eraser does nothing.
21
21
  */
22
- extern type ByteArray
23
- // = 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 =
@@ -283,11 +283,11 @@ def each(bytes: ByteArray): Unit / emit[Byte] = {
283
283
  go(0)
284
284
  }
285
285
 
286
- def feed[R](bytes: ByteArray) { reader: () => R / read[Byte] }: R = {
286
+ def feed[R](bytes: ByteArray) { driver: () => R / next[Byte] }: R = {
287
287
  var i = 0
288
288
  try {
289
- reader()
290
- } with read[Byte] {
289
+ driver()
290
+ } with next[Byte] {
291
291
  resume {
292
292
  if (i < bytes.size) {
293
293
  val c = i
@@ -103,7 +103,7 @@ def hex{ body: => Unit / { write, HexSplices } }: Unit / emit[Byte] = {
103
103
  body()
104
104
  }
105
105
  with splice[String] { s =>
106
- feed(s){ loop { do splice[Char](do 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 _ => ()
@@ -175,24 +175,24 @@ extern def charWidth(c: Char) at {}: Int =
175
175
  js "(${c} > 0xffff) ? 2 : 1"
176
176
 
177
177
 
178
- def decodeChar(): Char / {read[Byte], stop} = {
179
- val b = do read().toInt
178
+ def decodeChar(): Char / {next[Byte], stop} = {
179
+ val b = do next().toInt
180
180
  if (b < 128) {
181
181
  b.toChar
182
182
  } else if (b < 224) {
183
183
  val part1 = bitwiseShl(bitwiseAnd(b, 31), 6)
184
- val part2 = bitwiseAnd(do read().toInt, 63)
184
+ val part2 = bitwiseAnd(do next().toInt, 63)
185
185
  bitwiseOr(part1, part2).toChar
186
186
  } else if (b < 240) {
187
187
  val part1 = bitwiseShl(bitwiseAnd(b, 15), 12)
188
- val part2 = bitwiseShl(bitwiseAnd(do read().toInt, 63), 6)
189
- val part3 = bitwiseAnd(do read().toInt, 63)
188
+ val part2 = bitwiseShl(bitwiseAnd(do next().toInt, 63), 6)
189
+ val part3 = bitwiseAnd(do next().toInt, 63)
190
190
  bitwiseOr(bitwiseOr(part1, part2), part3).toChar
191
191
  } else {
192
192
  val part1 = bitwiseShl(bitwiseAnd(b, 7), 18)
193
- val part2 = bitwiseShl(bitwiseAnd(do read().toInt, 63), 12)
194
- val part3 = bitwiseShl(bitwiseAnd(do read().toInt, 63), 6)
195
- val part4 = bitwiseAnd(do read().toInt, 63)
193
+ val part2 = bitwiseShl(bitwiseAnd(do next().toInt, 63), 12)
194
+ val part3 = bitwiseShl(bitwiseAnd(do next().toInt, 63), 6)
195
+ val part4 = bitwiseAnd(do next().toInt, 63)
196
196
  bitwiseOr(bitwiseOr(bitwiseOr(part1, part2), part3), part4).toChar
197
197
  }
198
198
  }
@@ -216,10 +216,10 @@ def encodeChar(char: Char): Unit / emit[Byte] = {
216
216
  }
217
217
  }
218
218
 
219
- def decodeUTF8[R] { reader: () => R / read[Char] }: R / read[Byte] =
219
+ def decodeUTF8[R] { reader: () => R / next[Char] }: R / next[Byte] =
220
220
  try {
221
221
  reader()
222
- } with read[Char] {
222
+ } with next[Char] {
223
223
  resume { decodeChar() }
224
224
  }
225
225
 
@@ -1,26 +1,33 @@
1
1
  module dictionary
2
2
 
3
+ import ref
3
4
  import array
4
5
  import bytearray
5
6
  import stream
6
7
 
7
-
8
- /// 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
+ }
@@ -83,6 +83,7 @@ def println(value: Unit): Unit = println(value.show)
83
83
  def println(value: Double): Unit = println(value.show)
84
84
  def println(value: Bool): Unit = println(value.show)
85
85
  def println(value: Byte): Unit = println(value.show)
86
+ def println(value: Char): Unit = println(value.show)
86
87
 
87
88
  extern def showBuiltin(value: Int) at {}: String =
88
89
  js "'' + ${value}"
@@ -135,8 +136,8 @@ extern def panic(msg: String) at io: Nothing =
135
136
  """
136
137
 
137
138
  extern def show[R](value: R) at {}: String =
138
- js "$effekt.show(${value})"
139
- chez "(show_impl ${value})"
139
+ js "undefined"
140
+ chez "(void)"
140
141
  llvm "ret %Pos poison"
141
142
 
142
143
  extern def genericShow[R](value: R) at {}: String =
@@ -746,6 +747,15 @@ extern def isUndefined[A](value: A) at {}: Bool =
746
747
  chez "(eq? ${value} #f)"
747
748
  vm "effekt::isUndefined[A](A)"
748
749
 
750
+ // Ascription
751
+ // ==========
752
+
753
+ /// Ascribe a type, for example `f().as[Int]`.
754
+ def as[A](x: A): A = x
755
+
756
+ /// Witness absurdity, for example `f().absurd`.
757
+ /// Very often the type argument is inferred.
758
+ def absurd[A](x: Nothing): A = x match {}
749
759
 
750
760
  // Tuples
751
761
  // ======
@@ -33,7 +33,7 @@ def send[A, B](sender: Sender[A, B], value: A): B = {
33
33
  sender.set(rest)
34
34
  // TODO avoid yield
35
35
  yield()
36
- this.unsafeFire(value)
36
+ this.fire(value)
37
37
  }
38
38
 
39
39
  /// Receives a value from a channel and blocks until a sender arrives.
@@ -51,7 +51,7 @@ def receive[A, B](receiver: Receiver[A, B], value: B): A = {
51
51
  receiver.set(rest)
52
52
  // TODO avoid yield
53
53
  yield()
54
- this.unsafeWait(value)
54
+ this.wait(value)
55
55
  }
56
56
 
57
57
  // TODO streaming
@@ -26,7 +26,8 @@ namespace js {
26
26
  const readline = require('node:readline');
27
27
  """
28
28
 
29
- extern type JSConsole
29
+ extern type JSConsole =
30
+ js "readline.createInterface return type"
30
31
 
31
32
  extern def newConsole() at io: JSConsole =
32
33
  jsNode """readline.createInterface({
@@ -74,8 +74,8 @@ def appendFile(path: String, contents: String): Unit / Exception[IOError] = {
74
74
  def writeFileUTF8[R](path: String) { stream: () => R / emit[Char] }: R / Exception[IOError] =
75
75
  writeFile(path) { encodeUTF8 { stream() } }
76
76
 
77
- def readFileUTF8[R](path: String) { reader: () => R / read[Char] }: R / Exception[IOError] =
78
- readFile(path) { decodeUTF8 { reader() } }
77
+ def readFileUTF8[R](path: String) { driver: () => R / next[Char] }: R / Exception[IOError] =
78
+ readFile(path) { decodeUTF8 { driver() } }
79
79
 
80
80
  def writeFile[R](path: String) { stream: () => R / emit[Byte] }: R / Exception[IOError] = {
81
81
 
@@ -108,7 +108,7 @@ def writeFile[R](path: String) { stream: () => R / emit[Byte] }: R / Exception[I
108
108
  }
109
109
  }
110
110
 
111
- def readFile[R](path: String) { reader: () => R / read[Byte] }: R / Exception[IOError] = {
111
+ def readFile[R](path: String) { driver: () => R / next[Byte] }: R / Exception[IOError] = {
112
112
 
113
113
  val file = openForReading(path);
114
114
  with on[IOError].finalize { close(file) }
@@ -128,8 +128,8 @@ def readFile[R](path: String) { reader: () => R / read[Byte] }: R / Exception[IO
128
128
  }
129
129
 
130
130
  try {
131
- reader()
132
- } with read[Byte] {
131
+ driver()
132
+ } with next[Byte] {
133
133
  resume {
134
134
  if (offset >= length) {
135
135
  pull()
@@ -42,13 +42,13 @@ def listen(listener: Listener, handler: Connection => Unit at {io, async, global
42
42
  def shutdown(listener: Listener): Unit =
43
43
  internal::shutdown(listener)
44
44
 
45
- def streaming[R](connection: Connection) { program: () => R / {read[ByteArray], emit[ByteArray]} }: R / Exception[IOError] =
45
+ def streaming[R](connection: Connection) { program: () => R / {next[ByteArray], emit[ByteArray]} }: R / Exception[IOError] =
46
46
  try {
47
47
  program()
48
48
  } with emit[ByteArray] { bytes =>
49
49
  write(connection, bytes, 0, bytes.size)
50
50
  resume(())
51
- } with read[ByteArray] { () =>
51
+ } with next[ByteArray] { () =>
52
52
  val bytes = bytearray::allocate(4096)
53
53
  read(connection, bytes, 0, bytes.size) match {
54
54
  case r and r == bytes.size => resume { return bytes }
@@ -37,7 +37,7 @@ def await[T](promise: Promise[T]): T =
37
37
  val signal = signal()
38
38
  promise.set(Pending(Cons(signal, signals)))
39
39
  // TODO perhaps yield to avoid stack overflow
40
- signal.unsafeWait(())
40
+ signal.wait(())
41
41
  }
42
42
 
43
43
  /// Resolves the given promise, unblocking all awaiting tasks.
@@ -48,6 +48,6 @@ def resolve[T](promise: Promise[T], value: T): Unit =
48
48
  case Pending(signals) =>
49
49
  promise.set(Resolved(value))
50
50
  // TODO perhaps yield to avoid stack overflow
51
- signals.reverse.foreach { signal => unsafeFire(signal, value) }
51
+ signals.reverse.foreach { signal => fire(signal, value) }
52
52
  }
53
53
 
@@ -5,32 +5,29 @@ module io/signal
5
5
 
6
6
  /// Must be fired exactly once with an A receiving a B,
7
7
  /// and must be waited for exactly once with a B receiving an A.
8
- extern type Signal[A, B]
8
+ extern type Signal[A, B] =
9
+ js "{ state: int, value, stack }"
10
+ llvm "%Pos"
9
11
 
10
- extern def signal[A, B]() at global: Signal[A, B] =
11
- js "signal$make()"
12
- llvm """
13
- %signal = call %Pos @c_signal_make()
14
- ret %Pos %signal
15
- """
12
+ extern llvm """
13
+ %Signal = type { %Header, i64, ptr, %Pos }
16
14
 
17
- extern def unsafeFire[A, B](signal: Signal[A, B], value: A) at async: B =
18
- js "$effekt.capture(callback => signal$notify(${signal}, ${value}, callback))"
19
- llvm """
20
- call void @c_signal_notify(%Pos ${signal}, %Pos ${value}, %Stack %stack)
15
+ define void @signal_erase(ptr %envPtr) {
16
+ %base = getelementptr %Header, ptr %envPtr, i64 -1
17
+ %statePtr = getelementptr %Signal, ptr %base, i64 0, i32 1
18
+ %stackPtr = getelementptr %Signal, ptr %base, i64 0, i32 2
19
+ %valuePtr = getelementptr %Signal, ptr %base, i64 0, i32 3
20
+ %state = load i64, ptr %statePtr
21
+ switch i64 %state, label %none [i64 0, label %free i64 1, label %free i64 2, label %free]
22
+ free:
23
+ %stack = load %Stack, ptr %stackPtr
24
+ %value = load %Pos, ptr %valuePtr
25
+ call void @erasePositive(%Pos %value)
26
+ call void @eraseStack(%Stack %stack)
21
27
  ret void
22
- """
23
-
24
- extern def unsafeWait[A, B](signal: Signal[A, B], value: B) at async: A =
25
- js "$effekt.capture(callback => signal$notify(${signal}, ${value}, callback))"
26
- llvm """
27
- call void @c_signal_notify(%Pos ${signal}, %Pos ${value}, %Stack %stack)
28
+ none:
28
29
  ret void
29
- """
30
-
31
- extern llvm """
32
- declare %Pos @c_signal_make()
33
- declare void @c_signal_notify(%Pos, %Pos, %Stack)
30
+ }
34
31
  """
35
32
 
36
33
  extern js """
@@ -53,3 +50,70 @@ extern js """
53
50
  }
54
51
  }
55
52
  """
53
+
54
+ extern def signal[A, B]() at global: Signal[A, B] =
55
+ js "signal$make()"
56
+ llvm """
57
+ %base = call ptr @calloc(i64 1, i64 48)
58
+ %eraserPtr = getelementptr %Signal, ptr %base, i64 0, i32 0, i32 1
59
+ store ptr @signal_erase, ptr %eraserPtr
60
+ %result = insertvalue %Pos { i64 0, ptr poison }, ptr %base, 1
61
+ ret %Pos %result
62
+ """
63
+
64
+ extern def fire[A, B](signal: Signal[A, B], value: A) at async: B =
65
+ js "$effekt.capture(callback => signal$notify(${signal}, ${value}, callback))"
66
+ llvm """
67
+ %base = extractvalue %Pos ${signal}, 1
68
+ %statePtr = getelementptr %Signal, ptr %base, i64 0, i32 1
69
+ %stackPtr = getelementptr %Signal, ptr %base, i64 0, i32 2
70
+ %valuePtr = getelementptr %Signal, ptr %base, i64 0, i32 3
71
+ %state = load i64, ptr %statePtr
72
+ switch i64 %state, label %panic [i64 0, label %init i64 1, label %fire]
73
+ init:
74
+ store i64 2, ptr %statePtr
75
+ store %Stack %stack, ptr %stackPtr
76
+ store %Pos ${value}, ptr %valuePtr
77
+ call void @erasePositive(%Pos ${signal})
78
+ ret void
79
+ fire:
80
+ %otherStack = load %Stack, ptr %stackPtr
81
+ %otherValue = load %Pos, ptr %valuePtr
82
+ store i64 3, ptr %statePtr
83
+ call void @erasePositive(%Pos ${signal})
84
+ call void @resume_Pos(%Stack %otherStack, %Pos ${value})
85
+ call void @resume_Pos(%Stack %stack, %Pos %otherValue)
86
+ ret void
87
+ panic:
88
+ call void @exit(i64 1)
89
+ ret void
90
+ """
91
+
92
+ extern def wait[A, B](signal: Signal[A, B], value: B) at async: A =
93
+ js "$effekt.capture(callback => signal$notify(${signal}, ${value}, callback))"
94
+ llvm """
95
+ %base = extractvalue %Pos ${signal}, 1
96
+ %statePtr = getelementptr %Signal, ptr %base, i64 0, i32 1
97
+ %stackPtr = getelementptr %Signal, ptr %base, i64 0, i32 2
98
+ %valuePtr = getelementptr %Signal, ptr %base, i64 0, i32 3
99
+ %state = load i64, ptr %statePtr
100
+ switch i64 %state, label %panic [i64 0, label %init i64 2, label %wait]
101
+ init:
102
+ store i64 1, ptr %statePtr
103
+ store %Stack %stack, ptr %stackPtr
104
+ store %Pos ${value}, ptr %valuePtr
105
+ call void @erasePositive(%Pos ${signal})
106
+ ret void
107
+ wait:
108
+ %otherStack = load %Stack, ptr %stackPtr
109
+ %otherValue = load %Pos, ptr %valuePtr
110
+ store i64 3, ptr %statePtr
111
+ call void @erasePositive(%Pos ${signal})
112
+ call void @resume_Pos(%Stack %otherStack, %Pos ${value})
113
+ call void @resume_Pos(%Stack %stack, %Pos %otherValue)
114
+ ret void
115
+ panic:
116
+ call void @exit(i64 1)
117
+ ret void
118
+ """
119
+
@@ -90,40 +90,6 @@ def encodeJson[R]{ body: => R / JsonBuilder }: R / emit[String] = {
90
90
  // --------------------------------------------------------------------------------
91
91
 
92
92
 
93
- /// Read a double value, in the common format (TODO document)
94
- def readDouble(): Double / { Scan[Char], Exception[WrongFormat]} = {
95
- def exponent(pre: Double): Double / fail = {
96
- try {
97
- if(do peek() == 'e' || do peek() == 'E') {
98
- skip[Char]()
99
- val e = do peek[Char]() match {
100
- case '+' => skip[Char](); readDecimal()
101
- case '-' => skip[Char](); neg(readDecimal())
102
- case _ => readDecimal()
103
- }
104
- pre * pow(10.0, e)
105
- } else { pre }
106
- } with stop {
107
- pre
108
- }
109
- }
110
- def fraction(pre: Int): Double / fail = {
111
- if (succeeds { must { readIf('.') } }) {
112
- var b = 0.1
113
- var r = pre.toDouble
114
- while (optionally[Int] { must { readDigit() } } is Some(d)) {
115
- r = r + b * d.toDouble
116
- b = b * 0.1
117
- }
118
- exponent(r)
119
- } else {
120
- pre.toDouble
121
- }
122
- }
123
- with returning::expect("Expected double")
124
- fraction(readInteger())
125
- }
126
-
127
93
  def expectString(string: String): Unit / { Scan[Char], Exception[WrongFormat] } =
128
94
  expect("Expected " ++ string) { readString(string) }
129
95
 
@@ -133,9 +99,9 @@ def readQuotedString(): Unit / { Scan[Char], emit[Char], Exception[WrongFormat]
133
99
  with expect("Unexpected end of input while reading a string")
134
100
  skipWhitespace()
135
101
  expect("Expected \"") { must { readIf('"') } }
136
- while(must { do read[Char]() } is c and c != '"') {
102
+ while(must { do next[Char]() } is c and c != '"') {
137
103
  c match {
138
- case '\\' => must { do read[Char]() } match {
104
+ case '\\' => must { do next[Char]() } match {
139
105
  case '"' => do emit('\"')
140
106
  case '\\' => do emit('\\')
141
107
  case '/' => do emit('/')
@@ -159,8 +125,8 @@ def decodeJson(): Unit / {Scan[Char], JsonBuilder, Exception[WrongFormat]} = {
159
125
  case 'n' => expectString("null"); do null()
160
126
  case 't' => expectString("true"); do bool(true)
161
127
  case 'f' => expectString("false"); do bool(false)
162
- case '-' => do number(readDouble())
163
- case d and d.isDigit => do number(readDouble())
128
+ case '-' => do number(returning::expect("Expected double") { readDouble() })
129
+ case d and d.isDigit => do number(returning::expect("Expected double") { readDouble() })
164
130
  case '"' => do string(collect { readQuotedString() })
165
131
  case '{' => do dict{ decodeJsonObject() }
166
132
  case '[' => do list{ decodeJsonList() }
@@ -310,15 +276,23 @@ namespace test {
310
276
 
311
277
  // Read quoted string
312
278
  feed("\"\ta\n\ra\"") {
313
- with scanner[Char]
279
+ with peeking[Char]
314
280
  println(string::collect { readQuotedString() })
315
281
  }
316
282
 
317
283
  println("")
318
284
 
285
+ feed("-1.5") {
286
+ with peeking[Char]
287
+ with on[WrongFormat].report
288
+ println(returning::expect("Expected double") { readDouble() })
289
+ }
290
+
291
+ println("")
292
+
319
293
  // Parse example
320
294
  feed("""{ "a": null, "b": [true,false,false,true], "f": 12.532 }"""){
321
- with scanner[Char]
295
+ with peeking[Char]
322
296
 
323
297
  def k = new JsonObjectBuilder {
324
298
  def field[T](k){v} = { println(k); ignore{v} }
@@ -362,7 +336,7 @@ namespace test {
362
336
  "a": null,
363
337
  "b": [true, false, false, true], "f": 12.532
364
338
  } """){
365
- with returning::scanner[Char, JsonValue]
339
+ with returning::peeking[Char, JsonValue]
366
340
  build {
367
341
  decodeJson()
368
342
  }.second
@@ -379,7 +353,7 @@ namespace test {
379
353
  "a": null,
380
354
  "b": [true, false, false, true], "f": 12.532
381
355
  } """){
382
- with scanner[Char]
356
+ with peeking[Char]
383
357
  decodeJson()
384
358
  }
385
359
  }