@grain/stdlib 0.4.4 → 0.5.0

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 (97) hide show
  1. package/CHANGELOG.md +87 -0
  2. package/LICENSE +1 -1
  3. package/array.gr +92 -73
  4. package/array.md +18 -18
  5. package/bigint.gr +497 -0
  6. package/bigint.md +811 -0
  7. package/buffer.gr +56 -217
  8. package/buffer.md +24 -17
  9. package/bytes.gr +103 -205
  10. package/bytes.md +19 -0
  11. package/char.gr +152 -166
  12. package/char.md +200 -0
  13. package/exception.md +6 -0
  14. package/float32.gr +159 -82
  15. package/float32.md +315 -0
  16. package/float64.gr +163 -82
  17. package/float64.md +315 -0
  18. package/hash.gr +53 -49
  19. package/int32.gr +479 -230
  20. package/int32.md +937 -0
  21. package/int64.gr +479 -230
  22. package/int64.md +937 -0
  23. package/list.gr +530 -116
  24. package/list.md +1141 -0
  25. package/map.gr +302 -121
  26. package/map.md +525 -0
  27. package/number.gr +51 -57
  28. package/number.md +37 -3
  29. package/option.gr +25 -25
  30. package/option.md +1 -1
  31. package/package.json +3 -3
  32. package/pervasives.gr +504 -52
  33. package/pervasives.md +1116 -0
  34. package/queue.gr +8 -1
  35. package/queue.md +10 -0
  36. package/random.gr +196 -0
  37. package/random.md +179 -0
  38. package/range.gr +26 -26
  39. package/regex.gr +1833 -842
  40. package/regex.md +11 -11
  41. package/result.md +1 -1
  42. package/runtime/bigint.gr +2045 -0
  43. package/runtime/bigint.md +326 -0
  44. package/runtime/dataStructures.gr +99 -279
  45. package/runtime/dataStructures.md +391 -0
  46. package/runtime/debug.gr +0 -1
  47. package/runtime/debug.md +6 -0
  48. package/runtime/equal.gr +40 -37
  49. package/runtime/equal.md +6 -0
  50. package/runtime/exception.gr +28 -15
  51. package/runtime/exception.md +30 -0
  52. package/runtime/gc.gr +50 -20
  53. package/runtime/gc.md +36 -0
  54. package/runtime/malloc.gr +32 -22
  55. package/runtime/malloc.md +55 -0
  56. package/runtime/numberUtils.gr +297 -142
  57. package/runtime/numberUtils.md +54 -0
  58. package/runtime/numbers.gr +1204 -453
  59. package/runtime/numbers.md +300 -0
  60. package/runtime/string.gr +193 -228
  61. package/runtime/string.md +24 -0
  62. package/runtime/stringUtils.gr +62 -38
  63. package/runtime/stringUtils.md +6 -0
  64. package/runtime/unsafe/constants.gr +17 -0
  65. package/runtime/unsafe/constants.md +72 -0
  66. package/runtime/unsafe/conv.gr +10 -10
  67. package/runtime/unsafe/conv.md +71 -0
  68. package/runtime/unsafe/errors.md +204 -0
  69. package/runtime/unsafe/memory.gr +14 -3
  70. package/runtime/unsafe/memory.md +54 -0
  71. package/runtime/unsafe/printWasm.gr +4 -4
  72. package/runtime/unsafe/printWasm.md +24 -0
  73. package/runtime/unsafe/tags.gr +11 -10
  74. package/runtime/unsafe/tags.md +120 -0
  75. package/runtime/unsafe/wasmf32.gr +9 -2
  76. package/runtime/unsafe/wasmf32.md +168 -0
  77. package/runtime/unsafe/wasmf64.gr +9 -2
  78. package/runtime/unsafe/wasmf64.md +168 -0
  79. package/runtime/unsafe/wasmi32.gr +65 -47
  80. package/runtime/unsafe/wasmi32.md +282 -0
  81. package/runtime/unsafe/wasmi64.gr +78 -50
  82. package/runtime/unsafe/wasmi64.md +300 -0
  83. package/runtime/utils/printing.gr +62 -0
  84. package/runtime/utils/printing.md +18 -0
  85. package/runtime/wasi.gr +200 -46
  86. package/runtime/wasi.md +839 -0
  87. package/set.gr +125 -121
  88. package/set.md +24 -21
  89. package/stack.gr +29 -29
  90. package/stack.md +4 -6
  91. package/string.gr +434 -415
  92. package/string.md +3 -3
  93. package/sys/file.gr +477 -482
  94. package/sys/process.gr +33 -47
  95. package/sys/random.gr +48 -20
  96. package/sys/random.md +38 -0
  97. package/sys/time.gr +12 -28
@@ -1,18 +1,23 @@
1
- /* grainc-flags --compilation-mode=runtime */
1
+ /* grainc-flags --no-pervasives */
2
2
 
3
3
  import Memory from "runtime/unsafe/memory"
4
4
  import Tags from "runtime/unsafe/tags"
5
5
  import Exception from "runtime/exception"
6
+ import BI from "runtime/bigint"
6
7
 
8
+ import {
9
+ _SMAX32_I64 as _I32_MAX,
10
+ _SMIN32_I64 as _I32_MIN,
11
+ } from "runtime/unsafe/constants"
7
12
  import WasmI32 from "runtime/unsafe/wasmi32"
8
13
  import WasmI64 from "runtime/unsafe/wasmi64"
9
14
  import WasmF32 from "runtime/unsafe/wasmf32"
10
15
  import WasmF64 from "runtime/unsafe/wasmf64"
11
16
 
12
- primitive (!) : Bool -> Bool = "@not"
13
- primitive (&&) : (Bool, Bool) -> Bool = "@and"
14
- primitive (||) : (Bool, Bool) -> Bool = "@or"
15
- primitive throw : Exception -> a = "@throw"
17
+ primitive (!): Bool -> Bool = "@not"
18
+ primitive (&&): (Bool, Bool) -> Bool = "@and"
19
+ primitive (||): (Bool, Bool) -> Bool = "@or"
20
+ primitive throw: Exception -> a = "@throw"
16
21
 
17
22
  exception UnknownNumberTag
18
23
 
@@ -21,60 +26,82 @@ import {
21
26
  newInt32,
22
27
  newInt64,
23
28
  newFloat32,
24
- newFloat64
29
+ newFloat64,
25
30
  } from "runtime/dataStructures"
26
31
 
27
- export newRational
28
- export newInt32
29
- export newInt64
30
- export newFloat32
31
- export newFloat64
32
-
33
- let _I32_MAX = 0x7fffffffN
34
- let _I32_MIN = -0x7fffffffN
32
+ @unsafe
35
33
  let _F32_MAX = 3.40282347e+38W
34
+ @unsafe
36
35
  let _F32_MIN = 1.401298464324817e-45W
36
+ @unsafe
37
37
  let _F32_MAX_SAFE_INTEGER = 16777215.w
38
+ @unsafe
38
39
  let _F64_MAX_SAFE_INTEGER = 9007199254740991.W
39
40
 
40
41
  let (==) = WasmI32.eq
41
42
  let (!=) = WasmI32.ne
42
43
 
