@grain/stdlib 0.4.1 → 0.4.5
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/CHANGELOG.md +63 -0
- package/LICENSE +21 -0
- package/README.md +34 -0
- package/array.gr +200 -89
- package/array.md +81 -5
- package/buffer.gr +93 -36
- package/bytes.gr +512 -407
- package/bytes.md +621 -0
- package/char.gr +119 -55
- package/char.md +200 -0
- package/hash.gr +42 -15
- package/hash.md +44 -0
- package/list.gr +121 -50
- package/map.gr +106 -110
- package/number.gr +37 -1
- package/number.md +66 -0
- package/option.gr +260 -53
- package/option.md +579 -0
- package/package.json +33 -29
- package/pervasives.gr +32 -20
- package/queue.gr +102 -30
- package/queue.md +191 -0
- package/range.gr +26 -26
- package/range.md +1 -1
- package/regex.gr +3055 -0
- package/regex.md +449 -0
- package/result.gr +216 -70
- package/result.md +446 -0
- package/runtime/dataStructures.gr +28 -29
- package/runtime/debug.gr +0 -1
- package/runtime/equal.gr +37 -16
- package/runtime/exception.gr +28 -15
- package/runtime/gc.gr +33 -20
- package/runtime/malloc.gr +19 -11
- package/runtime/numberUtils.gr +208 -105
- package/runtime/numbers.gr +217 -118
- package/runtime/string.gr +150 -59
- package/runtime/stringUtils.gr +176 -0
- package/runtime/unsafe/conv.gr +51 -8
- package/runtime/unsafe/memory.gr +14 -3
- package/runtime/unsafe/printWasm.gr +4 -4
- package/runtime/unsafe/tags.gr +2 -2
- package/runtime/unsafe/wasmf32.gr +9 -2
- package/runtime/unsafe/wasmf64.gr +9 -2
- package/runtime/unsafe/wasmi32.gr +65 -47
- package/runtime/unsafe/wasmi64.gr +78 -50
- package/runtime/wasi.gr +199 -45
- package/set.gr +281 -119
- package/set.md +502 -0
- package/stack.gr +26 -26
- package/stack.md +143 -0
- package/string.gr +697 -329
- package/string.md +815 -0
- package/sys/file.gr +356 -177
- package/sys/process.gr +10 -6
- package/sys/random.gr +3 -6
- package/sys/time.gr +3 -3
package/runtime/string.gr
CHANGED
|
@@ -14,7 +14,7 @@ import WasmI32, {
|
|
|
14
14
|
geS as (>=),
|
|
15
15
|
gtS as (>),
|
|
16
16
|
leS as (<=),
|
|
17
|
-
ltS as (<)
|
|
17
|
+
ltS as (<),
|
|
18
18
|
} from "runtime/unsafe/wasmi32"
|
|
19
19
|
import WasmI64 from "runtime/unsafe/wasmi64"
|
|
20
20
|
import WasmF32 from "runtime/unsafe/wasmf32"
|
|
@@ -25,29 +25,39 @@ import NumberUtils from "runtime/numberUtils"
|
|
|
25
25
|
|
|
26
26
|
import { allocateString, allocateArray } from "runtime/dataStructures"
|
|
27
27
|
|
|
28
|
-
import foreign wasm fd_write: (
|
|
28
|
+
import foreign wasm fd_write: (
|
|
29
|
+
WasmI32,
|
|
30
|
+
WasmI32,
|
|
31
|
+
WasmI32,
|
|
32
|
+
WasmI32,
|
|
33
|
+
) -> WasmI32 from "wasi_snapshot_preview1"
|
|
29
34
|
|
|
30
|
-
primitive (!)
|
|
31
|
-
primitive (&&)
|
|
32
|
-
primitive (||)
|
|
35
|
+
primitive (!): Bool -> Bool = "@not"
|
|
36
|
+
primitive (&&): (Bool, Bool) -> Bool = "@and"
|
|
37
|
+
primitive (||): (Bool, Bool) -> Bool = "@or"
|
|
33
38
|
|
|
34
|
-
enum StringList {
|
|
39
|
+
enum StringList {
|
|
40
|
+
SLEmpty,
|
|
41
|
+
SLCons(String, StringList),
|
|
42
|
+
}
|
|
35
43
|
|
|
36
44
|
@disableGC
|
|
37
45
|
let slConsDisableGc = (a, b) => {
|
|
38
46
|
Memory.incRef(WasmI32.fromGrain(SLCons))
|
|
47
|
+
Memory.incRef(WasmI32.fromGrain(a))
|
|
48
|
+
// for easier chaining, we don't incRef `b`
|
|
39
49
|
SLCons(a, b)
|
|
40
50
|
}
|
|
41
51
|
|
|
42
52
|
@disableGC
|
|
43
|
-
let mut _RUNTIME_TYPE_METADATA_PTR = 0x01n
|
|
53
|
+
let mut _RUNTIME_TYPE_METADATA_PTR = 0x01n
|
|
44
54
|
|
|
45
55
|
@disableGC
|
|
46
56
|
let initPtr = () => {
|
|
47
57
|
// hack to avoid incRef on this pointer
|
|
48
58
|
_RUNTIME_TYPE_METADATA_PTR = 0x408n
|
|
49
59
|
}
|
|
50
|
-
initPtr()
|
|
60
|
+
initPtr()
|
|
51
61
|
|
|
52
62
|
@disableGC
|
|
53
63
|
let findTypeMetadata = (moduleId, typeId) => {
|
|
@@ -80,7 +90,7 @@ let findTypeMetadata = (moduleId, typeId) => {
|
|
|
80
90
|
}
|
|
81
91
|
|
|
82
92
|
@disableGC
|
|
83
|
-
let getVariantName =
|
|
93
|
+
let getVariantName = variant => {
|
|
84
94
|
let moduleId = WasmI32.load(variant, 4n) >> 1n
|
|
85
95
|
let typeId = WasmI32.load(variant, 8n) >> 1n
|
|
86
96
|
let variantId = WasmI32.load(variant, 12n) >> 1n
|
|
@@ -111,7 +121,7 @@ let getVariantName = (variant) => {
|
|
|
111
121
|
}
|
|
112
122
|
|
|
113
123
|
@disableGC
|
|
114
|
-
let getRecordFieldNames =
|
|
124
|
+
let getRecordFieldNames = record_ => {
|
|
115
125
|
let moduleId = WasmI32.load(record_, 4n) >> 1n
|
|
116
126
|
let typeId = WasmI32.load(record_, 8n) >> 1n
|
|
117
127
|
let arity = WasmI32.load(record_, 12n)
|
|
@@ -130,7 +140,7 @@ let getRecordFieldNames = (record_) => {
|
|
|
130
140
|
let fieldLength = WasmI32.load(fields + fieldOffset, 4n)
|
|
131
141
|
let fieldName = allocateString(fieldLength)
|
|
132
142
|
Memory.copy(fieldName + 8n, fields + fieldOffset + 8n, fieldLength)
|
|
133
|
-
WasmI32.store(fieldArray +
|
|
143
|
+
WasmI32.store(fieldArray + i * 4n, fieldName, 8n)
|
|
134
144
|
|
|
135
145
|
fieldOffset += WasmI32.load(fields + fieldOffset, 0n)
|
|
136
146
|
}
|
|
@@ -142,8 +152,9 @@ let getRecordFieldNames = (record_) => {
|
|
|
142
152
|
@disableGC
|
|
143
153
|
let rec totalBytes = (acc, list) => {
|
|
144
154
|
match (list) {
|
|
145
|
-
SLCons(hd, tl) =>
|
|
146
|
-
|
|
155
|
+
SLCons(hd, tl) =>
|
|
156
|
+
totalBytes(acc + WasmI32.load(WasmI32.fromGrain(hd), 4n), tl),
|
|
157
|
+
SLEmpty => acc,
|
|
147
158
|
}
|
|
148
159
|
}
|
|
149
160
|
|
|
@@ -156,25 +167,28 @@ let rec writeStrings = (buf, list) => {
|
|
|
156
167
|
Memory.copy(buf, hd + 8n, hdSize)
|
|
157
168
|
writeStrings(buf + hdSize, tl)
|
|
158
169
|
},
|
|
159
|
-
SLEmpty => void
|
|
170
|
+
SLEmpty => void,
|
|
160
171
|
}
|
|
161
172
|
}
|
|
162
173
|
|
|
163
174
|
@disableGC
|
|
164
|
-
let join =
|
|
175
|
+
let join = list => {
|
|
165
176
|
let len = totalBytes(0n, list)
|
|
166
177
|
let str = allocateString(len)
|
|
167
178
|
writeStrings(str + 8n, list)
|
|
168
179
|
WasmI32.toGrain(str): String
|
|
169
180
|
}
|
|
170
181
|
|
|
171
|
-
|
|
182
|
+
@disableGC
|
|
183
|
+
let reverse = list => {
|
|
184
|
+
@disableGC
|
|
172
185
|
let rec iter = (list, acc) => {
|
|
173
186
|
match (list) {
|
|
174
187
|
SLEmpty => acc,
|
|
175
|
-
SLCons(first, rest) => iter(rest,
|
|
188
|
+
SLCons(first, rest) => iter(rest, slConsDisableGc(first, acc)),
|
|
176
189
|
}
|
|
177
190
|
}
|
|
191
|
+
Memory.incRef(WasmI32.fromGrain(SLEmpty))
|
|
178
192
|
iter(list, SLEmpty)
|
|
179
193
|
}
|
|
180
194
|
|
|
@@ -235,7 +249,12 @@ let escape = (ptr, isString) => {
|
|
|
235
249
|
let mut newSize = 2n // extra space for quote characters
|
|
236
250
|
for (let mut i = 0n; i < size; i += 1n) {
|
|
237
251
|
let byte = WasmI32.load8U(ptr + i, startOffset)
|
|
238
|
-
if (
|
|
252
|
+
if (
|
|
253
|
+
byte >= _SEQ_B && byte <= _SEQ_R || /* b, f, n, r, t, v */
|
|
254
|
+
byte == _SEQ_V ||
|
|
255
|
+
byte == _SEQ_SLASH ||
|
|
256
|
+
byte == _SEQ_QUOTE
|
|
257
|
+
) {
|
|
239
258
|
newSize += 2n
|
|
240
259
|
} else {
|
|
241
260
|
newSize += 1n
|
|
@@ -249,7 +268,12 @@ let escape = (ptr, isString) => {
|
|
|
249
268
|
|
|
250
269
|
for (let mut i = 0n; i < size; i += 1n) {
|
|
251
270
|
let byte = WasmI32.load8U(ptr + i, startOffset)
|
|
252
|
-
if (
|
|
271
|
+
if (
|
|
272
|
+
byte >= _SEQ_B && byte <= _SEQ_R || /* b, f, n, r, t, v */
|
|
273
|
+
byte == _SEQ_V ||
|
|
274
|
+
byte == _SEQ_SLASH ||
|
|
275
|
+
byte == _SEQ_QUOTE
|
|
276
|
+
) {
|
|
253
277
|
WasmI32.store8(escapedString + j, _SEQ_SLASH, stringOffset)
|
|
254
278
|
j += 1n
|
|
255
279
|
let seq = match (byte) {
|
|
@@ -259,7 +283,7 @@ let escape = (ptr, isString) => {
|
|
|
259
283
|
r when r == _SEQ_R => 0x72n,
|
|
260
284
|
t when t == _SEQ_T => 0x74n,
|
|
261
285
|
v when v == _SEQ_V => 0x76n,
|
|
262
|
-
_ => byte
|
|
286
|
+
_ => byte,
|
|
263
287
|
}
|
|
264
288
|
WasmI32.store8(escapedString + j, seq, stringOffset)
|
|
265
289
|
j += 1n
|
|
@@ -381,19 +405,31 @@ let rec heapValueToString = (ptr, extraIndents, toplevel) => {
|
|
|
381
405
|
variantName
|
|
382
406
|
} else {
|
|
383
407
|
let comspace = ", "
|
|
408
|
+
let rparen = ")"
|
|
384
409
|
Memory.incRef(WasmI32.fromGrain(SLEmpty))
|
|
385
|
-
let mut strings = slConsDisableGc(
|
|
410
|
+
let mut strings = slConsDisableGc(rparen, SLEmpty)
|
|
386
411
|
for (let mut i = variantArity * 4n - 4n; i >= 0n; i -= 4n) {
|
|
387
|
-
let tmp = toStringHelp(
|
|
412
|
+
let tmp = toStringHelp(
|
|
413
|
+
WasmI32.load(ptr + i, 20n),
|
|
414
|
+
extraIndents,
|
|
415
|
+
false
|
|
416
|
+
)
|
|
388
417
|
strings = slConsDisableGc(tmp, strings)
|
|
418
|
+
Memory.decRef(WasmI32.fromGrain(tmp))
|
|
389
419
|
if (i > 0n) {
|
|
390
|
-
Memory.incRef(WasmI32.fromGrain(comspace))
|
|
391
420
|
strings = slConsDisableGc(comspace, strings)
|
|
392
421
|
}
|
|
393
422
|
}
|
|
394
423
|
Memory.incRef(WasmI32.fromGrain(variantName))
|
|
395
|
-
|
|
424
|
+
let lparen = "("
|
|
425
|
+
strings = slConsDisableGc(
|
|
426
|
+
variantName,
|
|
427
|
+
slConsDisableGc(lparen, strings)
|
|
428
|
+
)
|
|
396
429
|
let string = join(strings)
|
|
430
|
+
Memory.decRef(WasmI32.fromGrain(variantName))
|
|
431
|
+
Memory.decRef(WasmI32.fromGrain(lparen))
|
|
432
|
+
Memory.decRef(WasmI32.fromGrain(rparen))
|
|
397
433
|
Memory.decRef(WasmI32.fromGrain(strings))
|
|
398
434
|
Memory.decRef(WasmI32.fromGrain(comspace))
|
|
399
435
|
string
|
|
@@ -408,38 +444,60 @@ let rec heapValueToString = (ptr, extraIndents, toplevel) => {
|
|
|
408
444
|
"<record value>"
|
|
409
445
|
} else {
|
|
410
446
|
let prevPadAmount = extraIndents * 2n
|
|
411
|
-
let prevSpacePadding = if (prevPadAmount == 0n)
|
|
447
|
+
let prevSpacePadding = if (prevPadAmount == 0n) {
|
|
448
|
+
""
|
|
449
|
+
} else {
|
|
412
450
|
let v = allocateString(prevPadAmount)
|
|
413
|
-
Memory.fill(
|
|
414
|
-
|
|
451
|
+
Memory.fill(
|
|
452
|
+
v + 8n,
|
|
453
|
+
0x20n,
|
|
454
|
+
prevPadAmount
|
|
455
|
+
) // create indentation for closing brace
|
|
456
|
+
WasmI32.toGrain(v): String
|
|
415
457
|
}
|
|
416
458
|
let padAmount = (extraIndents + 1n) * 2n
|
|
417
459
|
let spacePadding = allocateString(padAmount)
|
|
418
460
|
Memory.fill(spacePadding + 8n, 0x20n, padAmount) // create indentation
|
|
419
461
|
let spacePadding = WasmI32.toGrain(spacePadding): String
|
|
420
462
|
Memory.incRef(WasmI32.fromGrain(SLEmpty))
|
|
421
|
-
let
|
|
463
|
+
let newline = "\n"
|
|
464
|
+
let rbrace = "}"
|
|
465
|
+
let mut strings = slConsDisableGc(
|
|
466
|
+
newline,
|
|
467
|
+
slConsDisableGc(prevSpacePadding, slConsDisableGc(rbrace, SLEmpty))
|
|
468
|
+
)
|
|
422
469
|
let colspace = ": "
|
|
423
470
|
let comlf = ",\n"
|
|
424
|
-
for (let mut i = recordArity * 4n - 4n; i >= 0n;
|
|
471
|
+
for (let mut i = recordArity * 4n - 4n; i >= 0n; i -= 4n) {
|
|
425
472
|
let fieldName = WasmI32.toGrain(WasmI32.load(fields + i, 8n)): String
|
|
426
|
-
let fieldValue = toStringHelp(
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
473
|
+
let fieldValue = toStringHelp(
|
|
474
|
+
WasmI32.load(ptr + i, 16n),
|
|
475
|
+
extraIndents + 1n,
|
|
476
|
+
false
|
|
477
|
+
)
|
|
478
|
+
strings = slConsDisableGc(
|
|
479
|
+
spacePadding,
|
|
480
|
+
slConsDisableGc(
|
|
481
|
+
fieldName,
|
|
482
|
+
slConsDisableGc(colspace, slConsDisableGc(fieldValue, strings))
|
|
483
|
+
)
|
|
484
|
+
)
|
|
485
|
+
Memory.decRef(WasmI32.fromGrain(fieldValue))
|
|
431
486
|
if (i > 0n) {
|
|
432
|
-
Memory.incRef(WasmI32.fromGrain(comlf))
|
|
433
487
|
strings = slConsDisableGc(comlf, strings)
|
|
434
488
|
}
|
|
435
489
|
}
|
|
436
|
-
|
|
490
|
+
let lbrace = "{\n"
|
|
491
|
+
strings = slConsDisableGc(lbrace, strings)
|
|
437
492
|
let string = join(strings)
|
|
438
493
|
|
|
439
494
|
Memory.decRef(WasmI32.fromGrain(strings))
|
|
440
495
|
Memory.decRef(WasmI32.fromGrain(spacePadding))
|
|
441
496
|
Memory.decRef(WasmI32.fromGrain(colspace))
|
|
442
497
|
Memory.decRef(WasmI32.fromGrain(comlf))
|
|
498
|
+
Memory.decRef(WasmI32.fromGrain(lbrace))
|
|
499
|
+
Memory.decRef(WasmI32.fromGrain(rbrace))
|
|
500
|
+
Memory.decRef(WasmI32.fromGrain(newline))
|
|
443
501
|
|
|
444
502
|
Memory.free(fields) // Avoid double-free of record field names
|
|
445
503
|
|
|
@@ -449,20 +507,24 @@ let rec heapValueToString = (ptr, extraIndents, toplevel) => {
|
|
|
449
507
|
t when t == Tags._GRAIN_ARRAY_HEAP_TAG => {
|
|
450
508
|
let arity = WasmI32.load(ptr, 4n)
|
|
451
509
|
Memory.incRef(WasmI32.fromGrain(SLEmpty))
|
|
452
|
-
let
|
|
510
|
+
let rbrack = "]"
|
|
511
|
+
let mut strings = slConsDisableGc(rbrack, SLEmpty)
|
|
453
512
|
let comspace = ", "
|
|
454
513
|
for (let mut i = arity * 4n - 4n; i >= 0n; i -= 4n) {
|
|
455
514
|
let item = toStringHelp(WasmI32.load(ptr + i, 8n), extraIndents, false)
|
|
456
515
|
strings = slConsDisableGc(item, strings)
|
|
516
|
+
Memory.decRef(WasmI32.fromGrain(item))
|
|
457
517
|
if (i > 0n) {
|
|
458
|
-
Memory.incRef(WasmI32.fromGrain(comspace))
|
|
459
518
|
strings = slConsDisableGc(comspace, strings)
|
|
460
519
|
}
|
|
461
520
|
}
|
|
462
|
-
|
|
521
|
+
let lbrack = "[> "
|
|
522
|
+
strings = slConsDisableGc(lbrack, strings)
|
|
463
523
|
let string = join(strings)
|
|
464
524
|
Memory.decRef(WasmI32.fromGrain(strings))
|
|
465
525
|
Memory.decRef(WasmI32.fromGrain(comspace))
|
|
526
|
+
Memory.decRef(WasmI32.fromGrain(lbrack))
|
|
527
|
+
Memory.decRef(WasmI32.fromGrain(rbrack))
|
|
466
528
|
|
|
467
529
|
string
|
|
468
530
|
},
|
|
@@ -479,9 +541,16 @@ let rec heapValueToString = (ptr, extraIndents, toplevel) => {
|
|
|
479
541
|
let numerator = NumberUtils.itoa32(WasmI32.load(ptr, 8n), 10n)
|
|
480
542
|
let denominator = NumberUtils.itoa32(WasmI32.load(ptr, 12n), 10n)
|
|
481
543
|
Memory.incRef(WasmI32.fromGrain(SLEmpty))
|
|
482
|
-
let
|
|
544
|
+
let slash = "/"
|
|
545
|
+
let strings = slConsDisableGc(
|
|
546
|
+
numerator,
|
|
547
|
+
slConsDisableGc(slash, slConsDisableGc(denominator, SLEmpty))
|
|
548
|
+
)
|
|
483
549
|
let string = join(strings)
|
|
484
550
|
Memory.decRef(WasmI32.fromGrain(strings))
|
|
551
|
+
Memory.decRef(WasmI32.fromGrain(numerator))
|
|
552
|
+
Memory.decRef(WasmI32.fromGrain(denominator))
|
|
553
|
+
Memory.decRef(WasmI32.fromGrain(slash))
|
|
485
554
|
string
|
|
486
555
|
},
|
|
487
556
|
t when t == Tags._GRAIN_FLOAT32_BOXED_NUM_TAG => {
|
|
@@ -492,7 +561,7 @@ let rec heapValueToString = (ptr, extraIndents, toplevel) => {
|
|
|
492
561
|
},
|
|
493
562
|
_ => {
|
|
494
563
|
"<unknown boxed number>"
|
|
495
|
-
}
|
|
564
|
+
},
|
|
496
565
|
}
|
|
497
566
|
},
|
|
498
567
|
t when t == Tags._GRAIN_TUPLE_HEAP_TAG => {
|
|
@@ -503,30 +572,38 @@ let rec heapValueToString = (ptr, extraIndents, toplevel) => {
|
|
|
503
572
|
WasmI32.store(ptr, 0x80000000n | tupleLength, 4n)
|
|
504
573
|
let comspace = ", "
|
|
505
574
|
Memory.incRef(WasmI32.fromGrain(SLEmpty))
|
|
506
|
-
let
|
|
575
|
+
let rparen = ")"
|
|
576
|
+
let mut strings = slConsDisableGc(rparen, SLEmpty)
|
|
507
577
|
if (tupleLength <= 1n) {
|
|
508
578
|
// Special case: unary tuple
|
|
509
|
-
|
|
579
|
+
let comma = ","
|
|
580
|
+
strings = slConsDisableGc(comma, strings)
|
|
581
|
+
Memory.decRef(WasmI32.fromGrain(comma))
|
|
582
|
+
void
|
|
510
583
|
}
|
|
511
584
|
for (let mut i = tupleLength * 4n - 4n; i >= 0n; i -= 4n) {
|
|
512
|
-
let item = toStringHelp(
|
|
513
|
-
|
|
514
|
-
|
|
585
|
+
let item = toStringHelp(
|
|
586
|
+
WasmI32.load(ptr + i, 8n),
|
|
587
|
+
extraIndents,
|
|
588
|
+
false
|
|
589
|
+
)
|
|
515
590
|
strings = slConsDisableGc(item, strings)
|
|
591
|
+
Memory.decRef(WasmI32.fromGrain(item))
|
|
516
592
|
if (i > 0n) {
|
|
517
|
-
Memory.incRef(WasmI32.fromGrain(comspace))
|
|
518
|
-
Memory.incRef(WasmI32.fromGrain(strings))
|
|
519
593
|
strings = slConsDisableGc(comspace, strings)
|
|
520
594
|
}
|
|
521
595
|
}
|
|
522
596
|
WasmI32.store(ptr, tupleLength, 4n)
|
|
523
597
|
|
|
524
598
|
Memory.incRef(WasmI32.fromGrain(strings))
|
|
525
|
-
|
|
599
|
+
let lparen = "("
|
|
600
|
+
strings = slConsDisableGc(lparen, strings)
|
|
526
601
|
|
|
527
602
|
let string = join(strings)
|
|
528
603
|
Memory.decRef(WasmI32.fromGrain(strings))
|
|
529
604
|
Memory.decRef(WasmI32.fromGrain(comspace))
|
|
605
|
+
Memory.decRef(WasmI32.fromGrain(rparen))
|
|
606
|
+
Memory.decRef(WasmI32.fromGrain(lparen))
|
|
530
607
|
|
|
531
608
|
string
|
|
532
609
|
}
|
|
@@ -538,14 +615,21 @@ let rec heapValueToString = (ptr, extraIndents, toplevel) => {
|
|
|
538
615
|
Memory.incRef(WasmI32.fromGrain(SLEmpty))
|
|
539
616
|
let strings = slConsDisableGc(
|
|
540
617
|
"<unknown heap tag type: 0x",
|
|
541
|
-
slConsDisableGc(
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
618
|
+
slConsDisableGc(
|
|
619
|
+
NumberUtils.itoa32(tag, 16n),
|
|
620
|
+
slConsDisableGc(
|
|
621
|
+
" | value: 0x",
|
|
622
|
+
slConsDisableGc(
|
|
623
|
+
NumberUtils.itoa32(ptr, 16n),
|
|
624
|
+
slConsDisableGc(">", SLEmpty)
|
|
625
|
+
)
|
|
626
|
+
)
|
|
627
|
+
)
|
|
628
|
+
)
|
|
545
629
|
let string = join(strings)
|
|
546
630
|
Memory.decRef(WasmI32.fromGrain(strings))
|
|
547
631
|
string
|
|
548
|
-
}
|
|
632
|
+
},
|
|
549
633
|
}
|
|
550
634
|
}, toStringHelp = (grainValue, extraIndents, toplevel) => {
|
|
551
635
|
if ((grainValue & 1n) != 0n) {
|
|
@@ -567,7 +651,9 @@ let rec heapValueToString = (ptr, extraIndents, toplevel) => {
|
|
|
567
651
|
let mut isFirst = true
|
|
568
652
|
|
|
569
653
|
Memory.incRef(WasmI32.fromGrain(SLEmpty))
|
|
570
|
-
let
|
|
654
|
+
let lbrack = "["
|
|
655
|
+
let commaspace = ", "
|
|
656
|
+
let mut strings = slConsDisableGc(lbrack, SLEmpty)
|
|
571
657
|
|
|
572
658
|
while (true) {
|
|
573
659
|
let variantId = WasmI32.load(cur, 12n) >> 1n // tagged number
|
|
@@ -575,24 +661,29 @@ let rec heapValueToString = (ptr, extraIndents, toplevel) => {
|
|
|
575
661
|
break
|
|
576
662
|
} else {
|
|
577
663
|
if (!isFirst) {
|
|
578
|
-
strings = slConsDisableGc(
|
|
664
|
+
strings = slConsDisableGc(commaspace, strings)
|
|
579
665
|
}
|
|
580
666
|
isFirst = false
|
|
581
667
|
let item = toStringHelp(WasmI32.load(cur, 20n), extraIndents, false)
|
|
582
668
|
strings = slConsDisableGc(item, strings)
|
|
669
|
+
Memory.decRef(WasmI32.fromGrain(item))
|
|
583
670
|
cur = WasmI32.load(cur, 24n)
|
|
584
671
|
}
|
|
585
672
|
}
|
|
586
|
-
|
|
673
|
+
let rbrack = "]"
|
|
674
|
+
strings = slConsDisableGc(rbrack, strings)
|
|
587
675
|
let reversed = reverse(strings)
|
|
588
676
|
let string = join(reversed)
|
|
589
677
|
Memory.decRef(WasmI32.fromGrain(strings))
|
|
590
678
|
Memory.decRef(WasmI32.fromGrain(reversed))
|
|
679
|
+
Memory.decRef(WasmI32.fromGrain(lbrack))
|
|
680
|
+
Memory.decRef(WasmI32.fromGrain(rbrack))
|
|
681
|
+
Memory.decRef(WasmI32.fromGrain(commaspace))
|
|
591
682
|
string
|
|
592
683
|
}
|
|
593
684
|
|
|
594
685
|
@disableGC
|
|
595
|
-
export let rec toString =
|
|
686
|
+
export let rec toString = value => {
|
|
596
687
|
let value = WasmI32.fromGrain(value)
|
|
597
688
|
let ret = toStringHelp(value, 0n, true)
|
|
598
689
|
Memory.decRef(value)
|
|
@@ -601,7 +692,7 @@ export let rec toString = (value) => {
|
|
|
601
692
|
}
|
|
602
693
|
|
|
603
694
|
@disableGC
|
|
604
|
-
export let rec print =
|
|
695
|
+
export let rec print = value => {
|
|
605
696
|
// First convert the value to string, if it isn't one already. Calling
|
|
606
697
|
// toString will either return value instance itself if it's already a
|
|
607
698
|
// string, or a new string with the content of value object, which will need
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
// TODO(#1050): Remove dependency on Pervasives once Option/Result types are imbedded in the compiler
|
|
2
|
+
|
|
3
|
+
import WasmI32, {
|
|
4
|
+
add as (+),
|
|
5
|
+
sub as (-),
|
|
6
|
+
gtU as (>),
|
|
7
|
+
geU as (>=),
|
|
8
|
+
ltU as (<),
|
|
9
|
+
shrS as (>>),
|
|
10
|
+
eq as (==),
|
|
11
|
+
ne as (!=),
|
|
12
|
+
and as (&),
|
|
13
|
+
} from "runtime/unsafe/wasmi32"
|
|
14
|
+
import WasmI64 from "runtime/unsafe/wasmi64"
|
|
15
|
+
import Memory from "runtime/unsafe/memory"
|
|
16
|
+
import Tags from "runtime/unsafe/tags"
|
|
17
|
+
import { reducedInteger } from "runtime/numbers"
|
|
18
|
+
|
|
19
|
+
@disableGC
|
|
20
|
+
export let rec parseInt = (string: String, radix: Number) => {
|
|
21
|
+
let _CHAR_0 = 0x30n
|
|
22
|
+
let _CHAR_B = 0x42n
|
|
23
|
+
let _CHAR_b = 0x62n
|
|
24
|
+
let _CHAR_O = 0x4fn
|
|
25
|
+
let _CHAR_o = 0x6fn
|
|
26
|
+
let _CHAR_X = 0x58n
|
|
27
|
+
let _CHAR_x = 0x78n
|
|
28
|
+
|
|
29
|
+
let _CHAR_A = 0x41n
|
|
30
|
+
let _CHAR_a = 0x61n
|
|
31
|
+
|
|
32
|
+
let _CHAR_UNDERSCORE = 0x5fn
|
|
33
|
+
let _CHAR_MINUS = 0x2dn
|
|
34
|
+
|
|
35
|
+
let _INT_MIN = -9223372036854775808N
|
|
36
|
+
|
|
37
|
+
// Don't need to process Unicode length since if the string
|
|
38
|
+
// contains non-ascii characters, it's not a valid integer
|
|
39
|
+
let strLen = WasmI32.load(WasmI32.fromGrain(string), 4n)
|
|
40
|
+
|
|
41
|
+
// Our pointer within the string we're parsing, offset by the
|
|
42
|
+
// header
|
|
43
|
+
let mut offset = WasmI32.fromGrain(string) + 8n
|
|
44
|
+
|
|
45
|
+
let strEnd = offset + strLen
|
|
46
|
+
|
|
47
|
+
let radix = WasmI32.fromGrain(radix)
|
|
48
|
+
let result = if (
|
|
49
|
+
WasmI32.eqz(radix & Tags._GRAIN_NUMBER_TAG_MASK) ||
|
|
50
|
+
radix < WasmI32.fromGrain(2) ||
|
|
51
|
+
radix > WasmI32.fromGrain(36)
|
|
52
|
+
) {
|
|
53
|
+
Memory.incRef(WasmI32.fromGrain(Err))
|
|
54
|
+
Err("Radix must be an integer between 2 and 36")
|
|
55
|
+
} else if (WasmI32.eqz(strLen)) {
|
|
56
|
+
Memory.incRef(WasmI32.fromGrain(Err))
|
|
57
|
+
Err("Invalid input")
|
|
58
|
+
} else {
|
|
59
|
+
let mut char = WasmI32.load8U(offset, 0n)
|
|
60
|
+
|
|
61
|
+
let mut limit = WasmI64.add(_INT_MIN, 1N)
|
|
62
|
+
|
|
63
|
+
// Check for a sign
|
|
64
|
+
let mut negative = false
|
|
65
|
+
if (char == _CHAR_MINUS) {
|
|
66
|
+
negative = true
|
|
67
|
+
offset += 1n
|
|
68
|
+
limit = _INT_MIN
|
|
69
|
+
char = WasmI32.load8U(offset, 0n)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
let mut radix = WasmI64.extendI32S(radix >> 1n)
|
|
73
|
+
|
|
74
|
+
// Check if we should override the supplied radix
|
|
75
|
+
if (char == _CHAR_0 && strLen > 2n) {
|
|
76
|
+
match (WasmI32.load8U(offset, 1n)) {
|
|
77
|
+
c when c == _CHAR_B || c == _CHAR_b => {
|
|
78
|
+
radix = 2N
|
|
79
|
+
offset += 2n
|
|
80
|
+
},
|
|
81
|
+
c when c == _CHAR_O || c == _CHAR_o => {
|
|
82
|
+
radix = 8N
|
|
83
|
+
offset += 2n
|
|
84
|
+
},
|
|
85
|
+
c when c == _CHAR_X || c == _CHAR_x => {
|
|
86
|
+
radix = 16N
|
|
87
|
+
offset += 2n
|
|
88
|
+
},
|
|
89
|
+
_ => void,
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
let mut value = 0N
|
|
94
|
+
|
|
95
|
+
// we use 0 to represent no error, 1 to represent an invalid
|
|
96
|
+
// input, and 2 to represent an overflow
|
|
97
|
+
let mut error = 1n
|
|
98
|
+
|
|
99
|
+
for (let mut i = offset; i < strEnd; i += 1n) {
|
|
100
|
+
let char = WasmI32.load8U(i, 0n)
|
|
101
|
+
|
|
102
|
+
// Ignore underscore characters
|
|
103
|
+
if (char == _CHAR_UNDERSCORE) {
|
|
104
|
+
continue
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// We've seen at least one non-underscore character, so we'll consider
|
|
108
|
+
// the input valid until we find out otherwise
|
|
109
|
+
|
|
110
|
+
error = 0n
|
|
111
|
+
|
|
112
|
+
let mut digit = 0n
|
|
113
|
+
|
|
114
|
+
match (char) {
|
|
115
|
+
c when c - _CHAR_0 < 10n => digit = char - _CHAR_0,
|
|
116
|
+
c when c - _CHAR_A < 26n => digit = char - _CHAR_A + 10n,
|
|
117
|
+
c when c - _CHAR_a < 26n => digit = char - _CHAR_a + 10n,
|
|
118
|
+
_ => {
|
|
119
|
+
error = 1n
|
|
120
|
+
// invalid digit
|
|
121
|
+
break
|
|
122
|
+
},
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (digit >= WasmI32.wrapI64(radix)) {
|
|
126
|
+
error = 1n
|
|
127
|
+
// invalid digit
|
|
128
|
+
break
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
let digit = WasmI64.extendI32U(digit)
|
|
132
|
+
|
|
133
|
+
value = WasmI64.mul(value, radix)
|
|
134
|
+
|
|
135
|
+
// Check for overflow
|
|
136
|
+
// 64-bit int min + 1
|
|
137
|
+
if (WasmI64.ltS(value, WasmI64.add(limit, digit))) {
|
|
138
|
+
error = 2n
|
|
139
|
+
// overflow
|
|
140
|
+
break
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// To quote the OpenJDK,
|
|
144
|
+
// "Accumulating negatively avoids surprises near MAX_VALUE"
|
|
145
|
+
// The minimum value of a 64-bit integer (-9223372036854775808) can't be
|
|
146
|
+
// represented as a positive number because it would be larger than the
|
|
147
|
+
// maximum 64-bit integer (9223372036854775807), so we'd be unable to
|
|
148
|
+
// parse negatives as positives and multiply by the sign at the end.
|
|
149
|
+
// Instead, we represent all positive numbers as negative numbers since
|
|
150
|
+
// we have one unit more headroom.
|
|
151
|
+
value = WasmI64.sub(value, digit)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
match (error) {
|
|
155
|
+
1n => {
|
|
156
|
+
Memory.incRef(WasmI32.fromGrain(Err))
|
|
157
|
+
Err("Invalid digit in input")
|
|
158
|
+
},
|
|
159
|
+
2n => {
|
|
160
|
+
Memory.incRef(WasmI32.fromGrain(Err))
|
|
161
|
+
Err("Input out of range of representable integers")
|
|
162
|
+
},
|
|
163
|
+
_ => {
|
|
164
|
+
let value = if (negative) value else WasmI64.mul(value, -1N)
|
|
165
|
+
let number = WasmI32.toGrain(reducedInteger(value)): Number
|
|
166
|
+
Memory.incRef(WasmI32.fromGrain(Ok))
|
|
167
|
+
Ok(number)
|
|
168
|
+
},
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
Memory.decRef(WasmI32.fromGrain(parseInt))
|
|
173
|
+
Memory.decRef(radix)
|
|
174
|
+
|
|
175
|
+
result
|
|
176
|
+
}
|