@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.
Files changed (137) hide show
  1. package/CHANGELOG.md +67 -0
  2. package/LICENSE +1 -1
  3. package/README.md +2 -2
  4. package/array.gr +55 -7
  5. package/array.md +606 -560
  6. package/bigint.md +228 -228
  7. package/buffer.gr +85 -53
  8. package/buffer.md +442 -319
  9. package/bytes.gr +112 -35
  10. package/bytes.md +299 -219
  11. package/char.gr +201 -99
  12. package/char.md +447 -120
  13. package/exception.gr +11 -11
  14. package/exception.md +29 -4
  15. package/float32.gr +327 -3
  16. package/float32.md +698 -111
  17. package/float64.gr +320 -3
  18. package/float64.md +698 -111
  19. package/fs.gr +1082 -0
  20. package/fs.md +630 -0
  21. package/hash.gr +142 -88
  22. package/hash.md +105 -17
  23. package/int16.md +178 -178
  24. package/int32.gr +26 -5
  25. package/int32.md +266 -231
  26. package/int64.gr +27 -2
  27. package/int64.md +266 -231
  28. package/int8.md +178 -178
  29. package/json.gr +366 -51
  30. package/json.md +431 -15
  31. package/list.gr +328 -31
  32. package/list.md +759 -336
  33. package/map.gr +20 -12
  34. package/map.md +266 -260
  35. package/marshal.gr +41 -40
  36. package/marshal.md +14 -14
  37. package/number.gr +278 -35
  38. package/number.md +688 -269
  39. package/option.md +162 -162
  40. package/package.json +5 -3
  41. package/path.gr +48 -0
  42. package/path.md +180 -89
  43. package/pervasives.gr +2 -2
  44. package/pervasives.md +275 -275
  45. package/priorityqueue.gr +7 -7
  46. package/priorityqueue.md +131 -131
  47. package/queue.gr +183 -29
  48. package/queue.md +404 -148
  49. package/random.md +43 -43
  50. package/range.gr +4 -4
  51. package/range.md +42 -42
  52. package/rational.md +123 -123
  53. package/regex.gr +52 -51
  54. package/regex.md +102 -102
  55. package/result.md +118 -118
  56. package/runtime/atof/common.md +39 -39
  57. package/runtime/atof/decimal.gr +6 -6
  58. package/runtime/atof/decimal.md +14 -14
  59. package/runtime/atof/lemire.gr +5 -5
  60. package/runtime/atof/lemire.md +1 -1
  61. package/runtime/atof/parse.gr +16 -16
  62. package/runtime/atof/parse.md +2 -2
  63. package/runtime/atof/slow.md +1 -1
  64. package/runtime/atof/table.md +2 -2
  65. package/runtime/atoi/parse.gr +3 -3
  66. package/runtime/atoi/parse.md +1 -1
  67. package/runtime/bigint.gr +15 -47
  68. package/runtime/bigint.md +54 -60
  69. package/runtime/compare.gr +2 -2
  70. package/runtime/compare.md +8 -8
  71. package/runtime/dataStructures.md +211 -211
  72. package/runtime/debugPrint.gr +4 -1
  73. package/runtime/debugPrint.md +9 -9
  74. package/runtime/equal.gr +99 -77
  75. package/runtime/equal.md +8 -8
  76. package/runtime/exception.gr +62 -82
  77. package/runtime/exception.md +62 -11
  78. package/runtime/gc.gr +39 -45
  79. package/runtime/gc.md +4 -4
  80. package/runtime/malloc.gr +7 -7
  81. package/runtime/malloc.md +13 -13
  82. package/runtime/math/kernel/cos.gr +70 -0
  83. package/runtime/math/kernel/cos.md +14 -0
  84. package/runtime/math/kernel/sin.gr +65 -0
  85. package/runtime/math/kernel/sin.md +14 -0
  86. package/runtime/math/kernel/tan.gr +136 -0
  87. package/runtime/math/kernel/tan.md +14 -0
  88. package/runtime/math/rempio2.gr +244 -0
  89. package/runtime/math/rempio2.md +14 -0
  90. package/runtime/math/trig.gr +130 -0
  91. package/runtime/math/trig.md +28 -0
  92. package/runtime/math/umuldi.gr +26 -0
  93. package/runtime/math/umuldi.md +14 -0
  94. package/runtime/numberUtils.gr +29 -29
  95. package/runtime/numberUtils.md +12 -12
  96. package/runtime/numbers.gr +373 -381
  97. package/runtime/numbers.md +348 -342
  98. package/runtime/string.gr +37 -105
  99. package/runtime/string.md +20 -26
  100. package/runtime/unsafe/constants.md +24 -24
  101. package/runtime/unsafe/conv.md +19 -19
  102. package/runtime/unsafe/memory.gr +24 -20
  103. package/runtime/unsafe/memory.md +27 -7
  104. package/runtime/unsafe/offsets.gr +36 -0
  105. package/runtime/unsafe/offsets.md +88 -0
  106. package/runtime/unsafe/panic.gr +28 -0
  107. package/runtime/unsafe/panic.md +14 -0
  108. package/runtime/unsafe/tags.md +32 -32
  109. package/runtime/unsafe/wasmf32.md +28 -28
  110. package/runtime/unsafe/wasmf64.md +28 -28
  111. package/runtime/unsafe/wasmi32.md +47 -47
  112. package/runtime/unsafe/wasmi64.md +50 -50
  113. package/runtime/utf8.gr +189 -0
  114. package/runtime/utf8.md +117 -0
  115. package/runtime/wasi.gr +4 -2
  116. package/runtime/wasi.md +147 -147
  117. package/set.gr +18 -11
  118. package/set.md +253 -247
  119. package/stack.gr +171 -2
  120. package/stack.md +371 -89
  121. package/string.gr +352 -557
  122. package/string.md +298 -255
  123. package/uint16.md +170 -170
  124. package/uint32.gr +25 -4
  125. package/uint32.md +249 -214
  126. package/uint64.gr +25 -5
  127. package/uint64.md +249 -214
  128. package/uint8.md +170 -170
  129. package/uri.gr +57 -53
  130. package/uri.md +88 -89
  131. package/wasi/file.gr +67 -59
  132. package/wasi/file.md +308 -308
  133. package/wasi/process.md +26 -26
  134. package/wasi/random.md +12 -12
  135. package/wasi/time.md +16 -16
  136. package/runtime/utils/printing.gr +0 -60
  137. package/runtime/utils/printing.md +0 -26