43
- let tagSimple = (x) => {
44
+ @unsafe
45
+ let tagSimple = x => {
44
46
  WasmI32.xor(WasmI32.shl(x, 1n), 1n)
45
47
  }
46
48
 
47
- let untagSimple = (x) => {
49
+ @unsafe
50
+ let untagSimple = x => {
48
51
  WasmI32.shrS(x, 1n)
49
52
  }
50
53
 
51
- let isSimpleNumber = (x) => {
52
- WasmI32.eq(WasmI32.and(x, Tags._GRAIN_NUMBER_TAG_MASK), Tags._GRAIN_NUMBER_TAG_TYPE)
54
+ @unsafe
55
+ let isSimpleNumber = x => {
56
+ WasmI32.eq(
57
+ WasmI32.and(x, Tags._GRAIN_NUMBER_TAG_MASK),
58
+ Tags._GRAIN_NUMBER_TAG_TYPE
59
+ )
53
60
  }
54
61
 
55
- export let isBoxedNumber = (x) => {
56
- if (WasmI32.eq(WasmI32.and(x, Tags._GRAIN_GENERIC_TAG_MASK), Tags._GRAIN_GENERIC_HEAP_TAG_TYPE)) {
62
+ @unsafe
63
+ export let isBoxedNumber = x => {
64
+ if (
65
+ WasmI32.eq(
66
+ WasmI32.and(x, Tags._GRAIN_GENERIC_TAG_MASK),
67
+ Tags._GRAIN_GENERIC_HEAP_TAG_TYPE
68
+ )
69
+ ) {
57
70
  WasmI32.eq(WasmI32.load(x, 0n), Tags._GRAIN_BOXED_NUM_HEAP_TAG)
58
71
  } else {
59
72
  false
60
73
  }
61
74
  }
62
75
 
63
- export let isFloat = (x) => {
76
+ @unsafe
77
+ export let isFloat = x => {
64
78
  if (isBoxedNumber(x)) {
65
79
  let tag = WasmI32.load(x, 4n)
66
- WasmI32.eq(tag, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) || WasmI32.eq(tag, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG)
80
+ WasmI32.eq(tag, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) ||
81
+ WasmI32.eq(tag, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG)
67
82
  } else {
68
83
  false
69
84
  }
70
85
  }
71
86
 
72
- export let isNumber = (x) => {
87
+ @unsafe
88
+ let isBigInt = x => {
89
+ if (isBoxedNumber(x)) {
90
+ let tag = WasmI32.load(x, 4n)
91
+ WasmI32.eq(tag, Tags._GRAIN_BIGINT_BOXED_NUM_TAG)
92
+ } else {
93
+ false
94
+ }
95
+ }
96
+
97
+ @unsafe
98
+ export let isNumber = x => {
73
99
  // x is a number if it is a literal number or a boxed_num heap value
74
100
  isSimpleNumber(x) || isBoxedNumber(x)
75
101
  }
76
102
 
77
- let safeI64toI32 = (x) => {
103
+ @unsafe
104
+ let safeI64toI32 = x => {
78
105
  if (WasmI64.gtS(x, _I32_MAX) || WasmI64.ltS(x, _I32_MIN)) {
79
106
  throw Exception.Overflow
80
107
  } else {
@@ -82,12 +109,16 @@ let safeI64toI32 = (x) => {
82
109
  }
83
110
  }
84
111
 
85
- let i32neg = (x) => WasmI32.sub(0n, x)
112
+ @unsafe
113
+ let i32neg = x => WasmI32.sub(0n, x)
86
114
 
87
- let i64not = (x) => WasmI64.xor(x, 0xffffffffffffffffN)
88
- let i64neg = (x) => WasmI64.sub(0N, x)
115
+ @unsafe
116
+ let i64not = x => WasmI64.xor(x, 0xffffffffffffffffN)
117
+ @unsafe
118
+ let i64neg = x => WasmI64.sub(0N, x)
89
119
 
90
120
  // https://en.wikipedia.org/wiki/Binary_GCD_algorithm
121
+ @unsafe
91
122
  let rec gcdHelp = (x, y) => {
92
123
  if (WasmI64.eq(x, y) || WasmI64.eqz(x)) {
93
124
  y
@@ -111,6 +142,7 @@ let rec gcdHelp = (x, y) => {
111
142
  }
112
143
  }
113
144
 
145
+ @unsafe
114
146
  let gcd = (x, y) => {
115
147
  // Algorithm above breaks on negatives, so
116
148
  // we make sure that they are positive at the beginning
@@ -127,43 +159,90 @@ let gcd = (x, y) => {
127
159
  gcdHelp(x, y)
128
160
  }
129
161
 
162
+ @unsafe
130
163
  let gcd32 = (x, y) => {
131
164
  WasmI32.wrapI64(gcd(WasmI64.extendI32S(x), WasmI64.extendI32S(y)))
132
165
  }
133
166
 
134
- export let reducedInteger = (x) => {
167
+ @unsafe
168
+ export let reducedInteger = x => {
135
169
  if (WasmI64.gtS(x, _I32_MAX) || WasmI64.ltS(x, _I32_MIN)) {
136
170
  newInt64(x)
137
- } else if (WasmI64.gtS(x, WasmI64.shrS(_I32_MAX, 1N)) || WasmI64.ltS(x, WasmI64.shrS(_I32_MIN, 1N))) {
171
+ } else if (
172
+ WasmI64.gtS(x, WasmI64.shrS(_I32_MAX, 1N)) ||
173
+ WasmI64.ltS(x, WasmI64.shrS(_I32_MIN, 1N))
174
+ ) {
138
175
  newInt32(WasmI32.wrapI64(x))
139
176
  } else {
140
177
  tagSimple(WasmI32.wrapI64(x))
141
178
  }
142
179
  }
143
180
 
144
- let reducedFraction = (x, y) => {
181
+ @unsafe
182
+ let reducedBigInteger = x => {
183
+ if (BI.canConvertToInt64(x)) {
184
+ // CONVENTION: We assume that this function is called in
185
+ // some sort of tail position, meaning that
186
+ // the original input is no longer used after
187
+ // this function returns.
188
+ let ret = reducedInteger(BI.toInt64(x))
189
+ Memory.decRef(x)
190
+ ret
191
+ } else {
192
+ x
193
+ }
194
+ }
195
+
196
+ @unsafe
197
+ let reducedFractionBigInt = (x, y) => {
145
198
  let mut x = x
146
199
  let mut y = y
200
+ let mut needsDecref = false
147
201
 
148
- if (WasmI32.ltS(y, 0n)) {
202
+ if (BI.isNegative(y)) {
149
203
  // Normalization 1: Never do negative/negative
150
204
  // Normalization 2: Never allow a negative denominator
151
- x = i32neg(x)
152
- y = i32neg(y)
205
+ needsDecref = true
206
+ x = BI.negate(x)
207
+ y = BI.negate(y)
153
208
  }
154
- if (WasmI32.eqz(y)) {
209
+ if (BI.eqz(y)) {
155
210
  throw Exception.DivisionByZero
156
211
  }
157
- if (WasmI32.eqz(WasmI32.remS(x, y))) {
158
- // Avoid allocation if possible
159
- reducedInteger(WasmI64.extendI32S(WasmI32.divS(x, y)))
212
+ let quotremResult = Memory.malloc(8n)
213
+ BI.quotRem(x, y, quotremResult)
214
+ // Note that the contents of quotRem are malloc'ed
215
+ // inside of quotRem and need to be manually freed.
216
+ let q = WasmI32.load(quotremResult, 0n)
217
+ let r = WasmI32.load(quotremResult, 4n)
218
+ // free container used to store quotrem result
219
+ Memory.free(quotremResult)
220
+ let ret = if (BI.eqz(r)) {
221
+ // if remainder is zero, then return the quotient.
222
+ // We decRef the remainder, since we no longer need it
223
+ Memory.decRef(r)
224
+ reducedBigInteger(q)
160
225
  } else {
161
- // x not evenly divisible by y
162
- let factor = gcd32(x, y)
163
- newRational(WasmI32.divS(x, factor), WasmI32.divS(y, factor))
226
+ // remainder is nonzero. we don't need the quotient and
227
+ // remainder anymore, so we discard them.
228
+ Memory.decRef(q)
229
+ Memory.decRef(r)
230
+ let factor = BI.gcd(x, y)
231
+ let xdiv = BI.div(x, factor)
232
+ let ydiv = BI.div(y, factor)
233
+ let ret = newRational(xdiv, ydiv)
234
+ Memory.decRef(factor)
235
+ ret
236
+ }
237
+ if (needsDecref) {
238
+ Memory.decRef(x)
239
+ Memory.decRef(y)
240
+ void
164
241
  }
242
+ ret
165
243
  }
166
244
 
245
+ @unsafe
167
246
  let reducedFraction64 = (x, y) => {
168
247
  let mut x = x
169
248
  let mut y = y
@@ -181,28 +260,10 @@ let reducedFraction64 = (x, y) => {
181
260
  reducedInteger(WasmI64.divS(x, y))
182
261
  } else {
183
262
  let factor = gcd(x, y)
184
- let xdiv = safeI64toI32(WasmI64.divS(x, factor))
185
- let ydiv = safeI64toI32(WasmI64.divS(y, factor))
186
- newRational(xdiv, ydiv)
187
- }
188
- }
189
-
190
- let safeI32Multiply = (x, y) => {
191
- let prod = WasmI64.mul(WasmI64.extendI32S(x), WasmI64.extendI32S(y))
192
- if (WasmI64.gtS(prod, _I32_MAX) || WasmI64.ltS(prod, _I32_MIN)) {
193
- throw Exception.Overflow
263
+ let xdiv = WasmI64.divS(x, factor)
264
+ let ydiv = WasmI64.divS(y, factor)
265
+ newRational(BI.makeWrappedInt64(xdiv), BI.makeWrappedInt64(ydiv))
194
266
  }
195
- WasmI32.wrapI64(prod)
196
- }
197
-
198
- let safeI64Multiply = (x, y) => {
199
- let prod = WasmI64.mul(x, y)
200
- if (WasmI64.ne(x, 0N)) {
201
- if (WasmI64.ne(WasmI64.divS(prod, x), y)) {
202
- throw Exception.Overflow
203
- }
204
- }
205
- prod
206
267
  }
207
268
 
208
269
  // Accessor functions
@@ -228,36 +289,42 @@ let safeI64Multiply = (x, y) => {
228
289
  * [numerator, denominator]
229
290
  */
230
291
 
231
- export let boxedNumberTag = (xptr) => {
292
+ @unsafe
293
+ export let boxedNumberTag = xptr => {
232
294
  WasmI32.load(xptr, 4n)
233
295
  }
234
296
 
235
- export let boxedInt32Number = (xptr) => {
297
+ @unsafe
298
+ export let boxedInt32Number = xptr => {
236
299
  WasmI32.load(xptr, 8n)
237
300
  }
238
301
 
239
- export let boxedInt64Number = (xptr) => {
302
+ @unsafe
303
+ export let boxedInt64Number = xptr => {
240
304
  WasmI64.load(xptr, 8n)
241
305
  }
242
306
 
243
- export let boxedFloat32Number = (xptr) => {
307
+ @unsafe
308
+ export let boxedFloat32Number = xptr => {
244
309
  WasmF32.load(xptr, 8n)
245
310
  }
246
311
 
247
- export let boxedFloat64Number = (xptr) => {
312
+ @unsafe
313
+ export let boxedFloat64Number = xptr => {
248
314
  WasmF64.load(xptr, 8n)
249
315
  }
250
316
 
251
- export let boxedRationalNumerator = (xptr) => {
317
+ @unsafe
318
+ export let boxedRationalNumerator = xptr => {
252
319
  WasmI32.load(xptr, 8n)
253
320
  }
254
321
 
255
- export let boxedRationalDenominator = (xptr) => {
322
+ @unsafe
323
+ export let boxedRationalDenominator = xptr => {
256
324
  WasmI32.load(xptr, 12n)
257
325
  }
258
326
 
259
-
260
-
327
+ @unsafe
261
328
  export let coerceNumberToWasmF32 = (x: Number) => {
262
329
  let x = WasmI32.fromGrain(x)
263
330
  if (isSimpleNumber(x)) {
@@ -271,8 +338,14 @@ export let coerceNumberToWasmF32 = (x: Number) => {
271
338
  t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
272
339
  WasmF32.convertI64S(boxedInt64Number(x))
273
340
  },
341
+ t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
342
+ BI.toFloat32(x)
343
+ },
274
344
  t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => {
275
- WasmF32.div(WasmF32.convertI32S(boxedRationalNumerator(x)), WasmF32.convertI32S(boxedRationalDenominator(x)))
345
+ WasmF32.div(
346
+ BI.toFloat32(boxedRationalNumerator(x)),
347
+ BI.toFloat32(boxedRationalDenominator(x))
348
+ )
276
349
  },
277
350
  t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
278
351
  boxedFloat32Number(x)
@@ -288,11 +361,12 @@ export let coerceNumberToWasmF32 = (x: Number) => {
288
361
  },
289
362
  _ => {
290
363
  throw UnknownNumberTag
291
- }
364
+ },
292
365
  }
293
366
  }
294
367
  }
295
368
 
369
+ @unsafe
296
370
  export let coerceNumberToWasmF64 = (x: Number) => {
297
371
  let x = WasmI32.fromGrain(x)
298
372
  if (isSimpleNumber(x)) {
@@ -306,8 +380,14 @@ export let coerceNumberToWasmF64 = (x: Number) => {
306
380
  t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
307
381
  WasmF64.convertI64S(boxedInt64Number(x))
308
382
  },
383
+ t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
384
+ BI.toFloat64(x)
385
+ },
309
386
  t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => {
310
- WasmF64.div(WasmF64.convertI32S(boxedRationalNumerator(x)), WasmF64.convertI32S(boxedRationalDenominator(x)))
387
+ WasmF64.div(
388
+ BI.toFloat64(boxedRationalNumerator(x)),
389
+ BI.toFloat64(boxedRationalDenominator(x))
390
+ )
311
391
  },
312
392
  t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
313
393
  WasmF64.promoteF32(boxedFloat32Number(x))
@@ -317,11 +397,12 @@ export let coerceNumberToWasmF64 = (x: Number) => {
317
397
  },
318
398
  _ => {
319
399
  throw UnknownNumberTag
320
- }
400
+ },
321
401
  }
322
402
  }
323
403
  }
324
404
 
405
+ @unsafe
325
406
  export let coerceNumberToWasmI64 = (x: Number) => {
326
407
  let x = WasmI32.fromGrain(x)
327
408
  if (isSimpleNumber(x)) {
@@ -335,14 +416,18 @@ export let coerceNumberToWasmI64 = (x: Number) => {
335
416
  t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
336
417
  boxedInt64Number(x)
337
418
  },
419
+ t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
420
+ BI.toInt64(x)
421
+ },
338
422
  _ => {
339
423
  // rationals are never integral, and we refuse to coerce floats to ints
340
424
  throw Exception.NumberNotIntlike
341
- }
425
+ },
342
426
  }
343
427
  }
344
428
  }
345
429
 
430
+ @unsafe
346
431
  export let coerceNumberToWasmI32 = (x: Number) => {
347
432
  let x = WasmI32.fromGrain(x)
348
433
  if (isSimpleNumber(x)) {
@@ -360,29 +445,63 @@ export let coerceNumberToWasmI32 = (x: Number) => {
360
445
  }
361
446
  WasmI32.wrapI64(int64)
362
447
  },
448
+ t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
449
+ BI.toInt32(x)
450
+ },
363
451
  _ => {
364
452
  // rationals are never integral, and we refuse to coerce floats to ints
365
453
  throw Exception.NumberNotIntlike
366
- }
454
+ },
367
455
  }
368
456
  }
369
457
  }
370
458
 
459
+ @unsafe
460
+ export let coerceNumberToBigInt = (x: Number) => {
461
+ let x = WasmI32.fromGrain(x)
462
+ if (isSimpleNumber(x)) {
463
+ BI.makeWrappedInt32(untagSimple(x))
464
+ } else {
465
+ let xtag = boxedNumberTag(x)
466
+ match (xtag) {
467
+ t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => {
468
+ BI.makeWrappedInt32(boxedInt32Number(x))
469
+ },
470
+ t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
471
+ BI.makeWrappedInt64(boxedInt64Number(x))
472
+ },
473
+ t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
474
+ Memory.incRef(x)
475
+ x
476
+ },
477
+ _ => {
478
+ // rationals are never integral, and we refuse to coerce floats to ints
479
+ throw Exception.NumberNotIntlike
480
+ },
481
+ }
482
+ }
483
+ }
371
484
 
372
- let isIntegerF32 = (value) => {
485
+ @unsafe
486
+ let isIntegerF32 = value => {
373
487
  WasmF32.eq(value, WasmF32.trunc(value))
374
488
  }
375
489
 
376
- let isIntegerF64 = (value) => {
490
+ @unsafe
491
+ let isIntegerF64 = value => {
377
492
  WasmF64.eq(value, WasmF64.trunc(value))
378
493
  }
379
494
 
380
- let isSafeIntegerF32 = (value) => {
381
- WasmF32.le(WasmF32.abs(value), _F32_MAX_SAFE_INTEGER) && WasmF32.eq(WasmF32.trunc(value), value)
495
+ @unsafe
496
+ let isSafeIntegerF32 = value => {
497
+ WasmF32.le(WasmF32.abs(value), _F32_MAX_SAFE_INTEGER) &&
498
+ WasmF32.eq(WasmF32.trunc(value), value)
382
499
  }
383
500
 
384
- let isSafeIntegerF64 = (value) => {
385
- WasmF64.le(WasmF64.abs(value), _F64_MAX_SAFE_INTEGER) && WasmF64.eq(WasmF64.trunc(value), value)
501
+ @unsafe
502
+ let isSafeIntegerF64 = value => {
503
+ WasmF64.le(WasmF64.abs(value), _F64_MAX_SAFE_INTEGER) &&
504
+ WasmF64.eq(WasmF64.trunc(value), value)
386
505
  }
387
506
 
388
507
  /** Number-aware equality checking
@@ -394,6 +513,7 @@ let isSafeIntegerF64 = (value) => {
394
513
  * export them!
395
514
  */
396
515
 
516
+ @unsafe
397
517
  let numberEqualSimpleHelp = (x, y) => {
398
518
  // PRECONDITION: x is a "simple" number (value tag is 0) and x !== y and isNumber(y)
399
519
  if (isSimpleNumber(y)) {
@@ -411,26 +531,31 @@ let numberEqualSimpleHelp = (x, y) => {
411
531
  let yBoxedVal = boxedInt64Number(y)
412
532
  WasmI64.eq(WasmI64.extendI32S(xval), yBoxedVal)
413
533
  },
534
+ t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
535
+ WasmI32.eqz(BI.cmpI64(y, WasmI64.extendI32S(xval)))
536
+ },
414
537
  t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => {
415
538
  // NOTE: we always store in most reduced form, so a rational and an int are never equal
416
539
  false
417
540
  },
418
541
  t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
419
542
  let yBoxedVal = boxedFloat32Number(y)
420
- isSafeIntegerF32(yBoxedVal) && WasmF32.eq(WasmF32.convertI32S(xval), yBoxedVal)
543
+ isSafeIntegerF32(yBoxedVal) &&
544
+ WasmF32.eq(WasmF32.convertI32S(xval), yBoxedVal)
421
545
  },
422
546
  t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
423
547
  let yBoxedVal = boxedFloat64Number(y)
424
- isSafeIntegerF64(yBoxedVal) && WasmF64.eq(WasmF64.convertI32S(xval), yBoxedVal)
548
+ isSafeIntegerF64(yBoxedVal) &&
549
+ WasmF64.eq(WasmF64.convertI32S(xval), yBoxedVal)
425
550
  },
426
551
  _ => {
427
552
  throw UnknownNumberTag
428
- }
553
+ },
429
554
  }
430
555
  }
431
556
  }
432
557
 
433
-
558
+ @unsafe
434
559
  let numberEqualInt64Help = (xBoxedVal, y) => {
435
560
  // PRECONDITION: x !== y and isNumber(y)
436
561
  // Basic number:
@@ -448,30 +573,37 @@ let numberEqualInt64Help = (xBoxedVal, y) => {
448
573
  let yBoxedVal = boxedInt64Number(y)
449
574
  WasmI64.eq(xBoxedVal, yBoxedVal)
450
575
  },
576
+ t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
577
+ WasmI32.eqz(BI.cmpI64(y, xBoxedVal))
578
+ },
451
579
  t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => {
452
580
  // NOTE: we always store in most reduced form, so a rational and an int are never equal
453
581
  false
454
582
  },
455
583
  t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
456
584
  let yBoxedVal = boxedFloat32Number(y)
457
- isSafeIntegerF32(yBoxedVal) && WasmI64.eq(xBoxedVal, WasmI64.truncF32S(yBoxedVal))
585
+ isSafeIntegerF32(yBoxedVal) &&
586
+ WasmI64.eq(xBoxedVal, WasmI64.truncF32S(yBoxedVal))
458
587
  },
459
588
  t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
460
589
  let yBoxedVal = boxedFloat64Number(y)
461
- isSafeIntegerF64(yBoxedVal) && WasmI64.eq(xBoxedVal, WasmI64.truncF64S(yBoxedVal))
590
+ isSafeIntegerF64(yBoxedVal) &&
591
+ WasmI64.eq(xBoxedVal, WasmI64.truncF64S(yBoxedVal))
462
592
  },
463
593
  _ => {
464
594
  throw UnknownNumberTag
465
- }
595
+ },
466
596
  }
467
597
  }
468
598
  }
469
599
 
600
+ @unsafe
470
601
  let numberEqualInt32Help = (xBoxedVal, y) => {
471
602
  // We can just pretend it's 64-bit for the equality check
472
603
  numberEqualInt64Help(WasmI64.extendI32S(xBoxedVal), y)
473
604
  }
474
605
 
606
+ @unsafe
475
607
  let numberEqualRationalHelp = (xptr, y) => {
476
608
  // PRECONDITION: x is rational and x !== y and isNumber(y)
477
609
  // Basic number: (we know it's not equal, since we never store ints as rationals)
@@ -489,30 +621,40 @@ let numberEqualRationalHelp = (xptr, y) => {
489
621
  t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
490
622
  false
491
623
  },
624
+ t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
625
+ false
626
+ },
492
627
  t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => {
493
628
  let yNumerator = boxedRationalNumerator(y)
494
629
  let yDenominator = boxedRationalDenominator(y)
495
- WasmI32.eq(xNumerator, yNumerator) && WasmI32.eq(xDenominator, yDenominator)
630
+ BI.eq(xNumerator, yNumerator) && BI.eq(xDenominator, yDenominator)
496
631
  },
497
632
  t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
498
633
  let yBoxedVal = boxedFloat32Number(y)
499
- let xAsFloat = WasmF32.div(WasmF32.convertI32S(xNumerator), WasmF32.convertI32S(xDenominator))
634
+ let xAsFloat = WasmF32.div(
635
+ BI.toFloat32(xNumerator),
636
+ BI.toFloat32(xDenominator)
637
+ )
500
638
  // TODO: (#303) maybe we should have some sort of tolerance?
501
639
  WasmF32.eq(xAsFloat, yBoxedVal)
502
640
  },
503
641
  t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
504
642
  let yBoxedVal = boxedFloat64Number(y)
505
- let xAsFloat = WasmF64.div(WasmF64.convertI32S(xNumerator), WasmF64.convertI32S(xDenominator))
643
+ let xAsFloat = WasmF64.div(
644
+ BI.toFloat64(xNumerator),
645
+ BI.toFloat64(xDenominator)
646
+ )
506
647
  // TODO: (#303) maybe we should have some sort of tolerance?
507
648
  WasmF64.eq(xAsFloat, yBoxedVal)
508
649
  },
