@grain/stdlib 0.5.2 → 0.5.3
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 +21 -0
- package/array.gr +56 -1
- package/array.md +83 -0
- package/bigint.md +30 -30
- package/buffer.gr +24 -22
- package/float32.md +3 -3
- package/float64.md +3 -3
- package/immutablepriorityqueue.gr +332 -0
- package/immutablepriorityqueue.md +248 -0
- package/list.gr +73 -0
- package/list.md +110 -0
- package/map.gr +1 -2
- package/marshal.gr +1058 -0
- package/marshal.md +76 -0
- package/number.gr +41 -0
- package/number.md +80 -5
- package/package.json +1 -1
- package/pervasives.gr +16 -5
- package/pervasives.md +28 -0
- package/priorityqueue.gr +241 -0
- package/priorityqueue.md +279 -0
- package/regex.gr +5 -5
- package/runtime/compare.gr +178 -0
- package/runtime/compare.md +6 -0
- package/runtime/equal.gr +1 -2
- package/runtime/numbers.gr +307 -68
- package/runtime/numbers.md +24 -0
- package/set.gr +1 -2
- package/string.gr +97 -15
- package/string.md +65 -1
- package/sys/file.gr +3 -3
- 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/runtime/numbers.gr
CHANGED
|
@@ -20,6 +20,7 @@ primitive (||): (Bool, Bool) -> Bool = "@or"
|
|
|
20
20
|
primitive throw: Exception -> a = "@throw"
|
|
21
21
|
|
|
22
22
|
exception UnknownNumberTag
|
|
23
|
+
exception InvariantViolation
|
|
23
24
|
|
|
24
25
|
import {
|
|
25
26
|
newRational,
|
|
@@ -84,6 +85,28 @@ export let isFloat = x => {
|
|
|
84
85
|
}
|
|
85
86
|
}
|
|
86
87
|
|
|
88
|
+
@unsafe
|
|
89
|
+
export let isInteger = x => {
|
|
90
|
+
if (isBoxedNumber(x)) {
|
|
91
|
+
let tag = WasmI32.load(x, 4n)
|
|
92
|
+
WasmI32.eq(tag, Tags._GRAIN_INT32_BOXED_NUM_TAG) ||
|
|
93
|
+
WasmI32.eq(tag, Tags._GRAIN_INT64_BOXED_NUM_TAG) ||
|
|
94
|
+
WasmI32.eq(tag, Tags._GRAIN_BIGINT_BOXED_NUM_TAG)
|
|
95
|
+
} else {
|
|
96
|
+
true
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
@unsafe
|
|
101
|
+
export let isRational = x => {
|
|
102
|
+
if (isBoxedNumber(x)) {
|
|
103
|
+
let tag = WasmI32.load(x, 4n)
|
|
104
|
+
WasmI32.eq(tag, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG)
|
|
105
|
+
} else {
|
|
106
|
+
false
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
87
110
|
@unsafe
|
|
88
111
|
let isBigInt = x => {
|
|
89
112
|
if (isBoxedNumber(x)) {
|
|
@@ -635,7 +658,7 @@ let numberEqualRationalHelp = (xptr, y) => {
|
|
|
635
658
|
BI.toFloat32(xNumerator),
|
|
636
659
|
BI.toFloat32(xDenominator)
|
|
637
660
|
)
|
|
638
|
-
// TODO
|
|
661
|
+
// TODO(#303): maybe we should have some sort of tolerance?
|
|
639
662
|
WasmF32.eq(xAsFloat, yBoxedVal)
|
|
640
663
|
},
|
|
641
664
|
t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
|
|
@@ -644,7 +667,7 @@ let numberEqualRationalHelp = (xptr, y) => {
|
|
|
644
667
|
BI.toFloat64(xNumerator),
|
|
645
668
|
BI.toFloat64(xDenominator)
|
|
646
669
|
)
|
|
647
|
-
// TODO
|
|
670
|
+
// TODO(#303): maybe we should have some sort of tolerance?
|
|
648
671
|
WasmF64.eq(xAsFloat, yBoxedVal)
|
|
649
672
|
},
|
|
650
673
|
_ => {
|
|
@@ -686,12 +709,12 @@ let numberEqualFloat64Help = (x, y) => {
|
|
|
686
709
|
},
|
|
687
710
|
t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
|
|
688
711
|
let yBoxedVal = boxedFloat32Number(y)
|
|
689
|
-
// TODO
|
|
712
|
+
// TODO(#303): maybe we should have some sort of tolerance?
|
|
690
713
|
WasmF64.eq(x, WasmF64.promoteF32(yBoxedVal))
|
|
691
714
|
},
|
|
692
715
|
t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
|
|
693
716
|
let yBoxedVal = boxedFloat64Number(y)
|
|
694
|
-
// TODO
|
|
717
|
+
// TODO(#303): maybe we should have some sort of tolerance?
|
|
695
718
|
WasmF64.eq(x, yBoxedVal)
|
|
696
719
|
},
|
|
697
720
|
_ => {
|
|
@@ -873,7 +896,6 @@ let numberAddSubSimpleHelp = (x, y, isSub) => {
|
|
|
873
896
|
let xval = WasmF32.convertI32S(xval)
|
|
874
897
|
let result = if (isSub) WasmF32.sub(xval, yBoxedVal)
|
|
875
898
|
else WasmF32.add(xval, yBoxedVal)
|
|
876
|
-
// TODO: (#304) is this safe?
|
|
877
899
|
newFloat32(result)
|
|
878
900
|
},
|
|
879
901
|
t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
|
|
@@ -971,7 +993,6 @@ let numberAddSubInt64Help = (xval, y, isSub) => {
|
|
|
971
993
|
let yBoxedVal = boxedFloat32Number(y)
|
|
972
994
|
let result = if (isSub) WasmF32.sub(xval, yBoxedVal)
|
|
973
995
|
else WasmF32.add(xval, yBoxedVal)
|
|
974
|
-
// TODO(#304): this isn't safe enough
|
|
975
996
|
newFloat32(result)
|
|
976
997
|
},
|
|
977
998
|
t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
|
|
@@ -1083,7 +1104,6 @@ let numberAddSubBigIntHelp = (x, y, isSub) => {
|
|
|
1083
1104
|
let yBoxedVal = boxedFloat32Number(y)
|
|
1084
1105
|
let result = if (isSub) WasmF32.sub(xval, yBoxedVal)
|
|
1085
1106
|
else WasmF32.add(xval, yBoxedVal)
|
|
1086
|
-
// TODO: (#304) this isn't safe enough
|
|
1087
1107
|
newFloat32(result)
|
|
1088
1108
|
},
|
|
1089
1109
|
t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
|
|
@@ -1326,7 +1346,6 @@ let numberTimesDivideInt64Help = (xval, y, isDivide) => {
|
|
|
1326
1346
|
t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
|
|
1327
1347
|
let xval = WasmF32.convertI64S(xval)
|
|
1328
1348
|
let yBoxedVal = boxedFloat32Number(y)
|
|
1329
|
-
// TODO: (#304) is this safe?
|
|
1330
1349
|
if (isDivide) {
|
|
1331
1350
|
newFloat32(WasmF32.div(xval, yBoxedVal))
|
|
1332
1351
|
} else {
|
|
@@ -1407,7 +1426,6 @@ let numberTimesDivideBigIntHelp = (x, y, isDivide) => {
|
|
|
1407
1426
|
// we can only fit rather small bigints (<4 limbs) into an F32
|
|
1408
1427
|
let xval = BI.toFloat64(x)
|
|
1409
1428
|
let yBoxedVal = WasmF64.promoteF32(boxedFloat32Number(y))
|
|
1410
|
-
// TODO: (#304) is this safe?
|
|
1411
1429
|
if (isDivide) {
|
|
1412
1430
|
newFloat64(WasmF64.div(xval, yBoxedVal))
|
|
1413
1431
|
} else {
|
|
@@ -1530,7 +1548,6 @@ let numberTimesDivideRationalHelp = (x, y, isDivide) => {
|
|
|
1530
1548
|
let yDenominator = boxedRationalDenominator(y)
|
|
1531
1549
|
// (a / b) * (c / d) == (a * c) / (b * d)
|
|
1532
1550
|
// (a / b) / (c / d) == (a * d) / (b * c)
|
|
1533
|
-
// TODO: (#304) this could maybe be written in a more overflow-proof way
|
|
1534
1551
|
let numerator = if (isDivide) BI.mul(xNumerator, yDenominator)
|
|
1535
1552
|
else BI.mul(xNumerator, yNumerator)
|
|
1536
1553
|
let denominator = if (isDivide) BI.mul(xDenominator, yNumerator)
|
|
@@ -1681,9 +1698,18 @@ let numberMod = (x, y) => {
|
|
|
1681
1698
|
}
|
|
1682
1699
|
|
|
1683
1700
|
/*
|
|
1684
|
-
* =====
|
|
1685
|
-
*
|
|
1686
|
-
*
|
|
1701
|
+
* ===== COMPARISONS =====
|
|
1702
|
+
* Int/int and float/float comparisons are always accurate.
|
|
1703
|
+
* Rational/rational comparisons are approximations with the exception of
|
|
1704
|
+
* equality, which is always accurate.
|
|
1705
|
+
*
|
|
1706
|
+
* Values compared to floats or rationals are first converted to floats.
|
|
1707
|
+
*
|
|
1708
|
+
* All comparison operators consider NaN not equal to, less than, or greater
|
|
1709
|
+
* than NaN, with the exception of `compare`, which considers NaN equal to
|
|
1710
|
+
* itself and otherwise smaller than any other float value. This provides a
|
|
1711
|
+
* total order (https://en.wikipedia.org/wiki/Total_order) over all numerical
|
|
1712
|
+
* values, making `compare` suitable for sorting or ordering.
|
|
1687
1713
|
*/
|
|
1688
1714
|
|
|
1689
1715
|
@unsafe
|
|
@@ -1721,81 +1747,286 @@ let cmpBigInt = (x: WasmI32, y: WasmI32) => {
|
|
|
1721
1747
|
}
|
|
1722
1748
|
}
|
|
1723
1749
|
|
|
1724
|
-
// TODO: (#305) is this safe? I think it's safe?
|
|
1725
1750
|
@unsafe
|
|
1726
|
-
|
|
1727
|
-
let
|
|
1728
|
-
|
|
1729
|
-
if (isBigInt(xw32)) {
|
|
1730
|
-
WasmI32.ltS(cmpBigInt(xw32, yw32), 0n)
|
|
1731
|
-
} else if (isBigInt(yw32)) {
|
|
1732
|
-
WasmI32.geS(cmpBigInt(yw32, xw32), 0n)
|
|
1751
|
+
let cmpFloat = (x: WasmI32, y: WasmI32, is64: Bool, totalOrdering: Bool) => {
|
|
1752
|
+
let xf = if (is64) {
|
|
1753
|
+
boxedFloat64Number(x)
|
|
1733
1754
|
} else {
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1755
|
+
WasmF64.promoteF32(boxedFloat32Number(x))
|
|
1756
|
+
}
|
|
1757
|
+
if (isSimpleNumber(y)) {
|
|
1758
|
+
let yf = WasmF64.convertI32S(untagSimple(y))
|
|
1759
|
+
// special NaN cases
|
|
1760
|
+
if (totalOrdering && WasmF64.ne(xf, xf)) {
|
|
1761
|
+
if (WasmF64.ne(yf, yf)) {
|
|
1762
|
+
0n
|
|
1763
|
+
} else {
|
|
1764
|
+
-1n
|
|
1765
|
+
}
|
|
1766
|
+
} else if (totalOrdering && WasmF64.ne(yf, yf)) {
|
|
1767
|
+
if (WasmF64.ne(xf, xf)) {
|
|
1768
|
+
0n
|
|
1769
|
+
} else {
|
|
1770
|
+
1n
|
|
1771
|
+
}
|
|
1772
|
+
} else {
|
|
1773
|
+
if (WasmF64.lt(xf, yf)) -1n else if (WasmF64.gt(xf, yf)) 1n else 0n
|
|
1774
|
+
}
|
|
1775
|
+
} else {
|
|
1776
|
+
let yBoxedNumberTag = boxedNumberTag(y)
|
|
1777
|
+
if (yBoxedNumberTag == Tags._GRAIN_BIGINT_BOXED_NUM_TAG) {
|
|
1778
|
+
WasmI32.sub(0n, cmpBigInt(y, x))
|
|
1779
|
+
} else {
|
|
1780
|
+
let yf = match (yBoxedNumberTag) {
|
|
1781
|
+
t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => {
|
|
1782
|
+
WasmF64.convertI32S(boxedInt32Number(y))
|
|
1783
|
+
},
|
|
1784
|
+
t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
|
|
1785
|
+
WasmF64.convertI64S(boxedInt64Number(y))
|
|
1786
|
+
},
|
|
1787
|
+
t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
|
|
1788
|
+
throw InvariantViolation
|
|
1789
|
+
},
|
|
1790
|
+
t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => {
|
|
1791
|
+
WasmF64.div(
|
|
1792
|
+
BI.toFloat64(boxedRationalNumerator(y)),
|
|
1793
|
+
BI.toFloat64(boxedRationalDenominator(y))
|
|
1794
|
+
)
|
|
1795
|
+
},
|
|
1796
|
+
t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
|
|
1797
|
+
WasmF64.promoteF32(boxedFloat32Number(y))
|
|
1798
|
+
},
|
|
1799
|
+
t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
|
|
1800
|
+
boxedFloat64Number(y)
|
|
1801
|
+
},
|
|
1802
|
+
_ => {
|
|
1803
|
+
throw UnknownNumberTag
|
|
1804
|
+
},
|
|
1805
|
+
}
|
|
1806
|
+
// special NaN cases
|
|
1807
|
+
if (totalOrdering && WasmF64.ne(xf, xf)) {
|
|
1808
|
+
if (WasmF64.ne(yf, yf)) {
|
|
1809
|
+
0n
|
|
1810
|
+
} else {
|
|
1811
|
+
-1n
|
|
1812
|
+
}
|
|
1813
|
+
} else if (totalOrdering && WasmF64.ne(yf, yf)) {
|
|
1814
|
+
if (WasmF64.ne(xf, xf)) {
|
|
1815
|
+
0n
|
|
1816
|
+
} else {
|
|
1817
|
+
1n
|
|
1818
|
+
}
|
|
1819
|
+
} else {
|
|
1820
|
+
if (WasmF64.lt(xf, yf)) -1n else if (WasmF64.gt(xf, yf)) 1n else 0n
|
|
1821
|
+
}
|
|
1822
|
+
}
|
|
1737
1823
|
}
|
|
1738
1824
|
}
|
|
1739
1825
|
|
|
1740
1826
|
@unsafe
|
|
1741
|
-
|
|
1742
|
-
let
|
|
1743
|
-
|
|
1744
|
-
if (isBigInt(xw32)) {
|
|
1745
|
-
WasmI32.gtS(cmpBigInt(xw32, yw32), 0n)
|
|
1746
|
-
} else if (isBigInt(yw32)) {
|
|
1747
|
-
WasmI32.leS(cmpBigInt(yw32, xw32), 0n)
|
|
1827
|
+
let cmpSmallInt = (x: WasmI32, y: WasmI32, is64: Bool, totalOrdering: Bool) => {
|
|
1828
|
+
let xi = if (is64) {
|
|
1829
|
+
boxedInt64Number(x)
|
|
1748
1830
|
} else {
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1831
|
+
WasmI64.extendI32S(boxedInt32Number(x))
|
|
1832
|
+
}
|
|
1833
|
+
if (isSimpleNumber(y)) {
|
|
1834
|
+
let yi = WasmI64.extendI32S(untagSimple(y))
|
|
1835
|
+
if (WasmI64.ltS(xi, yi)) -1n else if (WasmI64.gtS(xi, yi)) 1n else 0n
|
|
1836
|
+
} else {
|
|
1837
|
+
let yBoxedNumberTag = boxedNumberTag(y)
|
|
1838
|
+
match (yBoxedNumberTag) {
|
|
1839
|
+
t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => {
|
|
1840
|
+
let yi = WasmI64.extendI32S(boxedInt32Number(y))
|
|
1841
|
+
if (WasmI64.ltS(xi, yi)) -1n else if (WasmI64.gtS(xi, yi)) 1n else 0n
|
|
1842
|
+
},
|
|
1843
|
+
t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
|
|
1844
|
+
let yi = boxedInt64Number(y)
|
|
1845
|
+
if (WasmI64.ltS(xi, yi)) -1n else if (WasmI64.gtS(xi, yi)) 1n else 0n
|
|
1846
|
+
},
|
|
1847
|
+
t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
|
|
1848
|
+
WasmI32.sub(0n, cmpBigInt(y, x))
|
|
1849
|
+
},
|
|
1850
|
+
t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => {
|
|
1851
|
+
// Rationals and ints are never considered equal
|
|
1852
|
+
if (
|
|
1853
|
+
WasmF64.lt(
|
|
1854
|
+
WasmF64.convertI64S(xi),
|
|
1855
|
+
WasmF64.div(
|
|
1856
|
+
BI.toFloat64(boxedRationalNumerator(y)),
|
|
1857
|
+
BI.toFloat64(boxedRationalDenominator(y))
|
|
1858
|
+
)
|
|
1859
|
+
)
|
|
1860
|
+
) -1n else 1n
|
|
1861
|
+
},
|
|
1862
|
+
t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
|
|
1863
|
+
WasmI32.sub(0n, cmpFloat(y, x, false, totalOrdering))
|
|
1864
|
+
},
|
|
1865
|
+
t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
|
|
1866
|
+
WasmI32.sub(0n, cmpFloat(y, x, true, totalOrdering))
|
|
1867
|
+
},
|
|
1868
|
+
_ => {
|
|
1869
|
+
throw UnknownNumberTag
|
|
1870
|
+
},
|
|
1871
|
+
}
|
|
1752
1872
|
}
|
|
1753
1873
|
}
|
|
1754
1874
|
|
|
1755
1875
|
@unsafe
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1876
|
+
let cmpRational = (x: WasmI32, y: WasmI32, totalOrdering: Bool) => {
|
|
1877
|
+
if (isSimpleNumber(y)) {
|
|
1878
|
+
let xf = WasmF64.div(
|
|
1879
|
+
BI.toFloat64(boxedRationalNumerator(x)),
|
|
1880
|
+
BI.toFloat64(boxedRationalDenominator(x))
|
|
1881
|
+
)
|
|
1882
|
+
// Rationals and ints are never considered equal
|
|
1883
|
+
if (WasmF64.lt(xf, WasmF64.convertI32S(untagSimple(y)))) -1n else 1n
|
|
1763
1884
|
} else {
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1885
|
+
let yBoxedNumberTag = boxedNumberTag(y)
|
|
1886
|
+
match (yBoxedNumberTag) {
|
|
1887
|
+
t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => {
|
|
1888
|
+
WasmI32.sub(0n, cmpSmallInt(y, x, false, totalOrdering))
|
|
1889
|
+
},
|
|
1890
|
+
t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
|
|
1891
|
+
WasmI32.sub(0n, cmpSmallInt(y, x, true, totalOrdering))
|
|
1892
|
+
},
|
|
1893
|
+
t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
|
|
1894
|
+
WasmI32.sub(0n, cmpBigInt(y, x))
|
|
1895
|
+
},
|
|
1896
|
+
t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => {
|
|
1897
|
+
// Comparing rationals efficiently is an open problem
|
|
1898
|
+
// Producing a definitive answer is quite expensive, so if the two
|
|
1899
|
+
// values are not strictly equal we approximate an answer
|
|
1900
|
+
|
|
1901
|
+
let xNumerator = boxedRationalNumerator(x)
|
|
1902
|
+
let xDenominator = boxedRationalDenominator(x)
|
|
1903
|
+
let yNumerator = boxedRationalNumerator(y)
|
|
1904
|
+
let yDenominator = boxedRationalDenominator(y)
|
|
1905
|
+
|
|
1906
|
+
if (
|
|
1907
|
+
BI.cmp(xNumerator, yNumerator) == 0n &&
|
|
1908
|
+
BI.cmp(xDenominator, yDenominator) == 0n
|
|
1909
|
+
) {
|
|
1910
|
+
0n
|
|
1911
|
+
} else {
|
|
1912
|
+
let xf = WasmF64.div(
|
|
1913
|
+
BI.toFloat64(xNumerator),
|
|
1914
|
+
BI.toFloat64(xDenominator)
|
|
1915
|
+
)
|
|
1916
|
+
let yf = WasmF64.div(
|
|
1917
|
+
BI.toFloat64(yNumerator),
|
|
1918
|
+
BI.toFloat64(yDenominator)
|
|
1919
|
+
)
|
|
1920
|
+
if (WasmF64.lt(xf, yf)) -1n else 1n
|
|
1921
|
+
}
|
|
1922
|
+
},
|
|
1923
|
+
t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
|
|
1924
|
+
WasmI32.sub(0n, cmpFloat(y, x, false, totalOrdering))
|
|
1925
|
+
},
|
|
1926
|
+
t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
|
|
1927
|
+
WasmI32.sub(0n, cmpFloat(y, x, true, totalOrdering))
|
|
1928
|
+
},
|
|
1929
|
+
_ => {
|
|
1930
|
+
throw UnknownNumberTag
|
|
1931
|
+
},
|
|
1773
1932
|
}
|
|
1774
1933
|
}
|
|
1775
1934
|
}
|
|
1776
1935
|
|
|
1777
1936
|
@unsafe
|
|
1778
|
-
export let
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
WasmI32.leS(cmpBigInt(xw32, yw32), 0n)
|
|
1783
|
-
} else if (isBigInt(yw32)) {
|
|
1784
|
-
WasmI32.geS(cmpBigInt(yw32, xw32), 0n)
|
|
1785
|
-
} else {
|
|
1786
|
-
// Equality is finicky, so delegate
|
|
1787
|
-
let xval = coerceNumberToWasmF64(x)
|
|
1788
|
-
let yval = coerceNumberToWasmF64(y)
|
|
1789
|
-
if (WasmF64.gt(xval, yval)) {
|
|
1790
|
-
true
|
|
1937
|
+
export let cmp = (x: WasmI32, y: WasmI32, totalOrdering: Bool) => {
|
|
1938
|
+
if (isSimpleNumber(x)) {
|
|
1939
|
+
if (isSimpleNumber(y)) {
|
|
1940
|
+
if (WasmI32.ltS(x, y)) -1n else if (WasmI32.gtS(x, y)) 1n else 0n
|
|
1791
1941
|
} else {
|
|
1792
|
-
let
|
|
1793
|
-
|
|
1794
|
-
|
|
1942
|
+
let yBoxedNumberTag = boxedNumberTag(y)
|
|
1943
|
+
match (yBoxedNumberTag) {
|
|
1944
|
+
t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => {
|
|
1945
|
+
WasmI32.sub(0n, cmpSmallInt(y, x, false, totalOrdering))
|
|
1946
|
+
},
|
|
1947
|
+
t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
|
|
1948
|
+
WasmI32.sub(0n, cmpSmallInt(y, x, true, totalOrdering))
|
|
1949
|
+
},
|
|
1950
|
+
t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
|
|
1951
|
+
WasmI32.sub(0n, cmpBigInt(y, x))
|
|
1952
|
+
},
|
|
1953
|
+
t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => {
|
|
1954
|
+
WasmI32.sub(0n, cmpRational(y, x, totalOrdering))
|
|
1955
|
+
},
|
|
1956
|
+
t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
|
|
1957
|
+
WasmI32.sub(0n, cmpFloat(y, x, false, totalOrdering))
|
|
1958
|
+
},
|
|
1959
|
+
t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
|
|
1960
|
+
WasmI32.sub(0n, cmpFloat(y, x, true, totalOrdering))
|
|
1961
|
+
},
|
|
1962
|
+
_ => {
|
|
1963
|
+
throw UnknownNumberTag
|
|
1964
|
+
},
|
|
1965
|
+
}
|
|
1966
|
+
}
|
|
1967
|
+
} else {
|
|
1968
|
+
let xBoxedNumberTag = boxedNumberTag(x)
|
|
1969
|
+
match (xBoxedNumberTag) {
|
|
1970
|
+
t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => {
|
|
1971
|
+
cmpSmallInt(x, y, false, totalOrdering)
|
|
1972
|
+
},
|
|
1973
|
+
t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
|
|
1974
|
+
cmpSmallInt(x, y, true, totalOrdering)
|
|
1975
|
+
},
|
|
1976
|
+
t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
|
|
1977
|
+
cmpBigInt(x, y)
|
|
1978
|
+
},
|
|
1979
|
+
t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => {
|
|
1980
|
+
cmpRational(x, y, totalOrdering)
|
|
1981
|
+
},
|
|
1982
|
+
t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
|
|
1983
|
+
cmpFloat(x, y, false, totalOrdering)
|
|
1984
|
+
},
|
|
1985
|
+
t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
|
|
1986
|
+
cmpFloat(x, y, true, totalOrdering)
|
|
1987
|
+
},
|
|
1988
|
+
_ => {
|
|
1989
|
+
throw UnknownNumberTag
|
|
1990
|
+
},
|
|
1795
1991
|
}
|
|
1796
1992
|
}
|
|
1797
1993
|
}
|
|
1798
1994
|
|
|
1995
|
+
@unsafe
|
|
1996
|
+
export let (<) = (x: Number, y: Number) => {
|
|
1997
|
+
let x = WasmI32.fromGrain(x)
|
|
1998
|
+
let y = WasmI32.fromGrain(y)
|
|
1999
|
+
WasmI32.ltS(cmp(x, y, false), 0n)
|
|
2000
|
+
}
|
|
2001
|
+
|
|
2002
|
+
@unsafe
|
|
2003
|
+
export let (>) = (x: Number, y: Number) => {
|
|
2004
|
+
let x = WasmI32.fromGrain(x)
|
|
2005
|
+
let y = WasmI32.fromGrain(y)
|
|
2006
|
+
WasmI32.gtS(cmp(x, y, false), 0n)
|
|
2007
|
+
}
|
|
2008
|
+
|
|
2009
|
+
@unsafe
|
|
2010
|
+
export let (<=) = (x: Number, y: Number) => {
|
|
2011
|
+
let x = WasmI32.fromGrain(x)
|
|
2012
|
+
let y = WasmI32.fromGrain(y)
|
|
2013
|
+
WasmI32.leS(cmp(x, y, false), 0n)
|
|
2014
|
+
}
|
|
2015
|
+
|
|
2016
|
+
@unsafe
|
|
2017
|
+
export let (>=) = (x: Number, y: Number) => {
|
|
2018
|
+
let x = WasmI32.fromGrain(x)
|
|
2019
|
+
let y = WasmI32.fromGrain(y)
|
|
2020
|
+
WasmI32.geS(cmp(x, y, false), 0n)
|
|
2021
|
+
}
|
|
2022
|
+
|
|
2023
|
+
@unsafe
|
|
2024
|
+
export let compare = (x: Number, y: Number) => {
|
|
2025
|
+
let x = WasmI32.fromGrain(x)
|
|
2026
|
+
let y = WasmI32.fromGrain(y)
|
|
2027
|
+
WasmI32.toGrain(tagSimple(cmp(x, y, true))): Number
|
|
2028
|
+
}
|
|
2029
|
+
|
|
1799
2030
|
/*
|
|
1800
2031
|
* ===== EQUAL =====
|
|
1801
2032
|
*/
|
|
@@ -1811,7 +2042,7 @@ export let numberEq = (x: Number, y: Number) => {
|
|
|
1811
2042
|
* ===== LOGICAL OPERATIONS =====
|
|
1812
2043
|
* Only valid for int-like numbers. Coerce to i64/bigInt and do operations
|
|
1813
2044
|
*/
|
|
1814
|
-
// TODO
|
|
2045
|
+
// TODO(#306): Semantics around when things should stay i32/i64
|
|
1815
2046
|
|
|
1816
2047
|
@unsafe
|
|
1817
2048
|
export let lnot = (x: Number) => {
|
|
@@ -1833,7 +2064,15 @@ export let (<<) = (x: Number, y: Number) => {
|
|
|
1833
2064
|
} else {
|
|
1834
2065
|
let xval = coerceNumberToWasmI64(x)
|
|
1835
2066
|
let yval = coerceNumberToWasmI64(y)
|
|
1836
|
-
|
|
2067
|
+
// if the number will be shifted beyond the end of the i64 range, promote to BigInt
|
|
2068
|
+
// (note that we subtract one leading zero, since the leading bit is the sign bit)
|
|
2069
|
+
if (WasmI64.leU(WasmI64.sub(WasmI64.clz(i64abs(xval)), 1N), yval)) {
|
|
2070
|
+
let xbi = coerceNumberToBigInt(x)
|
|
2071
|
+
let yval = coerceNumberToWasmI32(y)
|
|
2072
|
+
WasmI32.toGrain(reducedBigInteger(BI.shl(xbi, yval))): Number
|
|
2073
|
+
} else {
|
|
2074
|
+
WasmI32.toGrain(reducedInteger(WasmI64.shl(xval, yval))): Number
|
|
2075
|
+
}
|
|
1837
2076
|
}
|
|
1838
2077
|
}
|
|
1839
2078
|
|
package/runtime/numbers.md
CHANGED
|
@@ -10,6 +10,18 @@ isBoxedNumber : WasmI32 -> Bool
|
|
|
10
10
|
isFloat : WasmI32 -> Bool
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
+
### Numbers.**isInteger**
|
|
14
|
+
|
|
15
|
+
```grain
|
|
16
|
+
isInteger : WasmI32 -> Bool
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### Numbers.**isRational**
|
|
20
|
+
|
|
21
|
+
```grain
|
|
22
|
+
isRational : WasmI32 -> Bool
|
|
23
|
+
```
|
|
24
|
+
|
|
13
25
|
### Numbers.**isNumber**
|
|
14
26
|
|
|
15
27
|
```grain
|
|
@@ -94,6 +106,12 @@ coerceNumberToWasmI32 : Number -> WasmI32
|
|
|
94
106
|
numberEqual : (WasmI32, WasmI32) -> Bool
|
|
95
107
|
```
|
|
96
108
|
|
|
109
|
+
### Numbers.**cmp**
|
|
110
|
+
|
|
111
|
+
```grain
|
|
112
|
+
cmp : (WasmI32, WasmI32, Bool) -> WasmI32
|
|
113
|
+
```
|
|
114
|
+
|
|
97
115
|
### Numbers.**(<)**
|
|
98
116
|
|
|
99
117
|
```grain
|
|
@@ -118,6 +136,12 @@ numberEqual : (WasmI32, WasmI32) -> Bool
|
|
|
118
136
|
(>=) : (Number, Number) -> Bool
|
|
119
137
|
```
|
|
120
138
|
|
|
139
|
+
### Numbers.**compare**
|
|
140
|
+
|
|
141
|
+
```grain
|
|
142
|
+
compare : (Number, Number) -> Number
|
|
143
|
+
```
|
|
144
|
+
|
|
121
145
|
### Numbers.**numberEq**
|
|
122
146
|
|
|
123
147
|
```grain
|
package/set.gr
CHANGED
|
@@ -454,8 +454,7 @@ export let intersect = (set1, set2) => {
|
|
|
454
454
|
set
|
|
455
455
|
}
|
|
456
456
|
|
|
457
|
-
// TODO: Should return a Record type instead of a Tuple
|
|
458
|
-
// Waiting on https://github.com/grain-lang/grain/issues/190
|
|
457
|
+
// TODO(#190): Should return a Record type instead of a Tuple
|
|
459
458
|
/**
|
|
460
459
|
* Provides data representing the internal state state of the set.
|
|
461
460
|
*
|