@@ -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
- void
32
+ ignore(s)
30
33
  }
31
34
 
32
35
  @unsafe
@@ -9,54 +9,54 @@ Functions and constants included in the DebugPrint module.
9
9
  ### DebugPrint.**print**
10
10
 
11
11
  ```grain
12
- print : (s: String) => Void
12
+ print: (s: String) => Void
13
13
  ```
14
14
 
15
15
  ### DebugPrint.**printI32**
16
16
 
17
17
  ```grain
18
- printI32 : (val: WasmI32) => Void
18
+ printI32: (val: WasmI32) => Void
19
19
  ```
20
20
 
21
21
  ### DebugPrint.**printI64**
22
22
 
23
23
  ```grain
24
- printI64 : (val: WasmI64) => Void
24
+ printI64: (val: WasmI64) => Void
25
25
  ```
26
26
 
27
27
  ### DebugPrint.**printF32**
28
28
 
29
29
  ```grain
30
- printF32 : (val: WasmF32) => Void
30
+ printF32: (val: WasmF32) => Void
31
31
  ```
32
32
 
33
33
  ### DebugPrint.**printF64**
34
34
 
35
35
  ```grain
36
- printF64 : (val: WasmF64) => Void
36
+ printF64: (val: WasmF64) => Void
37
37
  ```
38
38
 
39
39
  ### DebugPrint.**toStringI32**
40
40
 
41
41
  ```grain
42
- toStringI32 : (val: WasmI32) => String
42
+ toStringI32: (val: WasmI32) => String
43
43
  ```
