@grain/stdlib 0.6.0 → 0.6.2
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 +15 -0
- package/hash.gr +15 -3
- package/hash.md +6 -0
- package/json.gr +46 -59
- package/json.md +38 -0
- package/package.json +1 -1
- package/runtime/numberUtils.gr +2 -2
- package/runtime/numberUtils.md +12 -0
- package/runtime/string.gr +8 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.6.2](https://github.com/grain-lang/grain/compare/stdlib-v0.6.1...stdlib-v0.6.2) (2024-04-01)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Miscellaneous Chores
|
|
7
|
+
|
|
8
|
+
* **stdlib:** Synchronize Grain versions
|
|
9
|
+
|
|
10
|
+
## [0.6.1](https://github.com/grain-lang/grain/compare/stdlib-v0.6.0...stdlib-v0.6.1) (2024-03-29)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
|
|
15
|
+
* **stdlib:** Avoid WASI random_get in Hash stdlib during module startup ([#2078](https://github.com/grain-lang/grain/issues/2078)) ([7eadfb0](https://github.com/grain-lang/grain/commit/7eadfb097e64b043c860d27d21d36d4bfea1ea96))
|
|
16
|
+
* **stdlib:** Implement `print` using a single element io vec ([#2066](https://github.com/grain-lang/grain/issues/2066)) ([9eeb0f2](https://github.com/grain-lang/grain/commit/9eeb0f2edb14facc619c1ede27a5700a27e64e3f))
|
|
17
|
+
|
|
3
18
|
## [0.6.0](https://github.com/grain-lang/grain/compare/stdlib-v0.5.13...stdlib-v0.6.0) (2024-03-04)
|
|
4
19
|
|
|
5
20
|
|
package/hash.gr
CHANGED
|
@@ -43,9 +43,15 @@ from "wasi/random" include Random
|
|
|
43
43
|
from "result" include Result
|
|
44
44
|
|
|
45
45
|
@unsafe
|
|
46
|
-
let seed =
|
|
46
|
+
let mut seed = 0n
|
|
47
|
+
|
|
48
|
+
@unsafe
|
|
49
|
+
let initalize = () => {
|
|
50
|
+
// Delay initialization to the first call to `hash` to prevent WASI calls
|
|
51
|
+
// during startup
|
|
47
52
|
let random = Random.random()
|
|
48
|
-
coerceNumberToWasmI32(Result.unwrap(random))
|
|
53
|
+
seed = coerceNumberToWasmI32(Result.unwrap(random))
|
|
54
|
+
seed
|
|
49
55
|
}
|
|
50
56
|
|
|
51
57
|
@unsafe
|
|
@@ -239,6 +245,8 @@ let rec hashOne = (val, depth) => {
|
|
|
239
245
|
*
|
|
240
246
|
* @param anything: The value to hash
|
|
241
247
|
* @returns A hash for the given value
|
|
248
|
+
*
|
|
249
|
+
* @throws Failure(String): If WASI random_get fails
|
|
242
250
|
*
|
|
243
251
|
* @example assert Hash.hash(1) == Hash.hash(1)
|
|
244
252
|
* @example assert Hash.hash("Hello World") == Hash.hash("Hello World")
|
|
@@ -247,7 +255,11 @@ let rec hashOne = (val, depth) => {
|
|
|
247
255
|
*/
|
|
248
256
|
@unsafe
|
|
249
257
|
provide let hash = anything => {
|
|
250
|
-
h = seed
|
|
258
|
+
h = if (WasmI32.eqz(seed)) {
|
|
259
|
+
initalize()
|
|
260
|
+
} else {
|
|
261
|
+
seed
|
|
262
|
+
}
|
|
251
263
|
|
|
252
264
|
hashOne(WasmI32.fromGrain(anything), 0n)
|
|
253
265
|
finalize(0n)
|
package/hash.md
CHANGED
package/json.gr
CHANGED
|
@@ -55,10 +55,25 @@ let _Float64_BOXED_VALUE_OFFSET = 8n
|
|
|
55
55
|
* ])
|
|
56
56
|
*/
|
|
57
57
|
provide enum rec Json {
|
|
58
|
+
/**
|
|
59
|
+
* Represents the JSON `null` value.
|
|
60
|
+
*/
|
|
58
61
|
JsonNull,
|
|
62
|
+
/**
|
|
63
|
+
* Represents a JSON boolean value.
|
|
64
|
+
*/
|
|
59
65
|
JsonBoolean(Bool),
|
|
66
|
+
/**
|
|
67
|
+
* Represents a JSON number value.
|
|
68
|
+
*/
|
|
60
69
|
JsonNumber(Number),
|
|
70
|
+
/**
|
|
71
|
+
* Represents a JSON string value.
|
|
72
|
+
*/
|
|
61
73
|
JsonString(String),
|
|
74
|
+
/**
|
|
75
|
+
* Represents a JSON array value.
|
|
76
|
+
*/
|
|
62
77
|
JsonArray(List<Json>),
|
|
63
78
|
// Note that JsonObject here is deliberately defined as a simple list of key value pair tuples as opposed
|
|
64
79
|
// to for example a Map in order to accommodate the fact that the ECMA-404 standard doesn't prohibit
|
|
@@ -67,6 +82,9 @@ provide enum rec Json {
|
|
|
67
82
|
// has the benefit of List's immutability. It's a conscious decision that sacrifices ease of use of the
|
|
68
83
|
// API for lossless handing of these edge cases with intention of later building more ergonomic APIs on a
|
|
69
84
|
// higher level of abstraction.
|
|
85
|
+
/**
|
|
86
|
+
* Represents a JSON object value, as a list of (key, value).
|
|
87
|
+
*/
|
|
70
88
|
JsonObject(List<(String, Json)>),
|
|
71
89
|
}
|
|
72
90
|
|
|
@@ -494,7 +512,6 @@ let emitEscapedUnicodeSequence = (codePoint: Number, buffer: Buffer.Buffer) => {
|
|
|
494
512
|
// High surrogate
|
|
495
513
|
let lowSurrogate = (uPrime & 0b00000000001111111111) + 0xDC00
|
|
496
514
|
// Low surrogate
|
|
497
|
-
|
|
498
515
|
emitUTF16EscapeSequence(highSurrogate, buffer)
|
|
499
516
|
emitUTF16EscapeSequence(lowSurrogate, buffer)
|
|
500
517
|
}
|
|
@@ -558,21 +575,9 @@ let printNumberWasmI64 = (value: WasmI64, buffer: Buffer.Buffer) => {
|
|
|
558
575
|
Buffer.addString(s, buffer)
|
|
559
576
|
}
|
|
560
577
|
|
|
561
|
-
@unsafe
|
|
562
|
-
let isFinite = (value: WasmF64) => {
|
|
563
|
-
use WasmF64.{ (==), (-) }
|
|
564
|
-
value - value == 0.0W
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
@unsafe
|
|
568
|
-
let isNaN = (value: WasmF64) => {
|
|
569
|
-
use WasmF64.{ (!=) }
|
|
570
|
-
value != value
|
|
571
|
-
}
|
|
572
|
-
|
|
573
578
|
@unsafe
|
|
574
579
|
let printNumberWasmF64 = (value: WasmF64, buffer: Buffer.Buffer) => {
|
|
575
|
-
if (isFinite(value)) {
|
|
580
|
+
if (NumberUtils.isFinite(value)) {
|
|
576
581
|
let s = NumberUtils.dtoa(value)
|
|
577
582
|
Buffer.addString(s, buffer)
|
|
578
583
|
None
|
|
@@ -585,7 +590,7 @@ let printNumberWasmF64 = (value: WasmF64, buffer: Buffer.Buffer) => {
|
|
|
585
590
|
// directly. Other possible choices were to throw exceptions or to
|
|
586
591
|
// continue formatting without representing these values correctly
|
|
587
592
|
// (like JavaScript's JSON.stringify).
|
|
588
|
-
if (isNaN(value)) {
|
|
593
|
+
if (NumberUtils.isNaN(value)) {
|
|
589
594
|
Some(InvalidNumber("NaN is not allowed in JsonNumber"))
|
|
590
595
|
} else if (value < 0.0W) {
|
|
591
596
|
Some(InvalidNumber("-Infinity is not allowed in JsonNumber"))
|
|
@@ -1558,20 +1563,22 @@ and parseString = (parserState: JsonParserState) => {
|
|
|
1558
1563
|
// '"'
|
|
1559
1564
|
Some(e) => return Err(e),
|
|
1560
1565
|
None => {
|
|
1561
|
-
let mut done = false
|
|
1562
1566
|
let buffer = parserState.bufferParse
|
|
1563
1567
|
Buffer.clear(buffer)
|
|
1564
1568
|
|
|
1565
|
-
while (
|
|
1569
|
+
while (true) {
|
|
1566
1570
|
match (parserState.currentCodePoint) {
|
|
1567
1571
|
0x22 => { // '"'
|
|
1568
1572
|
next(parserState)
|
|
1569
|
-
done = true
|
|
1570
1573
|
break
|
|
1571
1574
|
},
|
|
1572
|
-
-1 => {
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
+
-1 => { // EOF
|
|
1576
|
+
return Err(
|
|
1577
|
+
buildUnexpectedTokenError(
|
|
1578
|
+
parserState,
|
|
1579
|
+
"unexpected end of string value"
|
|
1580
|
+
),
|
|
1581
|
+
)
|
|
1575
1582
|
},
|
|
1576
1583
|
0x5C => { // '\'
|
|
1577
1584
|
// Keep the starting position for better error reporting.
|
|
@@ -1757,17 +1764,8 @@ and parseString = (parserState: JsonParserState) => {
|
|
|
1757
1764
|
}
|
|
1758
1765
|
}
|
|
1759
1766
|
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
return Ok(s)
|
|
1763
|
-
} else {
|
|
1764
|
-
return Err(
|
|
1765
|
-
buildUnexpectedTokenError(
|
|
1766
|
-
parserState,
|
|
1767
|
-
"unexpected end of string value"
|
|
1768
|
-
),
|
|
1769
|
-
)
|
|
1770
|
-
}
|
|
1767
|
+
let s = Buffer.toString(buffer)
|
|
1768
|
+
return Ok(s)
|
|
1771
1769
|
},
|
|
1772
1770
|
}
|
|
1773
1771
|
}
|
|
@@ -1887,10 +1885,14 @@ and parseNumberValue = (parserState: JsonParserState) => {
|
|
|
1887
1885
|
}
|
|
1888
1886
|
},
|
|
1889
1887
|
}
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1888
|
+
|
|
1889
|
+
let result = if (result == 0 && isNegative) {
|
|
1890
|
+
-0.0
|
|
1891
|
+
} else {
|
|
1892
|
+
if (isNegative) result * -1 else result
|
|
1893
|
+
}
|
|
1894
|
+
|
|
1895
|
+
return Ok(JsonNumber(result))
|
|
1894
1896
|
}
|
|
1895
1897
|
and parseArray = (parserState: JsonParserState) => {
|
|
1896
1898
|
match (expectCodePointAndAdvance(0x5B, parserState)) {
|
|
@@ -1901,10 +1903,9 @@ and parseArray = (parserState: JsonParserState) => {
|
|
|
1901
1903
|
|
|
1902
1904
|
let mut elems = []: List<Json>
|
|
1903
1905
|
|
|
1904
|
-
let mut done = false
|
|
1905
1906
|
let mut first = true
|
|
1906
1907
|
let mut trailingComma = false
|
|
1907
|
-
while (
|
|
1908
|
+
while (true) {
|
|
1908
1909
|
let c = parserState.currentCodePoint
|
|
1909
1910
|
match (c) {
|
|
1910
1911
|
0x2C => { // ','
|
|
@@ -1922,12 +1923,12 @@ and parseArray = (parserState: JsonParserState) => {
|
|
|
1922
1923
|
},
|
|
1923
1924
|
0x5D => { // ']'
|
|
1924
1925
|
next(parserState)
|
|
1925
|
-
done = true
|
|
1926
1926
|
break
|
|
1927
1927
|
},
|
|
1928
|
-
-1 => {
|
|
1929
|
-
|
|
1930
|
-
|
|
1928
|
+
-1 => { // EOF
|
|
1929
|
+
return Err(
|
|
1930
|
+
buildUnexpectedTokenError(parserState, "unexpected end of array"),
|
|
1931
|
+
)
|
|
1931
1932
|
},
|
|
1932
1933
|
_ => {
|
|
1933
1934
|
// note that parseValue skips initial and final whitespace
|
|
@@ -1947,12 +1948,8 @@ and parseArray = (parserState: JsonParserState) => {
|
|
|
1947
1948
|
return Err(
|
|
1948
1949
|
buildUnexpectedTokenError(parserState, "unexpected end of array"),
|
|
1949
1950
|
)
|
|
1950
|
-
} else if (done) {
|
|
1951
|
-
return Ok(JsonArray(List.reverse(elems)))
|
|
1952
1951
|
} else {
|
|
1953
|
-
return
|
|
1954
|
-
buildUnexpectedTokenError(parserState, "unexpected end of array"),
|
|
1955
|
-
)
|
|
1952
|
+
return Ok(JsonArray(List.reverse(elems)))
|
|
1956
1953
|
}
|
|
1957
1954
|
},
|
|
1958
1955
|
}
|
|
@@ -1964,12 +1961,11 @@ and parseObject = (parserState: JsonParserState) => {
|
|
|
1964
1961
|
None => {
|
|
1965
1962
|
let mut entries = []: List<(String, Json)>
|
|
1966
1963
|
|
|
1967
|
-
let mut done = false
|
|
1968
1964
|
let mut first = true
|
|
1969
1965
|
|
|
1970
1966
|
// one iteration of this loop should correspond to a key-value pair
|
|
1971
1967
|
let mut trailingComma = false
|
|
1972
|
-
while (
|
|
1968
|
+
while (true) {
|
|
1973
1969
|
skipWhiteSpace(parserState)
|
|
1974
1970
|
|
|
1975
1971
|
let c = parserState.currentCodePoint
|
|
@@ -1994,7 +1990,6 @@ and parseObject = (parserState: JsonParserState) => {
|
|
|
1994
1990
|
return Err(buildUnexpectedTokenError(parserState, detail))
|
|
1995
1991
|
}
|
|
1996
1992
|
next(parserState)
|
|
1997
|
-
done = true
|
|
1998
1993
|
break
|
|
1999
1994
|
},
|
|
2000
1995
|
_ => {
|
|
@@ -2027,15 +2022,7 @@ and parseObject = (parserState: JsonParserState) => {
|
|
|
2027
2022
|
}
|
|
2028
2023
|
// end of entry loop
|
|
2029
2024
|
|
|
2030
|
-
|
|
2031
|
-
return Ok(JsonObject(List.reverse(entries)))
|
|
2032
|
-
} else {
|
|
2033
|
-
// This branch is not expected to actually execute,
|
|
2034
|
-
// but in case it does, may just as well do the right thing.
|
|
2035
|
-
return Err(
|
|
2036
|
-
buildUnexpectedTokenError(parserState, "unexpected end of object"),
|
|
2037
|
-
)
|
|
2038
|
-
}
|
|
2025
|
+
return Ok(JsonObject(List.reverse(entries)))
|
|
2039
2026
|
},
|
|
2040
2027
|
}
|
|
2041
2028
|
}
|
package/json.md
CHANGED
|
@@ -40,6 +40,44 @@ enum Json {
|
|
|
40
40
|
|
|
41
41
|
Data structure representing JSON in Grain.
|
|
42
42
|
|
|
43
|
+
Variants:
|
|
44
|
+
|
|
45
|
+
```grain
|
|
46
|
+
JsonNull
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Represents the JSON `null` value.
|
|
50
|
+
|
|
51
|
+
```grain
|
|
52
|
+
JsonBoolean(Bool)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Represents a JSON boolean value.
|
|
56
|
+
|
|
57
|
+
```grain
|
|
58
|
+
JsonNumber(Number)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Represents a JSON number value.
|
|
62
|
+
|
|
63
|
+
```grain
|
|
64
|
+
JsonString(String)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Represents a JSON string value.
|
|
68
|
+
|
|
69
|
+
```grain
|
|
70
|
+
JsonArray(List<Json>)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Represents a JSON array value.
|
|
74
|
+
|
|
75
|
+
```grain
|
|
76
|
+
JsonObject(List<(String, Json)>)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Represents a JSON object value, as a list of (key, value).
|
|
80
|
+
|
|
43
81
|
Examples:
|
|
44
82
|
|
|
45
83
|
```grain
|
package/package.json
CHANGED
package/runtime/numberUtils.gr
CHANGED
|
@@ -1452,13 +1452,13 @@ let get_dtoa_buf = () => {
|
|
|
1452
1452
|
}
|
|
1453
1453
|
|
|
1454
1454
|
@unsafe
|
|
1455
|
-
let isFinite = value => {
|
|
1455
|
+
provide let isFinite = value => {
|
|
1456
1456
|
use WasmF64.{ (==), (-) }
|
|
1457
1457
|
value - value == 0.0W
|
|
1458
1458
|
}
|
|
1459
1459
|
|
|
1460
1460
|
@unsafe
|
|
1461
|
-
let isNaN = value => {
|
|
1461
|
+
provide let isNaN = value => {
|
|
1462
1462
|
use WasmF64.{ (!=) }
|
|
1463
1463
|
value != value
|
|
1464
1464
|
}
|
package/runtime/numberUtils.md
CHANGED
|
@@ -60,6 +60,18 @@ utoa64 : (value: WasmI64, radix: WasmI32) => String
|
|
|
60
60
|
itoa64 : (value: WasmI64, radix: WasmI32) => String
|
|
61
61
|
```
|
|
62
62
|
|
|
63
|
+
### NumberUtils.**isFinite**
|
|
64
|
+
|
|
65
|
+
```grain
|
|
66
|
+
isFinite : (value: WasmF64) => Bool
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### NumberUtils.**isNaN**
|
|
70
|
+
|
|
71
|
+
```grain
|
|
72
|
+
isNaN : (value: WasmF64) => Bool
|
|
73
|
+
```
|
|
74
|
+
|
|
63
75
|
### NumberUtils.**dtoa**
|
|
64
76
|
|
|
65
77
|
```grain
|
package/runtime/string.gr
CHANGED
|
@@ -861,20 +861,20 @@ provide let print = (value, suffix="\n") => {
|
|
|
861
861
|
// First convert the value to string, if it isn't one already.
|
|
862
862
|
let valuePtr = WasmI32.fromGrain(value)
|
|
863
863
|
let s = toString(value)
|
|
864
|
-
let
|
|
865
|
-
let
|
|
866
|
-
// iov: [<ptr to string> <nbytes of string>
|
|
864
|
+
let combined = concat(s, suffix)
|
|
865
|
+
let ptr = WasmI32.fromGrain(combined)
|
|
866
|
+
// iov: [<ptr to string> <nbytes of string>]
|
|
867
867
|
// buf: <iov> <written>
|
|
868
868
|
// fd_write(STDOUT (1), iov, len(iov), written)
|
|
869
|
-
let buf = Memory.malloc(
|
|
869
|
+
let buf = Memory.malloc(20n)
|
|
870
870
|
let iov = buf
|
|
871
|
-
let written = buf +
|
|
871
|
+
let written = buf + 16n
|
|
872
872
|
WasmI32.store(iov, ptr + 8n, 0n)
|
|
873
873
|
WasmI32.store(iov, WasmI32.load(ptr, 4n), 4n)
|
|
874
|
-
|
|
875
|
-
WasmI32.store(iov, WasmI32.load(suffixPtr, 4n), 12n)
|
|
876
|
-
fd_write(1n, iov, 2n, written)
|
|
874
|
+
fd_write(1n, iov, 1n, written)
|
|
877
875
|
Memory.free(buf)
|
|
876
|
+
ignore(value)
|
|
877
|
+
ignore(suffix)
|
|
878
878
|
void
|
|
879
879
|
}
|
|
880
880
|
|