@grain/stdlib 0.5.2 → 0.5.4
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 +59 -0
- package/array.gr +61 -1
- package/array.md +113 -0
- package/bigint.md +30 -30
- package/buffer.gr +24 -22
- package/char.gr +2 -2
- package/float32.md +3 -3
- package/float64.md +3 -3
- package/immutablemap.gr +493 -0
- package/immutablemap.md +479 -0
- package/immutablepriorityqueue.gr +360 -0
- package/immutablepriorityqueue.md +291 -0
- package/immutableset.gr +498 -0
- package/immutableset.md +449 -0
- package/list.gr +75 -2
- package/list.md +110 -0
- package/map.gr +1 -2
- package/marshal.gr +1058 -0
- package/marshal.md +76 -0
- package/number.gr +689 -23
- package/number.md +362 -27
- package/package.json +1 -1
- package/pervasives.gr +16 -5
- package/pervasives.md +28 -0
- package/priorityqueue.gr +261 -0
- package/priorityqueue.md +309 -0
- package/queue.gr +14 -1
- package/queue.md +16 -1
- package/regex.gr +90 -67
- package/runtime/bigint.gr +4 -4
- package/runtime/compare.gr +179 -0
- package/runtime/compare.md +6 -0
- package/runtime/equal.gr +3 -3
- package/runtime/exception.gr +9 -5
- package/runtime/exception.md +8 -2
- package/runtime/gc.gr +2 -1
- package/runtime/malloc.gr +1 -3
- package/runtime/numberUtils.gr +11 -11
- package/runtime/numbers.gr +423 -100
- package/runtime/numbers.md +50 -0
- package/runtime/string.gr +4 -2
- package/set.gr +26 -27
- package/stack.gr +12 -0
- package/stack.md +15 -0
- package/string.gr +409 -53
- package/string.md +164 -1
- package/sys/file.gr +4 -4
- package/sys/file.md +3 -3
- package/sys/process.gr +3 -3
- package/sys/process.md +3 -3
- package/sys/random.gr +2 -2
- package/sys/random.md +2 -2
- package/sys/time.gr +2 -2
- package/sys/time.md +2 -2
package/regex.gr
CHANGED
|
@@ -121,10 +121,10 @@ let withConfig = (buf: RegExBuf, config: RegExParserConfig) => {
|
|
|
121
121
|
|
|
122
122
|
let parseErr = (buf: RegExBuf, msg: String, posShift) => {
|
|
123
123
|
"Invalid Regular Expression: " ++
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
124
|
+
msg ++
|
|
125
|
+
" (position " ++
|
|
126
|
+
toString(unbox(buf.cursor) + posShift) ++
|
|
127
|
+
")"
|
|
128
128
|
}
|
|
129
129
|
|
|
130
130
|
let next = (buf: RegExBuf) => {
|
|
@@ -241,7 +241,8 @@ let rec rangeAdd = (rng: CharRange, v: CharRangeElt) => {
|
|
|
241
241
|
_ when rangeContains(rng, v) => rng,
|
|
242
242
|
_ => rangeUnion(rng, [(v, v)]),
|
|
243
243
|
}
|
|
244
|
-
},
|
|
244
|
+
},
|
|
245
|
+
rangeUnion = (rng1, rng2) => {
|
|
245
246
|
match ((rng1, rng2)) {
|
|
246
247
|
([], _) => rng2,
|
|
247
248
|
(_, []) => rng1,
|
|
@@ -487,7 +488,7 @@ enum MergeMode {
|
|
|
487
488
|
}
|
|
488
489
|
|
|
489
490
|
let mergeAdjacent = lst => {
|
|
490
|
-
// see
|
|
491
|
+
// TODO: see below
|
|
491
492
|
let readyForAccum = (l, mode) => {
|
|
492
493
|
match (l) {
|
|
493
494
|
[] => true,
|
|
@@ -512,7 +513,7 @@ let mergeAdjacent = lst => {
|
|
|
512
513
|
// drop empty elements
|
|
513
514
|
[REEmpty, ...tl] => loop(mode, accum, tl),
|
|
514
515
|
[RELiteralString(""), ...tl] => loop(mode, accum, tl),
|
|
515
|
-
//
|
|
516
|
+
// TODO(#696): Clean up with or-patterns
|
|
516
517
|
_ when readyForAccum(l, mode) => {
|
|
517
518
|
match (accum) {
|
|
518
519
|
[] => [],
|
|
@@ -592,7 +593,7 @@ REGEX PARSING DEFINITIONS
|
|
|
592
593
|
|
|
593
594
|
// Range parsing ("[a-z]")
|
|
594
595
|
|
|
595
|
-
//
|
|
596
|
+
// TODO(#769): When byte-based regexes are supported, we'll need another limit of 255 for those.
|
|
596
597
|
let rangeLimit = 0x10FFFF
|
|
597
598
|
|
|
598
599
|
// These are snake-cased to avoid confusion with their capitalized counterparts
|
|
@@ -636,7 +637,8 @@ let rec parseRangeNot = (buf: RegExBuf) => {
|
|
|
636
637
|
Ok(_) => parseRange(buf),
|
|
637
638
|
}
|
|
638
639
|
}
|
|
639
|
-
},
|
|
640
|
+
},
|
|
641
|
+
parseRange = (buf: RegExBuf) => {
|
|
640
642
|
if (!more(buf)) {
|
|
641
643
|
Err(parseErr(buf, "Missing closing `]`", 0))
|
|
642
644
|
} else {
|
|
@@ -659,7 +661,8 @@ let rec parseRangeNot = (buf: RegExBuf) => {
|
|
|
659
661
|
Ok(_) => parseRangeRest(buf, [], None, None),
|
|
660
662
|
}
|
|
661
663
|
}
|
|
662
|
-
},
|
|
664
|
+
},
|
|
665
|
+
parseClass = (buf: RegExBuf) => {
|
|
663
666
|
if (!more(buf)) {
|
|
664
667
|
Err(
|
|
665
668
|
"no chars"
|
|
@@ -694,7 +697,8 @@ let rec parseRangeNot = (buf: RegExBuf) => {
|
|
|
694
697
|
Ok(c) => Err("unknown class: " ++ toString(c)),
|
|
695
698
|
}
|
|
696
699
|
}
|
|
697
|
-
},
|
|
700
|
+
},
|
|
701
|
+
parsePosixCharClass = (buf: RegExBuf) => {
|
|
698
702
|
if (!more(buf)) {
|
|
699
703
|
Err(parseErr(buf, "Missing POSIX character class after `[`", 0))
|
|
700
704
|
} else {
|
|
@@ -810,7 +814,8 @@ let rec parseRangeNot = (buf: RegExBuf) => {
|
|
|
810
814
|
),
|
|
811
815
|
}
|
|
812
816
|
}
|
|
813
|
-
},
|
|
817
|
+
},
|
|
818
|
+
parseRangeRest =
|
|
814
819
|
(
|
|
815
820
|
buf: RegExBuf,
|
|
816
821
|
rng: CharRange,
|
|
@@ -962,7 +967,8 @@ let rec parseRangeNot = (buf: RegExBuf) => {
|
|
|
962
967
|
},
|
|
963
968
|
}
|
|
964
969
|
}
|
|
965
|
-
},
|
|
970
|
+
},
|
|
971
|
+
parseRangeRestSpan =
|
|
966
972
|
(
|
|
967
973
|
buf: RegExBuf,
|
|
968
974
|
c,
|
|
@@ -1213,7 +1219,8 @@ let rec parseAtom = (buf: RegExBuf) => {
|
|
|
1213
1219
|
_ => parseLiteral(buf),
|
|
1214
1220
|
},
|
|
1215
1221
|
}
|
|
1216
|
-
},
|
|
1222
|
+
},
|
|
1223
|
+
parseLook = (buf: RegExBuf) => {
|
|
1217
1224
|
let preNumGroups = unbox(buf.config.groupNumber)
|
|
1218
1225
|
let spanNumGroups = () => unbox(buf.config.groupNumber) - preNumGroups
|
|
1219
1226
|
// (isMatch, isAhead)
|
|
@@ -1279,7 +1286,8 @@ let rec parseAtom = (buf: RegExBuf) => {
|
|
|
1279
1286
|
}
|
|
1280
1287
|
},
|
|
1281
1288
|
}
|
|
1282
|
-
},
|
|
1289
|
+
},
|
|
1290
|
+
parseTest = (buf: RegExBuf) => {
|
|
1283
1291
|
if (!more(buf)) {
|
|
1284
1292
|
Err(parseErr(buf, "Expected test", 0))
|
|
1285
1293
|
} else {
|
|
@@ -1316,7 +1324,8 @@ let rec parseAtom = (buf: RegExBuf) => {
|
|
|
1316
1324
|
),
|
|
1317
1325
|
}
|
|
1318
1326
|
}
|
|
1319
|
-
},
|
|
1327
|
+
},
|
|
1328
|
+
parseInteger = (buf: RegExBuf, n) => {
|
|
1320
1329
|
if (!more(buf)) {
|
|
1321
1330
|
Ok(n)
|
|
1322
1331
|
} else {
|
|
@@ -1331,7 +1340,8 @@ let rec parseAtom = (buf: RegExBuf) => {
|
|
|
1331
1340
|
Ok(_) => Ok(n),
|
|
1332
1341
|
}
|
|
1333
1342
|
}
|
|
1334
|
-
},
|
|
1343
|
+
},
|
|
1344
|
+
parseMode = (buf: RegExBuf) => {
|
|
1335
1345
|
let processState = ((cs, ml)) => {
|
|
1336
1346
|
let withCs = match (cs) {
|
|
1337
1347
|
None => buf.config,
|
|
@@ -1390,7 +1400,8 @@ let rec parseAtom = (buf: RegExBuf) => {
|
|
|
1390
1400
|
}
|
|
1391
1401
|
}
|
|
1392
1402
|
help((None, None))
|
|
1393
|
-
},
|
|
1403
|
+
},
|
|
1404
|
+
parseUnicodeCategories = (buf: RegExBuf, pC: String) => {
|
|
1394
1405
|
if (!more(buf)) {
|
|
1395
1406
|
Err(parseErr(buf, "Expected unicode category", 0))
|
|
1396
1407
|
} else {
|
|
@@ -1558,7 +1569,8 @@ let rec parseAtom = (buf: RegExBuf) => {
|
|
|
1558
1569
|
Ok(_) => Err(parseErr(buf, "Expected `{` after `\\" ++ pC ++ "`", 0)),
|
|
1559
1570
|
}
|
|
1560
1571
|
}
|
|
1561
|
-
},
|
|
1572
|
+
},
|
|
1573
|
+
parseLiteral = (buf: RegExBuf) => {
|
|
1562
1574
|
if (!more(buf)) {
|
|
1563
1575
|
Err(parseErr(buf, "Expected literal", 0))
|
|
1564
1576
|
} else {
|
|
@@ -1578,7 +1590,7 @@ let rec parseAtom = (buf: RegExBuf) => {
|
|
|
1578
1590
|
Err(
|
|
1579
1591
|
parseErr(buf, "unmatched `" ++ Char.toString(c) ++ "` in pattern", 0)
|
|
1580
1592
|
),
|
|
1581
|
-
//
|
|
1593
|
+
// TODO(#691): Enable case-insensitive regular expression matching
|
|
1582
1594
|
Ok(c) when buf.config.caseSensitive => {
|
|
1583
1595
|
ignore(next(buf))
|
|
1584
1596
|
Ok(RELiteral(c))
|
|
@@ -1592,7 +1604,8 @@ let rec parseAtom = (buf: RegExBuf) => {
|
|
|
1592
1604
|
},
|
|
1593
1605
|
}
|
|
1594
1606
|
}
|
|
1595
|
-
},
|
|
1607
|
+
},
|
|
1608
|
+
parseBackslashLiteral = (buf: RegExBuf) => {
|
|
1596
1609
|
if (!more(buf)) {
|
|
1597
1610
|
// Special case: EOS after backslash matches null
|
|
1598
1611
|
Err(parseErr(buf, "Expected to find escaped value after backslash", 0))
|
|
@@ -1655,7 +1668,8 @@ let rec parseAtom = (buf: RegExBuf) => {
|
|
|
1655
1668
|
},
|
|
1656
1669
|
}
|
|
1657
1670
|
}
|
|
1658
|
-
},
|
|
1671
|
+
},
|
|
1672
|
+
parseNonGreedy = (buf: RegExBuf) => {
|
|
1659
1673
|
let checkNotNested = res => {
|
|
1660
1674
|
if (!more(buf)) {
|
|
1661
1675
|
res
|
|
@@ -1681,7 +1695,8 @@ let rec parseAtom = (buf: RegExBuf) => {
|
|
|
1681
1695
|
Ok(_) => checkNotNested(Ok(false)),
|
|
1682
1696
|
}
|
|
1683
1697
|
}
|
|
1684
|
-
},
|
|
1698
|
+
},
|
|
1699
|
+
parsePCE = (buf: RegExBuf) => {
|
|
1685
1700
|
match (parseAtom(buf)) {
|
|
1686
1701
|
Err(e) => Err(e),
|
|
1687
1702
|
Ok(atom) => {
|
|
@@ -1775,7 +1790,8 @@ let rec parseAtom = (buf: RegExBuf) => {
|
|
|
1775
1790
|
}
|
|
1776
1791
|
},
|
|
1777
1792
|
}
|
|
1778
|
-
},
|
|
1793
|
+
},
|
|
1794
|
+
parsePCEs = (buf: RegExBuf, toplevel: Bool) => {
|
|
1779
1795
|
if (!more(buf)) {
|
|
1780
1796
|
Ok([])
|
|
1781
1797
|
} else {
|
|
@@ -1801,7 +1817,8 @@ let rec parseAtom = (buf: RegExBuf) => {
|
|
|
1801
1817
|
},
|
|
1802
1818
|
}
|
|
1803
1819
|
}
|
|
1804
|
-
},
|
|
1820
|
+
},
|
|
1821
|
+
parseRegex = (buf: RegExBuf) => {
|
|
1805
1822
|
if (!more(buf)) {
|
|
1806
1823
|
Ok(REEmpty)
|
|
1807
1824
|
} else {
|
|
@@ -1836,7 +1853,8 @@ let rec parseAtom = (buf: RegExBuf) => {
|
|
|
1836
1853
|
},
|
|
1837
1854
|
}
|
|
1838
1855
|
}
|
|
1839
|
-
},
|
|
1856
|
+
},
|
|
1857
|
+
parseRegexNonEmpty = (buf: RegExBuf) => {
|
|
1840
1858
|
match (parsePCEs(buf, false)) {
|
|
1841
1859
|
Err(e) => Err(e),
|
|
1842
1860
|
Ok(pces) => {
|
|
@@ -1922,7 +1940,7 @@ let rec isAnchored = (re: ParsedRegularExpression) => {
|
|
|
1922
1940
|
REAlts(a, b) => isAnchored(a) && isAnchored(b),
|
|
1923
1941
|
REConditional(_, rx1, rx2, _, _, _) =>
|
|
1924
1942
|
isAnchored(rx1) &&
|
|
1925
|
-
|
|
1943
|
+
Option.mapWithDefault(isAnchored, false, rx2),
|
|
1926
1944
|
REGroup(rx, _) => isAnchored(rx),
|
|
1927
1945
|
RECut(rx, _, _, _) => isAnchored(rx),
|
|
1928
1946
|
_ => false,
|
|
@@ -2305,10 +2323,10 @@ let charMatcher = (toMatch, next_m) =>
|
|
|
2305
2323
|
if (
|
|
2306
2324
|
{
|
|
2307
2325
|
pos < limit &&
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2326
|
+
match (matchBufChar(buf, pos)) {
|
|
2327
|
+
Err(_) => false,
|
|
2328
|
+
Ok(c) => toMatch == c,
|
|
2329
|
+
}
|
|
2312
2330
|
}
|
|
2313
2331
|
) next_m(buf, pos + 1, start, limit, end, state, stack) else None
|
|
2314
2332
|
}
|
|
@@ -2326,10 +2344,10 @@ let charTailMatcher = toMatch =>
|
|
|
2326
2344
|
if (
|
|
2327
2345
|
{
|
|
2328
2346
|
pos < limit &&
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2347
|
+
match (matchBufChar(buf, pos)) {
|
|
2348
|
+
Err(_) => false,
|
|
2349
|
+
Ok(c) => toMatch == c,
|
|
2350
|
+
}
|
|
2333
2351
|
}
|
|
2334
2352
|
) Some(pos + 1) else None
|
|
2335
2353
|
}
|
|
@@ -2382,13 +2400,13 @@ let stringMatcher = (toMatch, len, next_m) =>
|
|
|
2382
2400
|
if (
|
|
2383
2401
|
{
|
|
2384
2402
|
pos + len <= limit &&
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2403
|
+
subArraysEqual(
|
|
2404
|
+
buf.matchInputExploded,
|
|
2405
|
+
pos,
|
|
2406
|
+
String.explode(toMatch),
|
|
2407
|
+
0,
|
|
2408
|
+
len
|
|
2409
|
+
)
|
|
2392
2410
|
}
|
|
2393
2411
|
) next_m(buf, pos + len, start, limit, end, state, stack) else None
|
|
2394
2412
|
}
|
|
@@ -2406,13 +2424,13 @@ let stringTailMatcher = (toMatch, len) =>
|
|
|
2406
2424
|
if (
|
|
2407
2425
|
{
|
|
2408
2426
|
pos + len <= limit &&
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2427
|
+
subArraysEqual(
|
|
2428
|
+
buf.matchInputExploded,
|
|
2429
|
+
pos,
|
|
2430
|
+
String.explode(toMatch),
|
|
2431
|
+
0,
|
|
2432
|
+
len
|
|
2433
|
+
)
|
|
2416
2434
|
}
|
|
2417
2435
|
) Some(pos + len) else None
|
|
2418
2436
|
}
|
|
@@ -2513,10 +2531,10 @@ let rangeMatcher = (rng: CharRange, next_m) =>
|
|
|
2513
2531
|
if (
|
|
2514
2532
|
{
|
|
2515
2533
|
pos < limit &&
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2534
|
+
match (matchBufChar(buf, pos)) {
|
|
2535
|
+
Err(_) => false,
|
|
2536
|
+
Ok(c) => rangeContains(rng, Char.code(c)),
|
|
2537
|
+
}
|
|
2520
2538
|
}
|
|
2521
2539
|
) next_m(buf, pos + 1, start, limit, end, state, stack) else None
|
|
2522
2540
|
}
|
|
@@ -2534,10 +2552,10 @@ let rangeTailMatcher = (rng: CharRange) =>
|
|
|
2534
2552
|
if (
|
|
2535
2553
|
{
|
|
2536
2554
|
pos < limit &&
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2555
|
+
match (matchBufChar(buf, pos)) {
|
|
2556
|
+
Err(_) => false,
|
|
2557
|
+
Ok(c) => rangeContains(rng, Char.code(c)),
|
|
2558
|
+
}
|
|
2541
2559
|
}
|
|
2542
2560
|
) Some(pos + 1) else None
|
|
2543
2561
|
}
|
|
@@ -2636,7 +2654,7 @@ let isWordChar = c => {
|
|
|
2636
2654
|
|
|
2637
2655
|
let isWordBoundary = (buf, pos, start, limit, end) => {
|
|
2638
2656
|
!((pos == start || !isWordChar(matchBufChar(buf, pos - 1))) ==
|
|
2639
|
-
|
|
2657
|
+
(pos == end || !isWordChar(matchBufChar(buf, pos))))
|
|
2640
2658
|
}
|
|
2641
2659
|
|
|
2642
2660
|
let wordBoundaryMatcher = next_m =>
|
|
@@ -3320,7 +3338,7 @@ record RegularExpression {
|
|
|
3320
3338
|
* @section Values: Functions for working with regular expressions.
|
|
3321
3339
|
*/
|
|
3322
3340
|
|
|
3323
|
-
//
|
|
3341
|
+
// TODO(#661): re-add the following pieces of documentation:
|
|
3324
3342
|
/*
|
|
3325
3343
|
[Under POSIX character classes]
|
|
3326
3344
|
|
|
@@ -3672,10 +3690,12 @@ let makeMatchResult = (origString, start, end, state) => {
|
|
|
3672
3690
|
// Helpers for user-facing match functionality
|
|
3673
3691
|
|
|
3674
3692
|
let fastDriveRegexIsMatch = (rx, string, startOffset, endOffset) => {
|
|
3675
|
-
let state =
|
|
3693
|
+
let state =
|
|
3694
|
+
if (rx.reReferences) Array.make(rx.reNumGroups, None)
|
|
3676
3695
|
else Array.make(0, None)
|
|
3677
|
-
let toWrap =
|
|
3678
|
-
|
|
3696
|
+
let toWrap =
|
|
3697
|
+
if (startOffset == 0 && endOffset == String.length(string)) string
|
|
3698
|
+
else String.slice(startOffset, endOffset, string)
|
|
3679
3699
|
let buf = makeMatchBuffer(toWrap)
|
|
3680
3700
|
Option.isSome(
|
|
3681
3701
|
searchMatch(rx, buf, 0, 0, Array.length(buf.matchInputExploded), state)
|
|
@@ -3687,8 +3707,9 @@ let rec fastDriveRegexMatchAll = (rx, string, startOffset, endOffset) => {
|
|
|
3687
3707
|
[]
|
|
3688
3708
|
} else {
|
|
3689
3709
|
let state = Array.make(rx.reNumGroups, None)
|
|
3690
|
-
let toWrap =
|
|
3691
|
-
|
|
3710
|
+
let toWrap =
|
|
3711
|
+
if (startOffset == 0 && endOffset == String.length(string)) string
|
|
3712
|
+
else String.slice(startOffset, endOffset, string)
|
|
3692
3713
|
let buf = makeMatchBuffer(toWrap)
|
|
3693
3714
|
match (searchMatch(
|
|
3694
3715
|
rx,
|
|
@@ -3726,8 +3747,9 @@ let rec fastDriveRegexMatchAll = (rx, string, startOffset, endOffset) => {
|
|
|
3726
3747
|
|
|
3727
3748
|
let fastDriveRegexMatch = (rx, string, startOffset, endOffset) => {
|
|
3728
3749
|
let state = Array.make(rx.reNumGroups, None)
|
|
3729
|
-
let toWrap =
|
|
3730
|
-
|
|
3750
|
+
let toWrap =
|
|
3751
|
+
if (startOffset == 0 && endOffset == String.length(string)) string
|
|
3752
|
+
else String.slice(startOffset, endOffset, string)
|
|
3731
3753
|
let buf = makeMatchBuffer(toWrap)
|
|
3732
3754
|
match (searchMatch(
|
|
3733
3755
|
rx,
|
|
@@ -3954,11 +3976,12 @@ let regexReplaceHelp =
|
|
|
3954
3976
|
let mut out = []
|
|
3955
3977
|
let rec loop = searchPos => {
|
|
3956
3978
|
let state = Array.make(rx.reNumGroups, None)
|
|
3979
|
+
let inStart = max(0, searchPos - rx.reMaxLookbehind)
|
|
3957
3980
|
let poss = searchMatch(
|
|
3958
3981
|
rx,
|
|
3959
3982
|
buf,
|
|
3960
3983
|
searchPos,
|
|
3961
|
-
|
|
3984
|
+
inStart,
|
|
3962
3985
|
Array.length(buf.matchInputExploded),
|
|
3963
3986
|
state
|
|
3964
3987
|
)
|
package/runtime/bigint.gr
CHANGED
|
@@ -1827,10 +1827,10 @@ let baseCaseDivRem = (a: WasmI32, b: WasmI32, result: WasmI32) => {
|
|
|
1827
1827
|
let n = getHalfSize(b)
|
|
1828
1828
|
let m = getHalfSize(a) - n
|
|
1829
1829
|
let qsize = (if (WasmI32.eqz(WasmI32.and(m + 1n, 1n))) {
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1830
|
+
m + 1n
|
|
1831
|
+
} else {
|
|
1832
|
+
m + 2n
|
|
1833
|
+
}) >>
|
|
1834
1834
|
1n
|
|
1835
1835
|
let mut q = init(qsize)
|
|
1836
1836
|
let mut a = 0n
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/* grainc-flags --no-pervasives */
|
|
2
|
+
|
|
3
|
+
import WasmI32, {
|
|
4
|
+
eq as (==),
|
|
5
|
+
ne as (!=),
|
|
6
|
+
and as (&),
|
|
7
|
+
xor as (^),
|
|
8
|
+
or as (|),
|
|
9
|
+
add as (+),
|
|
10
|
+
sub as (-),
|
|
11
|
+
mul as (*),
|
|
12
|
+
ltS as (<),
|
|
13
|
+
gtS as (>),
|
|
14
|
+
remS as (%),
|
|
15
|
+
shl as (<<),
|
|
16
|
+
shrU as (>>>),
|
|
17
|
+
} from "runtime/unsafe/wasmi32"
|
|
18
|
+
import WasmI64 from "runtime/unsafe/wasmi64"
|
|
19
|
+
import Memory from "runtime/unsafe/memory"
|
|
20
|
+
import Tags from "runtime/unsafe/tags"
|
|
21
|
+
import { tagSimpleNumber } from "runtime/dataStructures"
|
|
22
|
+
import { isNumber, cmp as numberCompare } from "runtime/numbers"
|
|
23
|
+
|
|
24
|
+
primitive (!): Bool -> Bool = "@not"
|
|
25
|
+
primitive (||): (Bool, Bool) -> Bool = "@or"
|
|
26
|
+
primitive (&&): (Bool, Bool) -> Bool = "@and"
|
|
27
|
+
|
|
28
|
+
@unsafe
|
|
29
|
+
let zero = WasmI32.fromGrain(0)
|
|
30
|
+
|
|
31
|
+
@unsafe
|
|
32
|
+
let rec heapCompareHelp = (heapTag, xptr, yptr) => {
|
|
33
|
+
match (heapTag) {
|
|
34
|
+
t when t == Tags._GRAIN_ADT_HEAP_TAG => {
|
|
35
|
+
// Check if the same constructor variant
|
|
36
|
+
let xvariant = WasmI32.load(xptr, 12n)
|
|
37
|
+
let yvariant = WasmI32.load(yptr, 12n)
|
|
38
|
+
if (xvariant != yvariant) {
|
|
39
|
+
tagSimpleNumber(xvariant - yvariant)
|
|
40
|
+
} else {
|
|
41
|
+
let xarity = WasmI32.load(xptr, 16n)
|
|
42
|
+
let yarity = WasmI32.load(yptr, 16n)
|
|
43
|
+
|
|
44
|
+
let mut result = 0
|
|
45
|
+
|
|
46
|
+
let bytes = xarity * 4n
|
|
47
|
+
for (let mut i = 0n; i < bytes; i += 4n) {
|
|
48
|
+
let sub = compareHelp(
|
|
49
|
+
WasmI32.load(xptr + i, 20n),
|
|
50
|
+
WasmI32.load(yptr + i, 20n)
|
|
51
|
+
)
|
|
52
|
+
if (WasmI32.fromGrain(sub) != zero) {
|
|
53
|
+
result = sub
|
|
54
|
+
break
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
result
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
t when t == Tags._GRAIN_RECORD_HEAP_TAG => {
|
|
62
|
+
let xlength = WasmI32.load(xptr, 12n)
|
|
63
|
+
let ylength = WasmI32.load(yptr, 12n)
|
|
64
|
+
|
|
65
|
+
let mut result = 0
|
|
66
|
+
|
|
67
|
+
let bytes = xlength * 4n
|
|
68
|
+
for (let mut i = 0n; i < bytes; i += 4n) {
|
|
69
|
+
let sub = compareHelp(
|
|
70
|
+
WasmI32.load(xptr + i, 16n),
|
|
71
|
+
WasmI32.load(yptr + i, 16n)
|
|
72
|
+
)
|
|
73
|
+
if (WasmI32.fromGrain(sub) != zero) {
|
|
74
|
+
result = sub
|
|
75
|
+
break
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
result
|
|
80
|
+
},
|
|
81
|
+
t when t == Tags._GRAIN_ARRAY_HEAP_TAG => {
|
|
82
|
+
let xlength = WasmI32.load(xptr, 4n)
|
|
83
|
+
let ylength = WasmI32.load(yptr, 4n)
|
|
84
|
+
|
|
85
|
+
// Check if the same length
|
|
86
|
+
if (xlength != ylength) {
|
|
87
|
+
tagSimpleNumber(xlength - ylength)
|
|
88
|
+
} else {
|
|
89
|
+
let mut result = 0
|
|
90
|
+
let bytes = xlength * 4n
|
|
91
|
+
for (let mut i = 0n; i < bytes; i += 4n) {
|
|
92
|
+
let sub = compareHelp(
|
|
93
|
+
WasmI32.load(xptr + i, 8n),
|
|
94
|
+
WasmI32.load(yptr + i, 8n)
|
|
95
|
+
)
|
|
96
|
+
if (WasmI32.fromGrain(sub) != zero) {
|
|
97
|
+
result = sub
|
|
98
|
+
break
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
result
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
t when (
|
|
106
|
+
t == Tags._GRAIN_STRING_HEAP_TAG || t == Tags._GRAIN_BYTES_HEAP_TAG
|
|
107
|
+
) => {
|
|
108
|
+
let xlength = WasmI32.load(xptr, 4n)
|
|
109
|
+
let ylength = WasmI32.load(yptr, 4n)
|
|
110
|
+
|
|
111
|
+
if (xlength == ylength) {
|
|
112
|
+
tagSimpleNumber(Memory.compare(xptr + 8n, yptr + 8n, xlength))
|
|
113
|
+
} else {
|
|
114
|
+
if (xlength < ylength) {
|
|
115
|
+
let sub = Memory.compare(xptr + 8n, yptr + 8n, xlength)
|
|
116
|
+
// The shorter one comes first
|
|
117
|
+
if (sub == 0n) -1 else tagSimpleNumber(sub)
|
|
118
|
+
} else {
|
|
119
|
+
let sub = Memory.compare(xptr + 8n, yptr + 8n, ylength)
|
|
120
|
+
// The shorter one comes first
|
|
121
|
+
if (sub == 0n) 1 else tagSimpleNumber(sub)
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
t when t == Tags._GRAIN_TUPLE_HEAP_TAG => {
|
|
126
|
+
let xsize = WasmI32.load(xptr, 4n)
|
|
127
|
+
let ysize = WasmI32.load(yptr, 4n)
|
|
128
|
+
|
|
129
|
+
let mut result = 0
|
|
130
|
+
let bytes = xsize * 4n
|
|
131
|
+
for (let mut i = 0n; i < bytes; i += 4n) {
|
|
132
|
+
let sub = compareHelp(
|
|
133
|
+
WasmI32.load(xptr + i, 8n),
|
|
134
|
+
WasmI32.load(yptr + i, 8n)
|
|
135
|
+
)
|
|
136
|
+
if (WasmI32.fromGrain(sub) != zero) {
|
|
137
|
+
result = sub
|
|
138
|
+
break
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
result
|
|
143
|
+
},
|
|
144
|
+
_ => {
|
|
145
|
+
// No other implementation
|
|
146
|
+
tagSimpleNumber(xptr - yptr)
|
|
147
|
+
},
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
compareHelp = (x, y) => {
|
|
151
|
+
let xtag = x & Tags._GRAIN_GENERIC_TAG_MASK
|
|
152
|
+
let ytag = y & Tags._GRAIN_GENERIC_TAG_MASK
|
|
153
|
+
if ((xtag & ytag) != Tags._GRAIN_GENERIC_HEAP_TAG_TYPE) {
|
|
154
|
+
// Short circuit for non-pointer values
|
|
155
|
+
if ((xtag & Tags._GRAIN_NUMBER_TAG_MASK) == Tags._GRAIN_NUMBER_TAG_TYPE) {
|
|
156
|
+
// Signed comparisons are necessary for numbers
|
|
157
|
+
if (x < y) -1 else if (x > y) 1 else 0
|
|
158
|
+
} else {
|
|
159
|
+
// Unsigned comparisons are necessary for other stack-allocated values
|
|
160
|
+
if (WasmI32.ltU(x, y)) -1 else if (WasmI32.gtU(x, y)) 1 else 0
|
|
161
|
+
}
|
|
162
|
+
} else if (isNumber(x)) {
|
|
163
|
+
// Numbers have special comparison rules, e.g. NaN == NaN
|
|
164
|
+
tagSimpleNumber(numberCompare(x, y, true))
|
|
165
|
+
} else {
|
|
166
|
+
// Handle all other heap allocated things
|
|
167
|
+
// Can short circuit if pointers are the same
|
|
168
|
+
if (x == y) {
|
|
169
|
+
0
|
|
170
|
+
} else {
|
|
171
|
+
heapCompareHelp(WasmI32.load(x, 0n), x, y)
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
@unsafe
|
|
177
|
+
export let compare = (x: a, y: a) => {
|
|
178
|
+
compareHelp(WasmI32.fromGrain(x), WasmI32.fromGrain(y))
|
|
179
|
+
}
|
package/runtime/equal.gr
CHANGED
|
@@ -14,13 +14,12 @@ import WasmI32, {
|
|
|
14
14
|
} from "runtime/unsafe/wasmi32"
|
|
15
15
|
import WasmI64 from "runtime/unsafe/wasmi64"
|
|
16
16
|
import Tags from "runtime/unsafe/tags"
|
|
17
|
+
import { isNumber, numberEqual } from "runtime/numbers"
|
|
17
18
|
|
|
18
19
|
primitive (!): Bool -> Bool = "@not"
|
|
19
20
|
primitive (||): (Bool, Bool) -> Bool = "@or"
|
|
20
21
|
primitive (&&): (Bool, Bool) -> Bool = "@and"
|
|
21
22
|
|
|
22
|
-
import { isNumber, numberEqual } from "runtime/numbers"
|
|
23
|
-
|
|
24
23
|
@unsafe
|
|
25
24
|
let cycleMarker = 0x80000000n
|
|
26
25
|
|
|
@@ -190,7 +189,8 @@ let rec heapEqualHelp = (heapTag, xptr, yptr) => {
|
|
|
190
189
|
xptr == yptr
|
|
191
190
|
},
|
|
192
191
|
}
|
|
193
|
-
},
|
|
192
|
+
},
|
|
193
|
+
equalHelp = (x, y) => {
|
|
194
194
|
if (
|
|
195
195
|
(x & Tags._GRAIN_GENERIC_TAG_MASK) != 0n &&
|
|
196
196
|
(y & Tags._GRAIN_GENERIC_TAG_MASK) != 0n
|
package/runtime/exception.gr
CHANGED
|
@@ -9,6 +9,8 @@ import foreign wasm fd_write: (
|
|
|
9
9
|
WasmI32,
|
|
10
10
|
) -> WasmI32 from "wasi_snapshot_preview1"
|
|
11
11
|
|
|
12
|
+
primitive unreachable: () -> a = "@unreachable"
|
|
13
|
+
|
|
12
14
|
enum Option<a> {
|
|
13
15
|
Some(a),
|
|
14
16
|
None,
|
|
@@ -79,8 +81,8 @@ let exceptionToString = (e: Exception) => {
|
|
|
79
81
|
// the runtime heap, but this is the only module that needs to do it
|
|
80
82
|
let iov = WasmI32.fromGrain([> 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n])
|
|
81
83
|
|
|
82
|
-
export let
|
|
83
|
-
let ptr = WasmI32.fromGrain(
|
|
84
|
+
export let panic = (msg: String) => {
|
|
85
|
+
let ptr = WasmI32.fromGrain(msg)
|
|
84
86
|
let written = iov + 32n
|
|
85
87
|
let lf = iov + 36n
|
|
86
88
|
WasmI32.store(iov, ptr + 8n, 0n)
|
|
@@ -89,7 +91,11 @@ export let printException = (e: Exception) => {
|
|
|
89
91
|
WasmI32.store(iov, lf, 8n)
|
|
90
92
|
WasmI32.store(iov, 1n, 12n)
|
|
91
93
|
fd_write(2n, iov, 2n, written)
|
|
92
|
-
|
|
94
|
+
unreachable()
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export let panicWithException = (e: Exception) => {
|
|
98
|
+
panic(exceptionToString(e))
|
|
93
99
|
}
|
|
94
100
|
|
|
95
101
|
export exception IndexOutOfBounds
|
|
@@ -109,7 +115,6 @@ export exception MatchFailure
|
|
|
109
115
|
*/
|
|
110
116
|
export exception AssertionError(String)
|
|
111
117
|
export exception InvalidArgument(String)
|
|
112
|
-
export exception OutOfMemory
|
|
113
118
|
|
|
114
119
|
let runtimeErrorPrinter = e => {
|
|
115
120
|
match (e) {
|
|
@@ -123,7 +128,6 @@ let runtimeErrorPrinter = e => {
|
|
|
123
128
|
Some("NumberNotRational: Can't coerce number to rational"),
|
|
124
129
|
MatchFailure => Some("MatchFailure: No matching pattern"),
|
|
125
130
|
AssertionError(s) => Some(s),
|
|
126
|
-
OutOfMemory => Some("OutOfMemory: Maximum memory size exceeded"),
|
|
127
131
|
InvalidArgument(msg) => Some(msg),
|
|
128
132
|
_ => None,
|
|
129
133
|
}
|
package/runtime/exception.md
CHANGED
|
@@ -22,9 +22,15 @@ dangerouslyRegisterBasePrinter : a -> Void
|
|
|
22
22
|
dangerouslyRegisterPrinter : a -> Void
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
### Exception.**
|
|
25
|
+
### Exception.**panic**
|
|
26
26
|
|
|
27
27
|
```grain
|
|
28
|
-
|
|
28
|
+
panic : String -> a
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Exception.**panicWithException**
|
|
32
|
+
|
|
33
|
+
```grain
|
|
34
|
+
panicWithException : Exception -> a
|
|
29
35
|
```
|
|
30
36
|
|