44
44
 
45
45
  ### DebugPrint.**toStringI64**
46
46
 
47
47
  ```grain
48
- toStringI64 : (val: WasmI64) => String
48
+ toStringI64: (val: WasmI64) => String
49
49
  ```
50
50
 
51
51
  ### DebugPrint.**toStringF32**
52
52
 
53
53
  ```grain
54
- toStringF32 : (val: WasmF32) => String
54
+ toStringF32: (val: WasmF32) => String
55
55
  ```
56
56
 
57
57
  ### DebugPrint.**toStringF64**
58
58
 
59
59
  ```grain
60
- toStringF64 : (val: WasmF64) => String
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.{ (==), (!=), (&), (^), (+), (-), (*), (<), remS as (%), (<<) }
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
- if (WasmI32.load(xptr, 12n) != WasmI32.load(yptr, 12n)) {
27
- false
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
- } else {
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
- result
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
- } else {
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
- let bytes = xlength * 4n
74
- for (let mut i = 0n; i < bytes; i += 4n) {
75
- if (
76
- !equalHelp(WasmI32.load(xptr + i, 16n), WasmI32.load(yptr + i, 16n))
77
- ) {
78
- result = false
79
- break
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
- } else if ((xlength & cycleMarker) == cycleMarker) {
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
- let mut result = true
103
- let bytes = xlength * 4n
104
- for (let mut i = 0n; i < bytes; i += 4n) {
105
- if (
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
- WasmI32.store(xptr, xlength, 4n)
114
- WasmI32.store(yptr, ylength, 4n)
126
+ WasmI32.store(xptr, xlength ^ cycleMarker, 4n)
127
+ WasmI32.store(yptr, ylength ^ cycleMarker, 4n)
115
128
 
116
- result
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
- result = false
147
- break
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
- result
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 : (value1: a, value2: a) => Bool
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
- |`value1`|`a`|The first operand|
28
- |`value2`|`a`|The second operand|
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
- |`Bool`|`true` if the values are structurally equal or `false` otherwise|
32
+ | type | description |
33
+ | ------ | ---------------------------------------------------------------- |
34
+ | `Bool` | `true` if the values are structurally equal or `false` otherwise |
35
35
 
@@ -1,96 +1,76 @@
1
- @runtimeMode
1
+ @noPervasives
2
+ // Prevent this module from depending on itself
3
+ @noExceptions
2
4
  module Exception
3
5
 
4
- from "runtime/unsafe/wasmi32" include WasmI32
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 exceptionToString = (e: Exception) => {
55
- let mut result = _GENERIC_EXCEPTION_NAME
56
- let mut current = printers
57
- while (true) {
58
- if (current == 0n) return result
59
- let (printer, next) = WasmI32.toGrain(current):
60
- (Exception => Option<String>, WasmI32)
61
- // as GC is not available, manually increment the references
62
- match (incRef(printer)(incRef(e))) {
63
- Some(str) => return str,
64
- None => {
65
- current = next
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
- return result
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(exceptionToString(e))
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
- dangerouslyRegisterPrinter(runtimeErrorPrinter)
109
+ registerPrinter(runtimeErrorPrinter)
@@ -6,33 +6,84 @@ title: Exception
6
6
 
7
7
  Functions and constants included in the Exception module.
8
8
 
9
- ### Exception.**printers**
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
- printers : WasmI32
17
+ registerBasePrinter: (printer: (Exception => String)) => Void
13
18
  ```
14
19
 
15
- ### Exception.**dangerouslyRegisterBasePrinter**
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
- ```grain
18
- dangerouslyRegisterBasePrinter : (f: a) => Void
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
- ### Exception.**dangerouslyRegisterPrinter**
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
- dangerouslyRegisterPrinter : (f: a) => Void
37
+ registerPrinter: (printer: (Exception => Option<String>)) => Void
25
38
  ```
26
39
 
27
- ### Exception.**panic**
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
- panic : (msg: String) => a
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 : (e: Exception) => a
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
+