@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 +0 -0
- package/libraries/common/args.effekt +2 -2
- package/libraries/common/array.effekt +8 -9
- package/libraries/common/bytearray.effekt +7 -14
- package/libraries/common/bytestream.effekt +4 -4
- package/libraries/common/char.effekt +10 -16
- package/libraries/common/dictionary.effekt +44 -43
- package/libraries/common/effekt.effekt +18 -61
- package/libraries/common/io/channel.effekt +2 -2
- package/libraries/common/io/console.effekt +2 -1
- package/libraries/common/io/filesystem.effekt +5 -5
- package/libraries/common/io/network.effekt +2 -2
- package/libraries/common/io/promise.effekt +2 -2
- package/libraries/common/io/signal.effekt +86 -22
- package/libraries/common/json.effekt +16 -42
- package/libraries/common/list.effekt +4 -4
- package/libraries/common/process.effekt +6 -2
- package/libraries/common/random.effekt +29 -7
- package/libraries/common/ref.effekt +4 -4
- package/libraries/common/regex.effekt +6 -8
- package/libraries/common/resizable_array.effekt +4 -4
- package/libraries/common/scanner.effekt +36 -41
- package/libraries/common/stream.effekt +76 -36
- package/libraries/common/string.effekt +3 -8
- package/libraries/llvm/io.c +0 -55
- package/licenses/eclipse public license, version 2.0 - epl-2.0.html +2 -2
- package/licenses/mit license - mit-license.html +34 -32
- package/licenses/the bsd license - bsd-license.html +33 -31
- package/licenses/the mit license - mit.html +34 -32
- package/package.json +1 -1
|
@@ -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
|
|
102
|
+
while(must { do next[Char]() } is c and c != '"') {
|
|
137
103
|
c match {
|
|
138
|
-
case '\\' => must { do
|
|
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
|
|
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
|
|
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::
|
|
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
|
|
356
|
+
with peeking[Char]
|
|
383
357
|
decodeJson()
|
|
384
358
|
}
|
|
385
359
|
}
|
|
@@ -974,12 +974,12 @@ def tails[A](list: List[A]): Unit / emit[List[A]] =
|
|
|
974
974
|
case Cons(head, tail) => do emit(list); tails(tail)
|
|
975
975
|
}
|
|
976
976
|
|
|
977
|
-
/// Connects `list` as a producer to a given pull stream `
|
|
978
|
-
def feed[T, R](list: List[T]) {
|
|
977
|
+
/// Connects `list` as a producer to a given pull stream `driver` acting as a consumer.
|
|
978
|
+
def feed[T, R](list: List[T]) { driver: () => R / next[T] }: R = {
|
|
979
979
|
var l = list
|
|
980
980
|
try {
|
|
981
|
-
|
|
982
|
-
} with
|
|
981
|
+
driver()
|
|
982
|
+
} with next[T] {
|
|
983
983
|
resume {
|
|
984
984
|
l match {
|
|
985
985
|
case Nil() => do stop()
|
|
@@ -25,7 +25,9 @@ extern llvm """
|
|
|
25
25
|
declare %Pos @c_spawn(%Pos, %Pos, %Pos)
|
|
26
26
|
"""
|
|
27
27
|
|
|
28
|
-
extern type SpawnOptions
|
|
28
|
+
extern type SpawnOptions =
|
|
29
|
+
jsNode "{ stdio: list[int], onSpawn: fn => {} }"
|
|
30
|
+
llvm "%Pos"
|
|
29
31
|
extern def default() at {}: SpawnOptions =
|
|
30
32
|
jsNode """{ stdio: [0,1,2], onSpawn: (p) => {} }"""
|
|
31
33
|
llvm """
|
|
@@ -64,7 +66,9 @@ extern def onStderr(opts: SpawnOptions, callback: String => Unit at {io, global}
|
|
|
64
66
|
%opts = call %Pos @c_spawn_options_on_stderr(%Pos ${opts}, %Pos ${callback})
|
|
65
67
|
ret %Pos %opts
|
|
66
68
|
"""
|
|
67
|
-
extern type WritableStream
|
|
69
|
+
extern type WritableStream =
|
|
70
|
+
jsNode "stream.Writable"
|
|
71
|
+
llvm "%Pos"
|
|
68
72
|
extern def withStdin(opts: SpawnOptions, callback: WritableStream => Unit at {io, global}) at {}: SpawnOptions =
|
|
69
73
|
jsNode """(function () {
|
|
70
74
|
let old = ${opts};
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
module random
|
|
2
2
|
|
|
3
3
|
import stream
|
|
4
|
+
import array
|
|
5
|
+
import option
|
|
6
|
+
import exception
|
|
4
7
|
import io/filesystem
|
|
5
8
|
import io/error
|
|
6
9
|
|
|
@@ -38,7 +41,7 @@ def minstd(seed: Int): Unit / emit[Byte] = {
|
|
|
38
41
|
if (result < 0) result + m else result
|
|
39
42
|
}
|
|
40
43
|
|
|
41
|
-
|
|
44
|
+
forever {
|
|
42
45
|
state = nextInt()
|
|
43
46
|
val b = state.mod(256).toByte
|
|
44
47
|
do emit(b)
|
|
@@ -73,7 +76,7 @@ def devurandom { randomnessReader: () => Unit / random }: Unit / Exception[IOErr
|
|
|
73
76
|
try {
|
|
74
77
|
with readFile("/dev/urandom")
|
|
75
78
|
try randomnessReader() with random {
|
|
76
|
-
resume(do
|
|
79
|
+
resume(do next())
|
|
77
80
|
}
|
|
78
81
|
} with stop {
|
|
79
82
|
do raise(io::error::EOF(), "Unexpected EOF when reading /dev/urandom!")
|
|
@@ -88,14 +91,14 @@ def devurandom { randomnessReader: () => Unit / random }: Unit / Exception[IOErr
|
|
|
88
91
|
|
|
89
92
|
def randomByte(): Byte / random = do random()
|
|
90
93
|
def randomBytes(): Unit / {emit[Byte], random} =
|
|
91
|
-
|
|
94
|
+
forever { do emit(do random()) }
|
|
92
95
|
|
|
93
96
|
def randomBool(): Bool / random = {
|
|
94
97
|
val b = do random()
|
|
95
98
|
b.toInt.mod(2) == 1
|
|
96
99
|
}
|
|
97
100
|
def randomBools(): Unit / {emit[Bool], random} =
|
|
98
|
-
|
|
101
|
+
forever { do emit(randomBool()) }
|
|
99
102
|
|
|
100
103
|
def randomInt32(): Int / random = {
|
|
101
104
|
var result = 0
|
|
@@ -107,7 +110,7 @@ def randomInt32(): Int / random = {
|
|
|
107
110
|
result.mod(1.bitwiseShl(31)).abs * if (signBit) 1 else -1
|
|
108
111
|
}
|
|
109
112
|
def randomInt32s(): Unit / {emit[Int], random} =
|
|
110
|
-
|
|
113
|
+
forever { do emit(randomInt32()) }
|
|
111
114
|
|
|
112
115
|
/// `max` is _inclusive_!
|
|
113
116
|
def randomInt(min: Int, max: Int): Int / random = {
|
|
@@ -126,9 +129,10 @@ def randomInt(min: Int, max: Int): Int / random = {
|
|
|
126
129
|
min + (abs(result).mod(range))
|
|
127
130
|
}
|
|
128
131
|
}
|
|
132
|
+
|
|
129
133
|
/// `max` is _inclusive_!
|
|
130
134
|
def randomInts(min: Int, max: Int): Unit / {emit[Int], random} =
|
|
131
|
-
|
|
135
|
+
forever { do emit(randomInt(min, max)) }
|
|
132
136
|
|
|
133
137
|
|
|
134
138
|
/// Random double between 0.0 and 1.0
|
|
@@ -136,7 +140,25 @@ def randomDouble(): Double / random =
|
|
|
136
140
|
(randomInt32().toDouble / 1.bitwiseShl(31).toDouble).abs
|
|
137
141
|
// This is not perfect, but it will do for now.
|
|
138
142
|
def randomDoubles(): Unit / {emit[Double], random} =
|
|
139
|
-
|
|
143
|
+
forever { do emit(randomDouble()) }
|
|
144
|
+
|
|
145
|
+
/// Shuffle an array in-place using the Fisher-Yates algorithm.
|
|
146
|
+
def shuffle[A](arr: Array[A]): Unit / random = {
|
|
147
|
+
val n = arr.size
|
|
148
|
+
each(0, n - 1) { i =>
|
|
149
|
+
arr.swap(i, randomInt(i, n - 1))
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/// Pick a random element from an array.
|
|
154
|
+
///
|
|
155
|
+
/// Panics when called on an empty array.
|
|
156
|
+
def pick[A](arr: Array[A]): A / random =
|
|
157
|
+
if (arr.size == 0) {
|
|
158
|
+
panic("Pick from an empty array")
|
|
159
|
+
} else {
|
|
160
|
+
arr.get(randomInt(0, arr.size - 1))
|
|
161
|
+
}
|
|
140
162
|
|
|
141
163
|
|
|
142
164
|
namespace examples {
|
|
@@ -18,7 +18,10 @@ define void @c_ref_erase_field(ptr %0) {
|
|
|
18
18
|
"""
|
|
19
19
|
|
|
20
20
|
/// Global, mutable references
|
|
21
|
-
extern type Ref[T]
|
|
21
|
+
extern type Ref[T] =
|
|
22
|
+
js "{ value: T }"
|
|
23
|
+
chez "box"
|
|
24
|
+
llvm "%Pos"
|
|
22
25
|
|
|
23
26
|
/** We represent references like positive types in LLVM
|
|
24
27
|
* The tag is 0 and the obj points to memory with the following layout:
|
|
@@ -69,7 +72,6 @@ extern def ref[T](init: T) at global: Ref[T] =
|
|
|
69
72
|
|
|
70
73
|
ret %Pos %refWrap
|
|
71
74
|
"""
|
|
72
|
-
vm "ref::ref[T](T)"
|
|
73
75
|
|
|
74
76
|
/// Gets the referenced element of the `ref` in constant time.
|
|
75
77
|
extern def get[T](ref: Ref[T]) at global: T =
|
|
@@ -85,7 +87,6 @@ llvm """
|
|
|
85
87
|
|
|
86
88
|
ret %Pos %refField
|
|
87
89
|
"""
|
|
88
|
-
vm "ref::get[T](Ref[T])"
|
|
89
90
|
|
|
90
91
|
/// Sets the referenced element of the `ref` to `value` in constant time.
|
|
91
92
|
extern def set[T](ref: Ref[T], value: T) at global: Unit =
|
|
@@ -103,7 +104,6 @@ extern def set[T](ref: Ref[T], value: T) at global: Unit =
|
|
|
103
104
|
|
|
104
105
|
ret %Pos zeroinitializer
|
|
105
106
|
"""
|
|
106
|
-
vm "ref::set[T](Ref[T], T)"
|
|
107
107
|
|
|
108
108
|
/// Modifies the inner contents of the `ref` with a function `f`
|
|
109
109
|
def map[T](ref: Ref[T]) { f: T => T }: Unit =
|
|
@@ -4,14 +4,15 @@ import string
|
|
|
4
4
|
|
|
5
5
|
extern include chez "text/pregexp.scm"
|
|
6
6
|
|
|
7
|
-
extern type Regex
|
|
7
|
+
extern type Regex =
|
|
8
|
+
js "RegExp"
|
|
9
|
+
chez "pregexp"
|
|
8
10
|
|
|
9
11
|
record Match(matched: String, index: Int)
|
|
10
12
|
|
|
11
13
|
extern def regex(str: String) at {}: Regex =
|
|
12
14
|
js "new RegExp(${str})"
|
|
13
15
|
chez "(pregexp ${str})"
|
|
14
|
-
vm "regex::regex(String)"
|
|
15
16
|
|
|
16
17
|
def exec(reg: Regex, str: String): Option[Match] = {
|
|
17
18
|
val v = internal::exec(reg, str)
|
|
@@ -25,19 +26,17 @@ namespace internal {
|
|
|
25
26
|
|
|
26
27
|
/// The type RegexMatch is used internally to represent platform
|
|
27
28
|
/// dependent results of matching a regex.
|
|
28
|
-
extern type RegexMatch
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
extern type RegexMatch =
|
|
30
|
+
js "{ matched: String, index: Int } | undefined"
|
|
31
|
+
vm "scala.util.matching.Regex.Match | null"
|
|
31
32
|
|
|
32
33
|
extern def matched(r: RegexMatch) at {}: String =
|
|
33
34
|
js "${r}.matched"
|
|
34
35
|
chez "(vector-ref ${r} 0)"
|
|
35
|
-
vm "regex::matched(RegexMatch)"
|
|
36
36
|
|
|
37
37
|
extern def index(r: RegexMatch) at {}: Int =
|
|
38
38
|
js "${r}.index"
|
|
39
39
|
chez "(vector-ref ${r} 1)"
|
|
40
|
-
vm "regex::index(RegexMatch)"
|
|
41
40
|
|
|
42
41
|
extern js """
|
|
43
42
|
function regex$exec(reg, str) {
|
|
@@ -60,5 +59,4 @@ namespace internal {
|
|
|
60
59
|
extern def exec(reg: Regex, str: String) at io: RegexMatch =
|
|
61
60
|
js "regex$exec(${reg}, ${str})"
|
|
62
61
|
chez "(regex-exec ${reg} ${str})"
|
|
63
|
-
vm "regex::exec(Regex, String)"
|
|
64
62
|
}
|
|
@@ -224,12 +224,12 @@ def each[T](arr: ResizableArray[T]): Unit / emit[T] =
|
|
|
224
224
|
do emit(arr.rawContentPtr.get.get(i))
|
|
225
225
|
}
|
|
226
226
|
|
|
227
|
-
/// Connects `arr` as a producer to a given pull stream `
|
|
228
|
-
def feed[R, T](arr: ResizableArray[T]) {
|
|
227
|
+
/// Connects `arr` as a producer to a given pull stream `driver` acting as a consumer.
|
|
228
|
+
def feed[R, T](arr: ResizableArray[T]) { driver: () => R / next[T] }: R = {
|
|
229
229
|
var i = 0
|
|
230
230
|
try {
|
|
231
|
-
|
|
232
|
-
} with
|
|
231
|
+
driver()
|
|
232
|
+
} with next[T] {
|
|
233
233
|
resume {
|
|
234
234
|
if (i < arr.size) {
|
|
235
235
|
val v = arr.rawContentPtr.get.get(i)
|
|
@@ -3,19 +3,10 @@ module scanner
|
|
|
3
3
|
import stream
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
/// That is, this does not change what any future calls on the Scanner return.
|
|
8
|
-
effect peek[A](): A / stop
|
|
9
|
-
|
|
10
|
-
effect Scan[A] = {read[A], peek[A]}
|
|
6
|
+
effect Scan[A] = {next[A], peek[A]}
|
|
11
7
|
|
|
12
8
|
/// Advance the pull stream to the next element, discarding the current element.
|
|
13
|
-
def skip[A](): Unit / {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
/// Run a scanner by reading from an input stream, discarding its output.
|
|
17
|
-
def scanner[A] { scanner: () => Unit / Scan[A] }: Unit / read[A] =
|
|
18
|
-
returning::scanner[A, Unit]{scanner}
|
|
9
|
+
def skip[A](): Unit / {next[A], stop} = { do next(); () }
|
|
19
10
|
|
|
20
11
|
def expect(message: String) { scanner: () => Unit / fail }: Unit / Exception[WrongFormat] =
|
|
21
12
|
returning::expect[Unit](message){scanner}
|
|
@@ -23,7 +14,7 @@ def expect(message: String) { scanner: () => Unit / fail }: Unit / Exception[Wro
|
|
|
23
14
|
/// If conversion is successful read the next token, otherwise stop.
|
|
24
15
|
def readWhen[A, B] { convert: A => B / fail }: B / { Scan[A], stop } = {
|
|
25
16
|
val t = attempt { convert(do peek()) } { do stop() };
|
|
26
|
-
do
|
|
17
|
+
do next()
|
|
27
18
|
return t
|
|
28
19
|
}
|
|
29
20
|
|
|
@@ -31,7 +22,7 @@ def readWhen[A, B] { convert: A => B / fail }: B / { Scan[A], stop } = {
|
|
|
31
22
|
def readIf[A] { predicate: A => Bool }: A / { Scan[A], stop } = {
|
|
32
23
|
val t = do peek()
|
|
33
24
|
if (predicate(t)) {
|
|
34
|
-
do
|
|
25
|
+
do next()
|
|
35
26
|
return t
|
|
36
27
|
} else {
|
|
37
28
|
do stop()
|
|
@@ -92,10 +83,10 @@ def until[A, R] { predicate: A => Bool } { scanner: () => R / Scan[A] }: R / { S
|
|
|
92
83
|
resume {
|
|
93
84
|
if (stopped) { do stop() } else { do peek() }
|
|
94
85
|
}
|
|
95
|
-
} with
|
|
86
|
+
} with next[A] {
|
|
96
87
|
resume {
|
|
97
88
|
if (stopped) { do stop() } else {
|
|
98
|
-
val t = do
|
|
89
|
+
val t = do next()
|
|
99
90
|
boundary {
|
|
100
91
|
if (predicate(do peek())) { stopped = true; skip() }
|
|
101
92
|
}
|
|
@@ -166,38 +157,42 @@ def readInteger(): Int / { Scan[Char], fail } =
|
|
|
166
157
|
case _ => do fail()
|
|
167
158
|
}
|
|
168
159
|
|
|
169
|
-
namespace returning {
|
|
170
160
|
|
|
171
|
-
///
|
|
172
|
-
def
|
|
173
|
-
def
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
}
|
|
161
|
+
/// Read a decimal floating-point number with optional fraction and exponent.
|
|
162
|
+
def readDouble(): Double / { Scan[Char], fail} = {
|
|
163
|
+
def exponent(pre: Double): Double / fail = {
|
|
164
|
+
try {
|
|
165
|
+
if(do peek() == 'e' || do peek() == 'E') {
|
|
166
|
+
skip[Char]()
|
|
167
|
+
val e = do peek[Char]() match {
|
|
168
|
+
case '+' => skip[Char](); readDecimal()
|
|
169
|
+
case '-' => skip[Char](); neg(readDecimal())
|
|
170
|
+
case _ => readDecimal()
|
|
171
|
+
}
|
|
172
|
+
pre * pow(10.0, e)
|
|
173
|
+
} else { pre }
|
|
174
|
+
} with stop {
|
|
175
|
+
pre
|
|
187
176
|
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
177
|
+
}
|
|
178
|
+
def fraction(pre: Int): Double / fail = {
|
|
179
|
+
if (succeeds { must { readIf('.') } }) {
|
|
180
|
+
var b = if (pre >= 0) 0.1 else -0.1
|
|
181
|
+
var r = pre.toDouble
|
|
182
|
+
while (optionally[Int] { must { readDigit() } } is Some(d)) {
|
|
183
|
+
r = r + b * d.toDouble
|
|
184
|
+
b = b * 0.1
|
|
196
185
|
}
|
|
186
|
+
exponent(r)
|
|
187
|
+
} else {
|
|
188
|
+
exponent(pre.toDouble)
|
|
197
189
|
}
|
|
198
190
|
}
|
|
191
|
+
fraction(readInteger())
|
|
199
192
|
}
|
|
200
193
|
|
|
194
|
+
namespace returning {
|
|
195
|
+
|
|
201
196
|
def expect[R](message: String) { scanner: () => R / fail }: R / Exception[WrongFormat] =
|
|
202
197
|
try { scanner() } with fail { wrongFormat(message) }
|
|
203
198
|
|
|
@@ -217,7 +212,7 @@ namespace test {
|
|
|
217
212
|
with on[WrongFormat].panic
|
|
218
213
|
with expect("this grammar")
|
|
219
214
|
with feed(input)
|
|
220
|
-
with
|
|
215
|
+
with peeking[Char]
|
|
221
216
|
|
|
222
217
|
skipWhitespace()
|
|
223
218
|
println(readInteger().show)
|