@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.
Files changed (57) hide show
  1. package/CHANGELOG.md +63 -0
  2. package/LICENSE +21 -0
  3. package/README.md +34 -0
  4. package/array.gr +200 -89
  5. package/array.md +81 -5
  6. package/buffer.gr +93 -36
  7. package/bytes.gr +512 -407
  8. package/bytes.md +621 -0
  9. package/char.gr +119 -55
  10. package/char.md +200 -0
  11. package/hash.gr +42 -15
  12. package/hash.md +44 -0
  13. package/list.gr +121 -50
  14. package/map.gr +106 -110
  15. package/number.gr +37 -1
  16. package/number.md +66 -0
  17. package/option.gr +260 -53
  18. package/option.md +579 -0
  19. package/package.json +33 -29
  20. package/pervasives.gr +32 -20
  21. package/queue.gr +102 -30
  22. package/queue.md +191 -0
  23. package/range.gr +26 -26
  24. package/range.md +1 -1
  25. package/regex.gr +3055 -0
  26. package/regex.md +449 -0
  27. package/result.gr +216 -70
  28. package/result.md +446 -0
  29. package/runtime/dataStructures.gr +28 -29
  30. package/runtime/debug.gr +0 -1
  31. package/runtime/equal.gr +37 -16
  32. package/runtime/exception.gr +28 -15
  33. package/runtime/gc.gr +33 -20
  34. package/runtime/malloc.gr +19 -11
  35. package/runtime/numberUtils.gr +208 -105
  36. package/runtime/numbers.gr +217 -118
  37. package/runtime/string.gr +150 -59
  38. package/runtime/stringUtils.gr +176 -0
  39. package/runtime/unsafe/conv.gr +51 -8
  40. package/runtime/unsafe/memory.gr +14 -3
  41. package/runtime/unsafe/printWasm.gr +4 -4
  42. package/runtime/unsafe/tags.gr +2 -2
  43. package/runtime/unsafe/wasmf32.gr +9 -2
  44. package/runtime/unsafe/wasmf64.gr +9 -2
  45. package/runtime/unsafe/wasmi32.gr +65 -47
  46. package/runtime/unsafe/wasmi64.gr +78 -50
  47. package/runtime/wasi.gr +199 -45
  48. package/set.gr +281 -119
  49. package/set.md +502 -0
  50. package/stack.gr +26 -26
  51. package/stack.md +143 -0
  52. package/string.gr +697 -329
  53. package/string.md +815 -0
  54. package/sys/file.gr +356 -177
  55. package/sys/process.gr +10 -6
  56. package/sys/random.gr +3 -6
  57. 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: (WasmI32, WasmI32, WasmI32, WasmI32) -> WasmI32 from "wasi_snapshot_preview1"
28
+ import foreign wasm fd_write: (
29
+ WasmI32,
30
+ WasmI32,
31
+ WasmI32,
32
+ WasmI32,
33
+ ) -> WasmI32 from "wasi_snapshot_preview1"
29
34
 
30
- primitive (!) : Bool -> Bool = "@not"
31
- primitive (&&) : (Bool, Bool) -> Bool = "@and"
32
- primitive (||) : (Bool, Bool) -> Bool = "@or"
35
+ primitive (!): Bool -> Bool = "@not"
36
+ primitive (&&): (Bool, Bool) -> Bool = "@and"
37
+ primitive (||): (Bool, Bool) -> Bool = "@or"
33
38
 
34
- enum StringList { SLEmpty, SLCons(String, 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 = (variant) => {
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 = (record_) => {
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 + (i * 4n), fieldName, 8n)
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) => totalBytes(acc + WasmI32.load(WasmI32.fromGrain(hd), 4n), tl),
146
- SLEmpty => acc
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 = (list) => {
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
- let reverse = (list) => {
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, SLCons(first, acc))
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 (byte >= _SEQ_B && byte <= _SEQ_R /* b, f, n, r, t, v */ || byte == _SEQ_V || byte == _SEQ_SLASH || byte == _SEQ_QUOTE) {
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 (byte >= _SEQ_B && byte <= _SEQ_R /* b, f, n, r, t, v */ || byte == _SEQ_V || byte == _SEQ_SLASH || byte == _SEQ_QUOTE) {
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(")", SLEmpty)
410
+ let mut strings = slConsDisableGc(rparen, SLEmpty)
386
411
  for (let mut i = variantArity * 4n - 4n; i >= 0n; i -= 4n) {
387
- let tmp = toStringHelp(WasmI32.load(ptr + i, 20n), extraIndents, false)
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
- strings = slConsDisableGc(variantName, slConsDisableGc("(", strings))
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) "" else {
447
+ let prevSpacePadding = if (prevPadAmount == 0n) {
448
+ ""
449
+ } else {
412
450
  let v = allocateString(prevPadAmount)
413
- Memory.fill(v + 8n, 0x20n, prevPadAmount) // create indentation for closing brace
414
- WasmI32.toGrain(v) : String
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 mut strings = slConsDisableGc("\n", slConsDisableGc(prevSpacePadding, slConsDisableGc("}", SLEmpty)))
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; i -= 4n) {
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(WasmI32.load(ptr + i, 16n), extraIndents + 1n, false)
427
- Memory.incRef(WasmI32.fromGrain(spacePadding))
428
- Memory.incRef(WasmI32.fromGrain(fieldName))
429
- Memory.incRef(WasmI32.fromGrain(colspace))
430
- strings = slConsDisableGc(spacePadding, slConsDisableGc(fieldName, slConsDisableGc(colspace, slConsDisableGc(fieldValue, strings))))
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
- strings = slConsDisableGc("{\n", strings)
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 mut strings = slConsDisableGc("]", SLEmpty)
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
- strings = slConsDisableGc("[> ", strings)
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 strings = slConsDisableGc(numerator, slConsDisableGc("/", slConsDisableGc(denominator, SLEmpty)))
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 mut strings = slConsDisableGc(")", SLEmpty)
575
+ let rparen = ")"
576
+ let mut strings = slConsDisableGc(rparen, SLEmpty)
507
577
  if (tupleLength <= 1n) {
508
578
  // Special case: unary tuple
509
- strings = slConsDisableGc(",", strings)
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(WasmI32.load(ptr + i, 8n), extraIndents, false)
513
- Memory.incRef(WasmI32.fromGrain(item))
514
- Memory.incRef(WasmI32.fromGrain(strings))
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
- strings = slConsDisableGc("(", strings)
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(NumberUtils.itoa32(tag, 16n),
542
- slConsDisableGc(" | value: 0x",
543
- slConsDisableGc(NumberUtils.itoa32(ptr, 16n),
544
- slConsDisableGc(">", SLEmpty)))))
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 mut strings = slConsDisableGc("[", SLEmpty)
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(", ", strings)
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
- strings = slConsDisableGc("]", strings)
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 = (value) => {
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 = (value) => {
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
+ }