@grain/stdlib 0.6.6 → 0.7.1
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 +67 -0
- package/LICENSE +1 -1
- package/README.md +2 -2
- package/array.gr +55 -7
- package/array.md +606 -560
- package/bigint.md +228 -228
- package/buffer.gr +85 -53
- package/buffer.md +442 -319
- package/bytes.gr +112 -35
- package/bytes.md +299 -219
- package/char.gr +201 -99
- package/char.md +447 -120
- package/exception.gr +11 -11
- package/exception.md +29 -4
- package/float32.gr +327 -3
- package/float32.md +698 -111
- package/float64.gr +320 -3
- package/float64.md +698 -111
- package/fs.gr +1082 -0
- package/fs.md +630 -0
- package/hash.gr +142 -88
- package/hash.md +105 -17
- package/int16.md +178 -178
- package/int32.gr +26 -5
- package/int32.md +266 -231
- package/int64.gr +27 -2
- package/int64.md +266 -231
- package/int8.md +178 -178
- package/json.gr +366 -51
- package/json.md +431 -15
- package/list.gr +328 -31
- package/list.md +759 -336
- package/map.gr +20 -12
- package/map.md +266 -260
- package/marshal.gr +41 -40
- package/marshal.md +14 -14
- package/number.gr +278 -35
- package/number.md +688 -269
- package/option.md +162 -162
- package/package.json +5 -3
- package/path.gr +48 -0
- package/path.md +180 -89
- package/pervasives.gr +2 -2
- package/pervasives.md +275 -275
- package/priorityqueue.gr +7 -7
- package/priorityqueue.md +131 -131
- package/queue.gr +183 -29
- package/queue.md +404 -148
- package/random.md +43 -43
- package/range.gr +4 -4
- package/range.md +42 -42
- package/rational.md +123 -123
- package/regex.gr +52 -51
- package/regex.md +102 -102
- package/result.md +118 -118
- package/runtime/atof/common.md +39 -39
- package/runtime/atof/decimal.gr +6 -6
- package/runtime/atof/decimal.md +14 -14
- package/runtime/atof/lemire.gr +5 -5
- package/runtime/atof/lemire.md +1 -1
- package/runtime/atof/parse.gr +16 -16
- package/runtime/atof/parse.md +2 -2
- package/runtime/atof/slow.md +1 -1
- package/runtime/atof/table.md +2 -2
- package/runtime/atoi/parse.gr +3 -3
- package/runtime/atoi/parse.md +1 -1
- package/runtime/bigint.gr +15 -47
- package/runtime/bigint.md +54 -60
- package/runtime/compare.gr +2 -2
- package/runtime/compare.md +8 -8
- package/runtime/dataStructures.md +211 -211
- package/runtime/debugPrint.gr +4 -1
- package/runtime/debugPrint.md +9 -9
- package/runtime/equal.gr +99 -77
- package/runtime/equal.md +8 -8
- package/runtime/exception.gr +62 -82
- package/runtime/exception.md +62 -11
- package/runtime/gc.gr +39 -45
- package/runtime/gc.md +4 -4
- package/runtime/malloc.gr +7 -7
- package/runtime/malloc.md +13 -13
- package/runtime/math/kernel/cos.gr +70 -0
- package/runtime/math/kernel/cos.md +14 -0
- package/runtime/math/kernel/sin.gr +65 -0
- package/runtime/math/kernel/sin.md +14 -0
- package/runtime/math/kernel/tan.gr +136 -0
- package/runtime/math/kernel/tan.md +14 -0
- package/runtime/math/rempio2.gr +244 -0
- package/runtime/math/rempio2.md +14 -0
- package/runtime/math/trig.gr +130 -0
- package/runtime/math/trig.md +28 -0
- package/runtime/math/umuldi.gr +26 -0
- package/runtime/math/umuldi.md +14 -0
- package/runtime/numberUtils.gr +29 -29
- package/runtime/numberUtils.md +12 -12
- package/runtime/numbers.gr +373 -381
- package/runtime/numbers.md +348 -342
- package/runtime/string.gr +37 -105
- package/runtime/string.md +20 -26
- package/runtime/unsafe/constants.md +24 -24
- package/runtime/unsafe/conv.md +19 -19
- package/runtime/unsafe/memory.gr +24 -20
- package/runtime/unsafe/memory.md +27 -7
- package/runtime/unsafe/offsets.gr +36 -0
- package/runtime/unsafe/offsets.md +88 -0
- package/runtime/unsafe/panic.gr +28 -0
- package/runtime/unsafe/panic.md +14 -0
- package/runtime/unsafe/tags.md +32 -32
- package/runtime/unsafe/wasmf32.md +28 -28
- package/runtime/unsafe/wasmf64.md +28 -28
- package/runtime/unsafe/wasmi32.md +47 -47
- package/runtime/unsafe/wasmi64.md +50 -50
- package/runtime/utf8.gr +189 -0
- package/runtime/utf8.md +117 -0
- package/runtime/wasi.gr +4 -2
- package/runtime/wasi.md +147 -147
- package/set.gr +18 -11
- package/set.md +253 -247
- package/stack.gr +171 -2
- package/stack.md +371 -89
- package/string.gr +352 -557
- package/string.md +298 -255
- package/uint16.md +170 -170
- package/uint32.gr +25 -4
- package/uint32.md +249 -214
- package/uint64.gr +25 -5
- package/uint64.md +249 -214
- package/uint8.md +170 -170
- package/uri.gr +57 -53
- package/uri.md +88 -89
- package/wasi/file.gr +67 -59
- package/wasi/file.md +308 -308
- package/wasi/process.md +26 -26
- package/wasi/random.md +12 -12
- package/wasi/time.md +16 -16
- package/runtime/utils/printing.gr +0 -60
- package/runtime/utils/printing.md +0 -26
package/runtime/debugPrint.gr
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
@noPervasives
|
|
1
2
|
module DebugPrint
|
|
2
3
|
|
|
3
4
|
from "runtime/numberUtils" include NumberUtils as Utils
|
|
@@ -9,6 +10,8 @@ from "runtime/unsafe/memory" include Memory
|
|
|
9
10
|
foreign wasm fd_write:
|
|
10
11
|
(WasmI32, WasmI32, WasmI32, WasmI32) => WasmI32 from "wasi_snapshot_preview1"
|
|
11
12
|
|
|
13
|
+
primitive ignore = "@ignore"
|
|
14
|
+
|
|
12
15
|
@unsafe
|
|
13
16
|
provide let print = (s: String) => {
|
|
14
17
|
let ptr = WasmI32.fromGrain(s)
|
|
@@ -26,7 +29,7 @@ provide let print = (s: String) => {
|
|
|
26
29
|
WasmI32.store(iov, 1n, 12n)
|
|
27
30
|
fd_write(1n, iov, 2n, written)
|
|
28
31
|
Memory.free(buf)
|
|
29
|
-
|
|
32
|
+
ignore(s)
|
|
30
33
|
}
|
|
31
34
|
|
|
32
35
|
@unsafe
|
package/runtime/debugPrint.md
CHANGED
|
@@ -9,54 +9,54 @@ Functions and constants included in the DebugPrint module.
|
|
|
9
9
|
### DebugPrint.**print**
|
|
10
10
|
|
|
11
11
|
```grain
|
|
12
|
-
print
|
|
12
|
+
print: (s: String) => Void
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
### DebugPrint.**printI32**
|
|
16
16
|
|
|
17
17
|
```grain
|
|
18
|
-
printI32
|
|
18
|
+
printI32: (val: WasmI32) => Void
|
|
19
19
|
```
|
|
20
20
|
|
|
21
21
|
### DebugPrint.**printI64**
|
|
22
22
|
|
|
23
23
|
```grain
|
|
24
|
-
printI64
|
|
24
|
+
printI64: (val: WasmI64) => Void
|
|
25
25
|
```
|
|
26
26
|
|
|
27
27
|
### DebugPrint.**printF32**
|
|
28
28
|
|
|
29
29
|
```grain
|
|
30
|
-
printF32
|
|
30
|
+
printF32: (val: WasmF32) => Void
|
|
31
31
|
```
|
|
32
32
|
|
|
33
33
|
### DebugPrint.**printF64**
|
|
34
34
|
|
|
35
35
|
```grain
|
|
36
|
-
printF64
|
|
36
|
+
printF64: (val: WasmF64) => Void
|
|
37
37
|
```
|
|
38
38
|
|
|
39
39
|
### DebugPrint.**toStringI32**
|
|
40
40
|
|
|
41
41
|
```grain
|
|
42
|
-
toStringI32
|
|
42
|
+
toStringI32: (val: WasmI32) => String
|
|
43
43
|
```
|
|
44
44
|
|
|
45
45
|
### DebugPrint.**toStringI64**
|
|
46
46
|
|
|
47
47
|
```grain
|
|
48
|
-
toStringI64
|
|
48
|
+
toStringI64: (val: WasmI64) => String
|
|
49
49
|
```
|
|
50
50
|
|
|
51
51
|
### DebugPrint.**toStringF32**
|
|
52
52
|
|
|
53
53
|
```grain
|
|
54
|
-
toStringF32
|
|
54
|
+
toStringF32: (val: WasmF32) => String
|
|
55
55
|
```
|
|
56
56
|
|
|
57
57
|
### DebugPrint.**toStringF64**
|
|
58
58
|
|
|
59
59
|
```grain
|
|
60
|
-
toStringF64
|
|
60
|
+
toStringF64: (val: WasmF64) => String
|
|
61
61
|
```
|
|
62
62
|
|
package/runtime/equal.gr
CHANGED
|
@@ -3,7 +3,19 @@ module Equal
|
|
|
3
3
|
|
|
4
4
|
from "runtime/unsafe/memory" include Memory
|
|
5
5
|
from "runtime/unsafe/wasmi32" include WasmI32
|
|
6
|
-
use WasmI32.{
|
|
6
|
+
use WasmI32.{
|
|
7
|
+
(==),
|
|
8
|
+
(!=),
|
|
9
|
+
(&),
|
|
10
|
+
(^),
|
|
11
|
+
(+),
|
|
12
|
+
(-),
|
|
13
|
+
(*),
|
|
14
|
+
(<),
|
|
15
|
+
remS as (%),
|
|
16
|
+
(<<),
|
|
17
|
+
(>>),
|
|
18
|
+
}
|
|
7
19
|
from "runtime/unsafe/wasmi64" include WasmI64
|
|
8
20
|
from "runtime/unsafe/wasmf32" include WasmF32
|
|
9
21
|
from "runtime/unsafe/tags" include Tags
|
|
@@ -14,6 +26,10 @@ primitive (!) = "@not"
|
|
|
14
26
|
primitive (||) = "@or"
|
|
15
27
|
primitive (&&) = "@and"
|
|
16
28
|
primitive ignore = "@ignore"
|
|
29
|
+
primitive builtinId = "@builtin.id"
|
|
30
|
+
|
|
31
|
+
@unsafe
|
|
32
|
+
let _LIST_ID = WasmI32.fromGrain(builtinId("List"))
|
|
17
33
|
|
|
18
34
|
@unsafe
|
|
19
35
|
let cycleMarker = 0x80000000n
|
|
@@ -23,38 +39,47 @@ let rec heapEqualHelp = (heapTag, xptr, yptr) => {
|
|
|
23
39
|
match (heapTag) {
|
|
24
40
|
t when t == Tags._GRAIN_ADT_HEAP_TAG => {
|
|
25
41
|
// Check if the same constructor variant
|
|
26
|
-
|
|
27
|
-
|
|
42
|
+
let mut xVariantTag = WasmI32.load(xptr, 12n)
|
|
43
|
+
let mut yVariantTag = WasmI32.load(yptr, 12n)
|
|
44
|
+
if (xVariantTag != yVariantTag) {
|
|
45
|
+
return false
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Handle lists separately to avoid stack overflow
|
|
49
|
+
if (WasmI32.load(xptr, 8n) == _LIST_ID) {
|
|
50
|
+
if (xVariantTag >> 1n == 1n) return true // End of list
|
|
51
|
+
|
|
52
|
+
if (!equalHelp(WasmI32.load(xptr, 20n), WasmI32.load(yptr, 20n))) {
|
|
53
|
+
return false
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return equalHelp(WasmI32.load(xptr, 24n), WasmI32.load(yptr, 24n))
|
|
28
57
|
} else {
|
|
29
58
|
let xarity = WasmI32.load(xptr, 16n)
|
|
30
59
|
let yarity = WasmI32.load(yptr, 16n)
|
|
31
60
|
|
|
32
61
|
// Cycle check
|
|
33
62
|
if ((xarity & cycleMarker) == cycleMarker) {
|
|
34
|
-
true
|
|
35
|
-
}
|
|
36
|
-
WasmI32.store(xptr, xarity ^ cycleMarker, 16n)
|
|
37
|
-
WasmI32.store(yptr, yarity ^ cycleMarker, 16n)
|
|
38
|
-
|
|
39
|
-
let mut result = true
|
|
40
|
-
|
|
41
|
-
let bytes = xarity * 4n
|
|
42
|
-
for (let mut i = 0n; i < bytes; i += 4n) {
|
|
43
|
-
if (
|
|
44
|
-
!equalHelp(
|
|
45
|
-
WasmI32.load(xptr + i, 20n),
|
|
46
|
-
WasmI32.load(yptr + i, 20n)
|
|
47
|
-
)
|
|
48
|
-
) {
|
|
49
|
-
result = false
|
|
50
|
-
break
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
WasmI32.store(xptr, xarity, 16n)
|
|
54
|
-
WasmI32.store(yptr, yarity, 16n)
|
|
63
|
+
return true
|
|
64
|
+
}
|
|
55
65
|
|
|
56
|
-
|
|
66
|
+
WasmI32.store(xptr, xarity ^ cycleMarker, 16n)
|
|
67
|
+
WasmI32.store(yptr, yarity ^ cycleMarker, 16n)
|
|
68
|
+
|
|
69
|
+
let bytes = xarity * 4n
|
|
70
|
+
for (let mut i = 0n; i < bytes; i += 4n) {
|
|
71
|
+
if (
|
|
72
|
+
!equalHelp(WasmI32.load(xptr + i, 20n), WasmI32.load(yptr + i, 20n))
|
|
73
|
+
) {
|
|
74
|
+
WasmI32.store(xptr, xarity, 16n)
|
|
75
|
+
WasmI32.store(yptr, yarity, 16n)
|
|
76
|
+
return false
|
|
77
|
+
}
|
|
57
78
|
}
|
|
79
|
+
WasmI32.store(xptr, xarity, 16n)
|
|
80
|
+
WasmI32.store(yptr, yarity, 16n)
|
|
81
|
+
|
|
82
|
+
return true
|
|
58
83
|
}
|
|
59
84
|
},
|
|
60
85
|
t when t == Tags._GRAIN_RECORD_HEAP_TAG => {
|
|
@@ -63,27 +88,26 @@ let rec heapEqualHelp = (heapTag, xptr, yptr) => {
|
|
|
63
88
|
|
|
64
89
|
// Cycle check
|
|
65
90
|
if ((xlength & cycleMarker) == cycleMarker) {
|
|
66
|
-
true
|
|
67
|
-
}
|
|
68
|
-
WasmI32.store(xptr, xlength ^ cycleMarker, 12n)
|
|
69
|
-
WasmI32.store(yptr, ylength ^ cycleMarker, 12n)
|
|
70
|
-
|
|
71
|
-
let mut result = true
|
|
91
|
+
return true
|
|
92
|
+
}
|
|
72
93
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
94
|
+
WasmI32.store(xptr, xlength ^ cycleMarker, 12n)
|
|
95
|
+
WasmI32.store(yptr, ylength ^ cycleMarker, 12n)
|
|
96
|
+
|
|
97
|
+
let bytes = xlength * 4n
|
|
98
|
+
for (let mut i = 0n; i < bytes; i += 4n) {
|
|
99
|
+
if (
|
|
100
|
+
!equalHelp(WasmI32.load(xptr + i, 16n), WasmI32.load(yptr + i, 16n))
|
|
101
|
+
) {
|
|
102
|
+
WasmI32.store(xptr, xlength, 12n)
|
|
103
|
+
WasmI32.store(yptr, ylength, 12n)
|
|
104
|
+
return false
|
|
81
105
|
}
|
|
82
|
-
WasmI32.store(xptr, xlength, 12n)
|
|
83
|
-
WasmI32.store(yptr, ylength, 12n)
|
|
84
|
-
|
|
85
|
-
result
|
|
86
106
|
}
|
|
107
|
+
WasmI32.store(xptr, xlength, 12n)
|
|
108
|
+
WasmI32.store(yptr, ylength, 12n)
|
|
109
|
+
|
|
110
|
+
return true
|
|
87
111
|
},
|
|
88
112
|
t when t == Tags._GRAIN_ARRAY_HEAP_TAG => {
|
|
89
113
|
let xlength = WasmI32.load(xptr, 4n)
|
|
@@ -91,37 +115,37 @@ let rec heapEqualHelp = (heapTag, xptr, yptr) => {
|
|
|
91
115
|
|
|
92
116
|
// Check if the same length
|
|
93
117
|
if (xlength != ylength) {
|
|
94
|
-
false
|
|
95
|
-
}
|
|
96
|
-
// Cycle check
|
|
97
|
-
true
|
|
98
|
-
} else {
|
|
99
|
-
WasmI32.store(xptr, xlength ^ cycleMarker, 4n)
|
|
100
|
-
WasmI32.store(yptr, ylength ^ cycleMarker, 4n)
|
|
118
|
+
return false
|
|
119
|
+
}
|
|
101
120
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
!equalHelp(WasmI32.load(xptr + i, 8n), WasmI32.load(yptr + i, 8n))
|
|
107
|
-
) {
|
|
108
|
-
result = false
|
|
109
|
-
break
|
|
110
|
-
}
|
|
111
|
-
}
|
|
121
|
+
// Cycle check
|
|
122
|
+
if ((xlength & cycleMarker) == cycleMarker) {
|
|
123
|
+
return true
|
|
124
|
+
}
|
|
112
125
|
|
|
113
|
-
|
|
114
|
-
|
|
126
|
+
WasmI32.store(xptr, xlength ^ cycleMarker, 4n)
|
|
127
|
+
WasmI32.store(yptr, ylength ^ cycleMarker, 4n)
|
|
115
128
|
|
|
116
|
-
|
|
129
|
+
let bytes = xlength * 4n
|
|
130
|
+
for (let mut i = 0n; i < bytes; i += 4n) {
|
|
131
|
+
if (!equalHelp(WasmI32.load(xptr + i, 8n), WasmI32.load(yptr + i, 8n))) {
|
|
132
|
+
WasmI32.store(xptr, xlength, 4n)
|
|
133
|
+
WasmI32.store(yptr, ylength, 4n)
|
|
134
|
+
return false
|
|
135
|
+
}
|
|
117
136
|
}
|
|
137
|
+
|
|
138
|
+
WasmI32.store(xptr, xlength, 4n)
|
|
139
|
+
WasmI32.store(yptr, ylength, 4n)
|
|
140
|
+
|
|
141
|
+
return true
|
|
118
142
|
},
|
|
119
143
|
t when t == Tags._GRAIN_STRING_HEAP_TAG || t == Tags._GRAIN_BYTES_HEAP_TAG => {
|
|
120
144
|
let xlength = WasmI32.load(xptr, 4n)
|
|
121
145
|
let ylength = WasmI32.load(yptr, 4n)
|
|
122
146
|
|
|
123
147
|
// Check if the same length
|
|
124
|
-
if (xlength != ylength) {
|
|
148
|
+
return if (xlength != ylength) {
|
|
125
149
|
false
|
|
126
150
|
} else {
|
|
127
151
|
Memory.compare(xptr + 8n, yptr + 8n, xlength) == 0n
|
|
@@ -132,50 +156,48 @@ let rec heapEqualHelp = (heapTag, xptr, yptr) => {
|
|
|
132
156
|
let ysize = WasmI32.load(yptr, 4n)
|
|
133
157
|
|
|
134
158
|
if ((xsize & cycleMarker) == cycleMarker) {
|
|
135
|
-
true
|
|
159
|
+
return true
|
|
136
160
|
} else {
|
|
137
161
|
WasmI32.store(xptr, xsize ^ cycleMarker, 4n)
|
|
138
162
|
WasmI32.store(yptr, ysize ^ cycleMarker, 4n)
|
|
139
163
|
|
|
140
|
-
let mut result = true
|
|
141
164
|
let bytes = xsize * 4n
|
|
142
165
|
for (let mut i = 0n; i < bytes; i += 4n) {
|
|
143
166
|
if (
|
|
144
167
|
!equalHelp(WasmI32.load(xptr + i, 8n), WasmI32.load(yptr + i, 8n))
|
|
145
168
|
) {
|
|
146
|
-
|
|
147
|
-
|
|
169
|
+
WasmI32.store(xptr, xsize, 4n)
|
|
170
|
+
WasmI32.store(yptr, ysize, 4n)
|
|
171
|
+
return false
|
|
148
172
|
}
|
|
149
173
|
}
|
|
150
174
|
|
|
151
175
|
WasmI32.store(xptr, xsize, 4n)
|
|
152
176
|
WasmI32.store(yptr, ysize, 4n)
|
|
153
177
|
|
|
154
|
-
|
|
178
|
+
return true
|
|
155
179
|
}
|
|
156
180
|
},
|
|
157
181
|
t when t == Tags._GRAIN_UINT32_HEAP_TAG || t == Tags._GRAIN_INT32_HEAP_TAG => {
|
|
158
182
|
let xval = WasmI32.load(xptr, 4n)
|
|
159
183
|
let yval = WasmI32.load(yptr, 4n)
|
|
160
|
-
xval == yval
|
|
184
|
+
return xval == yval
|
|
161
185
|
},
|
|
162
186
|
// Float32 is handled by equalHelp directly
|
|
163
187
|
t when t == Tags._GRAIN_UINT64_HEAP_TAG => {
|
|
164
188
|
use WasmI64.{ (==) }
|
|
165
189
|
let xval = WasmI64.load(xptr, 8n)
|
|
166
190
|
let yval = WasmI64.load(yptr, 8n)
|
|
167
|
-
xval == yval
|
|
168
|
-
},
|
|
169
|
-
_ => {
|
|
170
|
-
// No other implementation
|
|
171
|
-
xptr == yptr
|
|
191
|
+
return xval == yval
|
|
172
192
|
},
|
|
193
|
+
// No other implementation
|
|
194
|
+
_ => return xptr == yptr,
|
|
173
195
|
}
|
|
174
196
|
}
|
|
175
197
|
and equalHelp = (x, y) => {
|
|
176
198
|
if (
|
|
177
|
-
(x & Tags._GRAIN_GENERIC_TAG_MASK) != 0n
|
|
178
|
-
(y & Tags._GRAIN_GENERIC_TAG_MASK) != 0n
|
|
199
|
+
(x & Tags._GRAIN_GENERIC_TAG_MASK) != 0n
|
|
200
|
+
&& (y & Tags._GRAIN_GENERIC_TAG_MASK) != 0n
|
|
179
201
|
) {
|
|
180
202
|
// Short circuit for non-pointer values
|
|
181
203
|
x == y
|
package/runtime/equal.md
CHANGED
|
@@ -14,7 +14,7 @@ No other changes yet.
|
|
|
14
14
|
</details>
|
|
15
15
|
|
|
16
16
|
```grain
|
|
17
|
-
equal
|
|
17
|
+
equal: (value1: a, value2: a) => Bool
|
|
18
18
|
```
|
|
19
19
|
|
|
20
20
|
Check that two values are equal. This checks for structural equality,
|
|
@@ -22,14 +22,14 @@ so it also works for comparing things like tuples and lists.
|
|
|
22
22
|
|
|
23
23
|
Parameters:
|
|
24
24
|
|
|
25
|
-
|param|type|description|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
| param | type | description |
|
|
26
|
+
| -------- | ---- | ------------------ |
|
|
27
|
+
| `value1` | `a` | The first operand |
|
|
28
|
+
| `value2` | `a` | The second operand |
|
|
29
29
|
|
|
30
30
|
Returns:
|
|
31
31
|
|
|
32
|
-
|type|description|
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
| type | description |
|
|
33
|
+
| ------ | ---------------------------------------------------------------- |
|
|
34
|
+
| `Bool` | `true` if the values are structurally equal or `false` otherwise |
|
|
35
35
|
|
package/runtime/exception.gr
CHANGED
|
@@ -1,96 +1,76 @@
|
|
|
1
|
-
@
|
|
1
|
+
@noPervasives
|
|
2
|
+
// Prevent this module from depending on itself
|
|
3
|
+
@noExceptions
|
|
2
4
|
module Exception
|
|
3
5
|
|
|
4
|
-
from "runtime/unsafe/
|
|
5
|
-
use WasmI32.{ (==), (+), (-) }
|
|
6
|
-
|
|
7
|
-
foreign wasm fd_write:
|
|
8
|
-
(WasmI32, WasmI32, WasmI32, WasmI32) => WasmI32 from "wasi_snapshot_preview1"
|
|
9
|
-
|
|
10
|
-
primitive unreachable = "@unreachable"
|
|
11
|
-
|
|
12
|
-
provide let mut printers = 0n
|
|
13
|
-
|
|
14
|
-
// These functions are dangerous because they leak runtime memory and perform
|
|
15
|
-
// no GC operations. As such, they should only be called by this module and/or
|
|
16
|
-
// modules that understand these restrictions, namely Pervasives.
|
|
17
|
-
|
|
18
|
-
provide let dangerouslyRegisterBasePrinter = f => {
|
|
19
|
-
let mut current = printers
|
|
20
|
-
while (true) {
|
|
21
|
-
// There will be at least one printer registered by the time this is called
|
|
22
|
-
let (_, next) = WasmI32.toGrain(current):
|
|
23
|
-
(Exception => Option<String>, WasmI32)
|
|
24
|
-
if (next == 0n) {
|
|
25
|
-
// Using a tuple in runtime mode is typically disallowed as there is no way
|
|
26
|
-
// to reclaim the memory, but this function is only called once
|
|
27
|
-
let newBase = (WasmI32.fromGrain(f), 0n)
|
|
28
|
-
WasmI32.store(current, WasmI32.fromGrain(newBase), 12n)
|
|
29
|
-
break
|
|
30
|
-
}
|
|
31
|
-
current = next
|
|
32
|
-
}
|
|
33
|
-
// We don't decRef the closure or arguments here to avoid a cyclic dep. on Memory.
|
|
34
|
-
// This is fine, as this function should only be called once.
|
|
35
|
-
void
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
provide let dangerouslyRegisterPrinter = f => {
|
|
39
|
-
printers = WasmI32.fromGrain((f, printers))
|
|
40
|
-
// We don't decRef the closure or arguments here to avoid a cyclic dep. on Memory.
|
|
41
|
-
// This is fine, as this function is only called seldomly.
|
|
42
|
-
void
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// avoid cirular dependency on gc
|
|
46
|
-
let incRef = v => {
|
|
47
|
-
let ptr = WasmI32.fromGrain(v) - 8n
|
|
48
|
-
WasmI32.store(ptr, WasmI32.load(ptr, 0n) + 1n, 0n)
|
|
49
|
-
v
|
|
50
|
-
}
|
|
6
|
+
from "runtime/unsafe/panic" include Panic
|
|
51
7
|
|
|
52
8
|
let _GENERIC_EXCEPTION_NAME = "GrainException"
|
|
53
|
-
|
|
54
|
-
let
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
9
|
+
let mut basePrinter = None
|
|
10
|
+
let mut printers = []
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Registers a base exception printer. If no other exception printers are
|
|
14
|
+
* registered, the base printer is used to convert an exception to a string.
|
|
15
|
+
*
|
|
16
|
+
* @param printer: The base exception printer to register
|
|
17
|
+
*
|
|
18
|
+
* @since v0.7.0
|
|
19
|
+
*/
|
|
20
|
+
provide let registerBasePrinter = (printer: Exception => String) =>
|
|
21
|
+
basePrinter = Some(printer)
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Registers an exception printer. When an exception is thrown, all registered
|
|
25
|
+
* printers are called in order from the most recently registered printer to
|
|
26
|
+
* the least recently registered printer. The first `Some` value returned is
|
|
27
|
+
* used as the exception's string value.
|
|
28
|
+
*
|
|
29
|
+
* @param printer: The exception printer to register
|
|
30
|
+
*
|
|
31
|
+
* @since v0.7.0
|
|
32
|
+
*/
|
|
33
|
+
provide let registerPrinter = (printer: Exception => Option<String>) =>
|
|
34
|
+
printers = [printer, ...printers]
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Gets the string representation of the given exception.
|
|
38
|
+
*
|
|
39
|
+
* @param e: The exception to stringify
|
|
40
|
+
*
|
|
41
|
+
* @returns The string representation of the exception
|
|
42
|
+
*
|
|
43
|
+
* @since v0.7.0
|
|
44
|
+
*/
|
|
45
|
+
provide let toString = (e: Exception) => {
|
|
46
|
+
let rec exceptionToString = (e, printers) => {
|
|
47
|
+
match (printers) {
|
|
48
|
+
[] => match (basePrinter) {
|
|
49
|
+
Some(f) => f(e),
|
|
50
|
+
None => _GENERIC_EXCEPTION_NAME,
|
|
51
|
+
},
|
|
52
|
+
[printer, ...rest] => {
|
|
53
|
+
match (printer(e)) {
|
|
54
|
+
Some(s) => s,
|
|
55
|
+
None => exceptionToString(e, rest),
|
|
56
|
+
}
|
|
66
57
|
},
|
|
67
58
|
}
|
|
68
59
|
}
|
|
69
|
-
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// HACK: Allocate static buffer for printing (40 bytes)
|
|
73
|
-
// Would be nice to have a better way to allocate a static block from
|
|
74
|
-
// the runtime heap, but this is the only module that needs to do it
|
|
75
|
-
let iov = WasmI32.fromGrain([> 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n])
|
|
76
|
-
|
|
77
|
-
provide let panic = (msg: String) => {
|
|
78
|
-
let ptr = WasmI32.fromGrain(msg)
|
|
79
|
-
let written = iov + 32n
|
|
80
|
-
let lf = iov + 36n
|
|
81
|
-
WasmI32.store(iov, ptr + 8n, 0n)
|
|
82
|
-
WasmI32.store(iov, WasmI32.load(ptr, 4n), 4n)
|
|
83
|
-
WasmI32.store8(lf, 10n, 0n)
|
|
84
|
-
WasmI32.store(iov, lf, 8n)
|
|
85
|
-
WasmI32.store(iov, 1n, 12n)
|
|
86
|
-
fd_write(2n, iov, 2n, written)
|
|
87
|
-
unreachable()
|
|
60
|
+
exceptionToString(e, printers)
|
|
88
61
|
}
|
|
89
62
|
|
|
63
|
+
/**
|
|
64
|
+
* Throws an uncatchable exception and traps.
|
|
65
|
+
*
|
|
66
|
+
* @param e: The exception to throw
|
|
67
|
+
*/
|
|
90
68
|
provide let panicWithException = (e: Exception) => {
|
|
91
|
-
panic(
|
|
69
|
+
Panic.panic(toString(e))
|
|
92
70
|
}
|
|
93
71
|
|
|
72
|
+
// Runtime exceptions
|
|
73
|
+
|
|
94
74
|
provide exception DivisionByZero
|
|
95
75
|
provide exception ModuloByZero
|
|
96
76
|
provide exception Overflow
|
|
@@ -126,4 +106,4 @@ let runtimeErrorPrinter = e => {
|
|
|
126
106
|
}
|
|
127
107
|
}
|
|
128
108
|
|
|
129
|
-
|
|
109
|
+
registerPrinter(runtimeErrorPrinter)
|
package/runtime/exception.md
CHANGED
|
@@ -6,33 +6,84 @@ title: Exception
|
|
|
6
6
|
|
|
7
7
|
Functions and constants included in the Exception module.
|
|
8
8
|
|
|
9
|
-
### Exception.**
|
|
9
|
+
### Exception.**registerBasePrinter**
|
|
10
|
+
|
|
11
|
+
<details disabled>
|
|
12
|
+
<summary tabindex="-1">Added in <code>0.7.0</code></summary>
|
|
13
|
+
No other changes yet.
|
|
14
|
+
</details>
|
|
10
15
|
|
|
11
16
|
```grain
|
|
12
|
-
|
|
17
|
+
registerBasePrinter: (printer: (Exception => String)) => Void
|
|
13
18
|
```
|
|
14
19
|
|
|
15
|
-
|
|
20
|
+
Registers a base exception printer. If no other exception printers are
|
|
21
|
+
registered, the base printer is used to convert an exception to a string.
|
|
16
22
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
23
|
+
Parameters:
|
|
24
|
+
|
|
25
|
+
| param | type | description |
|
|
26
|
+
| --------- | --------------------- | -------------------------------------- |
|
|
27
|
+
| `printer` | `Exception => String` | The base exception printer to register |
|
|
28
|
+
|
|
29
|
+
### Exception.**registerPrinter**
|
|
20
30
|
|
|
21
|
-
|
|
31
|
+
<details disabled>
|
|
32
|
+
<summary tabindex="-1">Added in <code>0.7.0</code></summary>
|
|
33
|
+
No other changes yet.
|
|
34
|
+
</details>
|
|
22
35
|
|
|
23
36
|
```grain
|
|
24
|
-
|
|
37
|
+
registerPrinter: (printer: (Exception => Option<String>)) => Void
|
|
25
38
|
```
|
|
26
39
|
|
|
27
|
-
|
|
40
|
+
Registers an exception printer. When an exception is thrown, all registered
|
|
41
|
+
printers are called in order from the most recently registered printer to
|
|
42
|
+
the least recently registered printer. The first `Some` value returned is
|
|
43
|
+
used as the exception's string value.
|
|
44
|
+
|
|
45
|
+
Parameters:
|
|
46
|
+
|
|
47
|
+
| param | type | description |
|
|
48
|
+
| --------- | ----------------------------- | --------------------------------- |
|
|
49
|
+
| `printer` | `Exception => Option<String>` | The exception printer to register |
|
|
50
|
+
|
|
51
|
+
### Exception.**toString**
|
|
52
|
+
|
|
53
|
+
<details disabled>
|
|
54
|
+
<summary tabindex="-1">Added in <code>0.7.0</code></summary>
|
|
55
|
+
No other changes yet.
|
|
56
|
+
</details>
|
|
28
57
|
|
|
29
58
|
```grain
|
|
30
|
-
|
|
59
|
+
toString: (e: Exception) => String
|
|
31
60
|
```
|
|
32
61
|
|
|
62
|
+
Gets the string representation of the given exception.
|
|
63
|
+
|
|
64
|
+
Parameters:
|
|
65
|
+
|
|
66
|
+
| param | type | description |
|
|
67
|
+
| ----- | ----------- | -------------------------- |
|
|
68
|
+
| `e` | `Exception` | The exception to stringify |
|
|
69
|
+
|
|
70
|
+
Returns:
|
|
71
|
+
|
|
72
|
+
| type | description |
|
|
73
|
+
| -------- | ------------------------------------------ |
|
|
74
|
+
| `String` | The string representation of the exception |
|
|
75
|
+
|
|
33
76
|
### Exception.**panicWithException**
|
|
34
77
|
|
|
35
78
|
```grain
|
|
36
|
-
panicWithException
|
|
79
|
+
panicWithException: (e: Exception) => a
|
|
37
80
|
```
|
|
38
81
|
|
|
82
|
+
Throws an uncatchable exception and traps.
|
|
83
|
+
|
|
84
|
+
Parameters:
|
|
85
|
+
|
|
86
|
+
| param | type | description |
|
|
87
|
+
| ----- | ----------- | ---------------------- |
|
|
88
|
+
| `e` | `Exception` | The exception to throw |
|
|
89
|
+
|