509
650
  _ => {
510
651
  throw UnknownNumberTag
511
- }
652
+ },
512
653
  }
513
654
  }
514
655
  }
515
656
 
657
+ @unsafe
516
658
  let numberEqualFloat64Help = (x, y) => {
517
659
  let xIsInteger = isIntegerF64(x)
518
660
  // Basic number:
@@ -530,10 +672,16 @@ let numberEqualFloat64Help = (x, y) => {
530
672
  let yBoxedVal = boxedInt64Number(y)
531
673
  isSafeIntegerF64(x) && WasmF64.eq(x, WasmF64.convertI64S(yBoxedVal))
532
674
  },
675
+ t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
676
+ WasmI32.eqz(BI.cmpF64(y, x))
677
+ },
533
678
  t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => {
534
679
  let yNumerator = boxedRationalNumerator(y)
535
680
  let yDenominator = boxedRationalDenominator(y)
536
- let yAsFloat = WasmF64.div(WasmF64.convertI32S(yNumerator), WasmF64.convertI32S(yDenominator))
681
+ let yAsFloat = WasmF64.div(
682
+ BI.toFloat64(yNumerator),
683
+ BI.toFloat64(yDenominator)
684
+ )
537
685
  WasmF64.eq(x, yAsFloat)
538
686
  },
539
687
  t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
@@ -548,11 +696,12 @@ let numberEqualFloat64Help = (x, y) => {
548
696
  },
549
697
  _ => {
550
698
  throw UnknownNumberTag
551
- }
699
+ },
552
700
  }
553
701
  }
554
702
  }
555
703
 
704
+ @unsafe
556
705
  let numberEqualFloat32Help = (x, y) => {
557
706
  let xIsInteger = isIntegerF32(x)
558
707
  // Basic number:
@@ -568,11 +717,50 @@ let numberEqualFloat32Help = (x, y) => {
568
717
  },
569
718
  _ => {
570
719
  numberEqualFloat64Help(WasmF64.promoteF32(x), y)
571
- }
720
+ },
721
+ }
722
+ }
723
+ }
724
+
725
+ @unsafe
726
+ let numberEqualBigIntHelp = (x, y) => {
727
+ if (isSimpleNumber(y)) {
728
+ WasmI32.eqz(BI.cmpI64(x, WasmI64.extendI32S(untagSimple(y))))
729
+ } else {
730
+ // Boxed number
731
+ let yBoxedNumberTag = boxedNumberTag(y)
732
+ match (yBoxedNumberTag) {
733
+ t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => {
734
+ let yBoxedVal = boxedInt32Number(y)
735
+ WasmI32.eqz(BI.cmpI64(x, WasmI64.extendI32S(yBoxedVal)))
736
+ },
737
+ t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
738
+ let yBoxedVal = boxedInt64Number(y)
739
+ WasmI32.eqz(BI.cmpI64(x, yBoxedVal))
740
+ },
741
+ t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
742
+ BI.eq(x, y)
743
+ },
744
+ t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => {
745
+ // Rationals are reduced, so it must be unequal
746
+ false
747
+ },
748
+ t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
749
+ let yBoxedVal = boxedFloat32Number(y)
750
+ WasmI32.eqz(BI.cmpF32(x, yBoxedVal))
751
+ },
752
+ t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
753
+ let yBoxedVal = boxedFloat64Number(y)
754
+ WasmI32.eqz(BI.cmpF64(x, yBoxedVal))
755
+ },
756
+ _ => {
757
+ throw UnknownNumberTag
758
+ },
572
759
  }
573
760
  }
574
761
  }
575
762
 
763
+ @unsafe
576
764
  export let numberEqual = (x, y) => {
577
765
  if (isSimpleNumber(x)) {
578
766
  // Short circuit if non-pointer value is the same
@@ -598,9 +786,12 @@ export let numberEqual = (x, y) => {
598
786
  t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
599
787
  numberEqualFloat64Help(boxedFloat64Number(x), y)
600
788
  },
789
+ t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
790
+ numberEqualBigIntHelp(x, y)
791
+ },
601
792
  _ => {
602
793
  throw UnknownNumberTag
603
- }
794
+ },
604
795
  }
605
796
  }
606
797
  }
@@ -610,6 +801,7 @@ export let numberEqual = (x, y) => {
610
801
  * (same schema as equal())
611
802
  */
612
803
 
804
+ @unsafe
613
805
  let numberAddSubSimpleHelp = (x, y, isSub) => {
614
806
  // PRECONDITION: x is a "simple" number (value tag is 0) and isNumber(y)
615
807
  if (isSimpleNumber(y)) {
@@ -628,209 +820,424 @@ let numberAddSubSimpleHelp = (x, y, isSub) => {
628
820
  t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => {
629
821
  let xval = WasmI64.extendI32S(xval)
630
822
  let yBoxedVal = WasmI64.extendI32S(boxedInt32Number(y))
631
- let result = if (isSub) WasmI64.sub(xval, yBoxedVal) else WasmI64.add(xval, yBoxedVal)
823
+ let result = if (isSub) WasmI64.sub(xval, yBoxedVal)
824
+ else WasmI64.add(xval, yBoxedVal)
632
825
  reducedInteger(result)
633
826
  },
634
827
  t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
635
828
  let yBoxedVal = boxedInt64Number(y)
636
829
  let xval64 = WasmI64.extendI32S(xval)
637
- let result = if (isSub) WasmI64.sub(xval64, yBoxedVal) else WasmI64.add(xval64, yBoxedVal)
638
- if (WasmI64.geS(yBoxedVal, 0N) && WasmI64.ltS(result, xval64)) {
639
- throw Exception.Overflow
640
- } else if (WasmI64.ltS(yBoxedVal, 0N) && WasmI64.gtS(result, xval64)) {
641
- throw Exception.Overflow
830
+ let result = if (isSub) WasmI64.sub(xval64, yBoxedVal)
831
+ else WasmI64.add(xval64, yBoxedVal)
832
+ if (
833
+ WasmI64.geS(yBoxedVal, 0N) && WasmI64.ltS(result, xval64) ||
834
+ WasmI64.ltS(yBoxedVal, 0N) && WasmI64.gtS(result, xval64)
835
+ ) {
836
+ // Overflow. Promote to BigInt
837
+ let xBig = BI.makeWrappedInt32(xval)
838
+ let yBig = BI.makeWrappedInt64(yBoxedVal)
839
+ let res = if (isSub) {
840
+ BI.sub(xBig, yBig)
841
+ } else {
842
+ BI.add(xBig, yBig)
843
+ }
844
+ Memory.decRef(xBig)
845
+ Memory.decRef(yBig)
846
+ reducedBigInteger(res)
642
847
  } else {
643
848
  reducedInteger(result)
644
849
  }
645
850
  },
851
+ t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
852
+ // Promote x to bigint and do operation
853
+ let xBig = BI.makeWrappedInt32(xval)
854
+ let result = if (isSub) BI.sub(xBig, y) else BI.add(xBig, y)
855
+ Memory.decRef(xBig)
856
+ reducedBigInteger(result)
857
+ },
646
858
  t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => {
647
- let yNumerator = WasmI64.extendI32S(boxedRationalNumerator(y))
648
- let yDenominator = WasmI64.extendI32S(boxedRationalDenominator(y))
649
- let expandedXNumerator = safeI64Multiply(WasmI64.extendI32S(xval), yDenominator)
650
- let result = if (isSub) WasmI64.sub(expandedXNumerator, yNumerator) else WasmI64.add(expandedXNumerator, yNumerator)
651
- if (WasmI64.ltS(result, _I32_MIN) || WasmI64.gtS(result, _I32_MAX)) {
652
- throw Exception.Overflow
653
- }
654
- reducedFraction64(result, yDenominator)
859
+ let xBig = BI.makeWrappedInt32(xval)
860
+ let yNumerator = boxedRationalNumerator(y)
861
+ let yDenominator = boxedRationalDenominator(y)
862
+ let expandedXNumerator = BI.mul(xBig, yDenominator)
863
+ Memory.decRef(xBig)
864
+ let result = if (isSub) BI.sub(expandedXNumerator, yNumerator)
865
+ else BI.add(expandedXNumerator, yNumerator)
866
+ let ret = reducedFractionBigInt(result, yDenominator)
867
+ Memory.decRef(expandedXNumerator)
868
+ Memory.decRef(result)
869
+ ret
655
870
  },
656
871
  t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
657
872
  let yBoxedVal = boxedFloat32Number(y)
658
873
  let xval = WasmF32.convertI32S(xval)
659
- let result = if (isSub) WasmF32.sub(xval, yBoxedVal) else WasmF32.add(xval, yBoxedVal)
874
+ let result = if (isSub) WasmF32.sub(xval, yBoxedVal)
875
+ else WasmF32.add(xval, yBoxedVal)
660
876
  // TODO: (#304) is this safe?
661
877
  newFloat32(result)
662
878
  },
663
879
  t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
664
880
  let yBoxedVal = boxedFloat64Number(y)
665
881
  let xval = WasmF64.convertI32S(xval)
666
- let result = if (isSub) WasmF64.sub(xval, yBoxedVal) else WasmF64.add(xval, yBoxedVal)
882
+ let result = if (isSub) WasmF64.sub(xval, yBoxedVal)
883
+ else WasmF64.add(xval, yBoxedVal)
667
884
  newFloat64(result)
668
885
  },
669
886
  _ => {
670
887
  throw UnknownNumberTag
671
- }
888
+ },
672
889
  }
673
890
  }
674
891
  }
675
892
 
893
+ @unsafe
676
894
  let numberAddSubInt64Help = (xval, y, isSub) => {
677
895
  if (isSimpleNumber(y)) {
678
896
  let yval = WasmI64.extendI32S(untagSimple(y))
679
897
  let result = if (isSub) WasmI64.sub(xval, yval) else WasmI64.add(xval, yval)
680
- if (WasmI64.geS(yval, 0N) && WasmI64.ltS(result, xval)) {
681
- throw Exception.Overflow
682
- } else if (WasmI64.ltS(yval, 0N) && WasmI64.gtS(result, xval)) {
683
- throw Exception.Overflow
898
+ if (
899
+ WasmI64.geS(yval, 0N) && WasmI64.ltS(result, xval) ||
900
+ WasmI64.ltS(yval, 0N) && WasmI64.gtS(result, xval)
901
+ ) {
902
+ // Overflow. Promote to BigInt
903
+ let xBig = BI.makeWrappedInt64(xval)
904
+ let yBig = BI.makeWrappedInt64(yval)
905
+ let res = if (isSub) {
906
+ BI.sub(xBig, yBig)
907
+ } else {
908
+ BI.add(xBig, yBig)
909
+ }
910
+ Memory.decRef(xBig)
911
+ Memory.decRef(yBig)
912
+ reducedBigInteger(res)
913
+ } else {
914
+ reducedInteger(result)
684
915
  }
685
- reducedInteger(result)
686
916
  } else {
687
917
  let yBoxedNumberTag = boxedNumberTag(y)
688
918
  match (yBoxedNumberTag) {
689
919
  t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => {
690
920
  let yBoxedVal = WasmI64.extendI32S(boxedInt32Number(y))
691
- let result = if (isSub) WasmI64.sub(xval, yBoxedVal) else WasmI64.add(xval, yBoxedVal)
921
+ let result = if (isSub) WasmI64.sub(xval, yBoxedVal)
922
+ else WasmI64.add(xval, yBoxedVal)
692
923
  reducedInteger(result)
693
924
  },
694
925
  t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
695
926
  let yBoxedVal = boxedInt64Number(y)
696
927
  let xval64 = xval
697
- let result = if (isSub) WasmI64.sub(xval64, yBoxedVal) else WasmI64.add(xval64, yBoxedVal)
698
- if (WasmI64.geS(yBoxedVal, 0N) && WasmI64.ltS(result, xval64)) {
699
- throw Exception.Overflow
700
- } else if (WasmI64.ltS(yBoxedVal, 0N) && WasmI64.gtS(result, xval64)) {
701
- throw Exception.Overflow
928
+ let result = if (isSub) WasmI64.sub(xval64, yBoxedVal)
929
+ else WasmI64.add(xval64, yBoxedVal)
930
+ if (
931
+ WasmI64.geS(yBoxedVal, 0N) && WasmI64.ltS(result, xval64) ||
932
+ WasmI64.ltS(yBoxedVal, 0N) && WasmI64.gtS(result, xval64)
933
+ ) {
934
+ // Overflow. Promote to BigInt
935
+ let xBig = BI.makeWrappedInt64(xval64)
936
+ let yBig = BI.makeWrappedInt64(yBoxedVal)
937
+ let res = if (isSub) {
938
+ BI.sub(xBig, yBig)
939
+ } else {
940
+ BI.add(xBig, yBig)
941
+ }
942
+ Memory.decRef(xBig)
943
+ Memory.decRef(yBig)
944
+ reducedBigInteger(res)
702
945
  } else {
703
946
  reducedInteger(result)
704
947
  }
705
948
  },
949
+ t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
950
+ // Promote x to bigint and do operation
951
+ let xBig = BI.makeWrappedInt64(xval)
952
+ let result = if (isSub) BI.sub(xBig, y) else BI.add(xBig, y)
953
+ Memory.decRef(xBig)
954
+ reducedBigInteger(result)
955
+ },
706
956
  t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => {
707
- let yNumerator = WasmI64.extendI32S(boxedRationalNumerator(y))
708
- let yDenominator = WasmI64.extendI32S(boxedRationalDenominator(y))
709
- let expandedXNumerator = safeI64Multiply(xval, yDenominator)
710
- let result = if (isSub) WasmI64.sub(expandedXNumerator, yNumerator) else WasmI64.add(expandedXNumerator, yNumerator)
711
- if (WasmI64.ltS(result, _I32_MIN) || WasmI64.gtS(result, _I32_MAX)) {
712
- throw Exception.Overflow
713
- }
714
- reducedFraction64(result, yDenominator)
957
+ let xBig = BI.makeWrappedInt64(xval)
958
+ let yNumerator = boxedRationalNumerator(y)
959
+ let yDenominator = boxedRationalDenominator(y)
960
+ let expandedXNumerator = BI.mul(xBig, yDenominator)
961
+ Memory.decRef(xBig)
962
+ let result = if (isSub) BI.sub(expandedXNumerator, yNumerator)
963
+ else BI.add(expandedXNumerator, yNumerator)
964
+ let ret = reducedFractionBigInt(result, yDenominator)
965
+ Memory.decRef(expandedXNumerator)
966
+ Memory.decRef(result)
967
+ ret
715
968
  },
716
969
  t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
717
970
  let xval = WasmF32.convertI64S(xval)
718
971
  let yBoxedVal = boxedFloat32Number(y)
719
- let result = if (isSub) WasmF32.sub(xval, yBoxedVal) else WasmF32.add(xval, yBoxedVal)
720
- // TODO: (#304) this isn't safe enough
972
+ let result = if (isSub) WasmF32.sub(xval, yBoxedVal)
973
+ else WasmF32.add(xval, yBoxedVal)
974
+ // TODO(#304): this isn't safe enough
721
975
  newFloat32(result)
722
976
  },
723
977
  t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
724
978
  let xval = WasmF64.convertI64S(xval)
725
979
  let yBoxedVal = boxedFloat64Number(y)
726
- let result = if (isSub) WasmF64.sub(xval, yBoxedVal) else WasmF64.add(xval, yBoxedVal)
980
+ let result = if (isSub) WasmF64.sub(xval, yBoxedVal)
981
+ else WasmF64.add(xval, yBoxedVal)
727
982
  newFloat64(result)
728
983
  },
729
984
  _ => {
730
985
  throw UnknownNumberTag
731
- }
986
+ },
732
987
  }
