@grain/stdlib 0.4.3 → 0.4.4
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 +22 -0
- package/array.gr +118 -49
- package/array.md +60 -5
- package/buffer.gr +95 -41
- package/hash.gr +7 -2
- package/list.gr +54 -0
- package/number.gr +24 -6
- package/number.md +32 -0
- package/option.gr +244 -37
- package/option.md +579 -0
- package/package.json +1 -1
- package/queue.gr +98 -29
- package/queue.md +191 -0
- package/range.md +1 -1
- package/regex.md +9 -9
- package/result.gr +216 -70
- package/result.md +446 -0
- package/runtime/stringUtils.gr +172 -0
- package/set.gr +172 -5
- package/set.md +502 -0
- package/string.gr +30 -3
- package/string.md +31 -0
package/result.md
ADDED
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Result
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Utilities for working with the Result data type.
|
|
6
|
+
|
|
7
|
+
The Result type is an enum that represents the possibility of a success case (with the `Ok` variant),
|
|
8
|
+
or an error case (with the `Err` variant). Use a Result as the return type of a function that may return an error.
|
|
9
|
+
|
|
10
|
+
<details disabled>
|
|
11
|
+
<summary tabindex="-1">Added in <code>0.2.0</code></summary>
|
|
12
|
+
No other changes yet.
|
|
13
|
+
</details>
|
|
14
|
+
|
|
15
|
+
```grain
|
|
16
|
+
import Result from "result"
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
```grain
|
|
20
|
+
let success = Ok((x) => 1 + x) // Creates a successful Result containing (x) => 1 + x
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
```grain
|
|
24
|
+
let failure = Err("Something bad happened") // Creates an unsuccessful Result containing "Something bad happened"
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Values
|
|
28
|
+
|
|
29
|
+
Functions for working with the Result data type.
|
|
30
|
+
|
|
31
|
+
### Result.**isOk**
|
|
32
|
+
|
|
33
|
+
<details disabled>
|
|
34
|
+
<summary tabindex="-1">Added in <code>0.2.0</code></summary>
|
|
35
|
+
No other changes yet.
|
|
36
|
+
</details>
|
|
37
|
+
|
|
38
|
+
```grain
|
|
39
|
+
isOk : Result<a, b> -> Bool
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Checks if the Result is the `Ok` variant.
|
|
43
|
+
|
|
44
|
+
Parameters:
|
|
45
|
+
|
|
46
|
+
|param|type|description|
|
|
47
|
+
|-----|----|-----------|
|
|
48
|
+
|`result`|`Result<a, b>`|The result to check|
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
|
|
52
|
+
|type|description|
|
|
53
|
+
|----|-----------|
|
|
54
|
+
|`Bool`|`true` if the Result is the `Ok` variant or `false` otherwise|
|
|
55
|
+
|
|
56
|
+
### Result.**isErr**
|
|
57
|
+
|
|
58
|
+
<details disabled>
|
|
59
|
+
<summary tabindex="-1">Added in <code>0.2.0</code></summary>
|
|
60
|
+
No other changes yet.
|
|
61
|
+
</details>
|
|
62
|
+
|
|
63
|
+
```grain
|
|
64
|
+
isErr : Result<a, b> -> Bool
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Checks if the Result is the `Err` variant.
|
|
68
|
+
|
|
69
|
+
Parameters:
|
|
70
|
+
|
|
71
|
+
|param|type|description|
|
|
72
|
+
|-----|----|-----------|
|
|
73
|
+
|`result`|`Result<a, b>`|The result to check|
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
|
|
77
|
+
|type|description|
|
|
78
|
+
|----|-----------|
|
|
79
|
+
|`Bool`|`true` if the Result is the `Err` variant or `false` otherwise|
|
|
80
|
+
|
|
81
|
+
### Result.**toOption**
|
|
82
|
+
|
|
83
|
+
<details disabled>
|
|
84
|
+
<summary tabindex="-1">Added in <code>0.2.0</code></summary>
|
|
85
|
+
No other changes yet.
|
|
86
|
+
</details>
|
|
87
|
+
|
|
88
|
+
```grain
|
|
89
|
+
toOption : Result<a, b> -> Option<a>
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Converts the Result to an Option. An error value is discarded and replaced with `None`.
|
|
93
|
+
|
|
94
|
+
Parameters:
|
|
95
|
+
|
|
96
|
+
|param|type|description|
|
|
97
|
+
|-----|----|-----------|
|
|
98
|
+
|`result`|`Result<a, b>`|The result to convert|
|
|
99
|
+
|
|
100
|
+
Returns:
|
|
101
|
+
|
|
102
|
+
|type|description|
|
|
103
|
+
|----|-----------|
|
|
104
|
+
|`Option<a>`|`Some(value)` if the Result is `Ok(value)` or `None` if the Result is an `Err`|
|
|
105
|
+
|
|
106
|
+
### Result.**flatMap**
|
|
107
|
+
|
|
108
|
+
<details disabled>
|
|
109
|
+
<summary tabindex="-1">Added in <code>0.2.0</code></summary>
|
|
110
|
+
No other changes yet.
|
|
111
|
+
</details>
|
|
112
|
+
|
|
113
|
+
```grain
|
|
114
|
+
flatMap : ((a -> Result<b, c>), Result<a, c>) -> Result<b, c>
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
If the Result is `Ok(value)`, applies the given function to the `value` to produce a new Result.
|
|
118
|
+
|
|
119
|
+
Parameters:
|
|
120
|
+
|
|
121
|
+
|param|type|description|
|
|
122
|
+
|-----|----|-----------|
|
|
123
|
+
|`fn`|`a -> Result<b, c>`|The function to call on the value of an `Ok` variant|
|
|
124
|
+
|`result`|`Result<a, c>`|The result to map|
|
|
125
|
+
|
|
126
|
+
Returns:
|
|
127
|
+
|
|
128
|
+
|type|description|
|
|
129
|
+
|----|-----------|
|
|
130
|
+
|`Result<b, c>`|A new Result produced by the mapping function if the variant was `Ok` or the unmodified `Err` otherwise|
|
|
131
|
+
|
|
132
|
+
### Result.**flatMapErr**
|
|
133
|
+
|
|
134
|
+
<details disabled>
|
|
135
|
+
<summary tabindex="-1">Added in <code>0.2.0</code></summary>
|
|
136
|
+
No other changes yet.
|
|
137
|
+
</details>
|
|
138
|
+
|
|
139
|
+
```grain
|
|
140
|
+
flatMapErr : ((a -> Result<b, c>), Result<b, a>) -> Result<b, c>
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
If the Result is an `Err(value)`, applies the given function to the `value` to produce a new Result.
|
|
144
|
+
|
|
145
|
+
Parameters:
|
|
146
|
+
|
|
147
|
+
|param|type|description|
|
|
148
|
+
|-----|----|-----------|
|
|
149
|
+
|`fn`|`a -> Result<b, c>`|The function to call on the value of an `Err` variant|
|
|
150
|
+
|`result`|`Result<b, a>`|The result to map|
|
|
151
|
+
|
|
152
|
+
Returns:
|
|
153
|
+
|
|
154
|
+
|type|description|
|
|
155
|
+
|----|-----------|
|
|
156
|
+
|`Result<b, c>`|A new Result produced by the mapping function if the variant was `Err` or the unmodified `Ok` otherwise|
|
|
157
|
+
|
|
158
|
+
### Result.**map**
|
|
159
|
+
|
|
160
|
+
<details disabled>
|
|
161
|
+
<summary tabindex="-1">Added in <code>0.2.0</code></summary>
|
|
162
|
+
No other changes yet.
|
|
163
|
+
</details>
|
|
164
|
+
|
|
165
|
+
```grain
|
|
166
|
+
map : ((a -> b), Result<a, c>) -> Result<b, c>
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
If the Result is `Ok(value)`, applies the given function to the `value` and wraps the new value in an `Ok` variant.
|
|
170
|
+
|
|
171
|
+
Parameters:
|
|
172
|
+
|
|
173
|
+
|param|type|description|
|
|
174
|
+
|-----|----|-----------|
|
|
175
|
+
|`fn`|`a -> b`|The function to call on the value of an `Ok` variant|
|
|
176
|
+
|`result`|`Result<a, c>`|The result to map|
|
|
177
|
+
|
|
178
|
+
Returns:
|
|
179
|
+
|
|
180
|
+
|type|description|
|
|
181
|
+
|----|-----------|
|
|
182
|
+
|`Result<b, c>`|A new `Ok` variant produced by the mapping function if the variant was `Ok` or the unmodified `Err` otherwise|
|
|
183
|
+
|
|
184
|
+
### Result.**mapErr**
|
|
185
|
+
|
|
186
|
+
<details disabled>
|
|
187
|
+
<summary tabindex="-1">Added in <code>0.2.0</code></summary>
|
|
188
|
+
No other changes yet.
|
|
189
|
+
</details>
|
|
190
|
+
|
|
191
|
+
```grain
|
|
192
|
+
mapErr : ((a -> b), Result<c, a>) -> Result<c, b>
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
If the Result is `Err(value)`, applies the given function to the `value` and wraps the new value in an `Err` variant.
|
|
196
|
+
|
|
197
|
+
Parameters:
|
|
198
|
+
|
|
199
|
+
|param|type|description|
|
|
200
|
+
|-----|----|-----------|
|
|
201
|
+
|`fn`|`a -> b`|The function to call on the value of an `Err` variant|
|
|
202
|
+
|`result`|`Result<c, a>`|The result to map|
|
|
203
|
+
|
|
204
|
+
Returns:
|
|
205
|
+
|
|
206
|
+
|type|description|
|
|
207
|
+
|----|-----------|
|
|
208
|
+
|`Result<c, b>`|A new `Err` variant produced by the mapping function if the variant was `Err` or the unmodified `Ok` otherwise|
|
|
209
|
+
|
|
210
|
+
### Result.**mapWithDefault**
|
|
211
|
+
|
|
212
|
+
<details disabled>
|
|
213
|
+
<summary tabindex="-1">Added in <code>0.2.0</code></summary>
|
|
214
|
+
No other changes yet.
|
|
215
|
+
</details>
|
|
216
|
+
|
|
217
|
+
```grain
|
|
218
|
+
mapWithDefault : ((a -> b), b, Result<a, c>) -> b
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
If the Result is `Ok(value)`, applies the given function to the `value` to produce a new value, otherwise uses the default value.
|
|
222
|
+
Useful for unwrapping a successful Result while providing a fallback for any errors that can occur.
|
|
223
|
+
|
|
224
|
+
Parameters:
|
|
225
|
+
|
|
226
|
+
|param|type|description|
|
|
227
|
+
|-----|----|-----------|
|
|
228
|
+
|`fn`|`a -> b`|The function to call on the value of an `Ok` variant|
|
|
229
|
+
|`def`|`b`|A fallback value for an `Err` variant|
|
|
230
|
+
|`result`|`Result<a, c>`|The result to map|
|
|
231
|
+
|
|
232
|
+
Returns:
|
|
233
|
+
|
|
234
|
+
|type|description|
|
|
235
|
+
|----|-----------|
|
|
236
|
+
|`b`|The value produced by the mapping function if the result is of the `Ok` variant or the default value otherwise|
|
|
237
|
+
|
|
238
|
+
### Result.**mapWithDefaultFn**
|
|
239
|
+
|
|
240
|
+
<details disabled>
|
|
241
|
+
<summary tabindex="-1">Added in <code>0.2.0</code></summary>
|
|
242
|
+
No other changes yet.
|
|
243
|
+
</details>
|
|
244
|
+
|
|
245
|
+
```grain
|
|
246
|
+
mapWithDefaultFn : ((a -> b), (c -> b), Result<a, c>) -> b
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
If the Result is `Ok(value)`, applies the `fnOk` function to the `value` to produce a new value.
|
|
250
|
+
If the Result is `Err(value)`, applies the `fnErr` function to the `value` to produce a new value.
|
|
251
|
+
Useful for unwrapping a Result into a value, whether it is successful or unsuccessful.
|
|
252
|
+
|
|
253
|
+
Parameters:
|
|
254
|
+
|
|
255
|
+
|param|type|description|
|
|
256
|
+
|-----|----|-----------|
|
|
257
|
+
|`fnOk`|`a -> b`|The function to call on the value of an `Ok` variant|
|
|
258
|
+
|`fnErr`|`c -> b`|The function to call on the value of an `Err` variant|
|
|
259
|
+
|`result`|`Result<a, c>`|The result to map|
|
|
260
|
+
|
|
261
|
+
Returns:
|
|
262
|
+
|
|
263
|
+
|type|description|
|
|
264
|
+
|----|-----------|
|
|
265
|
+
|`b`|The value produced by one of the mapping functions|
|
|
266
|
+
|
|
267
|
+
### Result.**or**
|
|
268
|
+
|
|
269
|
+
<details disabled>
|
|
270
|
+
<summary tabindex="-1">Added in <code>0.2.0</code></summary>
|
|
271
|
+
No other changes yet.
|
|
272
|
+
</details>
|
|
273
|
+
|
|
274
|
+
```grain
|
|
275
|
+
( or ) : (Result<a, b>, Result<a, b>) -> Result<a, b>
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
Behaves like a logical OR (`||`) where the first Result is only returned if it is the `Ok` variant and falling back to the second Result in all other cases.
|
|
279
|
+
|
|
280
|
+
Parameters:
|
|
281
|
+
|
|
282
|
+
|param|type|description|
|
|
283
|
+
|-----|----|-----------|
|
|
284
|
+
|`result1`|`Result<a, b>`|The first result|
|
|
285
|
+
|`result2`|`Result<a, b>`|The second result|
|
|
286
|
+
|
|
287
|
+
Returns:
|
|
288
|
+
|
|
289
|
+
|type|description|
|
|
290
|
+
|----|-----------|
|
|
291
|
+
|`Result<a, b>`|The first Result if it is the `Ok` variant or the second Result otherwise|
|
|
292
|
+
|
|
293
|
+
### Result.**and**
|
|
294
|
+
|
|
295
|
+
<details disabled>
|
|
296
|
+
<summary tabindex="-1">Added in <code>0.2.0</code></summary>
|
|
297
|
+
No other changes yet.
|
|
298
|
+
</details>
|
|
299
|
+
|
|
300
|
+
```grain
|
|
301
|
+
and : (Result<a, b>, Result<a, b>) -> Result<a, b>
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
Behaves like a logical AND (`&&`) where the first Result is only returned if it is the `Err` variant and falling back to the second Result in all other cases.
|
|
305
|
+
|
|
306
|
+
Parameters:
|
|
307
|
+
|
|
308
|
+
|param|type|description|
|
|
309
|
+
|-----|----|-----------|
|
|
310
|
+
|`result1`|`Result<a, b>`|The first result|
|
|
311
|
+
|`result2`|`Result<a, b>`|The second result|
|
|
312
|
+
|
|
313
|
+
Returns:
|
|
314
|
+
|
|
315
|
+
|type|description|
|
|
316
|
+
|----|-----------|
|
|
317
|
+
|`Result<a, b>`|The second Result if both are the `Ok` variant or the first Result otherwise|
|
|
318
|
+
|
|
319
|
+
### Result.**peek**
|
|
320
|
+
|
|
321
|
+
<details disabled>
|
|
322
|
+
<summary tabindex="-1">Added in <code>0.2.0</code></summary>
|
|
323
|
+
No other changes yet.
|
|
324
|
+
</details>
|
|
325
|
+
|
|
326
|
+
```grain
|
|
327
|
+
peek : ((a -> b), (c -> d), Result<a, c>) -> Void
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
If the Result is `Ok(value)`, applies the `fnOk` function to the `value` without producing a new value.
|
|
331
|
+
If the Result is `Err(value)`, applies the `fnErr` function to the `value` without producing a new value.
|
|
332
|
+
Useful for inspecting Results without changing anything.
|
|
333
|
+
|
|
334
|
+
Parameters:
|
|
335
|
+
|
|
336
|
+
|param|type|description|
|
|
337
|
+
|-----|----|-----------|
|
|
338
|
+
|`fnOk`|`a -> b`|The function to call on the value of an `Ok` variant|
|
|
339
|
+
|`fnErr`|`c -> d`|The function to call on the value of an `Err` variant|
|
|
340
|
+
|`result`|`Result<a, c>`|The result to inspect|
|
|
341
|
+
|
|
342
|
+
### Result.**peekOk**
|
|
343
|
+
|
|
344
|
+
<details disabled>
|
|
345
|
+
<summary tabindex="-1">Added in <code>0.2.0</code></summary>
|
|
346
|
+
No other changes yet.
|
|
347
|
+
</details>
|
|
348
|
+
|
|
349
|
+
```grain
|
|
350
|
+
peekOk : ((a -> b), Result<a, c>) -> Void
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
If the Result is `Ok(value)`, applies the given function to the `value` without producing a new value.
|
|
354
|
+
|
|
355
|
+
Parameters:
|
|
356
|
+
|
|
357
|
+
|param|type|description|
|
|
358
|
+
|-----|----|-----------|
|
|
359
|
+
|`fn`|`a -> b`|The function to call on the value of an `Ok` variant|
|
|
360
|
+
|`result`|`Result<a, c>`|The result to inspect|
|
|
361
|
+
|
|
362
|
+
### Result.**peekErr**
|
|
363
|
+
|
|
364
|
+
<details disabled>
|
|
365
|
+
<summary tabindex="-1">Added in <code>0.2.0</code></summary>
|
|
366
|
+
No other changes yet.
|
|
367
|
+
</details>
|
|
368
|
+
|
|
369
|
+
```grain
|
|
370
|
+
peekErr : ((a -> b), Result<c, a>) -> Void
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
If the Result is `Err(value)`, applies the given function to the `value` without producing a new value.
|
|
374
|
+
|
|
375
|
+
Parameters:
|
|
376
|
+
|
|
377
|
+
|param|type|description|
|
|
378
|
+
|-----|----|-----------|
|
|
379
|
+
|`fn`|`a -> b`|The function to call on the value of an `Err` variant|
|
|
380
|
+
|`result`|`Result<c, a>`|The result to inspect|
|
|
381
|
+
|
|
382
|
+
### Result.**expect**
|
|
383
|
+
|
|
384
|
+
<details disabled>
|
|
385
|
+
<summary tabindex="-1">Added in <code>0.4.0</code></summary>
|
|
386
|
+
No other changes yet.
|
|
387
|
+
</details>
|
|
388
|
+
|
|
389
|
+
```grain
|
|
390
|
+
expect : (String, Result<a, b>) -> a
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
Extracts the value inside an `Ok` result, otherwise throw an
|
|
394
|
+
exception containing the message and contents of the `Err`.
|
|
395
|
+
|
|
396
|
+
Parameters:
|
|
397
|
+
|
|
398
|
+
|param|type|description|
|
|
399
|
+
|-----|----|-----------|
|
|
400
|
+
|`msg`|`String`|The message to prepend if the result contains an `Err`|
|
|
401
|
+
|`result`|`Result<a, b>`|The result to extract a value from|
|
|
402
|
+
|
|
403
|
+
Returns:
|
|
404
|
+
|
|
405
|
+
|type|description|
|
|
406
|
+
|----|-----------|
|
|
407
|
+
|`a`|The unwrapped value if the Result is the `Ok` variant|
|
|
408
|
+
|
|
409
|
+
Examples:
|
|
410
|
+
|
|
411
|
+
```grain
|
|
412
|
+
Result.expect("Unexpected error", Ok(1234)) + 42
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
### Result.**unwrap**
|
|
416
|
+
|
|
417
|
+
<details disabled>
|
|
418
|
+
<summary tabindex="-1">Added in <code>0.4.0</code></summary>
|
|
419
|
+
No other changes yet.
|
|
420
|
+
</details>
|
|
421
|
+
|
|
422
|
+
```grain
|
|
423
|
+
unwrap : Result<a, b> -> a
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
Extracts the value inside an `Ok` result, otherwise throw an
|
|
427
|
+
exception containing a default message and contents of the `Err`.
|
|
428
|
+
|
|
429
|
+
Parameters:
|
|
430
|
+
|
|
431
|
+
|param|type|description|
|
|
432
|
+
|-----|----|-----------|
|
|
433
|
+
|`result`|`Result<a, b>`|The result to extract a value from|
|
|
434
|
+
|
|
435
|
+
Returns:
|
|
436
|
+
|
|
437
|
+
|type|description|
|
|
438
|
+
|----|-----------|
|
|
439
|
+
|`a`|The unwrapped value if the result is the `Ok` variant|
|
|
440
|
+
|
|
441
|
+
Examples:
|
|
442
|
+
|
|
443
|
+
```grain
|
|
444
|
+
Result.unwrap(Err("This will throw"))
|
|
445
|
+
```
|
|
446
|
+
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
// TODO(#1050): Remove dependency on Pervasives once Option/Result types are imbedded in the compiler
|
|
2
|
+
|
|
3
|
+
import WasmI32, {
|
|
4
|
+
add as (+),
|
|
5
|
+
sub as (-),
|
|
6
|
+
gtU as (>),
|
|
7
|
+
geU as (>=),
|
|
8
|
+
ltU as (<),
|
|
9
|
+
shrS as (>>),
|
|
10
|
+
eq as (==),
|
|
11
|
+
ne as (!=),
|
|
12
|
+
and as (&),
|
|
13
|
+
} from "runtime/unsafe/wasmi32"
|
|
14
|
+
import WasmI64 from "runtime/unsafe/wasmi64"
|
|
15
|
+
import Memory from "runtime/unsafe/memory"
|
|
16
|
+
import Tags from "runtime/unsafe/tags"
|
|
17
|
+
import { reducedInteger } from "runtime/numbers"
|
|
18
|
+
|
|
19
|
+
@disableGC
|
|
20
|
+
export let rec parseInt = (string: String, radix: Number) => {
|
|
21
|
+
let _CHAR_0 = 0x30n
|
|
22
|
+
let _CHAR_B = 0x42n
|
|
23
|
+
let _CHAR_b = 0x62n
|
|
24
|
+
let _CHAR_O = 0x4fn
|
|
25
|
+
let _CHAR_o = 0x6fn
|
|
26
|
+
let _CHAR_X = 0x58n
|
|
27
|
+
let _CHAR_x = 0x78n
|
|
28
|
+
|
|
29
|
+
let _CHAR_A = 0x41n
|
|
30
|
+
let _CHAR_a = 0x61n
|
|
31
|
+
|
|
32
|
+
let _CHAR_UNDERSCORE = 0x5fn
|
|
33
|
+
let _CHAR_MINUS = 0x2dn
|
|
34
|
+
|
|
35
|
+
let _INT_MIN = -9223372036854775808N
|
|
36
|
+
|
|
37
|
+
// Don't need to process Unicode length since if the string
|
|
38
|
+
// contains non-ascii characters, it's not a valid integer
|
|
39
|
+
let strLen = WasmI32.load(WasmI32.fromGrain(string), 4n)
|
|
40
|
+
|
|
41
|
+
// Our pointer within the string we're parsing, offset by the
|
|
42
|
+
// header
|
|
43
|
+
let mut offset = WasmI32.fromGrain(string) + 8n
|
|
44
|
+
|
|
45
|
+
let strEnd = offset + strLen
|
|
46
|
+
|
|
47
|
+
let radix = WasmI32.fromGrain(radix)
|
|
48
|
+
let result = if (WasmI32.eqz(radix & Tags._GRAIN_NUMBER_TAG_MASK) || radix < WasmI32.fromGrain(2) || radix > WasmI32.fromGrain(36)) {
|
|
49
|
+
Memory.incRef(WasmI32.fromGrain(Err))
|
|
50
|
+
Err("Radix must be an integer between 2 and 36")
|
|
51
|
+
} else if (WasmI32.eqz(strLen)) {
|
|
52
|
+
Memory.incRef(WasmI32.fromGrain(Err))
|
|
53
|
+
Err("Invalid input")
|
|
54
|
+
} else {
|
|
55
|
+
let mut char = WasmI32.load8U(offset, 0n)
|
|
56
|
+
|
|
57
|
+
let mut limit = WasmI64.add(_INT_MIN, 1N)
|
|
58
|
+
|
|
59
|
+
// Check for a sign
|
|
60
|
+
let mut negative = false
|
|
61
|
+
if (char == _CHAR_MINUS) {
|
|
62
|
+
negative = true
|
|
63
|
+
offset += 1n
|
|
64
|
+
limit = _INT_MIN
|
|
65
|
+
char = WasmI32.load8U(offset, 0n)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
let mut radix = WasmI64.extendI32S(radix >> 1n)
|
|
69
|
+
|
|
70
|
+
// Check if we should override the supplied radix
|
|
71
|
+
if (char == _CHAR_0 && strLen > 2n) {
|
|
72
|
+
match (WasmI32.load8U(offset, 1n)) {
|
|
73
|
+
c when c == _CHAR_B || c == _CHAR_b => {
|
|
74
|
+
radix = 2N
|
|
75
|
+
offset += 2n
|
|
76
|
+
},
|
|
77
|
+
c when c == _CHAR_O || c == _CHAR_o => {
|
|
78
|
+
radix = 8N
|
|
79
|
+
offset += 2n
|
|
80
|
+
},
|
|
81
|
+
c when c == _CHAR_X || c == _CHAR_x => {
|
|
82
|
+
radix = 16N
|
|
83
|
+
offset += 2n
|
|
84
|
+
},
|
|
85
|
+
_ => void,
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
let mut value = 0N
|
|
90
|
+
|
|
91
|
+
// we use 0 to represent no error, 1 to represent an invalid
|
|
92
|
+
// input, and 2 to represent an overflow
|
|
93
|
+
let mut error = 1n
|
|
94
|
+
|
|
95
|
+
for (let mut i = offset; i < strEnd; i += 1n) {
|
|
96
|
+
let char = WasmI32.load8U(i, 0n)
|
|
97
|
+
|
|
98
|
+
// Ignore underscore characters
|
|
99
|
+
if (char == _CHAR_UNDERSCORE) {
|
|
100
|
+
continue
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// We've seen at least one non-underscore character, so we'll consider
|
|
104
|
+
// the input valid until we find out otherwise
|
|
105
|
+
|
|
106
|
+
error = 0n
|
|
107
|
+
|
|
108
|
+
let mut digit = 0n
|
|
109
|
+
|
|
110
|
+
match (char) {
|
|
111
|
+
c when c - _CHAR_0 < 10n => digit = char - _CHAR_0,
|
|
112
|
+
c when c - _CHAR_A < 26n => digit = char - _CHAR_A + 10n,
|
|
113
|
+
c when c - _CHAR_a < 26n => digit = char - _CHAR_a + 10n,
|
|
114
|
+
_ => {
|
|
115
|
+
error = 1n
|
|
116
|
+
// invalid digit
|
|
117
|
+
break
|
|
118
|
+
},
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (digit >= WasmI32.wrapI64(radix)) {
|
|
122
|
+
error = 1n
|
|
123
|
+
// invalid digit
|
|
124
|
+
break
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
let digit = WasmI64.extendI32U(digit)
|
|
128
|
+
|
|
129
|
+
value = WasmI64.mul(value, radix)
|
|
130
|
+
|
|
131
|
+
// Check for overflow
|
|
132
|
+
// 64-bit int min + 1
|
|
133
|
+
if (WasmI64.ltS(value, WasmI64.add(limit, digit))) {
|
|
134
|
+
error = 2n
|
|
135
|
+
// overflow
|
|
136
|
+
break
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// To quote the OpenJDK,
|
|
140
|
+
// "Accumulating negatively avoids surprises near MAX_VALUE"
|
|
141
|
+
// The minimum value of a 64-bit integer (-9223372036854775808) can't be
|
|
142
|
+
// represented as a positive number because it would be larger than the
|
|
143
|
+
// maximum 64-bit integer (9223372036854775807), so we'd be unable to
|
|
144
|
+
// parse negatives as positives and multiply by the sign at the end.
|
|
145
|
+
// Instead, we represent all positive numbers as negative numbers since
|
|
146
|
+
// we have one unit more headroom.
|
|
147
|
+
value = WasmI64.sub(value, digit)
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
match (error) {
|
|
151
|
+
1n => {
|
|
152
|
+
Memory.incRef(WasmI32.fromGrain(Err))
|
|
153
|
+
Err("Invalid digit in input")
|
|
154
|
+
},
|
|
155
|
+
2n => {
|
|
156
|
+
Memory.incRef(WasmI32.fromGrain(Err))
|
|
157
|
+
Err("Input out of range of representable integers")
|
|
158
|
+
},
|
|
159
|
+
_ => {
|
|
160
|
+
let value = if (negative) value else WasmI64.mul(value, -1N)
|
|
161
|
+
let number = WasmI32.toGrain(reducedInteger(value)): (Number)
|
|
162
|
+
Memory.incRef(WasmI32.fromGrain(Ok))
|
|
163
|
+
Ok(number)
|
|
164
|
+
},
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
Memory.decRef(WasmI32.fromGrain(parseInt))
|
|
169
|
+
Memory.decRef(radix)
|
|
170
|
+
|
|
171
|
+
result
|
|
172
|
+
}
|