@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/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 contains the NaN value (Not 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
- if (isBoxedNumber(asPtr)) {
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 contains the NaN value (Not 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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@grain/stdlib",
3
- "version": "0.5.7",
3
+ "version": "0.5.9",
4
4
  "description": "The standard library for the Grain language.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://grain-lang.org",
@@ -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, true))
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
+
@@ -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, totalOrdering: 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 (totalOrdering && WasmF64.ne(xf, xf)) {
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 (totalOrdering && WasmF64.ne(yf, yf)) {
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 (totalOrdering && WasmF64.ne(xf, xf)) {
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 (totalOrdering && WasmF64.ne(yf, yf)) {
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, totalOrdering: 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, totalOrdering))
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, totalOrdering))
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, totalOrdering: Bool) => {
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, totalOrdering))
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, totalOrdering))
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, totalOrdering))
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, totalOrdering))
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, totalOrdering: Bool) => {
1993
+ export let cmp = (x: WasmI32, y: WasmI32) => {
1968
1994
  if (isSimpleNumber(x)) {
1969
1995
  if (isSimpleNumber(y)) {
1970
- if (WasmI32.ltS(x, y)) -1n else if (WasmI32.gtS(x, y)) 1n else 0n
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, totalOrdering))
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, totalOrdering))
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, totalOrdering))
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, totalOrdering))
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, totalOrdering))
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, totalOrdering)
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, totalOrdering)
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, totalOrdering)
2037
+ cmpRational(x, y)
2011
2038
  },
2012
2039
  t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
2013
- cmpFloat(x, y, false, totalOrdering)
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, totalOrdering)
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, false), 0n)
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, false), 0n)
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, false), 0n)
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, false), 0n)
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, true))): Number
2091
+ WasmI32.toGrain(tagSimple(cmp(x, y))): Number
2058
2092
  }
2059
2093
 
2060
2094
  /*
@@ -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, Bool) -> 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
-