733
988
  }
734
989
  }
735
990
 
991
+ @unsafe
736
992
  let numberAddSubFloat32Help = (xval, y, isSub) => {
737
- if (!isSimpleNumber(y) && WasmI32.eq(boxedNumberTag(y), Tags._GRAIN_FLOAT64_BOXED_NUM_TAG)) {
993
+ if (
994
+ !isSimpleNumber(y) &&
995
+ WasmI32.eq(boxedNumberTag(y), Tags._GRAIN_FLOAT64_BOXED_NUM_TAG)
996
+ ) {
738
997
  // Special case: promote to f64 if RHS is f64
739
998
  let xval = WasmF64.promoteF32(xval)
740
999
  let yval = boxedFloat64Number(y)
741
1000
  let result = if (isSub) WasmF64.sub(xval, yval) else WasmF64.add(xval, yval)
742
1001
  newFloat64(result)
743
1002
  } else {
744
- let yval = coerceNumberToWasmF32(WasmI32.toGrain(y) : Number)
1003
+ // incRef y to reuse it via WasmI32.toGrain
1004
+ Memory.incRef(y)
1005
+ let yval = coerceNumberToWasmF32(WasmI32.toGrain(y): Number)
745
1006
  let result = if (isSub) WasmF32.sub(xval, yval) else WasmF32.add(xval, yval)
746
1007
  newFloat32(result)
747
1008
  }
748
1009
  }
749
1010
 
1011
+ @unsafe
750
1012
  let numberAddSubFloat64Help = (xval, y, isSub) => {
751
- let yval = coerceNumberToWasmF64(WasmI32.toGrain(y) : Number)
1013
+ // incRef y to reuse it via WasmI32.toGrain
1014
+ Memory.incRef(y)
1015
+ let yval = coerceNumberToWasmF64(WasmI32.toGrain(y): Number)
752
1016
  let result = if (isSub) WasmF64.sub(xval, yval) else WasmF64.add(xval, yval)
753
1017
  newFloat64(result)
754
1018
  }
755
1019
 
756
-
1020
+ @unsafe
757
1021
  let numberAddSubInt32Help = (xval, y, isSub) => {
758
1022
  numberAddSubInt64Help(WasmI64.extendI32S(xval), y, isSub)
759
1023
  }
760
1024
 
761
- let rec numberAddSubHelp = (x, y, isSub) => {
762
- if (isSimpleNumber(x)) {
763
- numberAddSubSimpleHelp(x, y, isSub)
1025
+ @unsafe
1026
+ let numberAddSubBigIntHelp = (x, y, isSub) => {
1027
+ if (isSimpleNumber(y)) {
1028
+ let yval = WasmI64.extendI32S(untagSimple(y))
1029
+ let yBig = BI.makeWrappedInt64(yval)
1030
+ let res = if (isSub) {
1031
+ BI.sub(x, yBig)
1032
+ } else {
1033
+ BI.add(x, yBig)
1034
+ }
1035
+ Memory.decRef(yBig)
1036
+ reducedBigInteger(res)
764
1037
  } else {
765
- let xtag = boxedNumberTag(x)
766
- match (xtag) {
1038
+ let yBoxedNumberTag = boxedNumberTag(y)
1039
+ match (yBoxedNumberTag) {
767
1040
  t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => {
768
- numberAddSubInt32Help(boxedInt32Number(x), y, isSub)
1041
+ let yBoxedVal = WasmI64.extendI32S(boxedInt32Number(y))
1042
+ let yBig = BI.makeWrappedInt64(yBoxedVal)
1043
+ let res = if (isSub) {
1044
+ BI.sub(x, yBig)
1045
+ } else {
1046
+ BI.add(x, yBig)
1047
+ }
1048
+ Memory.decRef(yBig)
1049
+ reducedBigInteger(res)
769
1050
  },
770
1051
  t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
771
- numberAddSubInt64Help(boxedInt64Number(x), y, isSub)
1052
+ let yBoxedVal = boxedInt64Number(y)
1053
+ let yBig = BI.makeWrappedInt64(yBoxedVal)
1054
+ let res = if (isSub) {
1055
+ BI.sub(x, yBig)
1056
+ } else {
1057
+ BI.add(x, yBig)
1058
+ }
1059
+ Memory.decRef(yBig)
1060
+ reducedBigInteger(res)
1061
+ },
1062
+ t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
1063
+ let res = if (isSub) {
1064
+ BI.sub(x, y)
1065
+ } else {
1066
+ BI.add(x, y)
1067
+ }
1068
+ reducedBigInteger(res)
772
1069
  },
773
1070
  t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => {
774
- numberAddSubRationalHelp(x, y, isSub)
1071
+ let yNumerator = boxedRationalNumerator(y)
1072
+ let yDenominator = boxedRationalDenominator(y)
1073
+ let expandedXNumerator = BI.mul(x, yDenominator)
1074
+ let result = if (isSub) BI.sub(expandedXNumerator, yNumerator)
1075
+ else BI.add(expandedXNumerator, yNumerator)
1076
+ Memory.decRef(expandedXNumerator)
1077
+ let ret = reducedFractionBigInt(result, yDenominator)
1078
+ Memory.decRef(result)
1079
+ ret
775
1080
  },
776
1081
  t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
777
- numberAddSubFloat32Help(boxedFloat32Number(x), y, isSub)
1082
+ let xval = BI.toFloat32(x)
1083
+ let yBoxedVal = boxedFloat32Number(y)
1084
+ let result = if (isSub) WasmF32.sub(xval, yBoxedVal)
1085
+ else WasmF32.add(xval, yBoxedVal)
1086
+ // TODO: (#304) this isn't safe enough
1087
+ newFloat32(result)
778
1088
  },
779
1089
  t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
780
- numberAddSubFloat64Help(boxedFloat64Number(x), y, isSub)
1090
+ let xval = BI.toFloat64(x)
1091
+ let yBoxedVal = boxedFloat64Number(y)
1092
+ let result = if (isSub) WasmF64.sub(xval, yBoxedVal)
1093
+ else WasmF64.add(xval, yBoxedVal)
1094
+ newFloat64(result)
781
1095
  },
782
1096
  _ => {
783
1097
  throw UnknownNumberTag
784
- }
1098
+ },
785
1099
  }
786
1100
  }
787
- },
788
- numberAddSubRationalHelp = (x, y, isSub) => {
1101
+ }
1102
+
1103
+ @unsafe
1104
+ let numberAddSubRationalHelp = (x, y, isSub) => {
1105
+ let xNumerator = boxedRationalNumerator(x)
1106
+ let xDenominator = boxedRationalDenominator(x)
789
1107
  if (isSimpleNumber(y)) {
790
- numberAddSubSimpleHelp(y, x, isSub)
1108
+ let yval = untagSimple(y)
1109
+ let yBig = BI.makeWrappedInt32(yval)
1110
+ let expandedYNumerator = BI.mul(xDenominator, yBig)
1111
+ let result = if (isSub) BI.sub(xNumerator, expandedYNumerator)
1112
+ else BI.add(xNumerator, expandedYNumerator)
1113
+ Memory.decRef(expandedYNumerator)
1114
+ Memory.decRef(yBig)
1115
+ let ret = reducedFractionBigInt(result, xDenominator)
1116
+ Memory.decRef(result)
1117
+ ret
791
1118
  } else {
792
1119
  let ytag = boxedNumberTag(y)
793
1120
  match (ytag) {
794
1121
  t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => {
795
1122
  // The one case we don't delegate is rational +/- rational
796
- let xNumerator = WasmI64.extendI32S(boxedRationalNumerator(x))
797
- let xDenominator = WasmI64.extendI32S(boxedRationalDenominator(x))
798
- let yNumerator = WasmI64.extendI32S(boxedRationalNumerator(y))
799
- let yDenominator = WasmI64.extendI32S(boxedRationalDenominator(y))
800
- // TODO: {#304) this could be written in a more overflow-proof way
801
- if (WasmI64.eq(xDenominator, yDenominator)) {
802
- let result = if (isSub) WasmI64.sub(xNumerator, yNumerator) else WasmI64.add(xNumerator, yNumerator)
803
- reducedFraction64(result, xDenominator)
1123
+ let xNumerator = boxedRationalNumerator(x)
1124
+ let xDenominator = boxedRationalDenominator(x)
1125
+ let yNumerator = boxedRationalNumerator(y)
1126
+ let yDenominator = boxedRationalDenominator(y)
1127
+ if (BI.eq(xDenominator, yDenominator)) {
1128
+ let newNumerator = if (isSub) BI.sub(xNumerator, yNumerator)
1129
+ else BI.add(xNumerator, yNumerator)
1130
+ let ret = reducedFractionBigInt(newNumerator, xDenominator)
1131
+ Memory.decRef(newNumerator)
1132
+ ret
804
1133
  } else {
805
- let numerator1 = safeI64Multiply(xNumerator, yDenominator)
806
- let numerator2 = safeI64Multiply(yNumerator, xDenominator)
807
- let numerator = if (isSub) WasmI64.sub(numerator1, numerator2) else WasmI64.add(numerator1, numerator2)
808
- let denominator = safeI64Multiply(xDenominator, yDenominator)
809
- reducedFraction64(numerator, denominator)
1134
+ let numerator1 = BI.mul(xNumerator, yDenominator)
1135
+ let numerator2 = BI.mul(yNumerator, xDenominator)
1136
+ let numerator = if (isSub) BI.sub(numerator1, numerator2)
1137
+ else BI.add(numerator1, numerator2)
1138
+ let denominator = BI.mul(xDenominator, yDenominator)
1139
+ let ret = reducedFractionBigInt(numerator, denominator)
1140
+ Memory.decRef(numerator1)
1141
+ Memory.decRef(numerator2)
1142
+ Memory.decRef(numerator)
1143
+ ret
810
1144
  }
811
- }, t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => {
812
- numberAddSubHelp(y, x, isSub)
1145
+ },
1146
+ t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => {
1147
+ let yBig = BI.makeWrappedInt32(boxedInt32Number(y))
1148
+ let expandedYNumerator = BI.mul(yBig, xDenominator)
1149
+ Memory.decRef(yBig)
1150
+ let result = if (isSub) BI.sub(xNumerator, expandedYNumerator)
1151
+ else BI.add(xNumerator, expandedYNumerator)
1152
+ let ret = reducedFractionBigInt(result, xDenominator)
1153
+ Memory.decRef(expandedYNumerator)
1154
+ Memory.decRef(result)
1155
+ ret
813
1156
  },
814
1157
  t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
815
- numberAddSubHelp(y, x, isSub)
1158
+ let yBig = BI.makeWrappedInt64(boxedInt64Number(y))
1159
+ let expandedYNumerator = BI.mul(yBig, xDenominator)
1160
+ Memory.decRef(yBig)
1161
+ let result = if (isSub) BI.sub(xNumerator, expandedYNumerator)
1162
+ else BI.add(xNumerator, expandedYNumerator)
1163
+ let ret = reducedFractionBigInt(result, xDenominator)
1164
+ Memory.decRef(expandedYNumerator)
1165
+ Memory.decRef(result)
1166
+ ret
1167
+ },
1168
+ t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
1169
+ let expandedYNumerator = BI.mul(xDenominator, y)
1170
+ let result = if (isSub) BI.sub(xNumerator, expandedYNumerator)
1171
+ else BI.add(xNumerator, expandedYNumerator)
1172
+ Memory.decRef(expandedYNumerator)
1173
+ let ret = reducedFractionBigInt(result, xDenominator)
1174
+ Memory.decRef(result)
1175
+ ret
816
1176
  },
817
1177
  t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
818
- numberAddSubHelp(y, x, isSub)
1178
+ let xval = WasmF32.div(
1179
+ BI.toFloat32(xNumerator),
1180
+ BI.toFloat32(xDenominator)
1181
+ )
1182
+ let result = if (isSub) WasmF32.sub(xval, boxedFloat32Number(y))
1183
+ else WasmF32.add(xval, boxedFloat32Number(y))
1184
+ newFloat32(result)
819
1185
  },
820
1186
  t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
821
- numberAddSubHelp(y, x, isSub)
1187
+ let xnumfloat = BI.toFloat64(xNumerator)
1188
+ let xdenfloat = BI.toFloat64(xDenominator)
1189
+ let xval = WasmF64.div(xnumfloat, xdenfloat)
1190
+ let yval = boxedFloat64Number(y)
1191
+ let result = if (isSub) WasmF64.sub(xval, yval)
1192
+ else WasmF64.add(xval, yval)
1193
+ let ret = newFloat64(result)
1194
+ ret
822
1195
  },
823
1196
  _ => {
824
1197
  throw UnknownNumberTag
825
- }
1198
+ },
826
1199
  }
827
1200
  }
828
1201
  }
829
1202
 
1203
+ @unsafe
1204
+ let numberAddSubHelp = (x, y, isSub) => {
1205
+ if (isSimpleNumber(x)) {
1206
+ numberAddSubSimpleHelp(x, y, isSub)
1207
+ } else {
1208
+ let xtag = boxedNumberTag(x)
1209
+ match (xtag) {
1210
+ t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => {
1211
+ numberAddSubInt32Help(boxedInt32Number(x), y, isSub)
1212
+ },
1213
+ t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
1214
+ numberAddSubInt64Help(boxedInt64Number(x), y, isSub)
1215
+ },
1216
+ t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
1217
+ numberAddSubBigIntHelp(x, y, isSub)
1218
+ },
1219
+ t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => {
1220
+ numberAddSubRationalHelp(x, y, isSub)
1221
+ },
1222
+ t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
1223
+ numberAddSubFloat32Help(boxedFloat32Number(x), y, isSub)
1224
+ },
1225
+ t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
1226
+ numberAddSubFloat64Help(boxedFloat64Number(x), y, isSub)
1227
+ },
1228
+ _ => {
1229
+ throw UnknownNumberTag
1230
+ },
1231
+ }
1232
+ }
1233
+ }
1234
+
1235
+ @unsafe
830
1236
  let numberAdd = (x, y) => {
831
1237
  WasmI32.toGrain(numberAddSubHelp(x, y, false)): Number
832
1238
  }
833
1239
 
1240
+ @unsafe
834
1241
  let numberSub = (x, y) => {
835
1242
  WasmI32.toGrain(numberAddSubHelp(x, y, true)): Number
836
1243
  }
