@grain/stdlib 0.5.7 → 0.5.9
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 +20 -0
- package/array.gr +0 -2
- package/immutablearray.gr +929 -0
- package/immutablearray.md +1038 -0
- package/number.gr +3 -21
- package/number.md +1 -2
- package/package.json +1 -1
- package/runtime/compare.gr +1 -1
- package/runtime/debugPrint.gr +51 -0
- package/runtime/debugPrint.md +30 -0
- package/runtime/numbers.gr +64 -30
- package/runtime/numbers.md +7 -1
- package/stack.gr +13 -0
- package/stack.md +42 -0
- package/runtime/unsafe/printWasm.gr +0 -41
- package/runtime/unsafe/printWasm.md +0 -24
package/number.gr
CHANGED
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
isInteger,
|
|
17
17
|
isRational,
|
|
18
18
|
isBoxedNumber,
|
|
19
|
+
isNaN,
|
|
19
20
|
scalbn,
|
|
20
21
|
} from "runtime/numbers"
|
|
21
22
|
import Atoi from "runtime/atoi/parse"
|
|
@@ -814,8 +815,7 @@ export let isFinite = (x: Number) => {
|
|
|
814
815
|
}
|
|
815
816
|
|
|
816
817
|
/**
|
|
817
|
-
* Checks if a number
|
|
818
|
-
* Only boxed floating point numbers can contain NaN.
|
|
818
|
+
* Checks if a number is the float NaN value (Not A Number).
|
|
819
819
|
*
|
|
820
820
|
* @param x: The number to check
|
|
821
821
|
* @returns `true` if the value is NaN, otherwise `false`
|
|
@@ -825,25 +825,7 @@ export let isFinite = (x: Number) => {
|
|
|
825
825
|
@unsafe
|
|
826
826
|
export let isNaN = (x: Number) => {
|
|
827
827
|
let asPtr = WasmI32.fromGrain(x)
|
|
828
|
-
|
|
829
|
-
// Boxed numbers can have multiple subtypes, of which float32 and float64 can be NaN.
|
|
830
|
-
let tag = WasmI32.load(asPtr, 4n)
|
|
831
|
-
if (WasmI32.eq(tag, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG)) {
|
|
832
|
-
// uses the fact that NaN is the only number not equal to itself
|
|
833
|
-
let wf64 = WasmF64.load(asPtr, 8n)
|
|
834
|
-
WasmF64.ne(wf64, wf64)
|
|
835
|
-
} else if (WasmI32.eq(tag, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG)) {
|
|
836
|
-
let wf32 = WasmF32.load(asPtr, 8n)
|
|
837
|
-
WasmF32.ne(wf32, wf32)
|
|
838
|
-
} else {
|
|
839
|
-
// Neither rational numbers nor boxed integers can be infinite or NaN.
|
|
840
|
-
// Grain doesn't allow creating a rational with denominator of zero either.
|
|
841
|
-
false
|
|
842
|
-
}
|
|
843
|
-
} else {
|
|
844
|
-
// Simple numbers are integers and cannot be NaN.
|
|
845
|
-
false
|
|
846
|
-
}
|
|
828
|
+
isNaN(asPtr)
|
|
847
829
|
}
|
|
848
830
|
|
|
849
831
|
/**
|
package/number.md
CHANGED
|
@@ -656,8 +656,7 @@ No other changes yet.
|
|
|
656
656
|
isNaN : Number -> Bool
|
|
657
657
|
```
|
|
658
658
|
|
|
659
|
-
Checks if a number
|
|
660
|
-
Only boxed floating point numbers can contain NaN.
|
|
659
|
+
Checks if a number is the float NaN value (Not A Number).
|
|
661
660
|
|
|
662
661
|
Parameters:
|
|
663
662
|
|
package/package.json
CHANGED
package/runtime/compare.gr
CHANGED
|
@@ -161,7 +161,7 @@ compareHelp = (x, y) => {
|
|
|
161
161
|
}
|
|
162
162
|
} else if (isNumber(x)) {
|
|
163
163
|
// Numbers have special comparison rules, e.g. NaN == NaN
|
|
164
|
-
tagSimpleNumber(numberCompare(x, y
|
|
164
|
+
tagSimpleNumber(numberCompare(x, y))
|
|
165
165
|
} else {
|
|
166
166
|
// Handle all other heap allocated things
|
|
167
167
|
// Can short circuit if pointers are the same
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import Utils from "runtime/numberUtils"
|
|
2
|
+
import WasmI32, { add as (+) } from "runtime/unsafe/wasmi32"
|
|
3
|
+
import WasmF64 from "runtime/unsafe/wasmf64"
|
|
4
|
+
import Memory from "runtime/unsafe/memory"
|
|
5
|
+
|
|
6
|
+
import foreign wasm fd_write: (
|
|
7
|
+
WasmI32,
|
|
8
|
+
WasmI32,
|
|
9
|
+
WasmI32,
|
|
10
|
+
WasmI32,
|
|
11
|
+
) -> WasmI32 from "wasi_snapshot_preview1"
|
|
12
|
+
|
|
13
|
+
@unsafe
|
|
14
|
+
export let print = (s: String) => {
|
|
15
|
+
let ptr = WasmI32.fromGrain(s)
|
|
16
|
+
// iov: [<ptr to string> <nbytes of string> <ptr to newline> <nbytes of newline>] (32 bytes)
|
|
17
|
+
// buf: <iov> <written> <newline char>
|
|
18
|
+
// fd_write(STDOUT (1), iov, len(iov), written)
|
|
19
|
+
let buf = Memory.malloc(37n)
|
|
20
|
+
let iov = buf
|
|
21
|
+
let written = buf + 32n
|
|
22
|
+
let lf = buf + 36n
|
|
23
|
+
WasmI32.store(iov, ptr + 8n, 0n)
|
|
24
|
+
WasmI32.store(iov, WasmI32.load(ptr, 4n), 4n)
|
|
25
|
+
WasmI32.store8(lf, 10n, 0n)
|
|
26
|
+
WasmI32.store(iov, lf, 8n)
|
|
27
|
+
WasmI32.store(iov, 1n, 12n)
|
|
28
|
+
fd_write(1n, iov, 2n, written)
|
|
29
|
+
Memory.free(buf)
|
|
30
|
+
void
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@unsafe
|
|
34
|
+
export let printI32 = val => {
|
|
35
|
+
print(Utils.itoa32(val, 10n))
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
@unsafe
|
|
39
|
+
export let printI64 = val => {
|
|
40
|
+
print(Utils.itoa64(val, 10n))
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
@unsafe
|
|
44
|
+
export let printF32 = val => {
|
|
45
|
+
print(Utils.dtoa(WasmF64.promoteF32(val)))
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
@unsafe
|
|
49
|
+
export let printF64 = val => {
|
|
50
|
+
print(Utils.dtoa(val))
|
|
51
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
### DebugPrint.**print**
|
|
2
|
+
|
|
3
|
+
```grain
|
|
4
|
+
print : String -> Void
|
|
5
|
+
```
|
|
6
|
+
|
|
7
|
+
### DebugPrint.**printI32**
|
|
8
|
+
|
|
9
|
+
```grain
|
|
10
|
+
printI32 : WasmI32 -> Void
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
### DebugPrint.**printI64**
|
|
14
|
+
|
|
15
|
+
```grain
|
|
16
|
+
printI64 : WasmI64 -> Void
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### DebugPrint.**printF32**
|
|
20
|
+
|
|
21
|
+
```grain
|
|
22
|
+
printF32 : WasmF32 -> Void
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### DebugPrint.**printF64**
|
|
26
|
+
|
|
27
|
+
```grain
|
|
28
|
+
printF64 : WasmF64 -> Void
|
|
29
|
+
```
|
|
30
|
+
|
package/runtime/numbers.gr
CHANGED
|
@@ -107,6 +107,29 @@ export let isRational = x => {
|
|
|
107
107
|
}
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
+
@unsafe
|
|
111
|
+
export let isNaN = x => {
|
|
112
|
+
if (isBoxedNumber(x)) {
|
|
113
|
+
// Boxed numbers can have multiple subtypes, of which float32 and float64 can be NaN.
|
|
114
|
+
let tag = WasmI32.load(x, 4n)
|
|
115
|
+
if (WasmI32.eq(tag, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG)) {
|
|
116
|
+
// uses the fact that NaN is the only number not equal to itself
|
|
117
|
+
let wf64 = WasmF64.load(x, 8n)
|
|
118
|
+
WasmF64.ne(wf64, wf64)
|
|
119
|
+
} else if (WasmI32.eq(tag, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG)) {
|
|
120
|
+
let wf32 = WasmF32.load(x, 8n)
|
|
121
|
+
WasmF32.ne(wf32, wf32)
|
|
122
|
+
} else {
|
|
123
|
+
// Neither rational numbers nor boxed integers can be infinite or NaN.
|
|
124
|
+
// Grain doesn't allow creating a rational with denominator of zero either.
|
|
125
|
+
false
|
|
126
|
+
}
|
|
127
|
+
} else {
|
|
128
|
+
// Simple numbers are integers and cannot be NaN.
|
|
129
|
+
false
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
110
133
|
@unsafe
|
|
111
134
|
let isBigInt = x => {
|
|
112
135
|
if (isBoxedNumber(x)) {
|
|
@@ -1777,8 +1800,11 @@ let cmpBigInt = (x: WasmI32, y: WasmI32) => {
|
|
|
1777
1800
|
}
|
|
1778
1801
|
}
|
|
1779
1802
|
|
|
1803
|
+
// cmpFloat applies a total ordering relation:
|
|
1804
|
+
// unlike regular float logic, NaN is considered equal to itself and
|
|
1805
|
+
// smaller than any other number
|
|
1780
1806
|
@unsafe
|
|
1781
|
-
let cmpFloat = (x: WasmI32, y: WasmI32, is64: Bool
|
|
1807
|
+
let cmpFloat = (x: WasmI32, y: WasmI32, is64: Bool) => {
|
|
1782
1808
|
let xf = if (is64) {
|
|
1783
1809
|
boxedFloat64Number(x)
|
|
1784
1810
|
} else {
|
|
@@ -1787,13 +1813,13 @@ let cmpFloat = (x: WasmI32, y: WasmI32, is64: Bool, totalOrdering: Bool) => {
|
|
|
1787
1813
|
if (isSimpleNumber(y)) {
|
|
1788
1814
|
let yf = WasmF64.convertI32S(untagSimple(y))
|
|
1789
1815
|
// special NaN cases
|
|
1790
|
-
if (
|
|
1816
|
+
if (WasmF64.ne(xf, xf)) {
|
|
1791
1817
|
if (WasmF64.ne(yf, yf)) {
|
|
1792
1818
|
0n
|
|
1793
1819
|
} else {
|
|
1794
1820
|
-1n
|
|
1795
1821
|
}
|
|
1796
|
-
} else if (
|
|
1822
|
+
} else if (WasmF64.ne(yf, yf)) {
|
|
1797
1823
|
if (WasmF64.ne(xf, xf)) {
|
|
1798
1824
|
0n
|
|
1799
1825
|
} else {
|
|
@@ -1834,13 +1860,13 @@ let cmpFloat = (x: WasmI32, y: WasmI32, is64: Bool, totalOrdering: Bool) => {
|
|
|
1834
1860
|
},
|
|
1835
1861
|
}
|
|
1836
1862
|
// special NaN cases
|
|
1837
|
-
if (
|
|
1863
|
+
if (WasmF64.ne(xf, xf)) {
|
|
1838
1864
|
if (WasmF64.ne(yf, yf)) {
|
|
1839
1865
|
0n
|
|
1840
1866
|
} else {
|
|
1841
1867
|
-1n
|
|
1842
1868
|
}
|
|
1843
|
-
} else if (
|
|
1869
|
+
} else if (WasmF64.ne(yf, yf)) {
|
|
1844
1870
|
if (WasmF64.ne(xf, xf)) {
|
|
1845
1871
|
0n
|
|
1846
1872
|
} else {
|
|
@@ -1854,7 +1880,7 @@ let cmpFloat = (x: WasmI32, y: WasmI32, is64: Bool, totalOrdering: Bool) => {
|
|
|
1854
1880
|
}
|
|
1855
1881
|
|
|
1856
1882
|
@unsafe
|
|
1857
|
-
let cmpSmallInt = (x: WasmI32, y: WasmI32, is64: Bool
|
|
1883
|
+
let cmpSmallInt = (x: WasmI32, y: WasmI32, is64: Bool) => {
|
|
1858
1884
|
let xi = if (is64) {
|
|
1859
1885
|
boxedInt64Number(x)
|
|
1860
1886
|
} else {
|
|
@@ -1890,10 +1916,10 @@ let cmpSmallInt = (x: WasmI32, y: WasmI32, is64: Bool, totalOrdering: Bool) => {
|
|
|
1890
1916
|
) -1n else 1n
|
|
1891
1917
|
},
|
|
1892
1918
|
t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
|
|
1893
|
-
WasmI32.sub(0n, cmpFloat(y, x, false
|
|
1919
|
+
WasmI32.sub(0n, cmpFloat(y, x, false))
|
|
1894
1920
|
},
|
|
1895
1921
|
t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
|
|
1896
|
-
WasmI32.sub(0n, cmpFloat(y, x, true
|
|
1922
|
+
WasmI32.sub(0n, cmpFloat(y, x, true))
|
|
1897
1923
|
},
|
|
1898
1924
|
_ => {
|
|
1899
1925
|
throw UnknownNumberTag
|
|
@@ -1903,7 +1929,7 @@ let cmpSmallInt = (x: WasmI32, y: WasmI32, is64: Bool, totalOrdering: Bool) => {
|
|
|
1903
1929
|
}
|
|
1904
1930
|
|
|
1905
1931
|
@unsafe
|
|
1906
|
-
let cmpRational = (x: WasmI32, y: WasmI32
|
|
1932
|
+
let cmpRational = (x: WasmI32, y: WasmI32) => {
|
|
1907
1933
|
if (isSimpleNumber(y)) {
|
|
1908
1934
|
let xf = WasmF64.div(
|
|
1909
1935
|
BI.toFloat64(boxedRationalNumerator(x)),
|
|
@@ -1915,10 +1941,10 @@ let cmpRational = (x: WasmI32, y: WasmI32, totalOrdering: Bool) => {
|
|
|
1915
1941
|
let yBoxedNumberTag = boxedNumberTag(y)
|
|
1916
1942
|
match (yBoxedNumberTag) {
|
|
1917
1943
|
t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => {
|
|
1918
|
-
WasmI32.sub(0n, cmpSmallInt(y, x, false
|
|
1944
|
+
WasmI32.sub(0n, cmpSmallInt(y, x, false))
|
|
1919
1945
|
},
|
|
1920
1946
|
t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
|
|
1921
|
-
WasmI32.sub(0n, cmpSmallInt(y, x, true
|
|
1947
|
+
WasmI32.sub(0n, cmpSmallInt(y, x, true))
|
|
1922
1948
|
},
|
|
1923
1949
|
t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
|
|
1924
1950
|
WasmI32.sub(0n, cmpBigInt(y, x))
|
|
@@ -1951,10 +1977,10 @@ let cmpRational = (x: WasmI32, y: WasmI32, totalOrdering: Bool) => {
|
|
|
1951
1977
|
}
|
|
1952
1978
|
},
|
|
1953
1979
|
t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
|
|
1954
|
-
WasmI32.sub(0n, cmpFloat(y, x, false
|
|
1980
|
+
WasmI32.sub(0n, cmpFloat(y, x, false))
|
|
1955
1981
|
},
|
|
1956
1982
|
t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
|
|
1957
|
-
WasmI32.sub(0n, cmpFloat(y, x, true
|
|
1983
|
+
WasmI32.sub(0n, cmpFloat(y, x, true))
|
|
1958
1984
|
},
|
|
1959
1985
|
_ => {
|
|
1960
1986
|
throw UnknownNumberTag
|
|
@@ -1964,30 +1990,31 @@ let cmpRational = (x: WasmI32, y: WasmI32, totalOrdering: Bool) => {
|
|
|
1964
1990
|
}
|
|
1965
1991
|
|
|
1966
1992
|
@unsafe
|
|
1967
|
-
export let cmp = (x: WasmI32, y: WasmI32
|
|
1993
|
+
export let cmp = (x: WasmI32, y: WasmI32) => {
|
|
1968
1994
|
if (isSimpleNumber(x)) {
|
|
1969
1995
|
if (isSimpleNumber(y)) {
|
|
1970
|
-
|
|
1996
|
+
// fast comparison path for simple numbers
|
|
1997
|
+
WasmI32.sub(x, y)
|
|
1971
1998
|
} else {
|
|
1972
1999
|
let yBoxedNumberTag = boxedNumberTag(y)
|
|
1973
2000
|
match (yBoxedNumberTag) {
|
|
1974
2001
|
t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => {
|
|
1975
|
-
WasmI32.sub(0n, cmpSmallInt(y, x, false
|
|
2002
|
+
WasmI32.sub(0n, cmpSmallInt(y, x, false))
|
|
1976
2003
|
},
|
|
1977
2004
|
t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
|
|
1978
|
-
WasmI32.sub(0n, cmpSmallInt(y, x, true
|
|
2005
|
+
WasmI32.sub(0n, cmpSmallInt(y, x, true))
|
|
1979
2006
|
},
|
|
1980
2007
|
t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
|
|
1981
2008
|
WasmI32.sub(0n, cmpBigInt(y, x))
|
|
1982
2009
|
},
|
|
1983
2010
|
t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => {
|
|
1984
|
-
WasmI32.sub(0n, cmpRational(y, x
|
|
2011
|
+
WasmI32.sub(0n, cmpRational(y, x))
|
|
1985
2012
|
},
|
|
1986
2013
|
t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
|
|
1987
|
-
WasmI32.sub(0n, cmpFloat(y, x, false
|
|
2014
|
+
WasmI32.sub(0n, cmpFloat(y, x, false))
|
|
1988
2015
|
},
|
|
1989
2016
|
t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
|
|
1990
|
-
WasmI32.sub(0n, cmpFloat(y, x, true
|
|
2017
|
+
WasmI32.sub(0n, cmpFloat(y, x, true))
|
|
1991
2018
|
},
|
|
1992
2019
|
_ => {
|
|
1993
2020
|
throw UnknownNumberTag
|
|
@@ -1998,22 +2025,22 @@ export let cmp = (x: WasmI32, y: WasmI32, totalOrdering: Bool) => {
|
|
|
1998
2025
|
let xBoxedNumberTag = boxedNumberTag(x)
|
|
1999
2026
|
match (xBoxedNumberTag) {
|
|
2000
2027
|
t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => {
|
|
2001
|
-
cmpSmallInt(x, y, false
|
|
2028
|
+
cmpSmallInt(x, y, false)
|
|
2002
2029
|
},
|
|
2003
2030
|
t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
|
|
2004
|
-
cmpSmallInt(x, y, true
|
|
2031
|
+
cmpSmallInt(x, y, true)
|
|
2005
2032
|
},
|
|
2006
2033
|
t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
|
|
2007
2034
|
cmpBigInt(x, y)
|
|
2008
2035
|
},
|
|
2009
2036
|
t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => {
|
|
2010
|
-
cmpRational(x, y
|
|
2037
|
+
cmpRational(x, y)
|
|
2011
2038
|
},
|
|
2012
2039
|
t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
|
|
2013
|
-
cmpFloat(x, y, false
|
|
2040
|
+
cmpFloat(x, y, false)
|
|
2014
2041
|
},
|
|
2015
2042
|
t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
|
|
2016
|
-
cmpFloat(x, y, true
|
|
2043
|
+
cmpFloat(x, y, true)
|
|
2017
2044
|
},
|
|
2018
2045
|
_ => {
|
|
2019
2046
|
throw UnknownNumberTag
|
|
@@ -2022,39 +2049,46 @@ export let cmp = (x: WasmI32, y: WasmI32, totalOrdering: Bool) => {
|
|
|
2022
2049
|
}
|
|
2023
2050
|
}
|
|
2024
2051
|
|
|
2052
|
+
// In the comparison functions below, NaN is neither greater than, less than,
|
|
2053
|
+
// or equal to any other number (including NaN), so any comparison involving
|
|
2054
|
+
// NaN is always false. The only exception to this rule is `compare`, which
|
|
2055
|
+
// applies a total ordering relation to allow numbers to be sortable (with
|
|
2056
|
+
// NaN being considered equal to itself and less than all other numbers in
|
|
2057
|
+
// this case).
|
|
2058
|
+
|
|
2025
2059
|
@unsafe
|
|
2026
2060
|
export let (<) = (x: Number, y: Number) => {
|
|
2027
2061
|
let x = WasmI32.fromGrain(x)
|
|
2028
2062
|
let y = WasmI32.fromGrain(y)
|
|
2029
|
-
WasmI32.ltS(cmp(x, y
|
|
2063
|
+
!isNaN(x) && !isNaN(y) && WasmI32.ltS(cmp(x, y), 0n)
|
|
2030
2064
|
}
|
|
2031
2065
|
|
|
2032
2066
|
@unsafe
|
|
2033
2067
|
export let (>) = (x: Number, y: Number) => {
|
|
2034
2068
|
let x = WasmI32.fromGrain(x)
|
|
2035
2069
|
let y = WasmI32.fromGrain(y)
|
|
2036
|
-
WasmI32.gtS(cmp(x, y
|
|
2070
|
+
!isNaN(x) && !isNaN(y) && WasmI32.gtS(cmp(x, y), 0n)
|
|
2037
2071
|
}
|
|
2038
2072
|
|
|
2039
2073
|
@unsafe
|
|
2040
2074
|
export let (<=) = (x: Number, y: Number) => {
|
|
2041
2075
|
let x = WasmI32.fromGrain(x)
|
|
2042
2076
|
let y = WasmI32.fromGrain(y)
|
|
2043
|
-
WasmI32.leS(cmp(x, y
|
|
2077
|
+
!isNaN(x) && !isNaN(y) && WasmI32.leS(cmp(x, y), 0n)
|
|
2044
2078
|
}
|
|
2045
2079
|
|
|
2046
2080
|
@unsafe
|
|
2047
2081
|
export let (>=) = (x: Number, y: Number) => {
|
|
2048
2082
|
let x = WasmI32.fromGrain(x)
|
|
2049
2083
|
let y = WasmI32.fromGrain(y)
|
|
2050
|
-
WasmI32.geS(cmp(x, y
|
|
2084
|
+
!isNaN(x) && !isNaN(y) && WasmI32.geS(cmp(x, y), 0n)
|
|
2051
2085
|
}
|
|
2052
2086
|
|
|
2053
2087
|
@unsafe
|
|
2054
2088
|
export let compare = (x: Number, y: Number) => {
|
|
2055
2089
|
let x = WasmI32.fromGrain(x)
|
|
2056
2090
|
let y = WasmI32.fromGrain(y)
|
|
2057
|
-
WasmI32.toGrain(tagSimple(cmp(x, y
|
|
2091
|
+
WasmI32.toGrain(tagSimple(cmp(x, y))): Number
|
|
2058
2092
|
}
|
|
2059
2093
|
|
|
2060
2094
|
/*
|
package/runtime/numbers.md
CHANGED
|
@@ -22,6 +22,12 @@ isInteger : WasmI32 -> Bool
|
|
|
22
22
|
isRational : WasmI32 -> Bool
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
+
### Numbers.**isNaN**
|
|
26
|
+
|
|
27
|
+
```grain
|
|
28
|
+
isNaN : WasmI32 -> Bool
|
|
29
|
+
```
|
|
30
|
+
|
|
25
31
|
### Numbers.**isNumber**
|
|
26
32
|
|
|
27
33
|
```grain
|
|
@@ -109,7 +115,7 @@ numberEqual : (WasmI32, WasmI32) -> Bool
|
|
|
109
115
|
### Numbers.**cmp**
|
|
110
116
|
|
|
111
117
|
```grain
|
|
112
|
-
cmp : (WasmI32, WasmI32
|
|
118
|
+
cmp : (WasmI32, WasmI32) -> WasmI32
|
|
113
119
|
```
|
|
114
120
|
|
|
115
121
|
### Numbers.**(<)**
|
package/stack.gr
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* @module Stack: An immutable stack implementation. A stack is a LIFO (last-in-first-out) data structure where new values are added, retrieved, and removed from the end.
|
|
3
3
|
* @example import Stack from "stack"
|
|
4
4
|
*
|
|
5
|
+
* @since v0.3.0
|
|
5
6
|
* @deprecated This module will be renamed to ImmutableStack in the v0.6.0 release of Grain.
|
|
6
7
|
*/
|
|
7
8
|
|
|
@@ -37,6 +38,7 @@ export let empty = {
|
|
|
37
38
|
*
|
|
38
39
|
* @returns An empty stack
|
|
39
40
|
*
|
|
41
|
+
* @since v0.3.0
|
|
40
42
|
* @deprecated This will be removed in the v0.6.0 release of Grain.
|
|
41
43
|
*/
|
|
42
44
|
export let make = () => {
|
|
@@ -48,6 +50,8 @@ export let make = () => {
|
|
|
48
50
|
*
|
|
49
51
|
* @param stack: The stack to check
|
|
50
52
|
* @returns `true` if the stack has no items or `false` otherwise
|
|
53
|
+
*
|
|
54
|
+
* @since v0.3.0
|
|
51
55
|
*/
|
|
52
56
|
export let isEmpty = stack => {
|
|
53
57
|
match (stack) {
|
|
@@ -61,6 +65,9 @@ export let isEmpty = stack => {
|
|
|
61
65
|
*
|
|
62
66
|
* @param stack: The stack to inspect
|
|
63
67
|
* @returns `Some(value)` containing the value at the top of the stack or `None` otherwise.
|
|
68
|
+
*
|
|
69
|
+
* @since v0.3.0
|
|
70
|
+
* @history v0.3.1: Rename from `head` to `peek`
|
|
64
71
|
*/
|
|
65
72
|
export let peek = stack => {
|
|
66
73
|
match (stack) {
|
|
@@ -75,6 +82,8 @@ export let peek = stack => {
|
|
|
75
82
|
* @param value: The item to be added
|
|
76
83
|
* @param stack: The stack being updated
|
|
77
84
|
* @returns A new stack with the item added to the end
|
|
85
|
+
*
|
|
86
|
+
* @since v0.3.0
|
|
78
87
|
*/
|
|
79
88
|
export let push = (value, stack) => {
|
|
80
89
|
match (stack) {
|
|
@@ -88,6 +97,8 @@ export let push = (value, stack) => {
|
|
|
88
97
|
*
|
|
89
98
|
* @param stack: The stack being updated
|
|
90
99
|
* @returns A new stack with the last item removed
|
|
100
|
+
*
|
|
101
|
+
* @since v0.3.0
|
|
91
102
|
*/
|
|
92
103
|
export let pop = stack => {
|
|
93
104
|
match (stack) {
|
|
@@ -101,6 +112,8 @@ export let pop = stack => {
|
|
|
101
112
|
*
|
|
102
113
|
* @param stack: The stack to inspect
|
|
103
114
|
* @returns The count of the items in the stack
|
|
115
|
+
*
|
|
116
|
+
* @since v0.3.2
|
|
104
117
|
*/
|
|
105
118
|
export let size = stack => {
|
|
106
119
|
match (stack) {
|
package/stack.md
CHANGED
|
@@ -6,6 +6,11 @@ title: Stack
|
|
|
6
6
|
|
|
7
7
|
An immutable stack implementation. A stack is a LIFO (last-in-first-out) data structure where new values are added, retrieved, and removed from the end.
|
|
8
8
|
|
|
9
|
+
<details disabled>
|
|
10
|
+
<summary tabindex="-1">Added in <code>0.3.0</code></summary>
|
|
11
|
+
No other changes yet.
|
|
12
|
+
</details>
|
|
13
|
+
|
|
9
14
|
```grain
|
|
10
15
|
import Stack from "stack"
|
|
11
16
|
```
|
|
@@ -43,6 +48,11 @@ An empty stack.
|
|
|
43
48
|
|
|
44
49
|
> **Deprecated:** This will be removed in the v0.6.0 release of Grain.
|
|
45
50
|
|
|
51
|
+
<details disabled>
|
|
52
|
+
<summary tabindex="-1">Added in <code>0.3.0</code></summary>
|
|
53
|
+
No other changes yet.
|
|
54
|
+
</details>
|
|
55
|
+
|
|
46
56
|
```grain
|
|
47
57
|
make : () -> Stack<a>
|
|
48
58
|
```
|
|
@@ -57,6 +67,11 @@ Returns:
|
|
|
57
67
|
|
|
58
68
|
### Stack.**isEmpty**
|
|
59
69
|
|
|
70
|
+
<details disabled>
|
|
71
|
+
<summary tabindex="-1">Added in <code>0.3.0</code></summary>
|
|
72
|
+
No other changes yet.
|
|
73
|
+
</details>
|
|
74
|
+
|
|
60
75
|
```grain
|
|
61
76
|
isEmpty : Stack<a> -> Bool
|
|
62
77
|
```
|
|
@@ -77,6 +92,18 @@ Returns:
|
|
|
77
92
|
|
|
78
93
|
### Stack.**peek**
|
|
79
94
|
|
|
95
|
+
<details>
|
|
96
|
+
<summary>Added in <code>0.3.0</code></summary>
|
|
97
|
+
<table>
|
|
98
|
+
<thead>
|
|
99
|
+
<tr><th>version</th><th>changes</th></tr>
|
|
100
|
+
</thead>
|
|
101
|
+
<tbody>
|
|
102
|
+
<tr><td><code>0.3.1</code></td><td>Rename from `head` to `peek`</td></tr>
|
|
103
|
+
</tbody>
|
|
104
|
+
</table>
|
|
105
|
+
</details>
|
|
106
|
+
|
|
80
107
|
```grain
|
|
81
108
|
peek : Stack<a> -> Option<a>
|
|
82
109
|
```
|
|
@@ -97,6 +124,11 @@ Returns:
|
|
|
97
124
|
|
|
98
125
|
### Stack.**push**
|
|
99
126
|
|
|
127
|
+
<details disabled>
|
|
128
|
+
<summary tabindex="-1">Added in <code>0.3.0</code></summary>
|
|
129
|
+
No other changes yet.
|
|
130
|
+
</details>
|
|
131
|
+
|
|
100
132
|
```grain
|
|
101
133
|
push : (a, Stack<a>) -> Stack<a>
|
|
102
134
|
```
|
|
@@ -118,6 +150,11 @@ Returns:
|
|
|
118
150
|
|
|
119
151
|
### Stack.**pop**
|
|
120
152
|
|
|
153
|
+
<details disabled>
|
|
154
|
+
<summary tabindex="-1">Added in <code>0.3.0</code></summary>
|
|
155
|
+
No other changes yet.
|
|
156
|
+
</details>
|
|
157
|
+
|
|
121
158
|
```grain
|
|
122
159
|
pop : Stack<a> -> Stack<a>
|
|
123
160
|
```
|
|
@@ -138,6 +175,11 @@ Returns:
|
|
|
138
175
|
|
|
139
176
|
### Stack.**size**
|
|
140
177
|
|
|
178
|
+
<details disabled>
|
|
179
|
+
<summary tabindex="-1">Added in <code>0.3.2</code></summary>
|
|
180
|
+
No other changes yet.
|
|
181
|
+
</details>
|
|
182
|
+
|
|
141
183
|
```grain
|
|
142
184
|
size : Stack<a> -> Number
|
|
143
185
|
```
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import Conv from "runtime/unsafe/conv"
|
|
2
|
-
import WasmI32 from "runtime/unsafe/wasmi32"
|
|
3
|
-
import Memory from "runtime/unsafe/memory"
|
|
4
|
-
|
|
5
|
-
// [FIXME] These all leak ATM (grain-lang/grain#791)
|
|
6
|
-
|
|
7
|
-
@unsafe
|
|
8
|
-
export let printI32 = val => {
|
|
9
|
-
let conv = Conv.toInt32(val)
|
|
10
|
-
let s1 = toString(conv)
|
|
11
|
-
let s2 = "n"
|
|
12
|
-
let s = s1 ++ s2
|
|
13
|
-
print(s)
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
@unsafe
|
|
17
|
-
export let printI64 = val => {
|
|
18
|
-
let conv = Conv.toInt64(val)
|
|
19
|
-
let s1 = toString(conv)
|
|
20
|
-
let s2 = "N"
|
|
21
|
-
let s = s1 ++ s2
|
|
22
|
-
print(s)
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
@unsafe
|
|
26
|
-
export let printF32 = val => {
|
|
27
|
-
let conv = Conv.toFloat32(val)
|
|
28
|
-
let s1 = toString(conv)
|
|
29
|
-
let s2 = "w"
|
|
30
|
-
let s = s1 ++ s2
|
|
31
|
-
print(s)
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
@unsafe
|
|
35
|
-
export let printF64 = val => {
|
|
36
|
-
let conv = Conv.toFloat64(val)
|
|
37
|
-
let s1 = toString(conv)
|
|
38
|
-
let s2 = "W"
|
|
39
|
-
let s = s1 ++ s2
|
|
40
|
-
print(s)
|
|
41
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
### PrintWasm.**printI32**
|
|
2
|
-
|
|
3
|
-
```grain
|
|
4
|
-
printI32 : WasmI32 -> Void
|
|
5
|
-
```
|
|
6
|
-
|
|
7
|
-
### PrintWasm.**printI64**
|
|
8
|
-
|
|
9
|
-
```grain
|
|
10
|
-
printI64 : WasmI64 -> Void
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
### PrintWasm.**printF32**
|
|
14
|
-
|
|
15
|
-
```grain
|
|
16
|
-
printF32 : WasmF32 -> Void
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
### PrintWasm.**printF64**
|
|
20
|
-
|
|
21
|
-
```grain
|
|
22
|
-
printF64 : WasmF64 -> Void
|
|
23
|
-
```
|
|
24
|
-
|