@@ -840,12 +1247,32 @@ let numberSub = (x, y) => {
840
1247
  * (same schema as equal())
841
1248
  */
842
1249
 
1250
+ @unsafe
1251
+ let safeI64Multiply = (x, y) => {
1252
+ let prod = WasmI64.mul(x, y)
1253
+ if (WasmI64.ne(x, 0N)) {
1254
+ if (WasmI64.ne(WasmI64.divS(prod, x), y)) {
1255
+ let xBig = BI.makeWrappedInt64(x)
1256
+ let yBig = BI.makeWrappedInt64(y)
1257
+ let result = BI.mul(xBig, yBig)
1258
+ Memory.decRef(xBig)
1259
+ Memory.decRef(yBig)
1260
+ result
1261
+ } else {
1262
+ reducedInteger(prod)
1263
+ }
1264
+ } else {
1265
+ reducedInteger(prod)
1266
+ }
1267
+ }
1268
+
1269
+ @unsafe
843
1270
  let numberTimesDivideInt64Help = (xval, y, isDivide) => {
844
1271
  if (isSimpleNumber(y)) {
845
1272
  if (isDivide) {
846
1273
  reducedFraction64(xval, WasmI64.extendI32S(untagSimple(y)))
847
1274
  } else {
848
- reducedInteger(safeI64Multiply(xval, WasmI64.extendI32S(untagSimple(y))))
1275
+ safeI64Multiply(xval, WasmI64.extendI32S(untagSimple(y)))
849
1276
  }
850
1277
  } else {
851
1278
  let yBoxedNumberTag = boxedNumberTag(y)
@@ -855,7 +1282,7 @@ let numberTimesDivideInt64Help = (xval, y, isDivide) => {
855
1282
  if (isDivide) {
856
1283
  reducedFraction64(xval, yBoxedVal)
857
1284
  } else {
858
- reducedInteger(safeI64Multiply(xval, yBoxedVal))
1285
+ safeI64Multiply(xval, yBoxedVal)
859
1286
  }
860
1287
  },
861
1288
  t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
@@ -863,21 +1290,38 @@ let numberTimesDivideInt64Help = (xval, y, isDivide) => {
863
1290
  if (isDivide) {
864
1291
  reducedFraction64(xval, yBoxedVal)
865
1292
  } else {
866
- reducedInteger(safeI64Multiply(xval, yBoxedVal))
1293
+ safeI64Multiply(xval, yBoxedVal)
1294
+ }
1295
+ },
1296
+ t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
1297
+ let xBig = BI.makeWrappedInt64(xval)
1298
+ let ret = if (isDivide) {
1299
+ reducedFractionBigInt(xBig, y)
1300
+ } else {
1301
+ reducedBigInteger(BI.mul(xBig, y))
867
1302
  }
1303
+ Memory.decRef(xBig)
1304
+ ret
868
1305
  },
869
1306
  t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => {
870
- let yNumerator = WasmI64.extendI32S(boxedRationalNumerator(y))
871
- let yDenominator = WasmI64.extendI32S(boxedRationalDenominator(y))
872
- if (isDivide) {
1307
+ let yNumerator = boxedRationalNumerator(y)
1308
+ let yDenominator = boxedRationalDenominator(y)
1309
+ let xBig = BI.makeWrappedInt64(xval)
1310
+ let ret = if (isDivide) {
873
1311
  // x / (a / b) == (x * b) / a
874
- let numerator = safeI64Multiply(xval, yDenominator)
875
- reducedFraction64(numerator, yNumerator)
1312
+ let numerator = BI.mul(xBig, yDenominator)
1313
+ let ret = reducedFractionBigInt(numerator, yNumerator)
1314
+ Memory.decRef(numerator)
1315
+ ret
876
1316
  } else {
877
1317
  // x * (a / b) == (x * a) / b
878
- let numerator = safeI64Multiply(xval, yNumerator)
879
- reducedFraction64(numerator, yDenominator)
1318
+ let numerator = BI.mul(xBig, yNumerator)
1319
+ let ret = reducedFractionBigInt(numerator, yDenominator)
1320
+ Memory.decRef(numerator)
1321
+ ret
880
1322
  }
1323
+ Memory.decRef(xBig)
1324
+ ret
881
1325
  },
882
1326
  t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
883
1327
  let xval = WasmF32.convertI64S(xval)
@@ -900,76 +1344,204 @@ let numberTimesDivideInt64Help = (xval, y, isDivide) => {
900
1344
  },
901
1345
  _ => {
902
1346
  throw UnknownNumberTag
903
- }
1347
+ },
1348
+ }
1349
+ }
1350
+ }
1351
+
1352
+ @unsafe
1353
+ let numberTimesDivideBigIntHelp = (x, y, isDivide) => {
1354
+ if (isSimpleNumber(y)) {
1355
+ let yBig = BI.makeWrappedInt32(untagSimple(y))
1356
+ let ret = if (isDivide) {
1357
+ reducedFractionBigInt(x, yBig)
1358
+ } else {
1359
+ reducedBigInteger(BI.mul(x, yBig))
1360
+ }
1361
+ Memory.decRef(yBig)
1362
+ ret
1363
+ } else {
1364
+ let yBoxedNumberTag = boxedNumberTag(y)
1365
+ match (yBoxedNumberTag) {
1366
+ t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => {
1367
+ let yBoxedVal = WasmI64.extendI32S(boxedInt32Number(y))
1368
+ let yBig = BI.makeWrappedInt64(yBoxedVal)
1369
+ let ret = if (isDivide) {
1370
+ reducedFractionBigInt(x, yBig)
1371
+ } else {
1372
+ reducedBigInteger(BI.mul(x, yBig))
1373
+ }
1374
+ Memory.decRef(yBig)
1375
+ ret
1376
+ },
1377
+ t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
1378
+ let yBoxedVal = boxedInt64Number(y)
1379
+ let yBig = BI.makeWrappedInt64(yBoxedVal)
1380
+ let ret = if (isDivide) {
1381
+ reducedFractionBigInt(x, yBig)
1382
+ } else {
1383
+ reducedBigInteger(BI.mul(x, yBig))
1384
+ }
1385
+ Memory.decRef(yBig)
1386
+ ret
1387
+ },
1388
+ t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => {
1389
+ let yNumerator = boxedRationalNumerator(y)
1390
+ let yDenominator = boxedRationalDenominator(y)
1391
+ if (isDivide) {
1392
+ // x / (a / b) == (x * b) / a
1393
+ let numerator = BI.mul(x, yDenominator)
1394
+ let ret = reducedFractionBigInt(numerator, yNumerator)
1395
+ Memory.decRef(numerator)
1396
+ ret
1397
+ } else {
1398
+ // x * (a / b) == (x * a) / b
1399
+ let numerator = BI.mul(x, yNumerator)
1400
+ let ret = reducedFractionBigInt(numerator, yDenominator)
1401
+ Memory.decRef(numerator)
1402
+ ret
1403
+ }
1404
+ },
1405
+ t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
1406
+ // We make the decision to always promote to f64 here, since
1407
+ // we can only fit rather small bigints (<4 limbs) into an F32
1408
+ let xval = BI.toFloat64(x)
1409
+ let yBoxedVal = WasmF64.promoteF32(boxedFloat32Number(y))
1410
+ // TODO: (#304) is this safe?
1411
+ if (isDivide) {
1412
+ newFloat64(WasmF64.div(xval, yBoxedVal))
1413
+ } else {
1414
+ newFloat64(WasmF64.mul(xval, yBoxedVal))
1415
+ }
1416
+ },
1417
+ t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
1418
+ let xval = BI.toFloat64(x)
1419
+ let yBoxedVal = boxedFloat64Number(y)
1420
+ if (isDivide) {
1421
+ newFloat64(WasmF64.div(xval, yBoxedVal))
1422
+ } else {
1423
+ newFloat64(WasmF64.mul(xval, yBoxedVal))
1424
+ }
1425
+ },
1426
+ _ => {
1427
+ throw UnknownNumberTag
1428
+ },
904
1429
  }
905
1430
  }
906
1431
  }
907
1432
 
1433
+ @unsafe
908
1434
  let numberTimesDivideSimpleHelp = (x, y, isDivide) => {
909
1435
  // PRECONDITION: x is a "simple" number (value tag is 0) and isNumber(y)
910
1436
  let xval = untagSimple(x) // <- actual int value of x
911
1437
  numberTimesDivideInt64Help(WasmI64.extendI32S(xval), y, isDivide)
912
1438
  }
913
1439
 
1440
+ @unsafe
914
1441
  let numberTimesDivideInt32Help = (xval, y, isDivide) => {
915
1442
  numberTimesDivideInt64Help(WasmI64.extendI32S(xval), y, isDivide)
916
1443
  }
917
1444
 
1445
+ @unsafe
918
1446
  let numberTimesDivideRationalHelp = (x, y, isDivide) => {
919
1447
  // Division isn't commutative, so we actually need to do the work
920
- let xNumerator = WasmI64.extendI32S(boxedRationalNumerator(x))
921
- let xDenominator = WasmI64.extendI32S(boxedRationalDenominator(x))
1448
+ let xNumerator = boxedRationalNumerator(x)
1449
+ let xDenominator = boxedRationalDenominator(x)
922
1450
  if (isSimpleNumber(y)) {
923
- if (isDivide) {
1451
+ let yBig = BI.makeWrappedInt32(untagSimple(y))
1452
+ let ret = if (isDivide) {
924
1453
  // (a / b) / y == a / (b * y)
925
- let denominator = safeI64Multiply(xDenominator, WasmI64.extendI32S(untagSimple(y)))
926
- reducedFraction64(xNumerator, denominator)
1454
+ let denominator = BI.mul(xDenominator, yBig)
1455
+ let ret = reducedFractionBigInt(xNumerator, denominator)
1456
+ Memory.decRef(denominator)
1457
+ ret
927
1458
  } else {
928
1459
  // (a / b) * y == (a * y) / b
929
- let numerator = safeI64Multiply(xNumerator, WasmI64.extendI32S(untagSimple(y)))
930
- reducedFraction64(numerator, xDenominator)
1460
+ let numerator = BI.mul(xNumerator, yBig)
1461
+ let ret = reducedFractionBigInt(numerator, xDenominator)
1462
+ Memory.decRef(numerator)
1463
+ ret
931
1464
  }
1465
+ if (WasmI32.ne(yBig, ret)) {
1466
+ Memory.decRef(yBig)
1467
+ void
1468
+ }
1469
+ ret
932
1470
  } else {
933
1471
  let ytag = boxedNumberTag(y)
934
1472
  match (ytag) {
935
1473
  t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => {
936
1474
  // Same idea as above
937
- if (isDivide) {
1475
+ let yBig = BI.makeWrappedInt32(boxedInt32Number(y))
1476
+ let ret = if (isDivide) {
938
1477
  // (a / b) / y == a / (b * y)
939
- let denominator = safeI64Multiply(xDenominator, WasmI64.extendI32S(boxedInt32Number(y)))
940
- reducedFraction64(xNumerator, denominator)
1478
+ let denominator = BI.mul(xDenominator, yBig)
1479
+ let ret = reducedFractionBigInt(xNumerator, denominator)
1480
+ Memory.decRef(denominator)
1481
+ ret
941
1482
  } else {
942
1483
  // (a / b) * y == (a * y) / b
943
- let numerator = safeI64Multiply(xNumerator, WasmI64.extendI32S(boxedInt32Number(y)))
944
- reducedFraction64(numerator, xDenominator)
1484
+ let numerator = BI.mul(xNumerator, yBig)
1485
+ let ret = reducedFractionBigInt(numerator, xDenominator)
1486
+ Memory.decRef(numerator)
1487
+ ret
945
1488
  }
1489
+ Memory.decRef(yBig)
1490
+ ret
946
1491
  },
947
1492
  t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
948
1493
  // Same idea as above
1494
+ let yBig = BI.makeWrappedInt64(boxedInt64Number(y))
1495
+ let ret = if (isDivide) {
1496
+ // (a / b) / y == a / (b * y)
1497
+ let denominator = BI.mul(xDenominator, yBig)
1498
+ let ret = reducedFractionBigInt(xNumerator, denominator)
1499
+ Memory.decRef(denominator)
1500
+ ret
1501
+ } else {
1502
+ // (a / b) * y == (a * y) / b
1503
+ let numerator = BI.mul(xNumerator, yBig)
1504
+ let ret = reducedFractionBigInt(numerator, xDenominator)
1505
+ Memory.decRef(numerator)
1506
+ ret
1507
+ }
1508
+ Memory.decRef(yBig)
1509
+ ret
1510
+ },
1511
+ t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
949
1512
  if (isDivide) {
950
1513
  // (a / b) / y == a / (b * y)
951
- let denominator = safeI64Multiply(xDenominator, boxedInt64Number(y))
952
- reducedFraction64(xNumerator, denominator)
1514
+ let denominator = BI.mul(xDenominator, y)
1515
+ let ret = reducedFractionBigInt(xNumerator, denominator)
1516
+ Memory.decRef(denominator)
1517
+ ret
953
1518
  } else {
954
1519
  // (a / b) * y == (a * y) / b
955
- let numerator = safeI64Multiply(xNumerator, boxedInt64Number(y))
956
- reducedFraction64(numerator, xDenominator)
1520
+ let numerator = BI.mul(xNumerator, y)
1521
+ let ret = reducedFractionBigInt(numerator, xDenominator)
1522
+ Memory.decRef(numerator)
1523
+ ret
957
1524
  }
958
1525
  },
959
1526
  t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => {
960
- let xNumerator = WasmI64.extendI32S(boxedRationalNumerator(x))
961
- let xDenominator = WasmI64.extendI32S(boxedRationalDenominator(x))
962
- let yNumerator = WasmI64.extendI32S(boxedRationalNumerator(y))
963
- let yDenominator = WasmI64.extendI32S(boxedRationalDenominator(y))
1527
+ let xNumerator = boxedRationalNumerator(x)
1528
+ let xDenominator = boxedRationalDenominator(x)
1529
+ let yNumerator = boxedRationalNumerator(y)
1530
+ let yDenominator = boxedRationalDenominator(y)
964
1531
  // (a / b) * (c / d) == (a * c) / (b * d)
965
1532
  // (a / b) / (c / d) == (a * d) / (b * c)
966
1533
  // TODO: (#304) this could maybe be written in a more overflow-proof way
967
- let numerator = if (isDivide) safeI64Multiply(xNumerator, yDenominator) else safeI64Multiply(xNumerator, yNumerator)
968
- let denominator = if (isDivide) safeI64Multiply(xDenominator, yNumerator) else safeI64Multiply(xDenominator, yDenominator)
969
- reducedFraction64(numerator, denominator)
1534
+ let numerator = if (isDivide) BI.mul(xNumerator, yDenominator)
1535
+ else BI.mul(xNumerator, yNumerator)
1536
+ let denominator = if (isDivide) BI.mul(xDenominator, yNumerator)
1537
+ else BI.mul(xDenominator, yDenominator)
1538
+ reducedFractionBigInt(numerator, denominator)
970
1539
  },
971
1540
  t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
972
- let asFloat = WasmF32.div(WasmF32.convertI64S(xNumerator), WasmF32.convertI64S(xDenominator))
1541
+ // TODO(#1190): We should probably use something more accurate if possible here
1542
+ let asFloat = WasmF32.demoteF64(
1543
+ WasmF64.div(BI.toFloat64(xNumerator), BI.toFloat64(xDenominator))
1544
+ )
973
1545
  if (isDivide) {
974
1546
  newFloat32(WasmF32.div(asFloat, boxedFloat32Number(y)))
975
1547
  } else {
@@ -977,7 +1549,11 @@ let numberTimesDivideRationalHelp = (x, y, isDivide) => {
977
1549
  }
978
1550
  },
979
1551
  t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
980
- let asFloat = WasmF64.div(WasmF64.convertI64S(xNumerator), WasmF64.convertI64S(xDenominator))
1552
+ // TODO(#1190): We should probably use something more accurate if possible here
1553
+ let asFloat = WasmF64.div(
1554
+ BI.toFloat64(xNumerator),
1555
+ BI.toFloat64(xDenominator)
1556
+ )
981
1557
  if (isDivide) {
982
1558
  newFloat64(WasmF64.div(asFloat, boxedFloat64Number(y)))
983
1559
  } else {
@@ -986,13 +1562,16 @@ let numberTimesDivideRationalHelp = (x, y, isDivide) => {
986
1562
  },
987
1563
  _ => {
988
1564
  throw UnknownNumberTag
989
- }
1565
+ },
990
1566
  }
991
1567
  }
992
1568
  }
993
1569
 
1570
+ @unsafe
994
1571
  let numberTimesDivideFloat64Help = (x, y, isDivide) => {
995
- let yAsFloat = coerceNumberToWasmF64(WasmI32.toGrain(y) : Number)
1572
+ // incRef y to reuse it via WasmI32.toGrain
1573
+ Memory.incRef(y)
1574
+ let yAsFloat = coerceNumberToWasmF64(WasmI32.toGrain(y): Number)
996
1575
  if (isDivide) {
997
1576
  newFloat64(WasmF64.div(x, yAsFloat))
998
1577
  } else {
@@ -1000,8 +1579,12 @@ let numberTimesDivideFloat64Help = (x, y, isDivide) => {
1000
1579
  }
1001
1580
  }
1002
1581
 
1582
+ @unsafe
1003
1583
  let numberTimesDivideFloat32Help = (x, y, isDivide) => {
1004
- if (isBoxedNumber(y) && WasmI32.eq(boxedNumberTag(y), Tags._GRAIN_INT64_BOXED_NUM_TAG)) {
1584
+ if (
1585
+ isBoxedNumber(y) &&
1586
+ WasmI32.eq(boxedNumberTag(y), Tags._GRAIN_INT64_BOXED_NUM_TAG)
1587
+ ) {
1005
1588
  // Special case: f32->f64 promotion
1006
1589
  if (isDivide) {
1007
1590
  newFloat64(WasmF64.div(WasmF64.promoteF32(x), boxedFloat64Number(y)))
@@ -1009,7 +1592,9 @@ let numberTimesDivideFloat32Help = (x, y, isDivide) => {
1009
1592
  newFloat64(WasmF64.mul(WasmF64.promoteF32(x), boxedFloat64Number(y)))
1010
1593
  }
1011
1594
  } else {
1012
- let yAsFloat = coerceNumberToWasmF32(WasmI32.toGrain(y) : Number)
1595
+ // incRef y to reuse it via WasmI32.toGrain
1596
+ Memory.incRef(y)
1597
+ let yAsFloat = coerceNumberToWasmF32(WasmI32.toGrain(y): Number)
1013
1598
  if (isDivide) {
1014
1599
  newFloat32(WasmF32.div(x, yAsFloat))
1015
1600
  } else {
@@ -1018,6 +1603,7 @@ let numberTimesDivideFloat32Help = (x, y, isDivide) => {
1018
1603
  }
1019
1604
  }
1020
1605
 
1606
+ @unsafe
1021
1607
  let numberTimesDivideHelp = (x, y, isDivide) => {
1022
1608
  if (isSimpleNumber(x)) {
1023
1609
  numberTimesDivideSimpleHelp(x, y, isDivide)
@@ -1030,6 +1616,9 @@ let numberTimesDivideHelp = (x, y, isDivide) => {
1030
1616
  t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
1031
1617
  numberTimesDivideInt64Help(boxedInt64Number(x), y, isDivide)
1032
1618
  },
1619
+ t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
1620
+ numberTimesDivideBigIntHelp(x, y, isDivide)
1621
+ },
1033
1622
  t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => {
1034
1623
  numberTimesDivideRationalHelp(x, y, isDivide)
1035
1624
  },
@@ -1041,15 +1630,17 @@ let numberTimesDivideHelp = (x, y, isDivide) => {
1041
1630
  },
1042
1631
  _ => {
1043
1632
  throw UnknownNumberTag
1044
- }
1633
+ },
1045
1634
  }
1046
1635
  }
1047
1636
  }
1048
1637
 
1638
+ @unsafe
1049
1639
  let numberTimes = (x, y) => {
1050
1640
  WasmI32.toGrain(numberTimesDivideHelp(x, y, false)): Number
1051
1641
  }
1052
1642
 
1643
+ @unsafe
1053
1644
  let numberDivide = (x, y) => {
1054
1645
  WasmI32.toGrain(numberTimesDivideHelp(x, y, true)): Number
1055
1646
  }
@@ -1059,18 +1650,30 @@ let numberDivide = (x, y) => {
1059
1650
  * (same schema as equal())
1060
1651
  */
1061
1652
 
1062
- let i64abs = (x) => if (WasmI64.geS(x, 0N)) x else WasmI64.sub(0N, x)
1653
+ @unsafe
1654
+ let i64abs = x => if (WasmI64.geS(x, 0N)) x else WasmI64.sub(0N, x)
1063
1655
 
1656
+ @unsafe
1064
1657
  let numberMod = (x, y) => {
1065
- let xval = coerceNumberToWasmI64(WasmI32.toGrain(x) : Number)
1066
- let yval = coerceNumberToWasmI64(WasmI32.toGrain(y) : Number)
1658
+ // incRef x and y to reuse them via WasmI32.toGrain
1659
+ Memory.incRef(x)
1660
+ Memory.incRef(y)
1661
+ let xval = coerceNumberToWasmI64(WasmI32.toGrain(x): Number)
1662
+ let yval = coerceNumberToWasmI64(WasmI32.toGrain(y): Number)
1067
1663
  if (WasmI64.eqz(yval)) {
1068
1664
  throw Exception.ModuloByZero
1069
1665
  }
1070
1666
  // We implement true modulo
1071
- if (WasmI64.ltS(xval, 0N) && WasmI64.gtS(yval, 0N) || WasmI64.gtS(xval, 0N) && WasmI64.ltS(yval, 0N)) {
1667
+ if (
1668
+ WasmI64.ltS(xval, 0N) && WasmI64.gtS(yval, 0N) ||
1669
+ WasmI64.gtS(xval, 0N) && WasmI64.ltS(yval, 0N)
1670
+ ) {
1072
1671
  let modval = WasmI64.remS(i64abs(xval), i64abs(yval))
1073
- let result = if (WasmI64.ne(modval, 0N)) WasmI64.mul(WasmI64.sub(i64abs(yval), modval), (if (WasmI64.ltS(yval, 0N)) -1N else 1N)) else modval
1672
+ let result = if (WasmI64.ne(modval, 0N))
1673
+ WasmI64.mul(
1674
+ WasmI64.sub(i64abs(yval), modval),
1675
+ if (WasmI64.ltS(yval, 0N)) -1N else 1N
1676
+ ) else modval
1074
1677
  reducedInteger(result)
1075
1678
  } else {
1076
1679
  reducedInteger(WasmI64.remS(xval, yval))
@@ -1082,384 +1685,532 @@ let numberMod = (x, y) => {
1082
1685
  * Coerce to float64 and then do comparisons
1083
1686
  * TODO: (#305) Could probably be made more efficient
1084
1687
  */
1688
+
1689
+ @unsafe
1690
+ let cmpBigInt = (x: WasmI32, y: WasmI32) => {
1691
+ if (isSimpleNumber(y)) {
1692
+ BI.cmpI64(x, WasmI64.extendI32S(untagSimple(y)))
1693
+ } else {
1694
+ let yBoxedNumberTag = boxedNumberTag(y)
1695
+ match (yBoxedNumberTag) {
1696
+ t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => {
1697
+ BI.cmpI64(x, WasmI64.extendI32S(boxedInt32Number(y)))
1698
+ },
1699
+ t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
1700
+ BI.cmpI64(x, boxedInt64Number(y))
1701
+ },
1702
+ t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
1703
+ BI.cmp(x, y)
1704
+ },
1705
+ t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => {
1706
+ let tmp = BI.mul(x, boxedRationalDenominator(y))
1707
+ let ret = BI.cmp(tmp, boxedRationalNumerator(y))
1708
+ Memory.decRef(tmp)
1709
+ ret
1710
+ },
1711
+ t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
1712
+ BI.cmpF32(x, boxedFloat32Number(y))
1713
+ },
1714
+ t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
1715
+ BI.cmpF64(x, boxedFloat64Number(y))
1716
+ },
1717
+ _ => {
1718
+ throw UnknownNumberTag
1719
+ },
1720
+ }
1721
+ }
1722
+ }
1723
+
1085
1724
  // TODO: (#305) is this safe? I think it's safe?
1086
- export let rec (<) = (x: Number, y: Number) => {
1087
- let xval = coerceNumberToWasmF64(x)
1088
- let yval = coerceNumberToWasmF64(y)
1089
- Memory.decRef(WasmI32.fromGrain(x))
1090
- Memory.decRef(WasmI32.fromGrain(y))
1091
- let ret = WasmF64.lt(xval, yval)
1092
- Memory.decRef(WasmI32.fromGrain((<)))
1093
- ret
1725
+ @unsafe
1726
+ export let (<) = (x: Number, y: Number) => {
1727
+ let xw32 = WasmI32.fromGrain(x)
1728
+ let yw32 = WasmI32.fromGrain(y)
1729
+ if (isBigInt(xw32)) {
1730
+ WasmI32.ltS(cmpBigInt(xw32, yw32), 0n)
1731
+ } else if (isBigInt(yw32)) {
1732
+ WasmI32.geS(cmpBigInt(yw32, xw32), 0n)
1733
+ } else {
1734
+ let xval = coerceNumberToWasmF64(x)
1735
+ let yval = coerceNumberToWasmF64(y)
1736
+ WasmF64.lt(xval, yval)
1737
+ }
1094
1738
  }
1095
1739
 
1096
- export let rec (>) = (x: Number, y: Number) => {
1097
- let xval = coerceNumberToWasmF64(x)
1098
- let yval = coerceNumberToWasmF64(y)
1099
- Memory.decRef(WasmI32.fromGrain(x))
1100
- Memory.decRef(WasmI32.fromGrain(y))
1101
- let ret = WasmF64.gt(xval, yval)
1102
- Memory.decRef(WasmI32.fromGrain((>)))
1103
- ret
1740
+ @unsafe
1741
+ export let (>) = (x: Number, y: Number) => {
1742
+ let xw32 = WasmI32.fromGrain(x)
1743
+ let yw32 = WasmI32.fromGrain(y)
1744
+ if (isBigInt(xw32)) {
1745
+ WasmI32.gtS(cmpBigInt(xw32, yw32), 0n)
1746
+ } else if (isBigInt(yw32)) {
1747
+ WasmI32.leS(cmpBigInt(yw32, xw32), 0n)
1748
+ } else {
1749
+ let xval = coerceNumberToWasmF64(x)
1750
+ let yval = coerceNumberToWasmF64(y)
1751
+ WasmF64.gt(xval, yval)
1752
+ }
1104
1753
  }
1105
1754
 
1106
- export let rec (<=) = (x: Number, y: Number) => {
1107
- // Equality is finicky, so delegate
1108
- let xval = coerceNumberToWasmF64(x)
1109
- let yval = coerceNumberToWasmF64(y)
1110
- let ret = if (WasmF64.lt(xval, yval)) {
1111
- true
1755
+ @unsafe
1756
+ export let (<=) = (x: Number, y: Number) => {
1757
+ let xw32 = WasmI32.fromGrain(x)
1758
+ let yw32 = WasmI32.fromGrain(y)
1759
+ if (isBigInt(xw32)) {
1760
+ WasmI32.leS(cmpBigInt(xw32, yw32), 0n)
1761
+ } else if (isBigInt(yw32)) {
1762
+ WasmI32.geS(cmpBigInt(yw32, xw32), 0n)
1112
1763
  } else {
1113
- let x = WasmI32.fromGrain(x)
1114
- let y = WasmI32.fromGrain(y)
1115
- numberEqual(x, y)
1764
+ // Equality is finicky, so delegate
1765
+ let xval = coerceNumberToWasmF64(x)
1766
+ let yval = coerceNumberToWasmF64(y)
1767
+ if (WasmF64.lt(xval, yval)) {
1768
+ true
1769
+ } else {
1770
+ let x = WasmI32.fromGrain(x)
1771
+ let y = WasmI32.fromGrain(y)
1772
+ numberEqual(x, y)
1773
+ }
1116
1774
  }
1117
- Memory.decRef(WasmI32.fromGrain(x))
1118
- Memory.decRef(WasmI32.fromGrain(y))
1119
- Memory.decRef(WasmI32.fromGrain((<=)))
1120
- ret
1121
1775
  }
1122
1776
 
1123
- export let rec (>=) = (x: Number, y: Number) => {
1124
- // Equality is finicky, so delegate
1125
- let xval = coerceNumberToWasmF64(x)
1126
- let yval = coerceNumberToWasmF64(y)
1127
- let ret = if (WasmF64.gt(xval, yval)) {
1128
- true
1777
+ @unsafe
1778
+ export let (>=) = (x: Number, y: Number) => {
1779
+ let xw32 = WasmI32.fromGrain(x)
1780
+ let yw32 = WasmI32.fromGrain(y)
1781
+ if (isBigInt(xw32)) {
1782
+ WasmI32.leS(cmpBigInt(xw32, yw32), 0n)
1783
+ } else if (isBigInt(yw32)) {
1784
+ WasmI32.geS(cmpBigInt(yw32, xw32), 0n)
1129
1785
  } else {
1130
- let x = WasmI32.fromGrain(x)
1131
- let y = WasmI32.fromGrain(y)
1132
- numberEqual(x, y)
1786
+ // Equality is finicky, so delegate
1787
+ let xval = coerceNumberToWasmF64(x)
1788
+ let yval = coerceNumberToWasmF64(y)
1789
+ if (WasmF64.gt(xval, yval)) {
1790
+ true
1791
+ } else {
1792
+ let x = WasmI32.fromGrain(x)
1793
+ let y = WasmI32.fromGrain(y)
1794
+ numberEqual(x, y)
1795
+ }
1133
1796
  }
1134
- Memory.decRef(WasmI32.fromGrain(x))
1135
- Memory.decRef(WasmI32.fromGrain(y))
1136
- Memory.decRef(WasmI32.fromGrain((>=)))
1137
- ret
1138
1797
  }
1139
1798
 
1140
1799
  /*
1141
1800
  * ===== EQUAL =====
1142
1801
  */
1143
1802
 
1144
- export let rec numberEq = (x: Number, y: Number) => {
1803
+ @unsafe
1804
+ export let numberEq = (x: Number, y: Number) => {
1145
1805
  let x = WasmI32.fromGrain(x)
1146
1806
  let y = WasmI32.fromGrain(y)
1147
- let ret = numberEqual(x, y)
1148
- Memory.decRef(x)
1149
- Memory.decRef(y)
1150
- Memory.decRef(WasmI32.fromGrain(numberEq))
1151
- ret
1807
+ numberEqual(x, y)
1152
1808
  }
1153
1809
 
1154
1810
  /*
1155
1811
  * ===== LOGICAL OPERATIONS =====
1156
- * Only valid for int-like numbers. Coerce to i64 and do operations
1812
+ * Only valid for int-like numbers. Coerce to i64/bigInt and do operations
1157
1813
  */
1158
1814
  // TODO: (#306) Semantics around when things should stay i32/i64
1159
1815
 
1160
- export let rec lnot = (x: Number) => {
1161
- let xval = coerceNumberToWasmI64(x)
1162
- let ret = WasmI32.toGrain(reducedInteger(i64not(xval))): Number
1163
- Memory.decRef(WasmI32.fromGrain(x))
1164
- Memory.decRef(WasmI32.fromGrain(lnot))
1165
- ret
1816
+ @unsafe
1817
+ export let lnot = (x: Number) => {
1818
+ let xw32 = WasmI32.fromGrain(x)
1819
+ if (isBigInt(xw32)) {
1820
+ WasmI32.toGrain(reducedBigInteger(BI.bitwiseNot(xw32))): Number
1821
+ } else {
1822
+ let xval = coerceNumberToWasmI64(x)
1823
+ WasmI32.toGrain(reducedInteger(i64not(xval))): Number
1824
+ }
1166
1825
  }
1167
1826
 
1168
- export let rec (<<) = (x: Number, y: Number) => {
1169
- let xval = coerceNumberToWasmI64(x)
1170
- let yval = coerceNumberToWasmI64(y)
1171
- let ret = WasmI32.toGrain(reducedInteger(WasmI64.shl(xval, yval))): Number
1172
- Memory.decRef(WasmI32.fromGrain(x))
1173
- Memory.decRef(WasmI32.fromGrain(y))
1174
- Memory.decRef(WasmI32.fromGrain((<<)))
1175
- ret
1827
+ @unsafe
1828
+ export let (<<) = (x: Number, y: Number) => {
1829
+ let xw32 = WasmI32.fromGrain(x)
1830
+ if (isBigInt(xw32)) {
1831
+ let yval = coerceNumberToWasmI32(y)
1832
+ WasmI32.toGrain(reducedBigInteger(BI.shl(xw32, yval))): Number
1833
+ } else {
1834
+ let xval = coerceNumberToWasmI64(x)
1835
+ let yval = coerceNumberToWasmI64(y)
1836
+ WasmI32.toGrain(reducedInteger(WasmI64.shl(xval, yval))): Number
1837
+ }
1176
1838
  }
1177
1839
 
1178
- export let rec (>>>) = (x: Number, y: Number) => {
1179
- let xval = coerceNumberToWasmI64(x)
1180
- let yval = coerceNumberToWasmI64(y)
1181
- let ret = WasmI32.toGrain(reducedInteger(WasmI64.shrU(xval, yval))): Number
1182
- Memory.decRef(WasmI32.fromGrain(x))
1183
- Memory.decRef(WasmI32.fromGrain(y))
1184
- Memory.decRef(WasmI32.fromGrain((>>>)))
1185
- ret
1840
+ @unsafe
1841
+ export let (>>>) = (x: Number, y: Number) => {
1842
+ let xw32 = WasmI32.fromGrain(x)
1843
+ if (isBigInt(xw32)) {
1844
+ let yval = coerceNumberToWasmI32(y)
1845
+ // [NOTE]: For BigInts, shrU is the same as shrS because there
1846
+ // are an *infinite* number of leading ones
1847
+ WasmI32.toGrain(reducedBigInteger(BI.shrS(xw32, yval))): Number
1848
+ } else {
1849
+ let xval = coerceNumberToWasmI64(x)
1850
+ let yval = coerceNumberToWasmI64(y)
1851
+ WasmI32.toGrain(reducedInteger(WasmI64.shrU(xval, yval))): Number
1852
+ }
1186
1853
  }
1187
1854
 
1188
- export let rec (&) = (x: Number, y: Number) => {
1189
- let xval = coerceNumberToWasmI64(x)
1190
- let yval = coerceNumberToWasmI64(y)
1191
- let ret = WasmI32.toGrain(reducedInteger(WasmI64.and(xval, yval))): Number
1192
- Memory.decRef(WasmI32.fromGrain(x))
1193
- Memory.decRef(WasmI32.fromGrain(y))
1194
- Memory.decRef(WasmI32.fromGrain((&)))
1195
- ret
1855
+ @unsafe
1856
+ export let (&) = (x: Number, y: Number) => {
1857
+ let xw32 = WasmI32.fromGrain(x)
1858
+ let yw32 = WasmI32.fromGrain(y)
1859
+ if (isBigInt(xw32) || isBigInt(yw32)) {
1860
+ let xval = coerceNumberToBigInt(x)
1861
+ let yval = coerceNumberToBigInt(y)
1862
+ let ret = WasmI32.toGrain(
1863
+ reducedBigInteger(BI.bitwiseAnd(xval, yval))
1864
+ ): Number
1865
+ if (!WasmI32.eq(xw32, xval)) {
1866
+ Memory.decRef(xval)
1867
+ void
1868
+ }
1869
+ if (!WasmI32.eq(yw32, yval)) {
1870
+ Memory.decRef(yval)
1871
+ void
1872
+ }
1873
+ ret
1874
+ } else {
1875
+ let xval = coerceNumberToWasmI64(x)
1876
+ let yval = coerceNumberToWasmI64(y)
1877
+ WasmI32.toGrain(reducedInteger(WasmI64.and(xval, yval))): Number
1878
+ }
1196
1879
  }
1197
1880
 
1198
- export let rec (|) = (x: Number, y: Number) => {
1199
- let xval = coerceNumberToWasmI64(x)
1200
- let yval = coerceNumberToWasmI64(y)
1201
- let ret = WasmI32.toGrain(reducedInteger(WasmI64.or(xval, yval))): Number
1202
- Memory.decRef(WasmI32.fromGrain(x))
1203
- Memory.decRef(WasmI32.fromGrain(y))
1204
- Memory.decRef(WasmI32.fromGrain((|)))
1205
- ret
1881
+ @unsafe
1882
+ export let (|) = (x: Number, y: Number) => {
1883
+ let xw32 = WasmI32.fromGrain(x)
1884
+ let yw32 = WasmI32.fromGrain(y)
1885
+ if (isBigInt(xw32) || isBigInt(yw32)) {
1886
+ let xval = coerceNumberToBigInt(x)
1887
+ let yval = coerceNumberToBigInt(y)
1888
+ let ret = WasmI32.toGrain(
1889
+ reducedBigInteger(BI.bitwiseOr(xval, yval))
1890
+ ): Number
1891
+ if (!WasmI32.eq(xw32, xval)) {
1892
+ Memory.decRef(xval)
1893
+ void
1894
+ }
1895
+ if (!WasmI32.eq(yw32, yval)) {
1896
+ Memory.decRef(yval)
1897
+ void
1898
+ }
1899
+ ret
1900
+ } else {
1901
+ let xval = coerceNumberToWasmI64(x)
1902
+ let yval = coerceNumberToWasmI64(y)
1903
+ WasmI32.toGrain(reducedInteger(WasmI64.or(xval, yval))): Number
1904
+ }
1206
1905
  }
1207
1906
 
1208
- export let rec (^) = (x: Number, y: Number) => {
1209
- let xval = coerceNumberToWasmI64(x)
1210
- let yval = coerceNumberToWasmI64(y)
1211
- let ret = WasmI32.toGrain(reducedInteger(WasmI64.xor(xval, yval))): Number
1212
- Memory.decRef(WasmI32.fromGrain(x))
1213
- Memory.decRef(WasmI32.fromGrain(y))
1214
- Memory.decRef(WasmI32.fromGrain((^)))
1215
- ret
1907
+ @unsafe
1908
+ export let (^) = (x: Number, y: Number) => {
1909
+ let xw32 = WasmI32.fromGrain(x)
1910
+ let yw32 = WasmI32.fromGrain(y)
1911
+ if (isBigInt(xw32) || isBigInt(yw32)) {
1912
+ let xval = coerceNumberToBigInt(x)
1913
+ let yval = coerceNumberToBigInt(y)
1914
+ let ret = WasmI32.toGrain(
1915
+ reducedBigInteger(BI.bitwiseXor(xval, yval))
1916
+ ): Number
1917
+ if (!WasmI32.eq(xw32, xval)) {
1918
+ Memory.decRef(xval)
1919
+ void
1920
+ }
1921
+ if (!WasmI32.eq(yw32, yval)) {
1922
+ Memory.decRef(yval)
1923
+ void
1924
+ }
1925
+ ret
1926
+ } else {
1927
+ let xval = coerceNumberToWasmI64(x)
1928
+ let yval = coerceNumberToWasmI64(y)
1929
+ WasmI32.toGrain(reducedInteger(WasmI64.xor(xval, yval))): Number
1930
+ }
1216
1931
  }
1217
1932
 
1218
- export let rec (>>) = (x: Number, y: Number) => {
1219
- let xval = coerceNumberToWasmI64(x)
1220
- let yval = coerceNumberToWasmI64(y)
1221
- let ret = WasmI32.toGrain(reducedInteger(WasmI64.shrS(xval, yval))): Number
1222
- Memory.decRef(WasmI32.fromGrain(x))
1223
- Memory.decRef(WasmI32.fromGrain(y))
1224
- Memory.decRef(WasmI32.fromGrain((>>)))
1225
- ret
1933
+ @unsafe
1934
+ export let (>>) = (x: Number, y: Number) => {
1935
+ let xw32 = WasmI32.fromGrain(x)
1936
+ if (isBigInt(xw32)) {
1937
+ let yval = coerceNumberToWasmI32(y)
1938
+ // [NOTE]: For BigInts, shrU is the same as shrS because there
1939
+ // are an *infinite* number of leading ones
1940
+ WasmI32.toGrain(reducedBigInteger(BI.shrS(xw32, yval))): Number
1941
+ } else {
1942
+ let xval = coerceNumberToWasmI64(x)
1943
+ let yval = coerceNumberToWasmI64(y)
1944
+ WasmI32.toGrain(reducedInteger(WasmI64.shrS(xval, yval))): Number
1945
+ }
1226
1946
  }
1227
1947
 
1228
-
1229
1948
  /// USER-EXPOSED COERCION FUNCTIONS
1230
1949
  //
1231
1950
  // [NOTE]: Coercion is a *conservative* process! For example, even if a float is 1.0,
1232
1951
  // we will fail if attempting to coerce to an int!
1233
1952
 
1953
+ @unsafe
1234
1954
  export let rec coerceNumberToInt32 = (x: Number) => {
1235
1955
  let x = WasmI32.fromGrain(x)
1236
- let result = if (!isSimpleNumber(x) && WasmI32.eq(boxedNumberTag(x), Tags._GRAIN_INT32_BOXED_NUM_TAG)) {
1237
- // avoid extra malloc
1956
+ let result = if (
1957
+ !isSimpleNumber(x) &&
1958
+ WasmI32.eq(boxedNumberTag(x), Tags._GRAIN_INT32_BOXED_NUM_TAG)
1959
+ ) {
1960
+ // avoid extra malloc and prevent x from being freed
1961
+ Memory.incRef(x)
1238
1962
  x
1239
1963
  } else {
1964
+ // incRef x to reuse it via WasmI32.toGrain
1965
+ Memory.incRef(x)
1240
1966
  // can possibly fail
1241
- newInt32(coerceNumberToWasmI32(WasmI32.toGrain(x) : Number))
1242
- }
1243
- let ret = WasmI32.toGrain(result): Int32
1244
- if (WasmI32.fromGrain(ret) != WasmI32.fromGrain(x)) {
1245
- Memory.decRef(WasmI32.fromGrain(x))
1246
- void
1967
+ newInt32(coerceNumberToWasmI32(WasmI32.toGrain(x): Number))
1247
1968
  }
1248
- Memory.decRef(WasmI32.fromGrain(coerceNumberToInt32))
1249
- ret
1969
+ WasmI32.toGrain(result): Int32
1250
1970
  }
1251
1971
 
1972
+ @unsafe
1252
1973
  export let rec coerceNumberToInt64 = (x: Number) => {
1253
1974
  let x = WasmI32.fromGrain(x)
1254
- let result = if (!isSimpleNumber(x) && WasmI32.eq(boxedNumberTag(x), Tags._GRAIN_INT64_BOXED_NUM_TAG)) {
1255
- // avoid extra malloc
1975
+ let result = if (
1976
+ !isSimpleNumber(x) &&
1977
+ WasmI32.eq(boxedNumberTag(x), Tags._GRAIN_INT64_BOXED_NUM_TAG)
1978
+ ) {
1979
+ // avoid extra malloc and prevent x from being freed
1980
+ Memory.incRef(x)
1256
1981
  x
1257
1982
  } else {
1258
- newInt64(coerceNumberToWasmI64(WasmI32.toGrain(x) : Number))
1983
+ // incRef x to reuse it via WasmI32.toGrain
1984
+ Memory.incRef(x)
1985
+ newInt64(coerceNumberToWasmI64(WasmI32.toGrain(x): Number))
1259
1986
  }
1260
- let ret = WasmI32.toGrain(result): Int64
1261
- if (WasmI32.fromGrain(ret) != WasmI32.fromGrain(x)) {
1262
- Memory.decRef(WasmI32.fromGrain(x))
1263
- void
1987
+ WasmI32.toGrain(result): Int64
1988
+ }
1989
+
1990
+ @unsafe
1991
+ export let rec coerceNumberToBigInt = (x: Number) => {
1992
+ let x = WasmI32.fromGrain(x)
1993
+ let result = if (isBigInt(x)) {
1994
+ // avoid extra malloc and prevent x from being freed
1995
+ Memory.incRef(x)
1996
+ x
1997
+ } else {
1998
+ // incRef x to reuse it via WasmI32.toGrain
1999
+ Memory.incRef(x)
2000
+ BI.makeWrappedInt64(coerceNumberToWasmI64(WasmI32.toGrain(x): Number))
1264
2001
  }
1265
- Memory.decRef(WasmI32.fromGrain(coerceNumberToInt64))
1266
- ret
2002
+ WasmI32.toGrain(result): BigInt
1267
2003
  }
1268
2004
 
1269
- export let rec coerceNumberToRational = (x: Number) => {
2005
+ @unsafe
2006
+ export let coerceNumberToRational = (x: Number) => {
1270
2007
  let x = WasmI32.fromGrain(x)
1271
2008
  let result = if (isSimpleNumber(x)) {
1272
- newRational(untagSimple(x), 1n)
2009
+ newRational(BI.makeWrappedInt32(untagSimple(x)), BI.makeWrappedInt32(1n))
1273
2010
  } else {
1274
2011
  let tag = boxedNumberTag(x)
1275
2012
  if (WasmI32.eq(tag, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG)) {
2013
+ // avoid extra malloc and prevent x from being freed
2014
+ Memory.incRef(x)
1276
2015
  x
1277
2016
  } else if (WasmI32.eq(tag, Tags._GRAIN_INT32_BOXED_NUM_TAG)) {
1278
- newRational(boxedInt32Number(x), 1n)
2017
+ newRational(
2018
+ BI.makeWrappedInt32(boxedInt32Number(x)),
2019
+ BI.makeWrappedInt32(1n)
2020
+ )
1279
2021
  } else if (WasmI32.eq(tag, Tags._GRAIN_INT64_BOXED_NUM_TAG)) {
1280
- newRational(coerceNumberToWasmI32(WasmI32.toGrain(x) : Number), 1n)
2022
+ // incRef x to reuse it via WasmI32.toGrain
2023
+ Memory.incRef(x)
2024
+ newRational(
2025
+ BI.makeWrappedInt32(coerceNumberToWasmI32(WasmI32.toGrain(x): Number)),
2026
+ BI.makeWrappedInt32(1n)
2027
+ )
1281
2028
  } else {
1282
2029
  throw Exception.NumberNotRational
1283
2030
  }
1284
2031
  }
1285
- let ret = WasmI32.toGrain(result): Rational
1286
- if (WasmI32.fromGrain(ret) != WasmI32.fromGrain(x)) {
1287
- Memory.decRef(WasmI32.fromGrain(x))
1288
- void
1289
- }
1290
- Memory.decRef(WasmI32.fromGrain(coerceNumberToRational))
1291
- ret
2032
+ WasmI32.toGrain(result): Rational
1292
2033
  }
1293
2034
 
1294
- export let rec coerceNumberToFloat32 = (x: Number) => {
2035
+ @unsafe
2036
+ export let coerceNumberToFloat32 = (x: Number) => {
1295
2037
  let x = WasmI32.fromGrain(x)
1296
- let result = if (!isSimpleNumber(x) && WasmI32.eq(boxedNumberTag(x), Tags._GRAIN_FLOAT32_BOXED_NUM_TAG)) {
1297
- // avoid extra malloc
2038
+ let result = if (
2039
+ !isSimpleNumber(x) &&
2040
+ WasmI32.eq(boxedNumberTag(x), Tags._GRAIN_FLOAT32_BOXED_NUM_TAG)
2041
+ ) {
2042
+ // avoid extra malloc and prevent x from being freed
2043
+ Memory.incRef(x)
1298
2044
  x
1299
2045
  } else {
1300
- newFloat32(coerceNumberToWasmF32(WasmI32.toGrain(x) : Number))
2046
+ // incRef x to reuse it via WasmI32.toGrain
2047
+ Memory.incRef(x)
2048
+ newFloat32(coerceNumberToWasmF32(WasmI32.toGrain(x): Number))
1301
2049
  }
1302
- let ret = WasmI32.toGrain(result): Float32
1303
- if (WasmI32.fromGrain(ret) != WasmI32.fromGrain(x)) {
1304
- Memory.decRef(WasmI32.fromGrain(x))
1305
- void
1306
- }
1307
- Memory.decRef(WasmI32.fromGrain(coerceNumberToFloat32))
1308
- ret
2050
+ WasmI32.toGrain(result): Float32
1309
2051
  }
1310
2052
 
1311
- export let rec coerceNumberToFloat64 = (x: Number) => {
2053
+ @unsafe
2054
+ export let coerceNumberToFloat64 = (x: Number) => {
1312
2055
  let x = WasmI32.fromGrain(x)
1313
- let result = if (!isSimpleNumber(x) && WasmI32.eq(boxedNumberTag(x), Tags._GRAIN_FLOAT64_BOXED_NUM_TAG)) {
1314
- // avoid extra malloc
2056
+ let result = if (
2057
+ !isSimpleNumber(x) &&
2058
+ WasmI32.eq(boxedNumberTag(x), Tags._GRAIN_FLOAT64_BOXED_NUM_TAG)
2059
+ ) {
2060
+ // avoid extra malloc and prevent x from being freed
2061
+ Memory.incRef(x)
1315
2062
  x
1316
2063
  } else {
1317
- newFloat64(coerceNumberToWasmF64(WasmI32.toGrain(x) : Number))
2064
+ // incRef x to reuse it via WasmI32.toGrain
2065
+ Memory.incRef(x)
2066
+ newFloat64(coerceNumberToWasmF64(WasmI32.toGrain(x): Number))
1318
2067
  }
1319
- let ret = WasmI32.toGrain(result): Float64
1320
- if (WasmI32.fromGrain(ret) != WasmI32.fromGrain(x)) {
1321
- Memory.decRef(WasmI32.fromGrain(x))
1322
- void
1323
- }
1324
- Memory.decRef(WasmI32.fromGrain(coerceNumberToFloat64))
1325
- ret
2068
+ WasmI32.toGrain(result): Float64
1326
2069
  }
1327
2070
 
1328
- // These coerceXX functions don't need Memory.decRef calls since they simply return their argument
1329
- export let rec coerceInt32ToNumber = (x: Int32) => {
1330
- let ret = WasmI32.toGrain(WasmI32.fromGrain(x)): Number
1331
- Memory.decRef(WasmI32.fromGrain(coerceInt32ToNumber))
1332
- ret
2071
+ @unsafe
2072
+ export let coerceInt32ToNumber = (x: Int32) => {
2073
+ let x = WasmI32.fromGrain(x)
2074
+ // incRef x to reuse it via WasmI32.toGrain
2075
+ Memory.incRef(x)
2076
+ WasmI32.toGrain(x): Number
1333
2077
  }
1334
2078
 
1335
- export let rec coerceInt64ToNumber = (x: Int64) => {
1336
- let ret = WasmI32.toGrain(WasmI32.fromGrain(x)): Number
1337
- Memory.decRef(WasmI32.fromGrain(coerceInt64ToNumber))
1338
- ret
2079
+ @unsafe
2080
+ export let coerceInt64ToNumber = (x: Int64) => {
2081
+ let x = WasmI32.fromGrain(x)
2082
+ // incRef x to reuse it via WasmI32.toGrain
2083
+ Memory.incRef(x)
2084
+ WasmI32.toGrain(x): Number
1339
2085
  }
1340
2086
 
1341
- export let rec coerceRationalToNumber = (x: Rational) => {
1342
- let ret = WasmI32.toGrain(WasmI32.fromGrain(x)): Number
1343
- Memory.decRef(WasmI32.fromGrain(coerceRationalToNumber))
1344
- ret
2087
+ @unsafe
2088
+ export let coerceBigIntToNumber = (x: BigInt) => {
2089
+ let x = WasmI32.fromGrain(x)
2090
+ // incRef x to reuse it via WasmI32.toGrain
2091
+ Memory.incRef(x)
2092
+ WasmI32.toGrain(x): Number
1345
2093
  }
1346
2094
 
1347
- export let rec coerceFloat32ToNumber = (x: Float32) => {
1348
- let ret = WasmI32.toGrain(WasmI32.fromGrain(x)): Number
1349
- Memory.decRef(WasmI32.fromGrain(coerceFloat32ToNumber))
1350
- ret
2095
+ @unsafe
2096
+ export let coerceRationalToNumber = (x: Rational) => {
2097
+ let x = WasmI32.fromGrain(x)
2098
+ // incRef x to reuse it via WasmI32.toGrain
2099
+ Memory.incRef(x)
2100
+ WasmI32.toGrain(x): Number
1351
2101
  }
1352
2102
 
1353
- export let rec coerceFloat64ToNumber = (x: Float64) => {
1354
- let ret = WasmI32.toGrain(WasmI32.fromGrain(x)): Number
1355
- Memory.decRef(WasmI32.fromGrain(coerceFloat64ToNumber))
1356
- ret
2103
+ @unsafe
2104
+ export let coerceFloat32ToNumber = (x: Float32) => {
2105
+ let x = WasmI32.fromGrain(x)
2106
+ // incRef x to reuse it via WasmI32.toGrain
2107
+ Memory.incRef(x)
2108
+ WasmI32.toGrain(x): Number
2109
+ }
2110
+
2111
+ @unsafe
2112
+ export let coerceFloat64ToNumber = (x: Float64) => {
2113
+ let x = WasmI32.fromGrain(x)
2114
+ // incRef x to reuse it via WasmI32.toGrain
2115
+ Memory.incRef(x)
2116
+ WasmI32.toGrain(x): Number
1357
2117
  }
1358
2118
 
1359
2119
  /// USER-EXPOSED CONVERSION FUNCTIONS
1360
2120
 
1361
- export let rec convertExactToInexact = (x: Number) => {
1362
- let ret = x
1363
- Memory.decRef(WasmI32.fromGrain(convertExactToInexact))
1364
- ret
2121
+ @unsafe
2122
+ export let convertExactToInexact = (x: Number) => {
2123
+ x
1365
2124
  }
1366
2125
 
1367
- let convertInexactToExactHelp = (x) => {
2126
+ @unsafe
2127
+ let convertInexactToExactHelp = x => {
1368
2128
  if (isSimpleNumber(x)) {
1369
2129
  x
1370
2130
  } else {
1371
2131
  let tag = boxedNumberTag(x)
1372
- if (WasmI32.eq(tag, Tags._GRAIN_INT32_BOXED_NUM_TAG) || WasmI32.eq(tag, Tags._GRAIN_INT64_BOXED_NUM_TAG) || WasmI32.eq(tag, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG)) {
2132
+ if (
2133
+ WasmI32.eq(tag, Tags._GRAIN_INT32_BOXED_NUM_TAG) ||
2134
+ WasmI32.eq(tag, Tags._GRAIN_INT64_BOXED_NUM_TAG) ||
2135
+ WasmI32.eq(tag, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) ||
2136
+ WasmI32.eq(tag, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG)
2137
+ ) {
2138
+ Memory.incRef(x)
1373
2139
  x
1374
2140
  } else {
1375
2141
  match (tag) {
1376
- t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => x,
1377
- t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => x,
1378
- t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => x,
1379
2142
  t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
1380
- reducedInteger(WasmI64.truncF32S(WasmF32.nearest(boxedFloat32Number(x))))
2143
+ // TODO(#1191): Investigate if BigInt is more accurate
2144
+ reducedInteger(
2145
+ WasmI64.truncF32S(WasmF32.nearest(boxedFloat32Number(x)))
2146
+ )
1381
2147
  },
1382
2148
  t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
1383
- reducedInteger(WasmI64.truncF64S(WasmF64.nearest(boxedFloat64Number(x))))
2149
+ // TODO(#1191): Investigate if BigInt is more accurate
2150
+ reducedInteger(
2151
+ WasmI64.truncF64S(WasmF64.nearest(boxedFloat64Number(x)))
2152
+ )
1384
2153
  },
1385
2154
  _ => {
1386
2155
  throw UnknownNumberTag
1387
- }
2156
+ },
1388
2157
  }
1389
2158
  }
1390
2159
  }
1391
2160
  }
1392
2161
 
1393
- export let rec convertInexactToExact = (x: Number) => {
1394
- let ret = WasmI32.toGrain(convertInexactToExactHelp(WasmI32.fromGrain(x))): Number
1395
- if (WasmI32.fromGrain(ret) != WasmI32.fromGrain(x)) {
1396
- Memory.decRef(WasmI32.fromGrain(x))
1397
- void
1398
- }
1399
- Memory.decRef(WasmI32.fromGrain(convertInexactToExact))
1400
- ret
2162
+ @unsafe
2163
+ export let convertInexactToExact = (x: Number) => {
2164
+ WasmI32.toGrain(convertInexactToExactHelp(WasmI32.fromGrain(x))): Number
1401
2165
  }
1402
2166
 
1403
- export let rec (+) = (x: Number, y: Number) => {
2167
+ @unsafe
2168
+ export let (+) = (x: Number, y: Number) => {
1404
2169
  let x = WasmI32.fromGrain(x)
1405
2170
  let y = WasmI32.fromGrain(y)
1406
- let ret = numberAdd(x, y)
1407
- Memory.decRef(x)
1408
- Memory.decRef(y)
1409
- Memory.decRef(WasmI32.fromGrain((+)))
1410
- ret
2171
+ numberAdd(x, y)
1411
2172
  }
1412
2173
 
1413
- export let rec (-) = (x: Number, y: Number) => {
2174
+ @unsafe
2175
+ export let (-) = (x: Number, y: Number) => {
1414
2176
  let x = WasmI32.fromGrain(x)
1415
2177
  let y = WasmI32.fromGrain(y)
1416
- let ret = numberSub(x, y)
1417
- Memory.decRef(x)
1418
- Memory.decRef(y)
1419
- Memory.decRef(WasmI32.fromGrain((-)))
1420
- ret
2178
+ numberSub(x, y)
1421
2179
  }
1422
2180
 
1423
- export let rec (*) = (x: Number, y: Number) => {
2181
+ @unsafe
2182
+ export let (*) = (x: Number, y: Number) => {
1424
2183
  let x = WasmI32.fromGrain(x)
1425
2184
  let y = WasmI32.fromGrain(y)
1426
- let ret = numberTimes(x, y)
1427
- Memory.decRef(x)
1428
- Memory.decRef(y)
1429
- Memory.decRef(WasmI32.fromGrain((*)))
1430
- ret
2185
+ numberTimes(x, y)
1431
2186
  }
1432
2187
 
1433
- export let rec (/) = (x: Number, y: Number) => {
2188
+ @unsafe
2189
+ export let (/) = (x: Number, y: Number) => {
1434
2190
  let x = WasmI32.fromGrain(x)
1435
2191
  let y = WasmI32.fromGrain(y)
1436
- let ret = numberDivide(x, y)
1437
- Memory.decRef(x)
1438
- Memory.decRef(y)
1439
- Memory.decRef(WasmI32.fromGrain((/)))
1440
- ret
2192
+ numberDivide(x, y)
1441
2193
  }
1442
2194
 
1443
- export let rec (%) = (x: Number, y: Number) => {
2195
+ @unsafe
2196
+ export let (%) = (x: Number, y: Number) => {
1444
2197
  let x = WasmI32.fromGrain(x)
1445
2198
  let y = WasmI32.fromGrain(y)
1446
- let ret = WasmI32.toGrain(numberMod(x, y)): Number
1447
- Memory.decRef(x)
1448
- Memory.decRef(y)
1449
- Memory.decRef(WasmI32.fromGrain((%)))
1450
- ret
2199
+ WasmI32.toGrain(numberMod(x, y)): Number
1451
2200
  }
1452
2201
 
1453
2202
  // inc/dec
1454
2203
 
1455
- export let incr = (x) => {
1456
- Memory.incRef(WasmI32.fromGrain((+)))
1457
- // skip incRef on x (to pass through)
2204
+ export let incr = x => {
1458
2205
  x + 1
1459
2206
  }
1460
2207
 
1461
- export let decr = (x) => {
1462
- Memory.incRef(WasmI32.fromGrain((-)))
1463
- // skip incRef on x (to pass through)
2208
+ export let decr = x => {
1464
2209
  x - 1
1465
2210
  }
2211
+
2212
+ @unsafe
2213
+ export let isBigInt = x => {
2214
+ let x = WasmI32.fromGrain(x)
2215
+ isBigInt(x)
2216
+ }