@grain/stdlib 0.5.13 → 0.6.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 (155) hide show
  1. package/CHANGELOG.md +193 -0
  2. package/LICENSE +1 -1
  3. package/README.md +25 -2
  4. package/array.gr +1512 -199
  5. package/array.md +2032 -94
  6. package/bigint.gr +239 -140
  7. package/bigint.md +450 -106
  8. package/buffer.gr +595 -102
  9. package/buffer.md +903 -145
  10. package/bytes.gr +401 -110
  11. package/bytes.md +551 -63
  12. package/char.gr +228 -49
  13. package/char.md +373 -7
  14. package/exception.gr +26 -12
  15. package/exception.md +29 -5
  16. package/float32.gr +130 -109
  17. package/float32.md +185 -57
  18. package/float64.gr +112 -99
  19. package/float64.md +185 -57
  20. package/hash.gr +47 -37
  21. package/hash.md +21 -3
  22. package/int16.gr +430 -0
  23. package/int16.md +618 -0
  24. package/int32.gr +200 -269
  25. package/int32.md +254 -289
  26. package/int64.gr +142 -225
  27. package/int64.md +254 -289
  28. package/int8.gr +511 -0
  29. package/int8.md +786 -0
  30. package/json.gr +2084 -0
  31. package/json.md +608 -0
  32. package/list.gr +120 -68
  33. package/list.md +125 -80
  34. package/map.gr +560 -57
  35. package/map.md +672 -56
  36. package/marshal.gr +239 -227
  37. package/marshal.md +36 -4
  38. package/number.gr +626 -676
  39. package/number.md +738 -153
  40. package/option.gr +33 -35
  41. package/option.md +58 -42
  42. package/package.json +2 -2
  43. package/path.gr +148 -187
  44. package/path.md +47 -96
  45. package/pervasives.gr +75 -416
  46. package/pervasives.md +85 -180
  47. package/priorityqueue.gr +433 -74
  48. package/priorityqueue.md +422 -54
  49. package/queue.gr +362 -80
  50. package/queue.md +433 -38
  51. package/random.gr +67 -75
  52. package/random.md +68 -40
  53. package/range.gr +135 -63
  54. package/range.md +198 -43
  55. package/rational.gr +284 -0
  56. package/rational.md +545 -0
  57. package/regex.gr +933 -1066
  58. package/regex.md +59 -60
  59. package/result.gr +23 -25
  60. package/result.md +54 -39
  61. package/runtime/atof/common.gr +78 -82
  62. package/runtime/atof/common.md +22 -10
  63. package/runtime/atof/decimal.gr +102 -127
  64. package/runtime/atof/decimal.md +28 -7
  65. package/runtime/atof/lemire.gr +56 -71
  66. package/runtime/atof/lemire.md +9 -1
  67. package/runtime/atof/parse.gr +83 -110
  68. package/runtime/atof/parse.md +12 -2
  69. package/runtime/atof/slow.gr +28 -35
  70. package/runtime/atof/slow.md +9 -1
  71. package/runtime/atof/table.gr +19 -18
  72. package/runtime/atof/table.md +10 -2
  73. package/runtime/atoi/parse.gr +153 -136
  74. package/runtime/atoi/parse.md +50 -1
  75. package/runtime/bigint.gr +410 -517
  76. package/runtime/bigint.md +71 -57
  77. package/runtime/compare.gr +176 -85
  78. package/runtime/compare.md +31 -1
  79. package/runtime/dataStructures.gr +144 -32
  80. package/runtime/dataStructures.md +267 -31
  81. package/runtime/debugPrint.gr +34 -15
  82. package/runtime/debugPrint.md +37 -5
  83. package/runtime/equal.gr +53 -52
  84. package/runtime/equal.md +30 -1
  85. package/runtime/exception.gr +38 -47
  86. package/runtime/exception.md +10 -8
  87. package/runtime/gc.gr +23 -152
  88. package/runtime/gc.md +13 -17
  89. package/runtime/malloc.gr +31 -31
  90. package/runtime/malloc.md +11 -3
  91. package/runtime/numberUtils.gr +191 -172
  92. package/runtime/numberUtils.md +17 -9
  93. package/runtime/numbers.gr +1695 -1021
  94. package/runtime/numbers.md +1098 -134
  95. package/runtime/string.gr +540 -242
  96. package/runtime/string.md +76 -6
  97. package/runtime/unsafe/constants.gr +30 -13
  98. package/runtime/unsafe/constants.md +80 -0
  99. package/runtime/unsafe/conv.gr +55 -28
  100. package/runtime/unsafe/conv.md +41 -9
  101. package/runtime/unsafe/memory.gr +10 -30
  102. package/runtime/unsafe/memory.md +15 -19
  103. package/runtime/unsafe/tags.gr +37 -21
  104. package/runtime/unsafe/tags.md +88 -8
  105. package/runtime/unsafe/wasmf32.gr +30 -36
  106. package/runtime/unsafe/wasmf32.md +64 -56
  107. package/runtime/unsafe/wasmf64.gr +30 -36
  108. package/runtime/unsafe/wasmf64.md +64 -56
  109. package/runtime/unsafe/wasmi32.gr +49 -66
  110. package/runtime/unsafe/wasmi32.md +102 -94
  111. package/runtime/unsafe/wasmi64.gr +52 -79
  112. package/runtime/unsafe/wasmi64.md +108 -100
  113. package/runtime/utils/printing.gr +13 -15
  114. package/runtime/utils/printing.md +11 -3
  115. package/runtime/wasi.gr +294 -295
  116. package/runtime/wasi.md +62 -42
  117. package/set.gr +574 -64
  118. package/set.md +634 -54
  119. package/stack.gr +181 -64
  120. package/stack.md +271 -42
  121. package/string.gr +453 -533
  122. package/string.md +241 -151
  123. package/uint16.gr +369 -0
  124. package/uint16.md +585 -0
  125. package/uint32.gr +470 -0
  126. package/uint32.md +737 -0
  127. package/uint64.gr +471 -0
  128. package/uint64.md +737 -0
  129. package/uint8.gr +369 -0
  130. package/uint8.md +585 -0
  131. package/uri.gr +1093 -0
  132. package/uri.md +477 -0
  133. package/{sys → wasi}/file.gr +914 -500
  134. package/{sys → wasi}/file.md +454 -50
  135. package/wasi/process.gr +292 -0
  136. package/{sys → wasi}/process.md +164 -6
  137. package/wasi/random.gr +77 -0
  138. package/wasi/random.md +80 -0
  139. package/{sys → wasi}/time.gr +15 -22
  140. package/{sys → wasi}/time.md +5 -5
  141. package/immutablearray.gr +0 -929
  142. package/immutablearray.md +0 -1038
  143. package/immutablemap.gr +0 -493
  144. package/immutablemap.md +0 -479
  145. package/immutablepriorityqueue.gr +0 -360
  146. package/immutablepriorityqueue.md +0 -291
  147. package/immutableset.gr +0 -498
  148. package/immutableset.md +0 -449
  149. package/runtime/debug.gr +0 -2
  150. package/runtime/debug.md +0 -6
  151. package/runtime/unsafe/errors.gr +0 -36
  152. package/runtime/unsafe/errors.md +0 -204
  153. package/sys/process.gr +0 -254
  154. package/sys/random.gr +0 -79
  155. package/sys/random.md +0 -66
@@ -1,124 +1,141 @@
1
- /* grainc-flags --no-pervasives */
2
-
3
- import Memory from "runtime/unsafe/memory"
4
- import Tags from "runtime/unsafe/tags"
5
- import Exception from "runtime/exception"
6
- import BI from "runtime/bigint"
7
-
8
- import {
1
+ @noPervasives
2
+ module Numbers
3
+
4
+ from "runtime/unsafe/memory" include Memory
5
+ from "runtime/unsafe/tags" include Tags
6
+ from "runtime/exception" include Exception
7
+ from "runtime/bigint" include Bigint as BI
8
+
9
+ from "runtime/unsafe/constants" include Constants
10
+ use Constants.{
11
+ _SMIN8_I32,
12
+ _SMAX8_I32,
13
+ _SMIN8_I64,
14
+ _SMAX8_I64,
15
+ _SMIN16_I32,
16
+ _SMAX16_I32,
17
+ _SMIN16_I64,
18
+ _SMAX16_I64,
19
+ _UMAX8_I32,
20
+ _UMAX8_I64,
21
+ _UMAX16_I32,
22
+ _UMAX16_I64,
9
23
  _SMAX32_I64 as _I32_MAX,
10
24
  _SMIN32_I64 as _I32_MIN,
11
- } from "runtime/unsafe/constants"
12
- import WasmI32 from "runtime/unsafe/wasmi32"
13
- import WasmI64 from "runtime/unsafe/wasmi64"
14
- import WasmF32 from "runtime/unsafe/wasmf32"
15
- import WasmF64 from "runtime/unsafe/wasmf64"
16
-
17
- primitive (!): Bool -> Bool = "@not"
18
- primitive (&&): (Bool, Bool) -> Bool = "@and"
19
- primitive (||): (Bool, Bool) -> Bool = "@or"
20
- primitive throw: Exception -> a = "@throw"
25
+ _SMAX_I64 as _I64_MAX,
26
+ _SMIN_I64 as _I64_MIN,
27
+ _UMAX32_I64 as _U32_MAX,
28
+ _UMIN32_I64 as _U32_MIN,
29
+ }
30
+ from "runtime/unsafe/wasmi32" include WasmI32
31
+ from "runtime/unsafe/wasmi64" include WasmI64
32
+ from "runtime/unsafe/wasmf32" include WasmF32
33
+ from "runtime/unsafe/wasmf64" include WasmF64
34
+
35
+ primitive (!) = "@not"
36
+ primitive (&&) = "@and"
37
+ primitive (||) = "@or"
38
+ primitive throw = "@throw"
39
+ primitive ignore = "@ignore"
21
40
 
22
41
  exception UnknownNumberTag
23
42
  exception InvariantViolation
24
43
 
25
- import {
44
+ from "runtime/dataStructures" include DataStructures
45
+ use DataStructures.{
26
46
  newRational,
27
47
  newInt32,
28
48
  newInt64,
29
49
  newFloat32,
30
50
  newFloat64,
31
- } from "runtime/dataStructures"
51
+ tagInt8,
52
+ tagInt16,
53
+ tagUint8,
54
+ tagUint16,
55
+ untagInt8,
56
+ untagInt16,
57
+ untagUint8,
58
+ untagUint16,
59
+ }
32
60
 
33
61
  @unsafe
34
62
  let _F32_MAX = 3.40282347e+38W
35
63
  @unsafe
36
64
  let _F32_MIN = 1.401298464324817e-45W
37
65
  @unsafe
38
- let _F32_MAX_SAFE_INTEGER = 16777215.w
66
+ let _F32_MAX_SAFE_INTEGER = 16777215.0w
39
67
  @unsafe
40
- let _F64_MAX_SAFE_INTEGER = 9007199254740991.W
68
+ let _F64_MAX_SAFE_INTEGER = 9007199254740991.0W
41
69
 
42
- let (==) = WasmI32.eq
43
- let (!=) = WasmI32.ne
70
+ use WasmI32.{ (==), (!=), (^), (<<), (>>) }
44
71
 
45
72
  @unsafe
46
- let tagSimple = x => {
47
- WasmI32.xor(WasmI32.shl(x, 1n), 1n)
73
+ provide let tagSimple = x => {
74
+ x << 1n ^ 1n
48
75
  }
49
76
 
50
77
  @unsafe
51
78
  let untagSimple = x => {
52
- WasmI32.shrS(x, 1n)
79
+ x >> 1n
53
80
  }
54
81
 
55
82
  @unsafe
56
83
  let isSimpleNumber = x => {
57
- WasmI32.eq(
58
- WasmI32.and(x, Tags._GRAIN_NUMBER_TAG_MASK),
59
- Tags._GRAIN_NUMBER_TAG_TYPE
60
- )
84
+ use WasmI32.{ (&) }
85
+ (x & Tags._GRAIN_NUMBER_TAG_MASK) == Tags._GRAIN_NUMBER_TAG_TYPE
61
86
  }
62
87
 
63
88
  @unsafe
64
- export let isBoxedNumber = x => {
65
- if (
66
- WasmI32.eq(
67
- WasmI32.and(x, Tags._GRAIN_GENERIC_TAG_MASK),
68
- Tags._GRAIN_GENERIC_HEAP_TAG_TYPE
69
- )
70
- ) {
71
- WasmI32.eq(WasmI32.load(x, 0n), Tags._GRAIN_BOXED_NUM_HEAP_TAG)
89
+ provide let isBoxedNumber = x => {
90
+ use WasmI32.{ (&) }
91
+ if ((x & Tags._GRAIN_GENERIC_TAG_MASK) == Tags._GRAIN_GENERIC_HEAP_TAG_TYPE) {
92
+ WasmI32.load(x, 0n) == Tags._GRAIN_BOXED_NUM_HEAP_TAG
72
93
  } else {
73
94
  false
74
95
  }
75
96
  }
76
97
 
77
98
  @unsafe
78
- export let isFloat = x => {
99
+ provide let isFloat = x => {
79
100
  if (isBoxedNumber(x)) {
80
101
  let tag = WasmI32.load(x, 4n)
81
- WasmI32.eq(tag, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) ||
82
- WasmI32.eq(tag, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG)
102
+ tag == Tags._GRAIN_FLOAT64_BOXED_NUM_TAG
83
103
  } else {
84
104
  false
85
105
  }
86
106
  }
87
107
 
88
108
  @unsafe
89
- export let isInteger = x => {
109
+ provide let isInteger = x => {
90
110
  if (isBoxedNumber(x)) {
91
111
  let tag = WasmI32.load(x, 4n)
92
- WasmI32.eq(tag, Tags._GRAIN_INT32_BOXED_NUM_TAG) ||
93
- WasmI32.eq(tag, Tags._GRAIN_INT64_BOXED_NUM_TAG) ||
94
- WasmI32.eq(tag, Tags._GRAIN_BIGINT_BOXED_NUM_TAG)
112
+ tag == Tags._GRAIN_INT64_BOXED_NUM_TAG ||
113
+ tag == Tags._GRAIN_BIGINT_BOXED_NUM_TAG
95
114
  } else {
96
115
  true
97
116
  }
98
117
  }
99
118
 
100
119
  @unsafe
101
- export let isRational = x => {
120
+ provide let isRational = x => {
102
121
  if (isBoxedNumber(x)) {
103
122
  let tag = WasmI32.load(x, 4n)
104
- WasmI32.eq(tag, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG)
123
+ tag == Tags._GRAIN_RATIONAL_BOXED_NUM_TAG
105
124
  } else {
106
125
  false
107
126
  }
108
127
  }
109
128
 
110
129
  @unsafe
111
- export let isNaN = x => {
130
+ provide let isNaN = x => {
131
+ use WasmF64.{ (!=) }
112
132
  if (isBoxedNumber(x)) {
113
- // Boxed numbers can have multiple subtypes, of which float32 and float64 can be NaN.
133
+ // Boxed numbers can have multiple subtypes, of which float64 can be NaN.
114
134
  let tag = WasmI32.load(x, 4n)
115
- if (WasmI32.eq(tag, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG)) {
135
+ if (tag == Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) {
116
136
  // uses the fact that NaN is the only number not equal to itself
117
137
  let wf64 = WasmF64.load(x, 8n)
118
- WasmF64.ne(wf64, wf64)
119
- } else if (WasmI32.eq(tag, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG)) {
120
- let wf32 = WasmF32.load(x, 8n)
121
- WasmF32.ne(wf32, wf32)
138
+ wf64 != wf64
122
139
  } else {
123
140
  // Neither rational numbers nor boxed integers can be infinite or NaN.
124
141
  // Grain doesn't allow creating a rational with denominator of zero either.
@@ -134,21 +151,22 @@ export let isNaN = x => {
134
151
  let isBigInt = x => {
135
152
  if (isBoxedNumber(x)) {
136
153
  let tag = WasmI32.load(x, 4n)
137
- WasmI32.eq(tag, Tags._GRAIN_BIGINT_BOXED_NUM_TAG)
154
+ tag == Tags._GRAIN_BIGINT_BOXED_NUM_TAG
138
155
  } else {
139
156
  false
140
157
  }
141
158
  }
142
159
 
143
160
  @unsafe
144
- export let isNumber = x => {
161
+ provide let isNumber = x => {
145
162
  // x is a number if it is a literal number or a boxed_num heap value
146
163
  isSimpleNumber(x) || isBoxedNumber(x)
147
164
  }
148
165
 
149
166
  @unsafe
150
167
  let safeI64toI32 = x => {
151
- if (WasmI64.gtS(x, _I32_MAX) || WasmI64.ltS(x, _I32_MIN)) {
168
+ use WasmI64.{ (<), (>) }
169
+ if (x > _I32_MAX || x < _I32_MIN) {
152
170
  throw Exception.Overflow
153
171
  } else {
154
172
  WasmI32.wrapI64(x)
@@ -156,48 +174,59 @@ let safeI64toI32 = x => {
156
174
  }
157
175
 
158
176
  @unsafe
159
- let i32neg = x => WasmI32.sub(0n, x)
177
+ let i32neg = x => {
178
+ use WasmI32.{ (-) }
179
+ 0n - x
180
+ }
160
181
 
161
182
  @unsafe
162
- let i64not = x => WasmI64.xor(x, 0xffffffffffffffffN)
183
+ let i64not = x => {
184
+ use WasmI64.{ (^) }
185
+ x ^ 0xffffffffffffffffN
186
+ }
163
187
  @unsafe
164
- let i64neg = x => WasmI64.sub(0N, x)
188
+ let i64neg = x => {
189
+ use WasmI64.{ (-) }
190
+ 0N - x
191
+ }
165
192
 
166
193
  // https://en.wikipedia.org/wiki/Binary_GCD_algorithm
167
194
  @unsafe
168
195
  let rec gcdHelp = (x, y) => {
169
- if (WasmI64.eq(x, y) || WasmI64.eqz(x)) {
196
+ use WasmI64.{ (==), (!=), (&), (-), (<<), (>>), (>) }
197
+ if (x == y || WasmI64.eqz(x)) {
170
198
  y
171
199
  } else if (WasmI64.eqz(y)) {
172
200
  x
173
- } else if (WasmI64.ne(WasmI64.and(i64not(x), 1N), 0N)) {
201
+ } else if ((i64not(x) & 1N) != 0N) {
174
202
  // x is even
175
- if (WasmI64.ne(WasmI64.and(y, 1N), 0N)) {
203
+ if ((y & 1N) != 0N) {
176
204
  // y is odd
177
- gcdHelp(WasmI64.shrS(x, 1N), y)
205
+ gcdHelp(x >> 1N, y)
178
206
  } else {
179
- WasmI64.shl(gcdHelp(WasmI64.shrS(x, 1N), WasmI64.shrS(y, 1N)), 1N)
207
+ gcdHelp(x >> 1N, y >> 1N) << 1N
180
208
  }
181
- } else if (WasmI64.ne(WasmI64.and(i64not(y), 1N), 0N)) {
209
+ } else if ((i64not(y) & 1N) != 0N) {
182
210
  // y is even and x is odd
183
- gcdHelp(x, WasmI64.shrS(y, 1N))
184
- } else if (WasmI64.gtS(x, y)) {
185
- gcdHelp(WasmI64.sub(x, y), y)
211
+ gcdHelp(x, y >> 1N)
212
+ } else if (x > y) {
213
+ gcdHelp(x - y, y)
186
214
  } else {
187
- gcdHelp(WasmI64.sub(y, x), x)
215
+ gcdHelp(y - x, x)
188
216
  }
189
217
  }
190
218
 
191
219
  @unsafe
192
220
  let gcd = (x, y) => {
221
+ use WasmI64.{ (<) }
193
222
  // Algorithm above breaks on negatives, so
194
223
  // we make sure that they are positive at the beginning
195
- let x = if (WasmI64.ltS(x, 0N)) {
224
+ let x = if (x < 0N) {
196
225
  i64neg(x)
197
226
  } else {
198
227
  x
199
228
  }
200
- let y = if (WasmI64.ltS(y, 0N)) {
229
+ let y = if (y < 0N) {
201
230
  i64neg(y)
202
231
  } else {
203
232
  y
@@ -211,14 +240,24 @@ let gcd32 = (x, y) => {
211
240
  }
212
241
 
213
242
  @unsafe
214
- export let reducedInteger = x => {
215
- if (WasmI64.gtS(x, _I32_MAX) || WasmI64.ltS(x, _I32_MIN)) {
243
+ provide let reducedInteger = x => {
244
+ use WasmI64.{ (>>), (<), (>) }
245
+ // TODO(#1736): Remove the formatter ignore when parsing is fixed
246
+ //formatter-ignore
247
+ if (x > (_I32_MAX >> 1N) || x < (_I32_MIN >> 1N)) {
248
+ newInt64(x)
249
+ } else {
250
+ tagSimple(WasmI32.wrapI64(x))
251
+ }
252
+ }
253
+
254
+ @unsafe
255
+ provide let reducedUnsignedInteger = x => {
256
+ use WasmI64.{ (>>>) }
257
+ if (WasmI64.gtU(x, _I64_MAX)) {
258
+ BI.makeWrappedUint64(x)
259
+ } else if (WasmI64.gtU(x, _I32_MAX >>> 1N)) {
216
260
  newInt64(x)
217
- } else if (
218
- WasmI64.gtS(x, WasmI64.shrS(_I32_MAX, 1N)) ||
219
- WasmI64.ltS(x, WasmI64.shrS(_I32_MIN, 1N))
220
- ) {
221
- newInt32(WasmI32.wrapI64(x))
222
261
  } else {
223
262
  tagSimple(WasmI32.wrapI64(x))
224
263
  }
@@ -240,7 +279,7 @@ let reducedBigInteger = x => {
240
279
  }
241
280
 
242
281
  @unsafe
243
- let reducedFractionBigInt = (x, y) => {
282
+ let reducedFractionBigInt = (x, y, keepRational) => {
244
283
  let mut x = x
245
284
  let mut y = y
246
285
  let mut needsDecref = false
@@ -263,7 +302,7 @@ let reducedFractionBigInt = (x, y) => {
263
302
  let r = WasmI32.load(quotremResult, 4n)
264
303
  // free container used to store quotrem result
265
304
  Memory.free(quotremResult)
266
- let ret = if (BI.eqz(r)) {
305
+ let ret = if (!keepRational && BI.eqz(r)) {
267
306
  // if remainder is zero, then return the quotient.
268
307
  // We decRef the remainder, since we no longer need it
269
308
  Memory.decRef(r)
@@ -290,10 +329,11 @@ let reducedFractionBigInt = (x, y) => {
290
329
 
291
330
  @unsafe
292
331
  let reducedFraction64 = (x, y) => {
332
+ use WasmI64.{ (/), (<) }
293
333
  let mut x = x
294
334
  let mut y = y
295
335
 
296
- if (WasmI64.ltS(y, 0N)) {
336
+ if (y < 0N) {
297
337
  // Normalization 1: Never do negative/negative
298
338
  // Normalization 2: Never allow a negative denominator
299
339
  x = i64neg(x)
@@ -303,11 +343,11 @@ let reducedFraction64 = (x, y) => {
303
343
  throw Exception.DivisionByZero
304
344
  }
305
345
  if (WasmI64.eqz(WasmI64.remS(x, y))) {
306
- reducedInteger(WasmI64.divS(x, y))
346
+ reducedInteger(x / y)
307
347
  } else {
308
348
  let factor = gcd(x, y)
309
- let xdiv = WasmI64.divS(x, factor)
310
- let ydiv = WasmI64.divS(y, factor)
349
+ let xdiv = x / factor
350
+ let ydiv = y / factor
311
351
  newRational(BI.makeWrappedInt64(xdiv), BI.makeWrappedInt64(ydiv))
312
352
  }
313
353
  }
@@ -336,69 +376,53 @@ let reducedFraction64 = (x, y) => {
336
376
  */
337
377
 
338
378
  @unsafe
339
- export let boxedNumberTag = xptr => {
379
+ provide let boxedNumberTag = xptr => {
340
380
  WasmI32.load(xptr, 4n)
341
381
  }
342
382
 
343
383
  @unsafe
344
- export let boxedInt32Number = xptr => {
345
- WasmI32.load(xptr, 8n)
346
- }
347
-
348
- @unsafe
349
- export let boxedInt64Number = xptr => {
384
+ provide let boxedInt64Number = xptr => {
350
385
  WasmI64.load(xptr, 8n)
351
386
  }
352
387
 
353
388
  @unsafe
354
- export let boxedFloat32Number = xptr => {
355
- WasmF32.load(xptr, 8n)
356
- }
357
-
358
- @unsafe
359
- export let boxedFloat64Number = xptr => {
389
+ provide let boxedFloat64Number = xptr => {
360
390
  WasmF64.load(xptr, 8n)
361
391
  }
362
392
 
363
393
  @unsafe
364
- export let boxedRationalNumerator = xptr => {
394
+ provide let boxedRationalNumerator = xptr => {
365
395
  WasmI32.load(xptr, 8n)
366
396
  }
367
397
 
368
398
  @unsafe
369
- export let boxedRationalDenominator = xptr => {
399
+ provide let boxedRationalDenominator = xptr => {
370
400
  WasmI32.load(xptr, 12n)
371
401
  }
372
402
 
373
403
  @unsafe
374
- export let coerceNumberToWasmF32 = (x: Number) => {
404
+ provide let coerceNumberToWasmF32 = (x: Number) => {
375
405
  let x = WasmI32.fromGrain(x)
376
406
  if (isSimpleNumber(x)) {
377
407
  WasmF32.convertI32S(untagSimple(x))
378
408
  } else {
379
409
  let xtag = boxedNumberTag(x)
380
410
  match (xtag) {
381
- t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => {
382
- WasmF32.convertI32S(boxedInt32Number(x))
383
- },
384
- t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
411
+ t when t == Tags._GRAIN_INT64_BOXED_NUM_TAG => {
385
412
  WasmF32.convertI64S(boxedInt64Number(x))
386
413
  },
387
- t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
414
+ t when t == Tags._GRAIN_BIGINT_BOXED_NUM_TAG => {
388
415
  BI.toFloat32(x)
389
416
  },
390
- t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => {
391
- WasmF32.div(
392
- BI.toFloat32(boxedRationalNumerator(x)),
417
+ t when t == Tags._GRAIN_RATIONAL_BOXED_NUM_TAG => {
418
+ use WasmF32.{ (/) }
419
+ BI.toFloat32(boxedRationalNumerator(x)) /
393
420
  BI.toFloat32(boxedRationalDenominator(x))
394
- )
395
421
  },
396
- t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
397
- boxedFloat32Number(x)
398
- },
399
- t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
422
+ t when t == Tags._GRAIN_FLOAT64_BOXED_NUM_TAG => {
423
+ use WasmF64.{ (<), (>) }
400
424
  let xval = boxedFloat64Number(x)
401
- if (WasmF64.gt(xval, _F32_MAX) || WasmF64.lt(xval, _F32_MIN)) {
425
+ if (xval > _F32_MAX || xval < _F32_MIN) {
402
426
  // Not an actual return value
403
427
  throw Exception.Overflow
404
428
  } else {
@@ -413,32 +437,25 @@ export let coerceNumberToWasmF32 = (x: Number) => {
413
437
  }
414
438
 
415
439
  @unsafe
416
- export let coerceNumberToWasmF64 = (x: Number) => {
440
+ provide let coerceNumberToWasmF64 = (x: Number) => {
417
441
  let x = WasmI32.fromGrain(x)
418
442
  if (isSimpleNumber(x)) {
419
443
  WasmF64.convertI32S(untagSimple(x))
420
444
  } else {
421
445
  let xtag = boxedNumberTag(x)
422
446
  match (xtag) {
423
- t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => {
424
- WasmF64.convertI32S(boxedInt32Number(x))
425
- },
426
- t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
447
+ t when t == Tags._GRAIN_INT64_BOXED_NUM_TAG => {
427
448
  WasmF64.convertI64S(boxedInt64Number(x))
428
449
  },
429
- t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
450
+ t when t == Tags._GRAIN_BIGINT_BOXED_NUM_TAG => {
430
451
  BI.toFloat64(x)
431
452
  },
432
- t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => {
433
- WasmF64.div(
434
- BI.toFloat64(boxedRationalNumerator(x)),
453
+ t when t == Tags._GRAIN_RATIONAL_BOXED_NUM_TAG => {
454
+ use WasmF64.{ (/) }
455
+ BI.toFloat64(boxedRationalNumerator(x)) /
435
456
  BI.toFloat64(boxedRationalDenominator(x))
436
- )
437
- },
438
- t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
439
- WasmF64.promoteF32(boxedFloat32Number(x))
440
457
  },
441
- t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
458
+ t when t == Tags._GRAIN_FLOAT64_BOXED_NUM_TAG => {
442
459
  boxedFloat64Number(x)
443
460
  },
444
461
  _ => {
@@ -449,20 +466,17 @@ export let coerceNumberToWasmF64 = (x: Number) => {
449
466
  }
450
467
 
451
468
  @unsafe
452
- export let coerceNumberToWasmI64 = (x: Number) => {
469
+ provide let coerceNumberToWasmI64 = (x: Number) => {
453
470
  let x = WasmI32.fromGrain(x)
454
471
  if (isSimpleNumber(x)) {
455
472
  WasmI64.extendI32S(untagSimple(x))
456
473
  } else {
457
474
  let xtag = boxedNumberTag(x)
458
475
  match (xtag) {
459
- t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => {
460
- WasmI64.extendI32S(boxedInt32Number(x))
461
- },
462
- t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
476
+ t when t == Tags._GRAIN_INT64_BOXED_NUM_TAG => {
463
477
  boxedInt64Number(x)
464
478
  },
465
- t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
479
+ t when t == Tags._GRAIN_BIGINT_BOXED_NUM_TAG => {
466
480
  BI.toInt64(x)
467
481
  },
468
482
  _ => {
@@ -474,24 +488,86 @@ export let coerceNumberToWasmI64 = (x: Number) => {
474
488
  }
475
489
 
476
490
  @unsafe
477
- export let coerceNumberToWasmI32 = (x: Number) => {
491
+ provide let coerceNumberToWasmI32 = (x: Number) => {
492
+ use WasmI64.{ (<), (>) }
478
493
  let x = WasmI32.fromGrain(x)
479
494
  if (isSimpleNumber(x)) {
480
495
  untagSimple(x)
481
496
  } else {
482
497
  let xtag = boxedNumberTag(x)
483
498
  match (xtag) {
484
- t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => {
485
- boxedInt32Number(x)
499
+ t when t == Tags._GRAIN_INT64_BOXED_NUM_TAG => {
500
+ let int64 = boxedInt64Number(x)
501
+ if (int64 > _I32_MAX || int64 < _I32_MIN) {
502
+ throw Exception.Overflow
503
+ }
504
+ WasmI32.wrapI64(int64)
505
+ },
506
+ t when t == Tags._GRAIN_BIGINT_BOXED_NUM_TAG => {
507
+ BI.toInt32(x)
508
+ },
509
+ _ => {
510
+ // rationals are never integral, and we refuse to coerce floats to ints
511
+ throw Exception.NumberNotIntlike
512
+ },
513
+ }
514
+ }
515
+ }
516
+
517
+ @unsafe
518
+ provide let coerceNumberToUnsignedWasmI64 = (x: Number) => {
519
+ use WasmI32.{ (<) }
520
+ let x = WasmI32.fromGrain(x)
521
+ if (isSimpleNumber(x)) {
522
+ let num = untagSimple(x)
523
+ if (num < 0n) {
524
+ throw Exception.Overflow
525
+ }
526
+ WasmI64.extendI32U(num)
527
+ } else {
528
+ let xtag = boxedNumberTag(x)
529
+ match (xtag) {
530
+ t when t == Tags._GRAIN_INT64_BOXED_NUM_TAG => {
531
+ use WasmI64.{ (<) }
532
+ let int64 = boxedInt64Number(x)
533
+ if (int64 < 0N) {
534
+ throw Exception.Overflow
535
+ }
536
+ int64
537
+ },
538
+ t when t == Tags._GRAIN_BIGINT_BOXED_NUM_TAG => {
539
+ BI.toUnsignedInt64(x)
540
+ },
541
+ _ => {
542
+ // rationals are never integral, and we refuse to coerce floats to ints
543
+ throw Exception.NumberNotIntlike
486
544
  },
487
- t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
545
+ }
546
+ }
547
+ }
548
+
549
+ @unsafe
550
+ provide let coerceNumberToUnsignedWasmI32 = (x: Number) => {
551
+ use WasmI32.{ (<) }
552
+ let x = WasmI32.fromGrain(x)
553
+ if (isSimpleNumber(x)) {
554
+ let num = untagSimple(x)
555
+ if (num < 0n) {
556
+ throw Exception.Overflow
557
+ }
558
+ num
559
+ } else {
560
+ let xtag = boxedNumberTag(x)
561
+ match (xtag) {
562
+ t when t == Tags._GRAIN_INT64_BOXED_NUM_TAG => {
563
+ use WasmI64.{ (<), (>) }
488
564
  let int64 = boxedInt64Number(x)
489
- if (WasmI64.gtS(int64, _I32_MAX) || WasmI64.ltS(int64, _I32_MIN)) {
565
+ if (int64 > _U32_MAX || int64 < _U32_MIN) {
490
566
  throw Exception.Overflow
491
567
  }
492
568
  WasmI32.wrapI64(int64)
493
569
  },
494
- t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
570
+ t when t == Tags._GRAIN_BIGINT_BOXED_NUM_TAG => {
495
571
  BI.toInt32(x)
496
572
  },
497
573
  _ => {
@@ -503,20 +579,17 @@ export let coerceNumberToWasmI32 = (x: Number) => {
503
579
  }
504
580
 
505
581
  @unsafe
506
- export let coerceNumberToBigInt = (x: Number) => {
582
+ let coerceNumberToBigInt = (x: Number) => {
507
583
  let x = WasmI32.fromGrain(x)
508
584
  if (isSimpleNumber(x)) {
509
585
  BI.makeWrappedInt32(untagSimple(x))
510
586
  } else {
511
587
  let xtag = boxedNumberTag(x)
512
588
  match (xtag) {
513
- t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => {
514
- BI.makeWrappedInt32(boxedInt32Number(x))
515
- },
516
- t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
589
+ t when t == Tags._GRAIN_INT64_BOXED_NUM_TAG => {
517
590
  BI.makeWrappedInt64(boxedInt64Number(x))
518
591
  },
519
- t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
592
+ t when t == Tags._GRAIN_BIGINT_BOXED_NUM_TAG => {
520
593
  Memory.incRef(x)
521
594
  x
522
595
  },
@@ -530,24 +603,26 @@ export let coerceNumberToBigInt = (x: Number) => {
530
603
 
531
604
  @unsafe
532
605
  let isIntegerF32 = value => {
533
- WasmF32.eq(value, WasmF32.trunc(value))
606
+ use WasmF32.{ (==) }
607
+ value == WasmF32.trunc(value)
534
608
  }
535
609
 
536
610
  @unsafe
537
611
  let isIntegerF64 = value => {
538
- WasmF64.eq(value, WasmF64.trunc(value))
612
+ use WasmF64.{ (==) }
613
+ value == WasmF64.trunc(value)
539
614
  }
540
615
 
541
616
  @unsafe
542
617
  let isSafeIntegerF32 = value => {
543
- WasmF32.le(WasmF32.abs(value), _F32_MAX_SAFE_INTEGER) &&
544
- WasmF32.eq(WasmF32.trunc(value), value)
618
+ use WasmF32.{ (==), (<=) }
619
+ WasmF32.abs(value) <= _F32_MAX_SAFE_INTEGER && WasmF32.trunc(value) == value
545
620
  }
546
621
 
547
622
  @unsafe
548
623
  let isSafeIntegerF64 = value => {
549
- WasmF64.le(WasmF64.abs(value), _F64_MAX_SAFE_INTEGER) &&
550
- WasmF64.eq(WasmF64.trunc(value), value)
624
+ use WasmF64.{ (==), (<=) }
625
+ WasmF64.abs(value) <= _F64_MAX_SAFE_INTEGER && WasmF64.trunc(value) == value
551
626
  }
552
627
 
553
628
  /** Number-aware equality checking
@@ -556,9 +631,8 @@ let isSafeIntegerF64 = value => {
556
631
  * to that number
557
632
  *
558
633
  * NOTE: The preconditions in these functions are important, so do NOT
559
- * export them!
634
+ * provide them!
560
635
  */
561
-
562
636
  @unsafe
563
637
  let numberEqualSimpleHelp = (x, y) => {
564
638
  // PRECONDITION: x is a "simple" number (value tag is 0) and x !== y and isNumber(y)
@@ -569,30 +643,22 @@ let numberEqualSimpleHelp = (x, y) => {
569
643
  let xval = untagSimple(x) // <- actual int value of x
570
644
  let yBoxedNumberTag = boxedNumberTag(y)
571
645
  match (yBoxedNumberTag) {
572
- t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => {
573
- let yBoxedVal = boxedInt32Number(y)
574
- WasmI32.eq(xval, yBoxedVal)
575
- },
576
- t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
646
+ t when t == Tags._GRAIN_INT64_BOXED_NUM_TAG => {
647
+ use WasmI64.{ (==) }
577
648
  let yBoxedVal = boxedInt64Number(y)
578
- WasmI64.eq(WasmI64.extendI32S(xval), yBoxedVal)
649
+ WasmI64.extendI32S(xval) == yBoxedVal
579
650
  },
580
- t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
651
+ t when t == Tags._GRAIN_BIGINT_BOXED_NUM_TAG => {
581
652
  WasmI32.eqz(BI.cmpI64(y, WasmI64.extendI32S(xval)))
582
653
  },
583
- t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => {
654
+ t when t == Tags._GRAIN_RATIONAL_BOXED_NUM_TAG => {
584
655
  // NOTE: we always store in most reduced form, so a rational and an int are never equal
585
656
  false
586
657
  },
587
- t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
588
- let yBoxedVal = boxedFloat32Number(y)
589
- isSafeIntegerF32(yBoxedVal) &&
590
- WasmF32.eq(WasmF32.convertI32S(xval), yBoxedVal)
591
- },
592
- t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
658
+ t when t == Tags._GRAIN_FLOAT64_BOXED_NUM_TAG => {
659
+ use WasmF64.{ (==) }
593
660
  let yBoxedVal = boxedFloat64Number(y)
594
- isSafeIntegerF64(yBoxedVal) &&
595
- WasmF64.eq(WasmF64.convertI32S(xval), yBoxedVal)
661
+ isSafeIntegerF64(yBoxedVal) && WasmF64.convertI32S(xval) == yBoxedVal
596
662
  },
597
663
  _ => {
598
664
  throw UnknownNumberTag
@@ -606,35 +672,28 @@ let numberEqualInt64Help = (xBoxedVal, y) => {
606
672
  // PRECONDITION: x !== y and isNumber(y)
607
673
  // Basic number:
608
674
  if (isSimpleNumber(y)) {
609
- WasmI64.eq(xBoxedVal, WasmI64.extendI32S(untagSimple(y)))
675
+ use WasmI64.{ (==) }
676
+ xBoxedVal == WasmI64.extendI32S(untagSimple(y))
610
677
  } else {
611
678
  // Boxed number:
612
679
  let yBoxedNumberTag = boxedNumberTag(y)
613
680
  match (yBoxedNumberTag) {
614
- t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => {
615
- let yBoxedVal = boxedInt32Number(y)
616
- WasmI64.eq(xBoxedVal, WasmI64.extendI32S(yBoxedVal))
617
- },
618
- t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
681
+ t when t == Tags._GRAIN_INT64_BOXED_NUM_TAG => {
682
+ use WasmI64.{ (==) }
619
683
  let yBoxedVal = boxedInt64Number(y)
620
- WasmI64.eq(xBoxedVal, yBoxedVal)
684
+ xBoxedVal == yBoxedVal
621
685
  },
622
- t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
686
+ t when t == Tags._GRAIN_BIGINT_BOXED_NUM_TAG => {
623
687
  WasmI32.eqz(BI.cmpI64(y, xBoxedVal))
624
688
  },
625
- t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => {
689
+ t when t == Tags._GRAIN_RATIONAL_BOXED_NUM_TAG => {
626
690
  // NOTE: we always store in most reduced form, so a rational and an int are never equal
627
691
  false
628
692
  },
629
- t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
630
- let yBoxedVal = boxedFloat32Number(y)
631
- isSafeIntegerF32(yBoxedVal) &&
632
- WasmI64.eq(xBoxedVal, WasmI64.truncF32S(yBoxedVal))
633
- },
634
- t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
693
+ t when t == Tags._GRAIN_FLOAT64_BOXED_NUM_TAG => {
694
+ use WasmI64.{ (==) }
635
695
  let yBoxedVal = boxedFloat64Number(y)
636
- isSafeIntegerF64(yBoxedVal) &&
637
- WasmI64.eq(xBoxedVal, WasmI64.truncF64S(yBoxedVal))
696
+ isSafeIntegerF64(yBoxedVal) && xBoxedVal == WasmI64.truncF64S(yBoxedVal)
638
697
  },
639
698
  _ => {
640
699
  throw UnknownNumberTag
@@ -643,12 +702,6 @@ let numberEqualInt64Help = (xBoxedVal, y) => {
643
702
  }
644
703
  }
645
704
 
646
- @unsafe
647
- let numberEqualInt32Help = (xBoxedVal, y) => {
648
- // We can just pretend it's 64-bit for the equality check
649
- numberEqualInt64Help(WasmI64.extendI32S(xBoxedVal), y)
650
- }
651
-
652
705
  @unsafe
653
706
  let numberEqualRationalHelp = (xptr, y) => {
654
707
  // PRECONDITION: x is rational and x !== y and isNumber(y)
@@ -661,37 +714,23 @@ let numberEqualRationalHelp = (xptr, y) => {
661
714
  // Boxed number:
662
715
  let yBoxedNumberTag = boxedNumberTag(y)
663
716
  match (yBoxedNumberTag) {
664
- t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => {
665
- false
666
- },
667
- t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
717
+ t when t == Tags._GRAIN_INT64_BOXED_NUM_TAG => {
668
718
  false
669
719
  },
670
- t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
720
+ t when t == Tags._GRAIN_BIGINT_BOXED_NUM_TAG => {
671
721
  false
672
722
  },
673
- t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => {
723
+ t when t == Tags._GRAIN_RATIONAL_BOXED_NUM_TAG => {
674
724
  let yNumerator = boxedRationalNumerator(y)
675
725
  let yDenominator = boxedRationalDenominator(y)
676
726
  BI.eq(xNumerator, yNumerator) && BI.eq(xDenominator, yDenominator)
677
727
  },
678
- t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
679
- let yBoxedVal = boxedFloat32Number(y)
680
- let xAsFloat = WasmF32.div(
681
- BI.toFloat32(xNumerator),
682
- BI.toFloat32(xDenominator)
683
- )
684
- // TODO(#303): maybe we should have some sort of tolerance?
685
- WasmF32.eq(xAsFloat, yBoxedVal)
686
- },
687
- t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
728
+ t when t == Tags._GRAIN_FLOAT64_BOXED_NUM_TAG => {
729
+ use WasmF64.{ (==), (/) }
688
730
  let yBoxedVal = boxedFloat64Number(y)
689
- let xAsFloat = WasmF64.div(
690
- BI.toFloat64(xNumerator),
691
- BI.toFloat64(xDenominator)
692
- )
731
+ let xAsFloat = BI.toFloat64(xNumerator) / BI.toFloat64(xDenominator)
693
732
  // TODO(#303): maybe we should have some sort of tolerance?
694
- WasmF64.eq(xAsFloat, yBoxedVal)
733
+ xAsFloat == yBoxedVal
695
734
  },
696
735
  _ => {
697
736
  throw UnknownNumberTag
@@ -705,40 +744,32 @@ let numberEqualFloat64Help = (x, y) => {
705
744
  let xIsInteger = isIntegerF64(x)
706
745
  // Basic number:
707
746
  if (isSimpleNumber(y)) {
708
- xIsInteger && WasmF64.eq(x, WasmF64.convertI32S(untagSimple(y)))
747
+ use WasmF64.{ (==) }
748
+ xIsInteger && x == WasmF64.convertI32S(untagSimple(y))
709
749
  } else {
710
750
  // Boxed number
711
751
  let yBoxedNumberTag = boxedNumberTag(y)
712
752
  match (yBoxedNumberTag) {
713
- t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => {
714
- let yBoxedVal = boxedInt32Number(y)
715
- isSafeIntegerF64(x) && WasmF64.eq(x, WasmF64.convertI32S(yBoxedVal))
716
- },
717
- t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
753
+ t when t == Tags._GRAIN_INT64_BOXED_NUM_TAG => {
754
+ use WasmF64.{ (==) }
718
755
  let yBoxedVal = boxedInt64Number(y)
719
- isSafeIntegerF64(x) && WasmF64.eq(x, WasmF64.convertI64S(yBoxedVal))
756
+ isSafeIntegerF64(x) && x == WasmF64.convertI64S(yBoxedVal)
720
757
  },
721
- t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
758
+ t when t == Tags._GRAIN_BIGINT_BOXED_NUM_TAG => {
722
759
  WasmI32.eqz(BI.cmpF64(y, x))
723
760
  },
724
- t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => {
761
+ t when t == Tags._GRAIN_RATIONAL_BOXED_NUM_TAG => {
762
+ use WasmF64.{ (==), (/) }
725
763
  let yNumerator = boxedRationalNumerator(y)
726
764
  let yDenominator = boxedRationalDenominator(y)
727
- let yAsFloat = WasmF64.div(
728
- BI.toFloat64(yNumerator),
729
- BI.toFloat64(yDenominator)
730
- )
731
- WasmF64.eq(x, yAsFloat)
732
- },
733
- t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
734
- let yBoxedVal = boxedFloat32Number(y)
735
- // TODO(#303): maybe we should have some sort of tolerance?
736
- WasmF64.eq(x, WasmF64.promoteF32(yBoxedVal))
765
+ let yAsFloat = BI.toFloat64(yNumerator) / BI.toFloat64(yDenominator)
766
+ x == yAsFloat
737
767
  },
738
- t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
768
+ t when t == Tags._GRAIN_FLOAT64_BOXED_NUM_TAG => {
769
+ use WasmF64.{ (==) }
739
770
  let yBoxedVal = boxedFloat64Number(y)
740
771
  // TODO(#303): maybe we should have some sort of tolerance?
741
- WasmF64.eq(x, yBoxedVal)
772
+ x == yBoxedVal
742
773
  },
743
774
  _ => {
744
775
  throw UnknownNumberTag
@@ -747,27 +778,6 @@ let numberEqualFloat64Help = (x, y) => {
747
778
  }
748
779
  }
749
780
 
750
- @unsafe
751
- let numberEqualFloat32Help = (x, y) => {
752
- let xIsInteger = isIntegerF32(x)
753
- // Basic number:
754
- if (isSimpleNumber(y)) {
755
- xIsInteger && WasmF32.eq(x, WasmF32.convertI32S(untagSimple(y)))
756
- } else {
757
- // Boxed number
758
- let yBoxedNumberTag = boxedNumberTag(y)
759
- match (yBoxedNumberTag) {
760
- t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
761
- // Special case: f32/f32 equality (need to handle here without promotion)
762
- WasmF32.eq(x, boxedFloat32Number(y))
763
- },
764
- _ => {
765
- numberEqualFloat64Help(WasmF64.promoteF32(x), y)
766
- },
767
- }
768
- }
769
- }
770
-
771
781
  @unsafe
772
782
  let numberEqualBigIntHelp = (x, y) => {
773
783
  if (isSimpleNumber(y)) {
@@ -776,26 +786,18 @@ let numberEqualBigIntHelp = (x, y) => {
776
786
  // Boxed number
777
787
  let yBoxedNumberTag = boxedNumberTag(y)
778
788
  match (yBoxedNumberTag) {
779
- t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => {
780
- let yBoxedVal = boxedInt32Number(y)
781
- WasmI32.eqz(BI.cmpI64(x, WasmI64.extendI32S(yBoxedVal)))
782
- },
783
- t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
789
+ t when t == Tags._GRAIN_INT64_BOXED_NUM_TAG => {
784
790
  let yBoxedVal = boxedInt64Number(y)
785
791
  WasmI32.eqz(BI.cmpI64(x, yBoxedVal))
786
792
  },
787
- t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
793
+ t when t == Tags._GRAIN_BIGINT_BOXED_NUM_TAG => {
788
794
  BI.eq(x, y)
789
795
  },
790
- t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => {
796
+ t when t == Tags._GRAIN_RATIONAL_BOXED_NUM_TAG => {
791
797
  // Rationals are reduced, so it must be unequal
792
798
  false
793
799
  },
794
- t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
795
- let yBoxedVal = boxedFloat32Number(y)
796
- WasmI32.eqz(BI.cmpF32(x, yBoxedVal))
797
- },
798
- t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
800
+ t when t == Tags._GRAIN_FLOAT64_BOXED_NUM_TAG => {
799
801
  let yBoxedVal = boxedFloat64Number(y)
800
802
  WasmI32.eqz(BI.cmpF64(x, yBoxedVal))
801
803
  },
@@ -807,32 +809,25 @@ let numberEqualBigIntHelp = (x, y) => {
807
809
  }
808
810
 
809
811
  @unsafe
810
- export let numberEqual = (x, y) => {
812
+ provide let numberEqual = (x, y) => {
811
813
  if (isSimpleNumber(x)) {
812
814
  // Short circuit if non-pointer value is the same
813
- WasmI32.eq(x, y) || numberEqualSimpleHelp(x, y)
815
+ x == y || numberEqualSimpleHelp(x, y)
814
816
  } else {
815
817
  // Boxed number
816
818
  let xBoxedNumberTag = boxedNumberTag(x)
817
819
  match (xBoxedNumberTag) {
818
- t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => {
819
- let xBoxedVal = boxedInt32Number(x)
820
- numberEqualInt32Help(xBoxedVal, y)
821
- },
822
- t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
820
+ t when t == Tags._GRAIN_INT64_BOXED_NUM_TAG => {
823
821
  let xBoxedVal = boxedInt64Number(x)
824
822
  numberEqualInt64Help(xBoxedVal, y)
825
823
  },
826
- t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => {
824
+ t when t == Tags._GRAIN_RATIONAL_BOXED_NUM_TAG => {
827
825
  numberEqualRationalHelp(x, y)
828
826
  },
829
- t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
830
- numberEqualFloat32Help(boxedFloat32Number(x), y)
831
- },
832
- t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
827
+ t when t == Tags._GRAIN_FLOAT64_BOXED_NUM_TAG => {
833
828
  numberEqualFloat64Help(boxedFloat64Number(x), y)
834
829
  },
835
- t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
830
+ t when t == Tags._GRAIN_BIGINT_BOXED_NUM_TAG => {
836
831
  numberEqualBigIntHelp(x, y)
837
832
  },
838
833
  _ => {
@@ -849,37 +844,29 @@ export let numberEqual = (x, y) => {
849
844
 
850
845
  @unsafe
851
846
  let numberAddSubSimpleHelp = (x, y, isSub) => {
847
+ use WasmI64.{ (+), (-) }
852
848
  // PRECONDITION: x is a "simple" number (value tag is 0) and isNumber(y)
853
849
  if (isSimpleNumber(y)) {
854
850
  let x = WasmI64.extendI32S(untagSimple(x))
855
851
  let y = WasmI64.extendI32S(untagSimple(y))
856
852
  let result = if (isSub) {
857
- WasmI64.sub(x, y)
853
+ x - y
858
854
  } else {
859
- WasmI64.add(x, y)
855
+ x + y
860
856
  }
861
857
  reducedInteger(result)
862
858
  } else {
863
859
  let xval = untagSimple(x) // <- actual int value of x
864
860
  let yBoxedNumberTag = boxedNumberTag(y)
865
861
  match (yBoxedNumberTag) {
866
- t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => {
867
- let xval = WasmI64.extendI32S(xval)
868
- let yBoxedVal = WasmI64.extendI32S(boxedInt32Number(y))
869
- let result =
870
- if (isSub) WasmI64.sub(xval, yBoxedVal)
871
- else WasmI64.add(xval, yBoxedVal)
872
- reducedInteger(result)
873
- },
874
- t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
862
+ t when t == Tags._GRAIN_INT64_BOXED_NUM_TAG => {
863
+ use WasmI64.{ (<), (>), (>=) }
875
864
  let yBoxedVal = boxedInt64Number(y)
876
865
  let xval64 = WasmI64.extendI32S(xval)
877
- let result =
878
- if (isSub) WasmI64.sub(xval64, yBoxedVal)
879
- else WasmI64.add(xval64, yBoxedVal)
866
+ let result = if (isSub) xval64 - yBoxedVal else xval64 + yBoxedVal
880
867
  if (
881
- WasmI64.geS(yBoxedVal, 0N) && WasmI64.ltS(result, xval64) ||
882
- WasmI64.ltS(yBoxedVal, 0N) && WasmI64.gtS(result, xval64)
868
+ yBoxedVal >= 0N && result < xval64 ||
869
+ yBoxedVal < 0N && result > xval64
883
870
  ) {
884
871
  // Overflow. Promote to BigInt
885
872
  let xBig = BI.makeWrappedInt32(xval)
@@ -896,41 +883,33 @@ let numberAddSubSimpleHelp = (x, y, isSub) => {
896
883
  reducedInteger(result)
897
884
  }
898
885
  },
899
- t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
886
+ t when t == Tags._GRAIN_BIGINT_BOXED_NUM_TAG => {
900
887
  // Promote x to bigint and do operation
901
888
  let xBig = BI.makeWrappedInt32(xval)
902
889
  let result = if (isSub) BI.sub(xBig, y) else BI.add(xBig, y)
903
890
  Memory.decRef(xBig)
904
891
  reducedBigInteger(result)
905
892
  },
906
- t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => {
893
+ t when t == Tags._GRAIN_RATIONAL_BOXED_NUM_TAG => {
907
894
  let xBig = BI.makeWrappedInt32(xval)
908
895
  let yNumerator = boxedRationalNumerator(y)
909
896
  let yDenominator = boxedRationalDenominator(y)
910
897
  let expandedXNumerator = BI.mul(xBig, yDenominator)
911
898
  Memory.decRef(xBig)
912
- let result =
913
- if (isSub) BI.sub(expandedXNumerator, yNumerator)
914
- else BI.add(expandedXNumerator, yNumerator)
915
- let ret = reducedFractionBigInt(result, yDenominator)
899
+ let result = if (isSub)
900
+ BI.sub(expandedXNumerator, yNumerator)
901
+ else
902
+ BI.add(expandedXNumerator, yNumerator)
903
+ let ret = reducedFractionBigInt(result, yDenominator, false)
916
904
  Memory.decRef(expandedXNumerator)
917
905
  Memory.decRef(result)
918
906
  ret
919
907
  },
920
- t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
921
- let yBoxedVal = boxedFloat32Number(y)
922
- let xval = WasmF32.convertI32S(xval)
923
- let result =
924
- if (isSub) WasmF32.sub(xval, yBoxedVal)
925
- else WasmF32.add(xval, yBoxedVal)
926
- newFloat32(result)
927
- },
928
- t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
908
+ t when t == Tags._GRAIN_FLOAT64_BOXED_NUM_TAG => {
909
+ use WasmF64.{ (+), (-) }
929
910
  let yBoxedVal = boxedFloat64Number(y)
930
911
  let xval = WasmF64.convertI32S(xval)
931
- let result =
932
- if (isSub) WasmF64.sub(xval, yBoxedVal)
933
- else WasmF64.add(xval, yBoxedVal)
912
+ let result = if (isSub) xval - yBoxedVal else xval + yBoxedVal
934
913
  newFloat64(result)
935
914
  },
936
915
  _ => {
@@ -942,13 +921,11 @@ let numberAddSubSimpleHelp = (x, y, isSub) => {
942
921
 
943
922
  @unsafe
944
923
  let numberAddSubInt64Help = (xval, y, isSub) => {
924
+ use WasmI64.{ (+), (-), (<), (>), (>), (>=) }
945
925
  if (isSimpleNumber(y)) {
946
926
  let yval = WasmI64.extendI32S(untagSimple(y))
947
- let result = if (isSub) WasmI64.sub(xval, yval) else WasmI64.add(xval, yval)
948
- if (
949
- WasmI64.geS(yval, 0N) && WasmI64.ltS(result, xval) ||
950
- WasmI64.ltS(yval, 0N) && WasmI64.gtS(result, xval)
951
- ) {
927
+ let result = if (isSub) xval - yval else xval + yval
928
+ if (yval >= 0N && result < xval || yval < 0N && result > xval) {
952
929
  // Overflow. Promote to BigInt
953
930
  let xBig = BI.makeWrappedInt64(xval)
954
931
  let yBig = BI.makeWrappedInt64(yval)
@@ -966,22 +943,13 @@ let numberAddSubInt64Help = (xval, y, isSub) => {
966
943
  } else {
967
944
  let yBoxedNumberTag = boxedNumberTag(y)
968
945
  match (yBoxedNumberTag) {
969
- t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => {
970
- let yBoxedVal = WasmI64.extendI32S(boxedInt32Number(y))
971
- let result =
972
- if (isSub) WasmI64.sub(xval, yBoxedVal)
973
- else WasmI64.add(xval, yBoxedVal)
974
- reducedInteger(result)
975
- },
976
- t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
946
+ t when t == Tags._GRAIN_INT64_BOXED_NUM_TAG => {
977
947
  let yBoxedVal = boxedInt64Number(y)
978
948
  let xval64 = xval
979
- let result =
980
- if (isSub) WasmI64.sub(xval64, yBoxedVal)
981
- else WasmI64.add(xval64, yBoxedVal)
949
+ let result = if (isSub) xval64 - yBoxedVal else xval64 + yBoxedVal
982
950
  if (
983
- WasmI64.geS(yBoxedVal, 0N) && WasmI64.ltS(result, xval64) ||
984
- WasmI64.ltS(yBoxedVal, 0N) && WasmI64.gtS(result, xval64)
951
+ yBoxedVal >= 0N && result < xval64 ||
952
+ yBoxedVal < 0N && result > xval64
985
953
  ) {
986
954
  // Overflow. Promote to BigInt
987
955
  let xBig = BI.makeWrappedInt64(xval64)
@@ -998,41 +966,33 @@ let numberAddSubInt64Help = (xval, y, isSub) => {
998
966
  reducedInteger(result)
999
967
  }
1000
968
  },
1001
- t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
969
+ t when t == Tags._GRAIN_BIGINT_BOXED_NUM_TAG => {
1002
970
  // Promote x to bigint and do operation
1003
971
  let xBig = BI.makeWrappedInt64(xval)
1004
972
  let result = if (isSub) BI.sub(xBig, y) else BI.add(xBig, y)
1005
973
  Memory.decRef(xBig)
1006
974
  reducedBigInteger(result)
1007
975
  },
1008
- t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => {
976
+ t when t == Tags._GRAIN_RATIONAL_BOXED_NUM_TAG => {
1009
977
  let xBig = BI.makeWrappedInt64(xval)
1010
978
  let yNumerator = boxedRationalNumerator(y)
1011
979
  let yDenominator = boxedRationalDenominator(y)
1012
980
  let expandedXNumerator = BI.mul(xBig, yDenominator)
1013
981
  Memory.decRef(xBig)
1014
- let result =
1015
- if (isSub) BI.sub(expandedXNumerator, yNumerator)
1016
- else BI.add(expandedXNumerator, yNumerator)
1017
- let ret = reducedFractionBigInt(result, yDenominator)
982
+ let result = if (isSub)
983
+ BI.sub(expandedXNumerator, yNumerator)
984
+ else
985
+ BI.add(expandedXNumerator, yNumerator)
986
+ let ret = reducedFractionBigInt(result, yDenominator, false)
1018
987
  Memory.decRef(expandedXNumerator)
1019
988
  Memory.decRef(result)
1020
989
  ret
1021
990
  },
1022
- t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
1023
- let xval = WasmF32.convertI64S(xval)
1024
- let yBoxedVal = boxedFloat32Number(y)
1025
- let result =
1026
- if (isSub) WasmF32.sub(xval, yBoxedVal)
1027
- else WasmF32.add(xval, yBoxedVal)
1028
- newFloat32(result)
1029
- },
1030
- t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
991
+ t when t == Tags._GRAIN_FLOAT64_BOXED_NUM_TAG => {
992
+ use WasmF64.{ (+), (-) }
1031
993
  let xval = WasmF64.convertI64S(xval)
1032
994
  let yBoxedVal = boxedFloat64Number(y)
1033
- let result =
1034
- if (isSub) WasmF64.sub(xval, yBoxedVal)
1035
- else WasmF64.add(xval, yBoxedVal)
995
+ let result = if (isSub) xval - yBoxedVal else xval + yBoxedVal
1036
996
  newFloat64(result)
1037
997
  },
1038
998
  _ => {
@@ -1042,40 +1002,16 @@ let numberAddSubInt64Help = (xval, y, isSub) => {
1042
1002
  }
1043
1003
  }
1044
1004
 
1045
- @unsafe
1046
- let numberAddSubFloat32Help = (xval, y, isSub) => {
1047
- if (
1048
- !isSimpleNumber(y) &&
1049
- WasmI32.eq(boxedNumberTag(y), Tags._GRAIN_FLOAT64_BOXED_NUM_TAG)
1050
- ) {
1051
- // Special case: promote to f64 if RHS is f64
1052
- let xval = WasmF64.promoteF32(xval)
1053
- let yval = boxedFloat64Number(y)
1054
- let result = if (isSub) WasmF64.sub(xval, yval) else WasmF64.add(xval, yval)
1055
- newFloat64(result)
1056
- } else {
1057
- // incRef y to reuse it via WasmI32.toGrain
1058
- Memory.incRef(y)
1059
- let yval = coerceNumberToWasmF32(WasmI32.toGrain(y): Number)
1060
- let result = if (isSub) WasmF32.sub(xval, yval) else WasmF32.add(xval, yval)
1061
- newFloat32(result)
1062
- }
1063
- }
1064
-
1065
1005
  @unsafe
1066
1006
  let numberAddSubFloat64Help = (xval, y, isSub) => {
1007
+ use WasmF64.{ (+), (-) }
1067
1008
  // incRef y to reuse it via WasmI32.toGrain
1068
1009
  Memory.incRef(y)
1069
1010
  let yval = coerceNumberToWasmF64(WasmI32.toGrain(y): Number)
1070
- let result = if (isSub) WasmF64.sub(xval, yval) else WasmF64.add(xval, yval)
1011
+ let result = if (isSub) xval - yval else xval + yval
1071
1012
  newFloat64(result)
1072
1013
  }
1073
1014
 
1074
- @unsafe
1075
- let numberAddSubInt32Help = (xval, y, isSub) => {
1076
- numberAddSubInt64Help(WasmI64.extendI32S(xval), y, isSub)
1077
- }
1078
-
1079
1015
  @unsafe
1080
1016
  let numberAddSubBigIntHelp = (x, y, isSub) => {
1081
1017
  if (isSimpleNumber(y)) {
@@ -1091,18 +1027,7 @@ let numberAddSubBigIntHelp = (x, y, isSub) => {
1091
1027
  } else {
1092
1028
  let yBoxedNumberTag = boxedNumberTag(y)
1093
1029
  match (yBoxedNumberTag) {
1094
- t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => {
1095
- let yBoxedVal = WasmI64.extendI32S(boxedInt32Number(y))
1096
- let yBig = BI.makeWrappedInt64(yBoxedVal)
1097
- let res = if (isSub) {
1098
- BI.sub(x, yBig)
1099
- } else {
1100
- BI.add(x, yBig)
1101
- }
1102
- Memory.decRef(yBig)
1103
- reducedBigInteger(res)
1104
- },
1105
- t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
1030
+ t when t == Tags._GRAIN_INT64_BOXED_NUM_TAG => {
1106
1031
  let yBoxedVal = boxedInt64Number(y)
1107
1032
  let yBig = BI.makeWrappedInt64(yBoxedVal)
1108
1033
  let res = if (isSub) {
@@ -1113,7 +1038,7 @@ let numberAddSubBigIntHelp = (x, y, isSub) => {
1113
1038
  Memory.decRef(yBig)
1114
1039
  reducedBigInteger(res)
1115
1040
  },
1116
- t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
1041
+ t when t == Tags._GRAIN_BIGINT_BOXED_NUM_TAG => {
1117
1042
  let res = if (isSub) {
1118
1043
  BI.sub(x, y)
1119
1044
  } else {
@@ -1121,32 +1046,24 @@ let numberAddSubBigIntHelp = (x, y, isSub) => {
1121
1046
  }
1122
1047
  reducedBigInteger(res)
1123
1048
  },
1124
- t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => {
1049
+ t when t == Tags._GRAIN_RATIONAL_BOXED_NUM_TAG => {
1125
1050
  let yNumerator = boxedRationalNumerator(y)
1126
1051
  let yDenominator = boxedRationalDenominator(y)
1127
1052
  let expandedXNumerator = BI.mul(x, yDenominator)
1128
- let result =
1129
- if (isSub) BI.sub(expandedXNumerator, yNumerator)
1130
- else BI.add(expandedXNumerator, yNumerator)
1053
+ let result = if (isSub)
1054
+ BI.sub(expandedXNumerator, yNumerator)
1055
+ else
1056
+ BI.add(expandedXNumerator, yNumerator)
1131
1057
  Memory.decRef(expandedXNumerator)
1132
- let ret = reducedFractionBigInt(result, yDenominator)
1058
+ let ret = reducedFractionBigInt(result, yDenominator, false)
1133
1059
  Memory.decRef(result)
1134
1060
  ret
1135
1061
  },
1136
- t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
1137
- let xval = BI.toFloat32(x)
1138
- let yBoxedVal = boxedFloat32Number(y)
1139
- let result =
1140
- if (isSub) WasmF32.sub(xval, yBoxedVal)
1141
- else WasmF32.add(xval, yBoxedVal)
1142
- newFloat32(result)
1143
- },
1144
- t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
1062
+ t when t == Tags._GRAIN_FLOAT64_BOXED_NUM_TAG => {
1063
+ use WasmF64.{ (+), (-) }
1145
1064
  let xval = BI.toFloat64(x)
1146
1065
  let yBoxedVal = boxedFloat64Number(y)
1147
- let result =
1148
- if (isSub) WasmF64.sub(xval, yBoxedVal)
1149
- else WasmF64.add(xval, yBoxedVal)
1066
+ let result = if (isSub) xval - yBoxedVal else xval + yBoxedVal
1150
1067
  newFloat64(result)
1151
1068
  },
1152
1069
  _ => {
@@ -1156,6 +1073,120 @@ let numberAddSubBigIntHelp = (x, y, isSub) => {
1156
1073
  }
1157
1074
  }
1158
1075
 
1076
+ @unsafe
1077
+ provide let addSubRational = (x, y, isSub, keepRational) => {
1078
+ let xNumerator = boxedRationalNumerator(x)
1079
+ let xDenominator = boxedRationalDenominator(x)
1080
+ let yNumerator = boxedRationalNumerator(y)
1081
+ let yDenominator = boxedRationalDenominator(y)
1082
+ if (BI.eq(xDenominator, yDenominator)) {
1083
+ let newNumerator = if (isSub)
1084
+ BI.sub(xNumerator, yNumerator)
1085
+ else
1086
+ BI.add(xNumerator, yNumerator)
1087
+ let ret = reducedFractionBigInt(newNumerator, xDenominator, keepRational)
1088
+ Memory.decRef(newNumerator)
1089
+ ret
1090
+ } else {
1091
+ let numerator1 = BI.mul(xNumerator, yDenominator)
1092
+ let numerator2 = BI.mul(yNumerator, xDenominator)
1093
+ let numerator = if (isSub)
1094
+ BI.sub(numerator1, numerator2)
1095
+ else
1096
+ BI.add(numerator1, numerator2)
1097
+ let denominator = BI.mul(xDenominator, yDenominator)
1098
+ let ret = reducedFractionBigInt(numerator, denominator, keepRational)
1099
+ Memory.decRef(numerator1)
1100
+ Memory.decRef(numerator2)
1101
+ Memory.decRef(numerator)
1102
+ ret
1103
+ }
1104
+ }
1105
+
1106
+ @unsafe
1107
+ provide let timesDivideRational = (x, y, isDivide, keepRational) => {
1108
+ let xNumerator = boxedRationalNumerator(x)
1109
+ let xDenominator = boxedRationalDenominator(x)
1110
+ let yNumerator = boxedRationalNumerator(y)
1111
+ let yDenominator = boxedRationalDenominator(y)
1112
+ // (a / b) * (c / d) == (a * c) / (b * d)
1113
+ // (a / b) / (c / d) == (a * d) / (b * c)
1114
+ let numerator = if (isDivide)
1115
+ BI.mul(xNumerator, yDenominator)
1116
+ else
1117
+ BI.mul(xNumerator, yNumerator)
1118
+ let denominator = if (isDivide)
1119
+ BI.mul(xDenominator, yNumerator)
1120
+ else
1121
+ BI.mul(xDenominator, yDenominator)
1122
+ reducedFractionBigInt(numerator, denominator, keepRational)
1123
+ }
1124
+
1125
+ @unsafe
1126
+ provide let rationalsEqual = (x, y) => {
1127
+ let xNumerator = boxedRationalNumerator(x)
1128
+ let xDenominator = boxedRationalDenominator(x)
1129
+ let yNumerator = boxedRationalNumerator(y)
1130
+ let yDenominator = boxedRationalDenominator(y)
1131
+ BI.eq(xNumerator, yNumerator) && BI.eq(xDenominator, yDenominator)
1132
+ }
1133
+
1134
+ @unsafe
1135
+ provide let cmpRationals = (x, y) => {
1136
+ // Comparing rationals efficiently is an open problem
1137
+ // Producing a definitive answer is quite expensive, so if the two
1138
+ // values are not strictly equal we approximate an answer
1139
+
1140
+ let xNumerator = boxedRationalNumerator(x)
1141
+ let xDenominator = boxedRationalDenominator(x)
1142
+ let yNumerator = boxedRationalNumerator(y)
1143
+ let yDenominator = boxedRationalDenominator(y)
1144
+
1145
+ if (
1146
+ BI.cmp(xNumerator, yNumerator) == 0n &&
1147
+ BI.cmp(xDenominator, yDenominator) == 0n
1148
+ ) {
1149
+ 0n
1150
+ } else {
1151
+ use WasmF64.{ (/), (<) }
1152
+ let xf = BI.toFloat64(xNumerator) / BI.toFloat64(xDenominator)
1153
+ let yf = BI.toFloat64(yNumerator) / BI.toFloat64(yDenominator)
1154
+ if (xf < yf) -1n else 1n
1155
+ }
1156
+ }
1157
+
1158
+ /**
1159
+ * Finds the numerator of the rational number.
1160
+ *
1161
+ * @param x: The rational number to inspect
1162
+ * @returns The numerator of the rational number
1163
+ *
1164
+ * @since v0.6.0
1165
+ */
1166
+ @unsafe
1167
+ provide let rationalNumerator = (x: Rational) => {
1168
+ let x = WasmI32.fromGrain(x)
1169
+ let num = boxedRationalNumerator(x)
1170
+ Memory.incRef(num)
1171
+ WasmI32.toGrain(reducedBigInteger(num)): Number
1172
+ }
1173
+
1174
+ /**
1175
+ * Finds the denominator of the rational number.
1176
+ *
1177
+ * @param x: The rational number to inspect
1178
+ * @returns The denominator of the rational number
1179
+ *
1180
+ * @since v0.6.0
1181
+ */
1182
+ @unsafe
1183
+ provide let rationalDenominator = (x: Rational) => {
1184
+ let x = WasmI32.fromGrain(x)
1185
+ let num = boxedRationalDenominator(x)
1186
+ Memory.incRef(num)
1187
+ WasmI32.toGrain(reducedBigInteger(num)): Number
1188
+ }
1189
+
1159
1190
  @unsafe
1160
1191
  let numberAddSubRationalHelp = (x, y, isSub) => {
1161
1192
  let xNumerator = boxedRationalNumerator(x)
@@ -1164,95 +1195,53 @@ let numberAddSubRationalHelp = (x, y, isSub) => {
1164
1195
  let yval = untagSimple(y)
1165
1196
  let yBig = BI.makeWrappedInt32(yval)
1166
1197
  let expandedYNumerator = BI.mul(xDenominator, yBig)
1167
- let result =
1168
- if (isSub) BI.sub(xNumerator, expandedYNumerator)
1169
- else BI.add(xNumerator, expandedYNumerator)
1198
+ let result = if (isSub)
1199
+ BI.sub(xNumerator, expandedYNumerator)
1200
+ else
1201
+ BI.add(xNumerator, expandedYNumerator)
1170
1202
  Memory.decRef(expandedYNumerator)
1171
1203
  Memory.decRef(yBig)
1172
- let ret = reducedFractionBigInt(result, xDenominator)
1204
+ let ret = reducedFractionBigInt(result, xDenominator, false)
1173
1205
  Memory.decRef(result)
1174
1206
  ret
1175
1207
  } else {
1176
1208
  let ytag = boxedNumberTag(y)
1177
1209
  match (ytag) {
1178
- t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => {
1210
+ t when t == Tags._GRAIN_RATIONAL_BOXED_NUM_TAG => {
1179
1211
  // The one case we don't delegate is rational +/- rational
1180
- let xNumerator = boxedRationalNumerator(x)
1181
- let xDenominator = boxedRationalDenominator(x)
1182
- let yNumerator = boxedRationalNumerator(y)
1183
- let yDenominator = boxedRationalDenominator(y)
1184
- if (BI.eq(xDenominator, yDenominator)) {
1185
- let newNumerator =
1186
- if (isSub) BI.sub(xNumerator, yNumerator)
1187
- else BI.add(xNumerator, yNumerator)
1188
- let ret = reducedFractionBigInt(newNumerator, xDenominator)
1189
- Memory.decRef(newNumerator)
1190
- ret
1191
- } else {
1192
- let numerator1 = BI.mul(xNumerator, yDenominator)
1193
- let numerator2 = BI.mul(yNumerator, xDenominator)
1194
- let numerator =
1195
- if (isSub) BI.sub(numerator1, numerator2)
1196
- else BI.add(numerator1, numerator2)
1197
- let denominator = BI.mul(xDenominator, yDenominator)
1198
- let ret = reducedFractionBigInt(numerator, denominator)
1199
- Memory.decRef(numerator1)
1200
- Memory.decRef(numerator2)
1201
- Memory.decRef(numerator)
1202
- ret
1203
- }
1204
- },
1205
- t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => {
1206
- let yBig = BI.makeWrappedInt32(boxedInt32Number(y))
1207
- let expandedYNumerator = BI.mul(yBig, xDenominator)
1208
- Memory.decRef(yBig)
1209
- let result =
1210
- if (isSub) BI.sub(xNumerator, expandedYNumerator)
1211
- else BI.add(xNumerator, expandedYNumerator)
1212
- let ret = reducedFractionBigInt(result, xDenominator)
1213
- Memory.decRef(expandedYNumerator)
1214
- Memory.decRef(result)
1215
- ret
1212
+ addSubRational(x, y, isSub, false)
1216
1213
  },
1217
- t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
1214
+ t when t == Tags._GRAIN_INT64_BOXED_NUM_TAG => {
1218
1215
  let yBig = BI.makeWrappedInt64(boxedInt64Number(y))
1219
1216
  let expandedYNumerator = BI.mul(yBig, xDenominator)
1220
1217
  Memory.decRef(yBig)
1221
- let result =
1222
- if (isSub) BI.sub(xNumerator, expandedYNumerator)
1223
- else BI.add(xNumerator, expandedYNumerator)
1224
- let ret = reducedFractionBigInt(result, xDenominator)
1218
+ let result = if (isSub)
1219
+ BI.sub(xNumerator, expandedYNumerator)
1220
+ else
1221
+ BI.add(xNumerator, expandedYNumerator)
1222
+ let ret = reducedFractionBigInt(result, xDenominator, false)
1225
1223
  Memory.decRef(expandedYNumerator)
1226
1224
  Memory.decRef(result)
1227
1225
  ret
1228
1226
  },
1229
- t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
1227
+ t when t == Tags._GRAIN_BIGINT_BOXED_NUM_TAG => {
1230
1228
  let expandedYNumerator = BI.mul(xDenominator, y)
1231
- let result =
1232
- if (isSub) BI.sub(xNumerator, expandedYNumerator)
1233
- else BI.add(xNumerator, expandedYNumerator)
1229
+ let result = if (isSub)
1230
+ BI.sub(xNumerator, expandedYNumerator)
1231
+ else
1232
+ BI.add(xNumerator, expandedYNumerator)
1234
1233
  Memory.decRef(expandedYNumerator)
1235
- let ret = reducedFractionBigInt(result, xDenominator)
1234
+ let ret = reducedFractionBigInt(result, xDenominator, false)
1236
1235
  Memory.decRef(result)
1237
1236
  ret
1238
1237
  },
1239
- t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
1240
- let xval = WasmF32.div(
1241
- BI.toFloat32(xNumerator),
1242
- BI.toFloat32(xDenominator)
1243
- )
1244
- let result =
1245
- if (isSub) WasmF32.sub(xval, boxedFloat32Number(y))
1246
- else WasmF32.add(xval, boxedFloat32Number(y))
1247
- newFloat32(result)
1248
- },
1249
- t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
1238
+ t when t == Tags._GRAIN_FLOAT64_BOXED_NUM_TAG => {
1239
+ use WasmF64.{ (/), (+), (-) }
1250
1240
  let xnumfloat = BI.toFloat64(xNumerator)
1251
1241
  let xdenfloat = BI.toFloat64(xDenominator)
1252
- let xval = WasmF64.div(xnumfloat, xdenfloat)
1242
+ let xval = xnumfloat / xdenfloat
1253
1243
  let yval = boxedFloat64Number(y)
1254
- let result =
1255
- if (isSub) WasmF64.sub(xval, yval) else WasmF64.add(xval, yval)
1244
+ let result = if (isSub) xval - yval else xval + yval
1256
1245
  let ret = newFloat64(result)
1257
1246
  ret
1258
1247
  },
@@ -1270,22 +1259,16 @@ let numberAddSubHelp = (x, y, isSub) => {
1270
1259
  } else {
1271
1260
  let xtag = boxedNumberTag(x)
1272
1261
  match (xtag) {
1273
- t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => {
1274
- numberAddSubInt32Help(boxedInt32Number(x), y, isSub)
1275
- },
1276
- t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
1262
+ t when t == Tags._GRAIN_INT64_BOXED_NUM_TAG => {
1277
1263
  numberAddSubInt64Help(boxedInt64Number(x), y, isSub)
1278
1264
  },
1279
- t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
1265
+ t when t == Tags._GRAIN_BIGINT_BOXED_NUM_TAG => {
1280
1266
  numberAddSubBigIntHelp(x, y, isSub)
1281
1267
  },
1282
- t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => {
1268
+ t when t == Tags._GRAIN_RATIONAL_BOXED_NUM_TAG => {
1283
1269
  numberAddSubRationalHelp(x, y, isSub)
1284
1270
  },
1285
- t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
1286
- numberAddSubFloat32Help(boxedFloat32Number(x), y, isSub)
1287
- },
1288
- t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
1271
+ t when t == Tags._GRAIN_FLOAT64_BOXED_NUM_TAG => {
1289
1272
  numberAddSubFloat64Help(boxedFloat64Number(x), y, isSub)
1290
1273
  },
1291
1274
  _ => {
@@ -1312,9 +1295,10 @@ let numberSub = (x, y) => {
1312
1295
 
1313
1296
  @unsafe
1314
1297
  let safeI64Multiply = (x, y) => {
1315
- let prod = WasmI64.mul(x, y)
1316
- if (WasmI64.ne(x, 0N)) {
1317
- if (WasmI64.ne(WasmI64.divS(prod, x), y)) {
1298
+ use WasmI64.{ (!=), (*), (/) }
1299
+ let prod = x * y
1300
+ if (x != 0N) {
1301
+ if (prod / x != y) {
1318
1302
  let xBig = BI.makeWrappedInt64(x)
1319
1303
  let yBig = BI.makeWrappedInt64(y)
1320
1304
  let result = BI.mul(xBig, yBig)
@@ -1340,15 +1324,7 @@ let numberTimesDivideInt64Help = (xval, y, isDivide) => {
1340
1324
  } else {
1341
1325
  let yBoxedNumberTag = boxedNumberTag(y)
1342
1326
  match (yBoxedNumberTag) {
1343
- t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => {
1344
- let yBoxedVal = WasmI64.extendI32S(boxedInt32Number(y))
1345
- if (isDivide) {
1346
- reducedFraction64(xval, yBoxedVal)
1347
- } else {
1348
- safeI64Multiply(xval, yBoxedVal)
1349
- }
1350
- },
1351
- t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
1327
+ t when t == Tags._GRAIN_INT64_BOXED_NUM_TAG => {
1352
1328
  let yBoxedVal = boxedInt64Number(y)
1353
1329
  if (isDivide) {
1354
1330
  reducedFraction64(xval, yBoxedVal)
@@ -1356,52 +1332,44 @@ let numberTimesDivideInt64Help = (xval, y, isDivide) => {
1356
1332
  safeI64Multiply(xval, yBoxedVal)
1357
1333
  }
1358
1334
  },
1359
- t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
1335
+ t when t == Tags._GRAIN_BIGINT_BOXED_NUM_TAG => {
1360
1336
  let xBig = BI.makeWrappedInt64(xval)
1361
1337
  let ret = if (isDivide) {
1362
- reducedFractionBigInt(xBig, y)
1338
+ reducedFractionBigInt(xBig, y, false)
1363
1339
  } else {
1364
1340
  reducedBigInteger(BI.mul(xBig, y))
1365
1341
  }
1366
1342
  Memory.decRef(xBig)
1367
1343
  ret
1368
1344
  },
1369
- t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => {
1345
+ t when t == Tags._GRAIN_RATIONAL_BOXED_NUM_TAG => {
1370
1346
  let yNumerator = boxedRationalNumerator(y)
1371
1347
  let yDenominator = boxedRationalDenominator(y)
1372
1348
  let xBig = BI.makeWrappedInt64(xval)
1373
1349
  let ret = if (isDivide) {
1374
1350
  // x / (a / b) == (x * b) / a
1375
1351
  let numerator = BI.mul(xBig, yDenominator)
1376
- let ret = reducedFractionBigInt(numerator, yNumerator)
1352
+ let ret = reducedFractionBigInt(numerator, yNumerator, false)
1377
1353
  Memory.decRef(numerator)
1378
1354
  ret
1379
1355
  } else {
1380
1356
  // x * (a / b) == (x * a) / b
1381
1357
  let numerator = BI.mul(xBig, yNumerator)
1382
- let ret = reducedFractionBigInt(numerator, yDenominator)
1358
+ let ret = reducedFractionBigInt(numerator, yDenominator, false)
1383
1359
  Memory.decRef(numerator)
1384
1360
  ret
1385
1361
  }
1386
1362
  Memory.decRef(xBig)
1387
1363
  ret
1388
1364
  },
1389
- t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
1390
- let xval = WasmF32.convertI64S(xval)
1391
- let yBoxedVal = boxedFloat32Number(y)
1392
- if (isDivide) {
1393
- newFloat32(WasmF32.div(xval, yBoxedVal))
1394
- } else {
1395
- newFloat32(WasmF32.mul(xval, yBoxedVal))
1396
- }
1397
- },
1398
- t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
1365
+ t when t == Tags._GRAIN_FLOAT64_BOXED_NUM_TAG => {
1366
+ use WasmF64.{ (/), (*) }
1399
1367
  let xval = WasmF64.convertI64S(xval)
1400
1368
  let yBoxedVal = boxedFloat64Number(y)
1401
1369
  if (isDivide) {
1402
- newFloat64(WasmF64.div(xval, yBoxedVal))
1370
+ newFloat64(xval / yBoxedVal)
1403
1371
  } else {
1404
- newFloat64(WasmF64.mul(xval, yBoxedVal))
1372
+ newFloat64(xval * yBoxedVal)
1405
1373
  }
1406
1374
  },
1407
1375
  _ => {
@@ -1416,7 +1384,7 @@ let numberTimesDivideBigIntHelp = (x, y, isDivide) => {
1416
1384
  if (isSimpleNumber(y)) {
1417
1385
  let yBig = BI.makeWrappedInt32(untagSimple(y))
1418
1386
  let ret = if (isDivide) {
1419
- reducedFractionBigInt(x, yBig)
1387
+ reducedFractionBigInt(x, yBig, false)
1420
1388
  } else {
1421
1389
  reducedBigInteger(BI.mul(x, yBig))
1422
1390
  }
@@ -1425,70 +1393,49 @@ let numberTimesDivideBigIntHelp = (x, y, isDivide) => {
1425
1393
  } else {
1426
1394
  let yBoxedNumberTag = boxedNumberTag(y)
1427
1395
  match (yBoxedNumberTag) {
1428
- t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => {
1429
- let yBoxedVal = WasmI64.extendI32S(boxedInt32Number(y))
1430
- let yBig = BI.makeWrappedInt64(yBoxedVal)
1431
- let ret = if (isDivide) {
1432
- reducedFractionBigInt(x, yBig)
1433
- } else {
1434
- reducedBigInteger(BI.mul(x, yBig))
1435
- }
1436
- Memory.decRef(yBig)
1437
- ret
1438
- },
1439
- t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
1396
+ t when t == Tags._GRAIN_INT64_BOXED_NUM_TAG => {
1440
1397
  let yBoxedVal = boxedInt64Number(y)
1441
1398
  let yBig = BI.makeWrappedInt64(yBoxedVal)
1442
1399
  let ret = if (isDivide) {
1443
- reducedFractionBigInt(x, yBig)
1400
+ reducedFractionBigInt(x, yBig, false)
1444
1401
  } else {
1445
1402
  reducedBigInteger(BI.mul(x, yBig))
1446
1403
  }
1447
1404
  Memory.decRef(yBig)
1448
1405
  ret
1449
1406
  },
1450
- t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
1407
+ t when t == Tags._GRAIN_BIGINT_BOXED_NUM_TAG => {
1451
1408
  if (isDivide) {
1452
- reducedFractionBigInt(x, y)
1409
+ reducedFractionBigInt(x, y, false)
1453
1410
  } else {
1454
1411
  reducedBigInteger(BI.mul(x, y))
1455
1412
  }
1456
1413
  },
1457
- t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => {
1414
+ t when t == Tags._GRAIN_RATIONAL_BOXED_NUM_TAG => {
1458
1415
  let yNumerator = boxedRationalNumerator(y)
1459
1416
  let yDenominator = boxedRationalDenominator(y)
1460
1417
  if (isDivide) {
1461
1418
  // x / (a / b) == (x * b) / a
1462
1419
  let numerator = BI.mul(x, yDenominator)
1463
- let ret = reducedFractionBigInt(numerator, yNumerator)
1420
+ let ret = reducedFractionBigInt(numerator, yNumerator, false)
1464
1421
  Memory.decRef(numerator)
1465
1422
  ret
1466
1423
  } else {
1467
1424
  // x * (a / b) == (x * a) / b
1468
1425
  let numerator = BI.mul(x, yNumerator)
1469
- let ret = reducedFractionBigInt(numerator, yDenominator)
1426
+ let ret = reducedFractionBigInt(numerator, yDenominator, false)
1470
1427
  Memory.decRef(numerator)
1471
1428
  ret
1472
1429
  }
1473
1430
  },
1474
- t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
1475
- // We make the decision to always promote to f64 here, since
1476
- // we can only fit rather small bigints (<4 limbs) into an F32
1477
- let xval = BI.toFloat64(x)
1478
- let yBoxedVal = WasmF64.promoteF32(boxedFloat32Number(y))
1479
- if (isDivide) {
1480
- newFloat64(WasmF64.div(xval, yBoxedVal))
1481
- } else {
1482
- newFloat64(WasmF64.mul(xval, yBoxedVal))
1483
- }
1484
- },
1485
- t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
1431
+ t when t == Tags._GRAIN_FLOAT64_BOXED_NUM_TAG => {
1432
+ use WasmF64.{ (/), (*) }
1486
1433
  let xval = BI.toFloat64(x)
1487
1434
  let yBoxedVal = boxedFloat64Number(y)
1488
1435
  if (isDivide) {
1489
- newFloat64(WasmF64.div(xval, yBoxedVal))
1436
+ newFloat64(xval / yBoxedVal)
1490
1437
  } else {
1491
- newFloat64(WasmF64.mul(xval, yBoxedVal))
1438
+ newFloat64(xval * yBoxedVal)
1492
1439
  }
1493
1440
  },
1494
1441
  _ => {
@@ -1505,13 +1452,9 @@ let numberTimesDivideSimpleHelp = (x, y, isDivide) => {
1505
1452
  numberTimesDivideInt64Help(WasmI64.extendI32S(xval), y, isDivide)
1506
1453
  }
1507
1454
 
1508
- @unsafe
1509
- let numberTimesDivideInt32Help = (xval, y, isDivide) => {
1510
- numberTimesDivideInt64Help(WasmI64.extendI32S(xval), y, isDivide)
1511
- }
1512
-
1513
1455
  @unsafe
1514
1456
  let numberTimesDivideRationalHelp = (x, y, isDivide) => {
1457
+ use WasmI32.{ (!=) }
1515
1458
  // Division isn't commutative, so we actually need to do the work
1516
1459
  let xNumerator = boxedRationalNumerator(x)
1517
1460
  let xDenominator = boxedRationalDenominator(x)
@@ -1520,17 +1463,17 @@ let numberTimesDivideRationalHelp = (x, y, isDivide) => {
1520
1463
  let ret = if (isDivide) {
1521
1464
  // (a / b) / y == a / (b * y)
1522
1465
  let denominator = BI.mul(xDenominator, yBig)
1523
- let ret = reducedFractionBigInt(xNumerator, denominator)
1466
+ let ret = reducedFractionBigInt(xNumerator, denominator, false)
1524
1467
  Memory.decRef(denominator)
1525
1468
  ret
1526
1469
  } else {
1527
1470
  // (a / b) * y == (a * y) / b
1528
1471
  let numerator = BI.mul(xNumerator, yBig)
1529
- let ret = reducedFractionBigInt(numerator, xDenominator)
1472
+ let ret = reducedFractionBigInt(numerator, xDenominator, false)
1530
1473
  Memory.decRef(numerator)
1531
1474
  ret
1532
1475
  }
1533
- if (WasmI32.ne(yBig, ret)) {
1476
+ if (yBig != ret) {
1534
1477
  Memory.decRef(yBig)
1535
1478
  void
1536
1479
  }
@@ -1538,95 +1481,51 @@ let numberTimesDivideRationalHelp = (x, y, isDivide) => {
1538
1481
  } else {
1539
1482
  let ytag = boxedNumberTag(y)
1540
1483
  match (ytag) {
1541
- t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => {
1542
- // Same idea as above
1543
- let yBig = BI.makeWrappedInt32(boxedInt32Number(y))
1544
- let ret = if (isDivide) {
1545
- // (a / b) / y == a / (b * y)
1546
- let denominator = BI.mul(xDenominator, yBig)
1547
- let ret = reducedFractionBigInt(xNumerator, denominator)
1548
- Memory.decRef(denominator)
1549
- ret
1550
- } else {
1551
- // (a / b) * y == (a * y) / b
1552
- let numerator = BI.mul(xNumerator, yBig)
1553
- let ret = reducedFractionBigInt(numerator, xDenominator)
1554
- Memory.decRef(numerator)
1555
- ret
1556
- }
1557
- Memory.decRef(yBig)
1558
- ret
1559
- },
1560
- t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
1484
+ t when t == Tags._GRAIN_INT64_BOXED_NUM_TAG => {
1561
1485
  // Same idea as above
1562
1486
  let yBig = BI.makeWrappedInt64(boxedInt64Number(y))
1563
1487
  let ret = if (isDivide) {
1564
1488
  // (a / b) / y == a / (b * y)
1565
1489
  let denominator = BI.mul(xDenominator, yBig)
1566
- let ret = reducedFractionBigInt(xNumerator, denominator)
1490
+ let ret = reducedFractionBigInt(xNumerator, denominator, false)
1567
1491
  Memory.decRef(denominator)
1568
1492
  ret
1569
1493
  } else {
1570
1494
  // (a / b) * y == (a * y) / b
1571
1495
  let numerator = BI.mul(xNumerator, yBig)
1572
- let ret = reducedFractionBigInt(numerator, xDenominator)
1496
+ let ret = reducedFractionBigInt(numerator, xDenominator, false)
1573
1497
  Memory.decRef(numerator)
1574
1498
  ret
1575
1499
  }
1576
1500
  Memory.decRef(yBig)
1577
1501
  ret
1578
1502
  },
1579
- t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
1503
+ t when t == Tags._GRAIN_BIGINT_BOXED_NUM_TAG => {
1580
1504
  if (isDivide) {
1581
1505
  // (a / b) / y == a / (b * y)
1582
1506
  let denominator = BI.mul(xDenominator, y)
1583
- let ret = reducedFractionBigInt(xNumerator, denominator)
1507
+ let ret = reducedFractionBigInt(xNumerator, denominator, false)
1584
1508
  Memory.decRef(denominator)
1585
1509
  ret
1586
1510
  } else {
1587
1511
  // (a / b) * y == (a * y) / b
1588
1512
  let numerator = BI.mul(xNumerator, y)
1589
- let ret = reducedFractionBigInt(numerator, xDenominator)
1513
+ let ret = reducedFractionBigInt(numerator, xDenominator, false)
1590
1514
  Memory.decRef(numerator)
1591
1515
  ret
1592
1516
  }
1593
1517
  },
1594
- t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => {
1595
- let xNumerator = boxedRationalNumerator(x)
1596
- let xDenominator = boxedRationalDenominator(x)
1597
- let yNumerator = boxedRationalNumerator(y)
1598
- let yDenominator = boxedRationalDenominator(y)
1599
- // (a / b) * (c / d) == (a * c) / (b * d)
1600
- // (a / b) / (c / d) == (a * d) / (b * c)
1601
- let numerator =
1602
- if (isDivide) BI.mul(xNumerator, yDenominator)
1603
- else BI.mul(xNumerator, yNumerator)
1604
- let denominator =
1605
- if (isDivide) BI.mul(xDenominator, yNumerator)
1606
- else BI.mul(xDenominator, yDenominator)
1607
- reducedFractionBigInt(numerator, denominator)
1608
- },
1609
- t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
1610
- // TODO(#1190): We should probably use something more accurate if possible here
1611
- let asFloat = WasmF32.demoteF64(
1612
- WasmF64.div(BI.toFloat64(xNumerator), BI.toFloat64(xDenominator))
1613
- )
1614
- if (isDivide) {
1615
- newFloat32(WasmF32.div(asFloat, boxedFloat32Number(y)))
1616
- } else {
1617
- newFloat32(WasmF32.mul(asFloat, boxedFloat32Number(y)))
1618
- }
1518
+ t when t == Tags._GRAIN_RATIONAL_BOXED_NUM_TAG => {
1519
+ timesDivideRational(x, y, isDivide, false)
1619
1520
  },
1620
- t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
1521
+ t when t == Tags._GRAIN_FLOAT64_BOXED_NUM_TAG => {
1522
+ use WasmF64.{ (/), (*) }
1621
1523
  // TODO(#1190): We should probably use something more accurate if possible here
1622
- let asFloat = WasmF64.div(
1623
- BI.toFloat64(xNumerator),
1624
- BI.toFloat64(xDenominator)
1625
- )
1524
+ let asFloat = BI.toFloat64(xNumerator) / BI.toFloat64(xDenominator)
1626
1525
  if (isDivide) {
1627
- newFloat64(WasmF64.div(asFloat, boxedFloat64Number(y)))
1526
+ newFloat64(asFloat / boxedFloat64Number(y))
1628
1527
  } else {
1629
- newFloat64(WasmF64.mul(asFloat, boxedFloat64Number(y)))
1528
+ newFloat64(asFloat * boxedFloat64Number(y))
1630
1529
  }
1631
1530
  },
1632
1531
  _ => {
@@ -1638,63 +1537,34 @@ let numberTimesDivideRationalHelp = (x, y, isDivide) => {
1638
1537
 
1639
1538
  @unsafe
1640
1539
  let numberTimesDivideFloat64Help = (x, y, isDivide) => {
1540
+ use WasmF64.{ (/), (*) }
1641
1541
  // incRef y to reuse it via WasmI32.toGrain
1642
1542
  Memory.incRef(y)
1643
1543
  let yAsFloat = coerceNumberToWasmF64(WasmI32.toGrain(y): Number)
1644
1544
  if (isDivide) {
1645
- newFloat64(WasmF64.div(x, yAsFloat))
1545
+ newFloat64(x / yAsFloat)
1646
1546
  } else {
1647
- newFloat64(WasmF64.mul(x, yAsFloat))
1547
+ newFloat64(x * yAsFloat)
1648
1548
  }
1649
1549
  }
1650
1550
 
1651
1551
  @unsafe
1652
- let numberTimesDivideFloat32Help = (x, y, isDivide) => {
1653
- if (
1654
- isBoxedNumber(y) &&
1655
- WasmI32.eq(boxedNumberTag(y), Tags._GRAIN_INT64_BOXED_NUM_TAG)
1656
- ) {
1657
- // Special case: f32->f64 promotion
1658
- if (isDivide) {
1659
- newFloat64(WasmF64.div(WasmF64.promoteF32(x), boxedFloat64Number(y)))
1660
- } else {
1661
- newFloat64(WasmF64.mul(WasmF64.promoteF32(x), boxedFloat64Number(y)))
1662
- }
1663
- } else {
1664
- // incRef y to reuse it via WasmI32.toGrain
1665
- Memory.incRef(y)
1666
- let yAsFloat = coerceNumberToWasmF32(WasmI32.toGrain(y): Number)
1667
- if (isDivide) {
1668
- newFloat32(WasmF32.div(x, yAsFloat))
1669
- } else {
1670
- newFloat32(WasmF32.mul(x, yAsFloat))
1671
- }
1672
- }
1673
- }
1674
-
1675
- @unsafe
1676
- let numberTimesDivideHelp = (x, y, isDivide) => {
1677
- if (isSimpleNumber(x)) {
1678
- numberTimesDivideSimpleHelp(x, y, isDivide)
1552
+ let numberTimesDivideHelp = (x, y, isDivide) => {
1553
+ if (isSimpleNumber(x)) {
1554
+ numberTimesDivideSimpleHelp(x, y, isDivide)
1679
1555
  } else {
1680
1556
  let xtag = boxedNumberTag(x)
1681
1557
  match (xtag) {
1682
- t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => {
1683
- numberTimesDivideInt32Help(boxedInt32Number(x), y, isDivide)
1684
- },
1685
- t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
1558
+ t when t == Tags._GRAIN_INT64_BOXED_NUM_TAG => {
1686
1559
  numberTimesDivideInt64Help(boxedInt64Number(x), y, isDivide)
1687
1560
  },
1688
- t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
1561
+ t when t == Tags._GRAIN_BIGINT_BOXED_NUM_TAG => {
1689
1562
  numberTimesDivideBigIntHelp(x, y, isDivide)
1690
1563
  },
1691
- t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => {
1564
+ t when t == Tags._GRAIN_RATIONAL_BOXED_NUM_TAG => {
1692
1565
  numberTimesDivideRationalHelp(x, y, isDivide)
1693
1566
  },
1694
- t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
1695
- numberTimesDivideFloat32Help(boxedFloat32Number(x), y, isDivide)
1696
- },
1697
- t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
1567
+ t when t == Tags._GRAIN_FLOAT64_BOXED_NUM_TAG => {
1698
1568
  numberTimesDivideFloat64Help(boxedFloat64Number(x), y, isDivide)
1699
1569
  },
1700
1570
  _ => {
@@ -1720,33 +1590,47 @@ let numberDivide = (x, y) => {
1720
1590
  */
1721
1591
 
1722
1592
  @unsafe
1723
- let i64abs = x => if (WasmI64.geS(x, 0N)) x else WasmI64.sub(0N, x)
1593
+ let i64abs = x => {
1594
+ use WasmI64.{ (-), (>=) }
1595
+ if (x >= 0N) x else 0N - x
1596
+ }
1724
1597
 
1725
1598
  @unsafe
1726
1599
  let numberMod = (x, y) => {
1600
+ use WasmI64.{ (!=), (-), (*), (<), (>) }
1727
1601
  // incRef x and y to reuse them via WasmI32.toGrain
1728
1602
  Memory.incRef(x)
1729
1603
  Memory.incRef(y)
1730
- let xval = coerceNumberToWasmI64(WasmI32.toGrain(x): Number)
1731
- let yval = coerceNumberToWasmI64(WasmI32.toGrain(y): Number)
1732
- if (WasmI64.eqz(yval)) {
1733
- throw Exception.ModuloByZero
1734
- }
1735
- // We implement true modulo
1736
- if (
1737
- WasmI64.ltS(xval, 0N) && WasmI64.gtS(yval, 0N) ||
1738
- WasmI64.gtS(xval, 0N) && WasmI64.ltS(yval, 0N)
1739
- ) {
1740
- let modval = WasmI64.remS(i64abs(xval), i64abs(yval))
1741
- let result =
1742
- if (WasmI64.ne(modval, 0N))
1743
- WasmI64.mul(
1744
- WasmI64.sub(i64abs(yval), modval),
1745
- if (WasmI64.ltS(yval, 0N)) -1N else 1N
1746
- ) else modval
1747
- reducedInteger(result)
1604
+ if (isFloat(x) || isFloat(y) || isRational(x) || isRational(y)) {
1605
+ use WasmF64.{ (==), (/), (*), (-) }
1606
+ let xval = coerceNumberToWasmF64(WasmI32.toGrain(x): Number)
1607
+ let yval = coerceNumberToWasmF64(WasmI32.toGrain(y): Number)
1608
+ let yInfinite = yval == InfinityW || yval == -InfinityW
1609
+ if (yval == 0.0W || yInfinite && (xval == InfinityW || xval == -InfinityW)) {
1610
+ newFloat64(NaNW)
1611
+ } else if (yInfinite) {
1612
+ newFloat64(xval)
1613
+ } else {
1614
+ newFloat64(xval - WasmF64.trunc(xval / yval) * yval)
1615
+ }
1748
1616
  } else {
1749
- reducedInteger(WasmI64.remS(xval, yval))
1617
+ let xval = coerceNumberToWasmI64(WasmI32.toGrain(x): Number)
1618
+ let yval = coerceNumberToWasmI64(WasmI32.toGrain(y): Number)
1619
+ if (WasmI64.eqz(yval)) {
1620
+ throw Exception.ModuloByZero
1621
+ }
1622
+ // We implement true modulo
1623
+ if (xval < 0N && yval > 0N || xval > 0N && yval < 0N) {
1624
+ let modval = WasmI64.remS(i64abs(xval), i64abs(yval))
1625
+ let result = if (modval != 0N) {
1626
+ i64abs(yval) - modval * (if (yval < 0N) -1N else 1N)
1627
+ } else {
1628
+ modval
1629
+ }
1630
+ reducedInteger(result)
1631
+ } else {
1632
+ reducedInteger(WasmI64.remS(xval, yval))
1633
+ }
1750
1634
  }
1751
1635
  }
1752
1636
 
@@ -1772,25 +1656,19 @@ let cmpBigInt = (x: WasmI32, y: WasmI32) => {
1772
1656
  } else {
1773
1657
  let yBoxedNumberTag = boxedNumberTag(y)
1774
1658
  match (yBoxedNumberTag) {
1775
- t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => {
1776
- BI.cmpI64(x, WasmI64.extendI32S(boxedInt32Number(y)))
1777
- },
1778
- t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
1659
+ t when t == Tags._GRAIN_INT64_BOXED_NUM_TAG => {
1779
1660
  BI.cmpI64(x, boxedInt64Number(y))
1780
1661
  },
1781
- t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
1662
+ t when t == Tags._GRAIN_BIGINT_BOXED_NUM_TAG => {
1782
1663
  BI.cmp(x, y)
1783
1664
  },
1784
- t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => {
1665
+ t when t == Tags._GRAIN_RATIONAL_BOXED_NUM_TAG => {
1785
1666
  let tmp = BI.mul(x, boxedRationalDenominator(y))
1786
1667
  let ret = BI.cmp(tmp, boxedRationalNumerator(y))
1787
1668
  Memory.decRef(tmp)
1788
1669
  ret
1789
1670
  },
1790
- t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
1791
- BI.cmpF32(x, boxedFloat32Number(y))
1792
- },
1793
- t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
1671
+ t when t == Tags._GRAIN_FLOAT64_BOXED_NUM_TAG => {
1794
1672
  BI.cmpF64(x, boxedFloat64Number(y))
1795
1673
  },
1796
1674
  _ => {
@@ -1804,55 +1682,51 @@ let cmpBigInt = (x: WasmI32, y: WasmI32) => {
1804
1682
  // unlike regular float logic, NaN is considered equal to itself and
1805
1683
  // smaller than any other number
1806
1684
  @unsafe
1807
- let cmpFloat = (x: WasmI32, y: WasmI32, is64: Bool) => {
1808
- let xf = if (is64) {
1809
- boxedFloat64Number(x)
1810
- } else {
1811
- WasmF64.promoteF32(boxedFloat32Number(x))
1812
- }
1685
+ let cmpFloat = (x: WasmI32, y: WasmI32) => {
1686
+ use WasmF64.{ (!=), (<), (>), (/) }
1687
+ use WasmI32.{ (-) }
1688
+ let xf = boxedFloat64Number(x)
1813
1689
  if (isSimpleNumber(y)) {
1814
1690
  let yf = WasmF64.convertI32S(untagSimple(y))
1815
1691
  // special NaN cases
1816
- if (WasmF64.ne(xf, xf)) {
1817
- if (WasmF64.ne(yf, yf)) {
1692
+ if (xf != xf) {
1693
+ if (yf != yf) {
1818
1694
  0n
1819
1695
  } else {
1820
1696
  -1n
1821
1697
  }
1822
- } else if (WasmF64.ne(yf, yf)) {
1823
- if (WasmF64.ne(xf, xf)) {
1698
+ } else if (yf != yf) {
1699
+ if (xf != xf) {
1824
1700
  0n
1825
1701
  } else {
1826
1702
  1n
1827
1703
  }
1828
1704
  } else {
1829
- if (WasmF64.lt(xf, yf)) -1n else if (WasmF64.gt(xf, yf)) 1n else 0n
1705
+ if (xf < yf) {
1706
+ -1n
1707
+ } else if (xf > yf) {
1708
+ 1n
1709
+ } else {
1710
+ 0n
1711
+ }
1830
1712
  }
1831
1713
  } else {
1832
1714
  let yBoxedNumberTag = boxedNumberTag(y)
1833
1715
  if (yBoxedNumberTag == Tags._GRAIN_BIGINT_BOXED_NUM_TAG) {
1834
- WasmI32.sub(0n, cmpBigInt(y, x))
1716
+ 0n - cmpBigInt(y, x)
1835
1717
  } else {
1836
1718
  let yf = match (yBoxedNumberTag) {
1837
- t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => {
1838
- WasmF64.convertI32S(boxedInt32Number(y))
1839
- },
1840
- t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
1719
+ t when t == Tags._GRAIN_INT64_BOXED_NUM_TAG => {
1841
1720
  WasmF64.convertI64S(boxedInt64Number(y))
1842
1721
  },
1843
- t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
1722
+ t when t == Tags._GRAIN_BIGINT_BOXED_NUM_TAG => {
1844
1723
  throw InvariantViolation
1845
1724
  },
1846
- t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => {
1847
- WasmF64.div(
1848
- BI.toFloat64(boxedRationalNumerator(y)),
1725
+ t when t == Tags._GRAIN_RATIONAL_BOXED_NUM_TAG => {
1726
+ BI.toFloat64(boxedRationalNumerator(y)) /
1849
1727
  BI.toFloat64(boxedRationalDenominator(y))
1850
- )
1851
- },
1852
- t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
1853
- WasmF64.promoteF32(boxedFloat32Number(y))
1854
1728
  },
1855
- t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
1729
+ t when t == Tags._GRAIN_FLOAT64_BOXED_NUM_TAG => {
1856
1730
  boxedFloat64Number(y)
1857
1731
  },
1858
1732
  _ => {
@@ -1860,66 +1734,75 @@ let cmpFloat = (x: WasmI32, y: WasmI32, is64: Bool) => {
1860
1734
  },
1861
1735
  }
1862
1736
  // special NaN cases
1863
- if (WasmF64.ne(xf, xf)) {
1864
- if (WasmF64.ne(yf, yf)) {
1737
+ if (xf != xf) {
1738
+ if (yf != yf) {
1865
1739
  0n
1866
1740
  } else {
1867
1741
  -1n
1868
1742
  }
1869
- } else if (WasmF64.ne(yf, yf)) {
1870
- if (WasmF64.ne(xf, xf)) {
1743
+ } else if (yf != yf) {
1744
+ if (xf != xf) {
1871
1745
  0n
1872
1746
  } else {
1873
1747
  1n
1874
1748
  }
1875
1749
  } else {
1876
- if (WasmF64.lt(xf, yf)) -1n else if (WasmF64.gt(xf, yf)) 1n else 0n
1750
+ if (xf < yf) {
1751
+ -1n
1752
+ } else if (xf > yf) {
1753
+ 1n
1754
+ } else {
1755
+ 0n
1756
+ }
1877
1757
  }
1878
1758
  }
1879
1759
  }
1880
1760
  }
1881
1761
 
1882
1762
  @unsafe
1883
- let cmpSmallInt = (x: WasmI32, y: WasmI32, is64: Bool) => {
1884
- let xi = if (is64) {
1885
- boxedInt64Number(x)
1886
- } else {
1887
- WasmI64.extendI32S(boxedInt32Number(x))
1888
- }
1763
+ let cmpSmallInt = (x: WasmI32, y: WasmI32) => {
1764
+ use WasmI64.{ (<), (>) }
1765
+ use WasmI32.{ (-) }
1766
+ let xi = boxedInt64Number(x)
1889
1767
  if (isSimpleNumber(y)) {
1890
1768
  let yi = WasmI64.extendI32S(untagSimple(y))
1891
- if (WasmI64.ltS(xi, yi)) -1n else if (WasmI64.gtS(xi, yi)) 1n else 0n
1769
+ if (xi < yi) {
1770
+ -1n
1771
+ } else if (xi > yi) {
1772
+ 1n
1773
+ } else {
1774
+ 0n
1775
+ }
1892
1776
  } else {
1893
1777
  let yBoxedNumberTag = boxedNumberTag(y)
1894
1778
  match (yBoxedNumberTag) {
1895
- t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => {
1896
- let yi = WasmI64.extendI32S(boxedInt32Number(y))
1897
- if (WasmI64.ltS(xi, yi)) -1n else if (WasmI64.gtS(xi, yi)) 1n else 0n
1898
- },
1899
- t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
1779
+ t when t == Tags._GRAIN_INT64_BOXED_NUM_TAG => {
1900
1780
  let yi = boxedInt64Number(y)
1901
- if (WasmI64.ltS(xi, yi)) -1n else if (WasmI64.gtS(xi, yi)) 1n else 0n
1781
+ if (xi < yi) {
1782
+ -1n
1783
+ } else if (xi > yi) {
1784
+ 1n
1785
+ } else {
1786
+ 0n
1787
+ }
1902
1788
  },
1903
- t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
1904
- WasmI32.sub(0n, cmpBigInt(y, x))
1789
+ t when t == Tags._GRAIN_BIGINT_BOXED_NUM_TAG => {
1790
+ 0n - cmpBigInt(y, x)
1905
1791
  },
1906
- t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => {
1792
+ t when t == Tags._GRAIN_RATIONAL_BOXED_NUM_TAG => {
1793
+ use WasmF64.{ (<), (/) }
1907
1794
  // Rationals and ints are never considered equal
1908
1795
  if (
1909
- WasmF64.lt(
1910
- WasmF64.convertI64S(xi),
1911
- WasmF64.div(
1912
- BI.toFloat64(boxedRationalNumerator(y)),
1913
- BI.toFloat64(boxedRationalDenominator(y))
1914
- )
1915
- )
1916
- ) -1n else 1n
1917
- },
1918
- t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
1919
- WasmI32.sub(0n, cmpFloat(y, x, false))
1796
+ WasmF64.convertI64S(xi) <
1797
+ BI.toFloat64(boxedRationalNumerator(y)) /
1798
+ BI.toFloat64(boxedRationalDenominator(y))
1799
+ )
1800
+ -1n
1801
+ else
1802
+ 1n
1920
1803
  },
1921
- t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
1922
- WasmI32.sub(0n, cmpFloat(y, x, true))
1804
+ t when t == Tags._GRAIN_FLOAT64_BOXED_NUM_TAG => {
1805
+ 0n - cmpFloat(y, x)
1923
1806
  },
1924
1807
  _ => {
1925
1808
  throw UnknownNumberTag
@@ -1930,57 +1813,27 @@ let cmpSmallInt = (x: WasmI32, y: WasmI32, is64: Bool) => {
1930
1813
 
1931
1814
  @unsafe
1932
1815
  let cmpRational = (x: WasmI32, y: WasmI32) => {
1816
+ use WasmI32.{ (-) }
1933
1817
  if (isSimpleNumber(y)) {
1934
- let xf = WasmF64.div(
1935
- BI.toFloat64(boxedRationalNumerator(x)),
1818
+ use WasmF64.{ (/), (<) }
1819
+ let xf = BI.toFloat64(boxedRationalNumerator(x)) /
1936
1820
  BI.toFloat64(boxedRationalDenominator(x))
1937
- )
1938
1821
  // Rationals and ints are never considered equal
1939
- if (WasmF64.lt(xf, WasmF64.convertI32S(untagSimple(y)))) -1n else 1n
1822
+ if (xf < WasmF64.convertI32S(untagSimple(y))) -1n else 1n
1940
1823
  } else {
1941
1824
  let yBoxedNumberTag = boxedNumberTag(y)
1942
1825
  match (yBoxedNumberTag) {
1943
- t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => {
1944
- WasmI32.sub(0n, cmpSmallInt(y, x, false))
1826
+ t when t == Tags._GRAIN_INT64_BOXED_NUM_TAG => {
1827
+ 0n - cmpSmallInt(y, x)
1945
1828
  },
1946
- t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
1947
- WasmI32.sub(0n, cmpSmallInt(y, x, true))
1829
+ t when t == Tags._GRAIN_BIGINT_BOXED_NUM_TAG => {
1830
+ 0n - cmpBigInt(y, x)
1948
1831
  },
1949
- t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
1950
- WasmI32.sub(0n, cmpBigInt(y, x))
1951
- },
1952
- t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => {
1953
- // Comparing rationals efficiently is an open problem
1954
- // Producing a definitive answer is quite expensive, so if the two
1955
- // values are not strictly equal we approximate an answer
1956
-
1957
- let xNumerator = boxedRationalNumerator(x)
1958
- let xDenominator = boxedRationalDenominator(x)
1959
- let yNumerator = boxedRationalNumerator(y)
1960
- let yDenominator = boxedRationalDenominator(y)
1961
-
1962
- if (
1963
- BI.cmp(xNumerator, yNumerator) == 0n &&
1964
- BI.cmp(xDenominator, yDenominator) == 0n
1965
- ) {
1966
- 0n
1967
- } else {
1968
- let xf = WasmF64.div(
1969
- BI.toFloat64(xNumerator),
1970
- BI.toFloat64(xDenominator)
1971
- )
1972
- let yf = WasmF64.div(
1973
- BI.toFloat64(yNumerator),
1974
- BI.toFloat64(yDenominator)
1975
- )
1976
- if (WasmF64.lt(xf, yf)) -1n else 1n
1977
- }
1832
+ t when t == Tags._GRAIN_RATIONAL_BOXED_NUM_TAG => {
1833
+ cmpRationals(x, y)
1978
1834
  },
1979
- t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
1980
- WasmI32.sub(0n, cmpFloat(y, x, false))
1981
- },
1982
- t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
1983
- WasmI32.sub(0n, cmpFloat(y, x, true))
1835
+ t when t == Tags._GRAIN_FLOAT64_BOXED_NUM_TAG => {
1836
+ 0n - cmpFloat(y, x)
1984
1837
  },
1985
1838
  _ => {
1986
1839
  throw UnknownNumberTag
@@ -1990,31 +1843,26 @@ let cmpRational = (x: WasmI32, y: WasmI32) => {
1990
1843
  }
1991
1844
 
1992
1845
  @unsafe
1993
- export let cmp = (x: WasmI32, y: WasmI32) => {
1846
+ provide let cmp = (x: WasmI32, y: WasmI32) => {
1847
+ use WasmI32.{ (-) }
1994
1848
  if (isSimpleNumber(x)) {
1995
1849
  if (isSimpleNumber(y)) {
1996
1850
  // fast comparison path for simple numbers
1997
- WasmI32.sub(x, y)
1851
+ x - y
1998
1852
  } else {
1999
1853
  let yBoxedNumberTag = boxedNumberTag(y)
2000
1854
  match (yBoxedNumberTag) {
2001
- t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => {
2002
- WasmI32.sub(0n, cmpSmallInt(y, x, false))
2003
- },
2004
- t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
2005
- WasmI32.sub(0n, cmpSmallInt(y, x, true))
1855
+ t when t == Tags._GRAIN_INT64_BOXED_NUM_TAG => {
1856
+ 0n - cmpSmallInt(y, x)
2006
1857
  },
2007
- t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
2008
- WasmI32.sub(0n, cmpBigInt(y, x))
1858
+ t when t == Tags._GRAIN_BIGINT_BOXED_NUM_TAG => {
1859
+ 0n - cmpBigInt(y, x)
2009
1860
  },
2010
- t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => {
2011
- WasmI32.sub(0n, cmpRational(y, x))
1861
+ t when t == Tags._GRAIN_RATIONAL_BOXED_NUM_TAG => {
1862
+ 0n - cmpRational(y, x)
2012
1863
  },
2013
- t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
2014
- WasmI32.sub(0n, cmpFloat(y, x, false))
2015
- },
2016
- t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
2017
- WasmI32.sub(0n, cmpFloat(y, x, true))
1864
+ t when t == Tags._GRAIN_FLOAT64_BOXED_NUM_TAG => {
1865
+ 0n - cmpFloat(y, x)
2018
1866
  },
2019
1867
  _ => {
2020
1868
  throw UnknownNumberTag
@@ -2024,23 +1872,17 @@ export let cmp = (x: WasmI32, y: WasmI32) => {
2024
1872
  } else {
2025
1873
  let xBoxedNumberTag = boxedNumberTag(x)
2026
1874
  match (xBoxedNumberTag) {
2027
- t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => {
2028
- cmpSmallInt(x, y, false)
2029
- },
2030
- t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
2031
- cmpSmallInt(x, y, true)
1875
+ t when t == Tags._GRAIN_INT64_BOXED_NUM_TAG => {
1876
+ cmpSmallInt(x, y)
2032
1877
  },
2033
- t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
1878
+ t when t == Tags._GRAIN_BIGINT_BOXED_NUM_TAG => {
2034
1879
  cmpBigInt(x, y)
2035
1880
  },
2036
- t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => {
1881
+ t when t == Tags._GRAIN_RATIONAL_BOXED_NUM_TAG => {
2037
1882
  cmpRational(x, y)
2038
1883
  },
2039
- t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
2040
- cmpFloat(x, y, false)
2041
- },
2042
- t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
2043
- cmpFloat(x, y, true)
1884
+ t when t == Tags._GRAIN_FLOAT64_BOXED_NUM_TAG => {
1885
+ cmpFloat(x, y)
2044
1886
  },
2045
1887
  _ => {
2046
1888
  throw UnknownNumberTag
@@ -2056,36 +1898,76 @@ export let cmp = (x: WasmI32, y: WasmI32) => {
2056
1898
  // NaN being considered equal to itself and less than all other numbers in
2057
1899
  // this case).
2058
1900
 
1901
+ /**
1902
+ * Checks if the first operand is less than the second operand.
1903
+ *
1904
+ * @param num1: The first operand
1905
+ * @param num2: The second operand
1906
+ * @returns `true` if the first operand is less than the second operand or `false` otherwise
1907
+ *
1908
+ * @since v0.1.0
1909
+ */
2059
1910
  @unsafe
2060
- export let (<) = (x: Number, y: Number) => {
2061
- let x = WasmI32.fromGrain(x)
2062
- let y = WasmI32.fromGrain(y)
2063
- !isNaN(x) && !isNaN(y) && WasmI32.ltS(cmp(x, y), 0n)
1911
+ provide let (<) = (num1: Number, num2: Number) => {
1912
+ use WasmI32.{ (<) }
1913
+ let x = WasmI32.fromGrain(num1)
1914
+ let y = WasmI32.fromGrain(num2)
1915
+ !isNaN(x) && !isNaN(y) && cmp(x, y) < 0n
2064
1916
  }
2065
1917
 
1918
+ /**
1919
+ * Checks if the first operand is greater than the second operand.
1920
+ *
1921
+ * @param num1: The first operand
1922
+ * @param num2: The second operand
1923
+ * @returns `true` if the first operand is greater than the second operand or `false` otherwise
1924
+ *
1925
+ * @since v0.1.0
1926
+ */
2066
1927
  @unsafe
2067
- export let (>) = (x: Number, y: Number) => {
2068
- let x = WasmI32.fromGrain(x)
2069
- let y = WasmI32.fromGrain(y)
2070
- !isNaN(x) && !isNaN(y) && WasmI32.gtS(cmp(x, y), 0n)
1928
+ provide let (>) = (num1: Number, num2: Number) => {
1929
+ use WasmI32.{ (>) }
1930
+ let x = WasmI32.fromGrain(num1)
1931
+ let y = WasmI32.fromGrain(num2)
1932
+ !isNaN(x) && !isNaN(y) && cmp(x, y) > 0n
2071
1933
  }
2072
1934
 
1935
+ /**
1936
+ * Checks if the first operand is less than or equal to the second operand.
1937
+ *
1938
+ * @param num1: The first operand
1939
+ * @param num2: The second operand
1940
+ * @returns `true` if the first operand is less than or equal to the second operand or `false` otherwise
1941
+ *
1942
+ * @since v0.1.0
1943
+ */
2073
1944
  @unsafe
2074
- export let (<=) = (x: Number, y: Number) => {
2075
- let x = WasmI32.fromGrain(x)
2076
- let y = WasmI32.fromGrain(y)
2077
- !isNaN(x) && !isNaN(y) && WasmI32.leS(cmp(x, y), 0n)
1945
+ provide let (<=) = (num1: Number, num2: Number) => {
1946
+ use WasmI32.{ (<=) }
1947
+ let x = WasmI32.fromGrain(num1)
1948
+ let y = WasmI32.fromGrain(num2)
1949
+ !isNaN(x) && !isNaN(y) && cmp(x, y) <= 0n
2078
1950
  }
2079
1951
 
1952
+ /**
1953
+ * Checks if the first operand is greater than or equal to the second operand.
1954
+ *
1955
+ * @param num1: The first operand
1956
+ * @param num2: The second operand
1957
+ * @returns `true` if the first operand is greater than or equal to the second operand or `false` otherwise
1958
+ *
1959
+ * @since v0.1.0
1960
+ */
2080
1961
  @unsafe
2081
- export let (>=) = (x: Number, y: Number) => {
2082
- let x = WasmI32.fromGrain(x)
2083
- let y = WasmI32.fromGrain(y)
2084
- !isNaN(x) && !isNaN(y) && WasmI32.geS(cmp(x, y), 0n)
1962
+ provide let (>=) = (num1: Number, num2: Number) => {
1963
+ use WasmI32.{ (>=) }
1964
+ let x = WasmI32.fromGrain(num1)
1965
+ let y = WasmI32.fromGrain(num2)
1966
+ !isNaN(x) && !isNaN(y) && cmp(x, y) >= 0n
2085
1967
  }
2086
1968
 
2087
1969
  @unsafe
2088
- export let compare = (x: Number, y: Number) => {
1970
+ provide let compare = (x: Number, y: Number) => {
2089
1971
  let x = WasmI32.fromGrain(x)
2090
1972
  let y = WasmI32.fromGrain(y)
2091
1973
  WasmI32.toGrain(tagSimple(cmp(x, y))): Number
@@ -2096,7 +1978,7 @@ export let compare = (x: Number, y: Number) => {
2096
1978
  */
2097
1979
 
2098
1980
  @unsafe
2099
- export let numberEq = (x: Number, y: Number) => {
1981
+ provide let numberEq = (x: Number, y: Number) => {
2100
1982
  let x = WasmI32.fromGrain(x)
2101
1983
  let y = WasmI32.fromGrain(y)
2102
1984
  numberEqual(x, y)
@@ -2108,143 +1990,221 @@ export let numberEq = (x: Number, y: Number) => {
2108
1990
  */
2109
1991
  // TODO(#306): Semantics around when things should stay i32/i64
2110
1992
 
1993
+ /**
1994
+ * Computes the bitwise NOT of the operand.
1995
+ *
1996
+ * @param value: The operand
1997
+ * @returns Containing the inverted bits of the operand
1998
+ *
1999
+ * @since v0.2.0
2000
+ */
2111
2001
  @unsafe
2112
- export let lnot = (x: Number) => {
2113
- let xw32 = WasmI32.fromGrain(x)
2002
+ provide let lnot = (value: Number) => {
2003
+ let xw32 = WasmI32.fromGrain(value)
2114
2004
  if (isBigInt(xw32)) {
2115
2005
  WasmI32.toGrain(reducedBigInteger(BI.bitwiseNot(xw32))): Number
2116
2006
  } else {
2117
- let xval = coerceNumberToWasmI64(x)
2007
+ let xval = coerceNumberToWasmI64(value)
2118
2008
  WasmI32.toGrain(reducedInteger(i64not(xval))): Number
2119
2009
  }
2120
2010
  }
2121
2011
 
2012
+ /**
2013
+ * Shifts the bits of the value left by the given number of bits.
2014
+ *
2015
+ * @param value: The value to shift
2016
+ * @param amount: The number of bits to shift by
2017
+ * @returns The shifted value
2018
+ *
2019
+ * @since v0.3.0
2020
+ * @history v0.2.0: Originally named `lsl`
2021
+ * @history v0.3.0: Renamed to `<<`
2022
+ */
2122
2023
  @unsafe
2123
- export let (<<) = (x: Number, y: Number) => {
2124
- let xw32 = WasmI32.fromGrain(x)
2024
+ provide let (<<) = (value: Number, amount: Number) => {
2025
+ use WasmI64.{ (-), (<<) }
2026
+ let xw32 = WasmI32.fromGrain(value)
2125
2027
  if (isBigInt(xw32)) {
2126
- let yval = coerceNumberToWasmI32(y)
2028
+ let yval = coerceNumberToWasmI32(amount)
2127
2029
  WasmI32.toGrain(reducedBigInteger(BI.shl(xw32, yval))): Number
2128
2030
  } else {
2129
- let xval = coerceNumberToWasmI64(x)
2130
- let yval = coerceNumberToWasmI64(y)
2031
+ let xval = coerceNumberToWasmI64(value)
2032
+ let yval = coerceNumberToWasmI64(amount)
2131
2033
  // if the number will be shifted beyond the end of the i64 range, promote to BigInt
2132
2034
  // (note that we subtract one leading zero, since the leading bit is the sign bit)
2133
- if (WasmI64.leU(WasmI64.sub(WasmI64.clz(i64abs(xval)), 1N), yval)) {
2134
- let xbi = coerceNumberToBigInt(x)
2135
- let yval = coerceNumberToWasmI32(y)
2035
+ if (WasmI64.leU(WasmI64.clz(i64abs(xval)) - 1N, yval)) {
2036
+ let xbi = coerceNumberToBigInt(value)
2037
+ let yval = coerceNumberToWasmI32(amount)
2136
2038
  WasmI32.toGrain(reducedBigInteger(BI.shl(xbi, yval))): Number
2137
2039
  } else {
2138
- WasmI32.toGrain(reducedInteger(WasmI64.shl(xval, yval))): Number
2040
+ WasmI32.toGrain(reducedInteger(xval << yval)): Number
2139
2041
  }
2140
2042
  }
2141
2043
  }
2142
2044
 
2045
+ /**
2046
+ * Shifts the bits of the value right by the given number of bits, preserving the sign bit.
2047
+ *
2048
+ * @param value: The value to shift
2049
+ * @param amount: The amount to shift by
2050
+ * @returns The shifted value
2051
+ *
2052
+ * @since v0.3.0
2053
+ * @history v0.2.0: Originally named `lsr`
2054
+ * @history v0.3.0: Renamed to `>>>`
2055
+ */
2143
2056
  @unsafe
2144
- export let (>>>) = (x: Number, y: Number) => {
2145
- let xw32 = WasmI32.fromGrain(x)
2057
+ provide let (>>>) = (value: Number, amount: Number) => {
2058
+ use WasmI64.{ (>>>) }
2059
+ let xw32 = WasmI32.fromGrain(value)
2146
2060
  if (isBigInt(xw32)) {
2147
- let yval = coerceNumberToWasmI32(y)
2061
+ let yval = coerceNumberToWasmI32(amount)
2148
2062
  // [NOTE]: For BigInts, shrU is the same as shrS because there
2149
2063
  // are an *infinite* number of leading ones
2150
2064
  WasmI32.toGrain(reducedBigInteger(BI.shrS(xw32, yval))): Number
2151
2065
  } else {
2152
- let xval = coerceNumberToWasmI64(x)
2153
- let yval = coerceNumberToWasmI64(y)
2154
- WasmI32.toGrain(reducedInteger(WasmI64.shrU(xval, yval))): Number
2066
+ let xval = coerceNumberToWasmI64(value)
2067
+ let yval = coerceNumberToWasmI64(amount)
2068
+ WasmI32.toGrain(reducedInteger(xval >>> yval)): Number
2155
2069
  }
2156
2070
  }
2157
2071
 
2072
+ /**
2073
+ * Computes the bitwise AND (`&`) on the given operands.
2074
+ *
2075
+ * @param value1: The first operand
2076
+ * @param value2: The second operand
2077
+ * @returns Containing a `1` in each bit position for which the corresponding bits of both operands are `1`
2078
+ *
2079
+ * @since v0.3.0
2080
+ * @history v0.2.0: Originally named `land`
2081
+ * @history v0.3.0: Renamed to `&`
2082
+ */
2158
2083
  @unsafe
2159
- export let (&) = (x: Number, y: Number) => {
2160
- let xw32 = WasmI32.fromGrain(x)
2161
- let yw32 = WasmI32.fromGrain(y)
2084
+ provide let (&) = (value1: Number, value2: Number) => {
2085
+ use WasmI64.{ (&) }
2086
+ let xw32 = WasmI32.fromGrain(value1)
2087
+ let yw32 = WasmI32.fromGrain(value2)
2162
2088
  if (isBigInt(xw32) || isBigInt(yw32)) {
2163
- let xval = coerceNumberToBigInt(x)
2164
- let yval = coerceNumberToBigInt(y)
2165
- let ret = WasmI32.toGrain(
2166
- reducedBigInteger(BI.bitwiseAnd(xval, yval))
2167
- ): Number
2168
- if (!WasmI32.eq(xw32, xval)) {
2089
+ let xval = coerceNumberToBigInt(value1)
2090
+ let yval = coerceNumberToBigInt(value2)
2091
+ let ret = WasmI32.toGrain(reducedBigInteger(BI.bitwiseAnd(xval, yval))):
2092
+ Number
2093
+ if (!(xw32 == xval)) {
2169
2094
  Memory.decRef(xval)
2170
2095
  void
2171
2096
  }
2172
- if (!WasmI32.eq(yw32, yval)) {
2097
+ if (!(yw32 == yval)) {
2173
2098
  Memory.decRef(yval)
2174
2099
  void
2175
2100
  }
2176
2101
  ret
2177
2102
  } else {
2178
- let xval = coerceNumberToWasmI64(x)
2179
- let yval = coerceNumberToWasmI64(y)
2180
- WasmI32.toGrain(reducedInteger(WasmI64.and(xval, yval))): Number
2103
+ let xval = coerceNumberToWasmI64(value1)
2104
+ let yval = coerceNumberToWasmI64(value2)
2105
+ WasmI32.toGrain(reducedInteger(xval & yval)): Number
2181
2106
  }
2182
2107
  }
2183
2108
 
2109
+ /**
2110
+ * Computes the bitwise OR (`|`) on the given operands.
2111
+ *
2112
+ * @param value1: The first operand
2113
+ * @param value2: The second operand
2114
+ * @returns Containing a `1` in each bit position for which the corresponding bits of either or both operands are `1`
2115
+ *
2116
+ * @since v0.3.0
2117
+ * @history v0.2.0: Originally named `lor`
2118
+ * @history v0.3.0: Renamed to `|`
2119
+ */
2184
2120
  @unsafe
2185
- export let (|) = (x: Number, y: Number) => {
2186
- let xw32 = WasmI32.fromGrain(x)
2187
- let yw32 = WasmI32.fromGrain(y)
2121
+ provide let (|) = (value1: Number, value2: Number) => {
2122
+ use WasmI64.{ (|) }
2123
+ let xw32 = WasmI32.fromGrain(value1)
2124
+ let yw32 = WasmI32.fromGrain(value2)
2188
2125
  if (isBigInt(xw32) || isBigInt(yw32)) {
2189
- let xval = coerceNumberToBigInt(x)
2190
- let yval = coerceNumberToBigInt(y)
2191
- let ret = WasmI32.toGrain(
2192
- reducedBigInteger(BI.bitwiseOr(xval, yval))
2193
- ): Number
2194
- if (!WasmI32.eq(xw32, xval)) {
2126
+ let xval = coerceNumberToBigInt(value1)
2127
+ let yval = coerceNumberToBigInt(value2)
2128
+ let ret = WasmI32.toGrain(reducedBigInteger(BI.bitwiseOr(xval, yval))):
2129
+ Number
2130
+ if (!(xw32 == xval)) {
2195
2131
  Memory.decRef(xval)
2196
2132
  void
2197
2133
  }
2198
- if (!WasmI32.eq(yw32, yval)) {
2134
+ if (!(yw32 == yval)) {
2199
2135
  Memory.decRef(yval)
2200
2136
  void
2201
2137
  }
2202
2138
  ret
2203
2139
  } else {
2204
- let xval = coerceNumberToWasmI64(x)
2205
- let yval = coerceNumberToWasmI64(y)
2206
- WasmI32.toGrain(reducedInteger(WasmI64.or(xval, yval))): Number
2140
+ let xval = coerceNumberToWasmI64(value1)
2141
+ let yval = coerceNumberToWasmI64(value2)
2142
+ WasmI32.toGrain(reducedInteger(xval | yval)): Number
2207
2143
  }
2208
2144
  }
2209
2145
 
2146
+ /**
2147
+ * Computes the bitwise XOR (`^`) on the given operands.
2148
+ *
2149
+ * @param value1: The first operand
2150
+ * @param value2: The second operand
2151
+ * @returns Containing a `1` in each bit position for which the corresponding bits of either but not both operands are `1`
2152
+ *
2153
+ * @since v0.3.0
2154
+ * @history v0.1.0: The `^` operator was originally an alias of `unbox`
2155
+ * @history v0.2.0: Originally named `lxor`
2156
+ * @history v0.3.0: Renamed to `^`
2157
+ */
2210
2158
  @unsafe
2211
- export let (^) = (x: Number, y: Number) => {
2212
- let xw32 = WasmI32.fromGrain(x)
2213
- let yw32 = WasmI32.fromGrain(y)
2159
+ provide let (^) = (value1: Number, value2: Number) => {
2160
+ use WasmI64.{ (^) }
2161
+ let xw32 = WasmI32.fromGrain(value1)
2162
+ let yw32 = WasmI32.fromGrain(value2)
2214
2163
  if (isBigInt(xw32) || isBigInt(yw32)) {
2215
- let xval = coerceNumberToBigInt(x)
2216
- let yval = coerceNumberToBigInt(y)
2217
- let ret = WasmI32.toGrain(
2218
- reducedBigInteger(BI.bitwiseXor(xval, yval))
2219
- ): Number
2220
- if (!WasmI32.eq(xw32, xval)) {
2164
+ let xval = coerceNumberToBigInt(value1)
2165
+ let yval = coerceNumberToBigInt(value2)
2166
+ let ret = WasmI32.toGrain(reducedBigInteger(BI.bitwiseXor(xval, yval))):
2167
+ Number
2168
+ if (!(xw32 == xval)) {
2221
2169
  Memory.decRef(xval)
2222
2170
  void
2223
2171
  }
2224
- if (!WasmI32.eq(yw32, yval)) {
2172
+ if (!(yw32 == yval)) {
2225
2173
  Memory.decRef(yval)
2226
2174
  void
2227
2175
  }
2228
2176
  ret
2229
2177
  } else {
2230
- let xval = coerceNumberToWasmI64(x)
2231
- let yval = coerceNumberToWasmI64(y)
2232
- WasmI32.toGrain(reducedInteger(WasmI64.xor(xval, yval))): Number
2178
+ let xval = coerceNumberToWasmI64(value1)
2179
+ let yval = coerceNumberToWasmI64(value2)
2180
+ WasmI32.toGrain(reducedInteger(xval ^ yval)): Number
2233
2181
  }
2234
2182
  }
2235
2183
 
2184
+ /**
2185
+ * Shifts the bits of the value right by the given number of bits.
2186
+ *
2187
+ * @param value: The value to shift
2188
+ * @param amount: The amount to shift by
2189
+ * @returns The shifted value
2190
+ *
2191
+ * @since v0.3.0
2192
+ * @history v0.2.0: Originally named `asr`
2193
+ * @history v0.3.0: Renamed to `>>`
2194
+ */
2236
2195
  @unsafe
2237
- export let (>>) = (x: Number, y: Number) => {
2238
- let xw32 = WasmI32.fromGrain(x)
2196
+ provide let (>>) = (value: Number, amount: Number) => {
2197
+ use WasmI64.{ (>>) }
2198
+ let xw32 = WasmI32.fromGrain(value)
2239
2199
  if (isBigInt(xw32)) {
2240
- let yval = coerceNumberToWasmI32(y)
2200
+ let yval = coerceNumberToWasmI32(amount)
2241
2201
  // [NOTE]: For BigInts, shrU is the same as shrS because there
2242
2202
  // are an *infinite* number of leading ones
2243
2203
  WasmI32.toGrain(reducedBigInteger(BI.shrS(xw32, yval))): Number
2244
2204
  } else {
2245
- let xval = coerceNumberToWasmI64(x)
2246
- let yval = coerceNumberToWasmI64(y)
2247
- WasmI32.toGrain(reducedInteger(WasmI64.shrS(xval, yval))): Number
2205
+ let xval = coerceNumberToWasmI64(value)
2206
+ let yval = coerceNumberToWasmI64(amount)
2207
+ WasmI32.toGrain(reducedInteger(xval >> yval)): Number
2248
2208
  }
2249
2209
  }
2250
2210
 
@@ -2254,30 +2214,167 @@ export let (>>) = (x: Number, y: Number) => {
2254
2214
  // we will fail if attempting to coerce to an int!
2255
2215
 
2256
2216
  @unsafe
2257
- export let coerceNumberToInt32 = (x: Number) => {
2217
+ let coerceNumberToShortUint = (x: Number, max32, max64, is8bit) => {
2218
+ use WasmI32.{ (&), (<), (>) }
2258
2219
  let x = WasmI32.fromGrain(x)
2259
- let result = if (
2260
- !isSimpleNumber(x) &&
2261
- WasmI32.eq(boxedNumberTag(x), Tags._GRAIN_INT32_BOXED_NUM_TAG)
2262
- ) {
2263
- // avoid extra malloc and prevent x from being freed
2264
- Memory.incRef(x)
2265
- x
2220
+ let int32 = if (isSimpleNumber(x)) {
2221
+ untagSimple(x)
2266
2222
  } else {
2267
- // incRef x to reuse it via WasmI32.toGrain
2268
- Memory.incRef(x)
2269
- // can possibly fail
2270
- newInt32(coerceNumberToWasmI32(WasmI32.toGrain(x): Number))
2223
+ let xtag = boxedNumberTag(x)
2224
+ match (xtag) {
2225
+ t when t == Tags._GRAIN_INT64_BOXED_NUM_TAG => {
2226
+ use WasmI64.{ (<), (>) }
2227
+ let int64 = boxedInt64Number(x)
2228
+ if (int64 > max64 || int64 < 0N) {
2229
+ throw Exception.Overflow
2230
+ }
2231
+ WasmI32.wrapI64(int64)
2232
+ },
2233
+ t when t == Tags._GRAIN_BIGINT_BOXED_NUM_TAG => {
2234
+ BI.toInt32(x)
2235
+ },
2236
+ _ => {
2237
+ // rationals are never integral, and we refuse to coerce floats to ints
2238
+ throw Exception.NumberNotIntlike
2239
+ },
2240
+ }
2271
2241
  }
2272
- WasmI32.toGrain(result): Int32
2242
+ if (int32 > max32 || int32 < 0n) {
2243
+ throw Exception.Overflow
2244
+ }
2245
+ if (is8bit) int32 & 0xffffn else int32 & 0xffffn
2273
2246
  }
2274
2247
 
2275
2248
  @unsafe
2276
- export let coerceNumberToInt64 = (x: Number) => {
2249
+ let coerceNumberToShortInt = (x: Number, min32, max32, min64, max64, is8bit) => {
2250
+ use WasmI32.{ (<), (>) }
2277
2251
  let x = WasmI32.fromGrain(x)
2252
+ let int32 = if (isSimpleNumber(x)) {
2253
+ untagSimple(x)
2254
+ } else {
2255
+ let xtag = boxedNumberTag(x)
2256
+ match (xtag) {
2257
+ t when t == Tags._GRAIN_INT64_BOXED_NUM_TAG => {
2258
+ use WasmI64.{ (<), (>) }
2259
+ let int64 = boxedInt64Number(x)
2260
+ if (int64 > max64 || int64 < min64) {
2261
+ throw Exception.Overflow
2262
+ }
2263
+ WasmI32.wrapI64(int64)
2264
+ },
2265
+ t when t == Tags._GRAIN_BIGINT_BOXED_NUM_TAG => {
2266
+ BI.toInt32(x)
2267
+ },
2268
+ _ => {
2269
+ // rationals are never integral, and we refuse to coerce floats to ints
2270
+ throw Exception.NumberNotIntlike
2271
+ },
2272
+ }
2273
+ }
2274
+ if (int32 > max32 || int32 < min32) {
2275
+ throw Exception.Overflow
2276
+ }
2277
+ if (is8bit) WasmI32.extendS8(int32) else WasmI32.extendS16(int32)
2278
+ }
2279
+
2280
+ /**
2281
+ * Converts a Number to an Int8.
2282
+ *
2283
+ * @param number: The value to convert
2284
+ * @returns The Number represented as an Int8
2285
+ *
2286
+ * @since v0.6.0
2287
+ */
2288
+ @unsafe
2289
+ provide let coerceNumberToInt8 = (number: Number) => {
2290
+ let val = coerceNumberToShortInt(
2291
+ number,
2292
+ _SMIN8_I32,
2293
+ _SMAX8_I32,
2294
+ _SMIN8_I64,
2295
+ _SMAX8_I64,
2296
+ true
2297
+ )
2298
+ tagInt8(val)
2299
+ }
2300
+
2301
+ /**
2302
+ * Converts a Number to an Int16.
2303
+ *
2304
+ * @param number: The value to convert
2305
+ * @returns The Number represented as an Int16
2306
+ *
2307
+ * @since v0.6.0
2308
+ */
2309
+ @unsafe
2310
+ provide let coerceNumberToInt16 = (number: Number) => {
2311
+ let val = coerceNumberToShortInt(
2312
+ number,
2313
+ _SMIN16_I32,
2314
+ _SMAX16_I32,
2315
+ _SMIN16_I64,
2316
+ _SMAX16_I64,
2317
+ false
2318
+ )
2319
+ tagInt16(val)
2320
+ }
2321
+
2322
+ /**
2323
+ * Converts a Number to a Uint8.
2324
+ *
2325
+ * @param number: The value to convert
2326
+ * @returns The Number represented as a Uint8
2327
+ *
2328
+ * @since v0.6.0
2329
+ */
2330
+ @unsafe
2331
+ provide let coerceNumberToUint8 = (number: Number) => {
2332
+ let val = coerceNumberToShortUint(number, _UMAX8_I32, _UMAX8_I64, true)
2333
+ tagUint8(val)
2334
+ }
2335
+
2336
+ /**
2337
+ * Converts a Number to a Uint16.
2338
+ *
2339
+ * @param number: The value to convert
2340
+ * @returns The Number represented as a Uint16
2341
+ *
2342
+ * @since v0.6.0
2343
+ */
2344
+ @unsafe
2345
+ provide let coerceNumberToUint16 = (number: Number) => {
2346
+ let val = coerceNumberToShortUint(number, _UMAX16_I32, _UMAX16_I64, false)
2347
+ tagUint16(val)
2348
+ }
2349
+
2350
+ /**
2351
+ * Converts a Number to an Int32.
2352
+ *
2353
+ * @param number: The value to convert
2354
+ * @returns The Number represented as an Int32
2355
+ *
2356
+ * @since v0.2.0
2357
+ */
2358
+ @unsafe
2359
+ provide let coerceNumberToInt32 = (number: Number) => {
2360
+ let result = newInt32(coerceNumberToWasmI32(number))
2361
+ WasmI32.toGrain(result): Int32
2362
+ }
2363
+
2364
+ /**
2365
+ * Converts a Number to an Int64.
2366
+ *
2367
+ * @param number: The value to convert
2368
+ * @returns The Number represented as an Int64
2369
+ *
2370
+ * @since v0.2.0
2371
+ */
2372
+ @unsafe
2373
+ provide let coerceNumberToInt64 = (number: Number) => {
2374
+ let x = WasmI32.fromGrain(number)
2278
2375
  let result = if (
2279
2376
  !isSimpleNumber(x) &&
2280
- WasmI32.eq(boxedNumberTag(x), Tags._GRAIN_INT64_BOXED_NUM_TAG)
2377
+ boxedNumberTag(x) == Tags._GRAIN_INT64_BOXED_NUM_TAG
2281
2378
  ) {
2282
2379
  // avoid extra malloc and prevent x from being freed
2283
2380
  Memory.incRef(x)
@@ -2290,38 +2387,39 @@ export let coerceNumberToInt64 = (x: Number) => {
2290
2387
  WasmI32.toGrain(result): Int64
2291
2388
  }
2292
2389
 
2390
+ /**
2391
+ * Converts a Number to a BigInt.
2392
+ *
2393
+ * @param number: The value to convert
2394
+ * @returns The Number represented as a BigInt
2395
+ *
2396
+ * @since v0.5.0
2397
+ */
2293
2398
  @unsafe
2294
- export let coerceNumberToBigInt = (x: Number) => {
2295
- let x = WasmI32.fromGrain(x)
2296
- let result = if (isBigInt(x)) {
2297
- // avoid extra malloc and prevent x from being freed
2298
- Memory.incRef(x)
2299
- x
2300
- } else {
2301
- // incRef x to reuse it via WasmI32.toGrain
2302
- Memory.incRef(x)
2303
- BI.makeWrappedInt64(coerceNumberToWasmI64(WasmI32.toGrain(x): Number))
2304
- }
2305
- WasmI32.toGrain(result): BigInt
2399
+ provide let coerceNumberToBigInt = (number: Number) => {
2400
+ WasmI32.toGrain(coerceNumberToBigInt(number)): BigInt
2306
2401
  }
2307
2402
 
2403
+ /**
2404
+ * Converts a Number to a Rational.
2405
+ *
2406
+ * @param number: The value to convert
2407
+ * @returns The Number represented as a Rational
2408
+ *
2409
+ * @since v0.6.0
2410
+ */
2308
2411
  @unsafe
2309
- export let coerceNumberToRational = (x: Number) => {
2310
- let x = WasmI32.fromGrain(x)
2412
+ provide let coerceNumberToRational = (number: Number) => {
2413
+ let x = WasmI32.fromGrain(number)
2311
2414
  let result = if (isSimpleNumber(x)) {
2312
2415
  newRational(BI.makeWrappedInt32(untagSimple(x)), BI.makeWrappedInt32(1n))
2313
2416
  } else {
2314
2417
  let tag = boxedNumberTag(x)
2315
- if (WasmI32.eq(tag, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG)) {
2418
+ if (tag == Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) {
2316
2419
  // avoid extra malloc and prevent x from being freed
2317
2420
  Memory.incRef(x)
2318
2421
  x
2319
- } else if (WasmI32.eq(tag, Tags._GRAIN_INT32_BOXED_NUM_TAG)) {
2320
- newRational(
2321
- BI.makeWrappedInt32(boxedInt32Number(x)),
2322
- BI.makeWrappedInt32(1n)
2323
- )
2324
- } else if (WasmI32.eq(tag, Tags._GRAIN_INT64_BOXED_NUM_TAG)) {
2422
+ } else if (tag == Tags._GRAIN_INT64_BOXED_NUM_TAG) {
2325
2423
  // incRef x to reuse it via WasmI32.toGrain
2326
2424
  Memory.incRef(x)
2327
2425
  newRational(
@@ -2335,30 +2433,34 @@ export let coerceNumberToRational = (x: Number) => {
2335
2433
  WasmI32.toGrain(result): Rational
2336
2434
  }
2337
2435
 
2436
+ /**
2437
+ * Converts a Number to a Float32.
2438
+ *
2439
+ * @param number: The value to convert
2440
+ * @returns The Number represented as a Float32
2441
+ *
2442
+ * @since v0.2.0
2443
+ */
2338
2444
  @unsafe
2339
- export let coerceNumberToFloat32 = (x: Number) => {
2340
- let x = WasmI32.fromGrain(x)
2341
- let result = if (
2342
- !isSimpleNumber(x) &&
2343
- WasmI32.eq(boxedNumberTag(x), Tags._GRAIN_FLOAT32_BOXED_NUM_TAG)
2344
- ) {
2345
- // avoid extra malloc and prevent x from being freed
2346
- Memory.incRef(x)
2347
- x
2348
- } else {
2349
- // incRef x to reuse it via WasmI32.toGrain
2350
- Memory.incRef(x)
2351
- newFloat32(coerceNumberToWasmF32(WasmI32.toGrain(x): Number))
2352
- }
2445
+ provide let coerceNumberToFloat32 = (number: Number) => {
2446
+ let result = newFloat32(coerceNumberToWasmF32(number))
2353
2447
  WasmI32.toGrain(result): Float32
2354
2448
  }
2355
2449
 
2450
+ /**
2451
+ * Converts a Number to a Float64.
2452
+ *
2453
+ * @param number: The value to convert
2454
+ * @returns The Number represented as a Float64
2455
+ *
2456
+ * @since v0.2.0
2457
+ */
2356
2458
  @unsafe
2357
- export let coerceNumberToFloat64 = (x: Number) => {
2358
- let x = WasmI32.fromGrain(x)
2459
+ provide let coerceNumberToFloat64 = (number: Number) => {
2460
+ let x = WasmI32.fromGrain(number)
2359
2461
  let result = if (
2360
2462
  !isSimpleNumber(x) &&
2361
- WasmI32.eq(boxedNumberTag(x), Tags._GRAIN_FLOAT64_BOXED_NUM_TAG)
2463
+ boxedNumberTag(x) == Tags._GRAIN_FLOAT64_BOXED_NUM_TAG
2362
2464
  ) {
2363
2465
  // avoid extra malloc and prevent x from being freed
2364
2466
  Memory.incRef(x)
@@ -2371,55 +2473,156 @@ export let coerceNumberToFloat64 = (x: Number) => {
2371
2473
  WasmI32.toGrain(result): Float64
2372
2474
  }
2373
2475
 
2476
+ /**
2477
+ * Converts an Int8 to a Number.
2478
+ *
2479
+ * @param value: The value to convert
2480
+ * @returns The Int8 represented as a Number
2481
+ *
2482
+ * @since v0.6.0
2483
+ */
2374
2484
  @unsafe
2375
- export let coerceInt32ToNumber = (x: Int32) => {
2376
- WasmI32.toGrain(
2377
- reducedInteger(WasmI64.extendI32S(boxedInt32Number(WasmI32.fromGrain(x))))
2378
- ): Number
2485
+ provide let coerceInt8ToNumber = (value: Int8) => {
2486
+ let num = untagInt8(value)
2487
+ WasmI32.toGrain(tagSimple(num)): Number
2379
2488
  }
2380
2489
 
2490
+ /**
2491
+ * Converts an Int16 to a Number.
2492
+ *
2493
+ * @param value: The value to convert
2494
+ * @returns The Int16 represented as a Number
2495
+ *
2496
+ * @since v0.6.0
2497
+ */
2381
2498
  @unsafe
2382
- export let coerceInt64ToNumber = (x: Int64) => {
2383
- WasmI32.toGrain(
2384
- reducedInteger(boxedInt64Number(WasmI32.fromGrain(x)))
2385
- ): Number
2499
+ provide let coerceInt16ToNumber = (value: Int16) => {
2500
+ let num = untagInt16(value)
2501
+ WasmI32.toGrain(tagSimple(num)): Number
2386
2502
  }
2387
2503
 
2504
+ /**
2505
+ * Converts a Uint8 to a Number.
2506
+ *
2507
+ * @param value: The value to convert
2508
+ * @returns The Uint8 represented as a Number
2509
+ *
2510
+ * @since v0.6.0
2511
+ */
2388
2512
  @unsafe
2389
- export let coerceBigIntToNumber = (x: BigInt) => {
2390
- let x = WasmI32.fromGrain(x)
2513
+ provide let coerceUint8ToNumber = (value: Uint8) => {
2514
+ let num = untagUint8(value)
2515
+ WasmI32.toGrain(tagSimple(num)): Number
2516
+ }
2517
+
2518
+ /**
2519
+ * Converts a Uint16 to a Number.
2520
+ *
2521
+ * @param value: The value to convert
2522
+ * @returns The Uint16 represented as a Number
2523
+ *
2524
+ * @since v0.6.0
2525
+ */
2526
+ @unsafe
2527
+ provide let coerceUint16ToNumber = (value: Uint16) => {
2528
+ let num = untagUint16(value)
2529
+ WasmI32.toGrain(tagSimple(num)): Number
2530
+ }
2531
+
2532
+ /**
2533
+ * Converts an Int32 to a Number.
2534
+ *
2535
+ * @param value: The value to convert
2536
+ * @returns The Int32 represented as a Number
2537
+ *
2538
+ * @since v0.2.0
2539
+ */
2540
+ @unsafe
2541
+ provide let coerceInt32ToNumber = (value: Int32) => {
2542
+ let x = WasmI32.load(WasmI32.fromGrain(value), 4n)
2543
+ let result = reducedInteger(WasmI64.extendI32S(x))
2544
+ WasmI32.toGrain(result): Number
2545
+ }
2546
+
2547
+ /**
2548
+ * Converts an Int64 to a Number.
2549
+ *
2550
+ * @param value: The value to convert
2551
+ * @returns The Int64 represented as a Number
2552
+ *
2553
+ * @since v0.2.0
2554
+ */
2555
+ @unsafe
2556
+ provide let coerceInt64ToNumber = (value: Int64) => {
2557
+ WasmI32.toGrain(reducedInteger(boxedInt64Number(WasmI32.fromGrain(value)))):
2558
+ Number
2559
+ }
2560
+
2561
+ /**
2562
+ * Converts a BigInt to a Number.
2563
+ *
2564
+ * @param num: The value to convert
2565
+ * @returns The BigInt represented as a Number
2566
+ *
2567
+ * @since v0.5.0
2568
+ */
2569
+ @unsafe
2570
+ provide let coerceBigIntToNumber = (num: BigInt) => {
2571
+ let x = WasmI32.fromGrain(num)
2391
2572
  // reducedBigInteger assumes that the bigint is dead,
2392
2573
  // but in our case, it is not
2393
2574
  Memory.incRef(x)
2394
2575
  WasmI32.toGrain(reducedBigInteger(x)): Number
2395
2576
  }
2396
2577
 
2578
+ /**
2579
+ * Converts a Rational to a Number.
2580
+ *
2581
+ * @param rational: The value to convert
2582
+ * @returns The Rational represented as a Number
2583
+ *
2584
+ * @since v0.6.0
2585
+ */
2397
2586
  @unsafe
2398
- export let coerceRationalToNumber = (x: Rational) => {
2399
- if (WasmI32.eq(boxedRationalDenominator(WasmI32.fromGrain(x)), 1n)) {
2400
- WasmI32.toGrain(
2401
- reducedInteger(
2402
- WasmI64.extendI32S(boxedRationalNumerator(WasmI32.fromGrain(x)))
2403
- )
2404
- ): Number
2587
+ provide let coerceRationalToNumber = (rational: Rational) => {
2588
+ let x = WasmI32.fromGrain(rational)
2589
+ let denom = boxedRationalDenominator(x)
2590
+ let x = if (BI.eq(denom, BI.makeWrappedInt32(1n))) {
2591
+ boxedRationalNumerator(x)
2405
2592
  } else {
2406
- let x = WasmI32.fromGrain(x)
2407
- // incRef x to reuse it via WasmI32.toGrain
2408
- Memory.incRef(x)
2409
- WasmI32.toGrain(x): Number
2593
+ x
2410
2594
  }
2595
+ // incRef x to reuse it via WasmI32.toGrain
2596
+ Memory.incRef(x)
2597
+ WasmI32.toGrain(x): Number
2411
2598
  }
2412
2599
 
2600
+ /**
2601
+ * Converts a Float32 to a Number.
2602
+ *
2603
+ * @param float: The value to convert
2604
+ * @returns The Float32 represented as a Number
2605
+ *
2606
+ * @since v0.2.0
2607
+ */
2413
2608
  @unsafe
2414
- export let coerceFloat32ToNumber = (x: Float32) => {
2415
- WasmI32.toGrain(
2416
- newFloat64(WasmF64.promoteF32(boxedFloat32Number(WasmI32.fromGrain(x))))
2417
- ): Number
2609
+ provide let coerceFloat32ToNumber = (float: Float32) => {
2610
+ let x = WasmF32.load(WasmI32.fromGrain(float), 4n)
2611
+ let x64 = WasmF64.promoteF32(x)
2612
+ WasmI32.toGrain(newFloat64(x64)): Number
2418
2613
  }
2419
2614
 
2615
+ /**
2616
+ * Converts a Float64 to a Number.
2617
+ *
2618
+ * @param float: The value to convert
2619
+ * @returns The Float64 represented as a Number
2620
+ *
2621
+ * @since v0.2.0
2622
+ */
2420
2623
  @unsafe
2421
- export let coerceFloat64ToNumber = (x: Float64) => {
2422
- let x = WasmI32.fromGrain(x)
2624
+ provide let coerceFloat64ToNumber = (float: Float64) => {
2625
+ let x = WasmI32.fromGrain(float)
2423
2626
  // incRef x to reuse it via WasmI32.toGrain
2424
2627
  Memory.incRef(x)
2425
2628
  WasmI32.toGrain(x): Number
@@ -2428,7 +2631,7 @@ export let coerceFloat64ToNumber = (x: Float64) => {
2428
2631
  /// USER-EXPOSED CONVERSION FUNCTIONS
2429
2632
 
2430
2633
  @unsafe
2431
- export let convertExactToInexact = (x: Number) => {
2634
+ provide let convertExactToInexact = (x: Number) => {
2432
2635
  x
2433
2636
  }
2434
2637
 
@@ -2439,22 +2642,15 @@ let convertInexactToExactHelp = x => {
2439
2642
  } else {
2440
2643
  let tag = boxedNumberTag(x)
2441
2644
  if (
2442
- WasmI32.eq(tag, Tags._GRAIN_INT32_BOXED_NUM_TAG) ||
2443
- WasmI32.eq(tag, Tags._GRAIN_INT64_BOXED_NUM_TAG) ||
2444
- WasmI32.eq(tag, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) ||
2445
- WasmI32.eq(tag, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG)
2645
+ tag == Tags._GRAIN_INT64_BOXED_NUM_TAG ||
2646
+ tag == Tags._GRAIN_BIGINT_BOXED_NUM_TAG ||
2647
+ tag == Tags._GRAIN_RATIONAL_BOXED_NUM_TAG
2446
2648
  ) {
2447
2649
  Memory.incRef(x)
2448
2650
  x
2449
2651
  } else {
2450
2652
  match (tag) {
2451
- t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
2452
- // TODO(#1191): Investigate if BigInt is more accurate
2453
- reducedInteger(
2454
- WasmI64.truncF32S(WasmF32.nearest(boxedFloat32Number(x)))
2455
- )
2456
- },
2457
- t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
2653
+ t when t == Tags._GRAIN_FLOAT64_BOXED_NUM_TAG => {
2458
2654
  // TODO(#1191): Investigate if BigInt is more accurate
2459
2655
  reducedInteger(
2460
2656
  WasmI64.truncF64S(WasmF64.nearest(boxedFloat64Number(x)))
@@ -2469,57 +2665,123 @@ let convertInexactToExactHelp = x => {
2469
2665
  }
2470
2666
 
2471
2667
  @unsafe
2472
- export let convertInexactToExact = (x: Number) => {
2668
+ provide let convertInexactToExact = (x: Number) => {
2473
2669
  WasmI32.toGrain(convertInexactToExactHelp(WasmI32.fromGrain(x))): Number
2474
2670
  }
2475
2671
 
2672
+ /**
2673
+ * Computes the sum of its operands.
2674
+ *
2675
+ * @param num1: The first operand
2676
+ * @param num2: The second operand
2677
+ * @returns The sum of the two operands
2678
+ *
2679
+ * @since v0.1.0
2680
+ */
2476
2681
  @unsafe
2477
- export let (+) = (x: Number, y: Number) => {
2478
- let x = WasmI32.fromGrain(x)
2479
- let y = WasmI32.fromGrain(y)
2480
- numberAdd(x, y)
2682
+ provide let (+) = (num1: Number, num2: Number) => {
2683
+ let ret = numberAdd(WasmI32.fromGrain(num1), WasmI32.fromGrain(num2))
2684
+ ignore(num1)
2685
+ ignore(num2)
2686
+ ret
2481
2687
  }
2482
2688
 
2689
+ /**
2690
+ * Computes the difference of its operands.
2691
+ *
2692
+ * @param num1: The first operand
2693
+ * @param num2: The second operand
2694
+ * @returns The difference of the two operands
2695
+ *
2696
+ * @since v0.1.0
2697
+ */
2483
2698
  @unsafe
2484
- export let (-) = (x: Number, y: Number) => {
2485
- let x = WasmI32.fromGrain(x)
2486
- let y = WasmI32.fromGrain(y)
2487
- numberSub(x, y)
2699
+ provide let (-) = (num1: Number, num2: Number) => {
2700
+ let ret = numberSub(WasmI32.fromGrain(num1), WasmI32.fromGrain(num2))
2701
+ ignore(num1)
2702
+ ignore(num2)
2703
+ ret
2488
2704
  }
2489
2705
 
2706
+ /**
2707
+ * Computes the product of its operands.
2708
+ *
2709
+ * @param num1: The first operand
2710
+ * @param num2: The second operand
2711
+ * @returns The product of the two operands
2712
+ *
2713
+ * @since v0.1.0
2714
+ */
2490
2715
  @unsafe
2491
- export let (*) = (x: Number, y: Number) => {
2492
- let x = WasmI32.fromGrain(x)
2493
- let y = WasmI32.fromGrain(y)
2494
- numberTimes(x, y)
2716
+ provide let (*) = (num1: Number, num2: Number) => {
2717
+ let ret = numberTimes(WasmI32.fromGrain(num1), WasmI32.fromGrain(num2))
2718
+ ignore(num1)
2719
+ ignore(num2)
2720
+ ret
2495
2721
  }
2496
2722
 
2723
+ /**
2724
+ * Computes the quotient of its operands.
2725
+ *
2726
+ * @param num1: The first operand
2727
+ * @param num2: The second operand
2728
+ * @returns The quotient of the two operands
2729
+ *
2730
+ * @since v0.1.0
2731
+ */
2497
2732
  @unsafe
2498
- export let (/) = (x: Number, y: Number) => {
2499
- let x = WasmI32.fromGrain(x)
2500
- let y = WasmI32.fromGrain(y)
2501
- numberDivide(x, y)
2733
+ provide let (/) = (num1: Number, num2: Number) => {
2734
+ let ret = numberDivide(WasmI32.fromGrain(num1), WasmI32.fromGrain(num2))
2735
+ ignore(num1)
2736
+ ignore(num2)
2737
+ ret
2502
2738
  }
2503
2739
 
2740
+ /**
2741
+ * Computes the remainder of the division of the first operand by the second.
2742
+ * The result will have the sign of the second operand.
2743
+ *
2744
+ * @param num1: The first operand
2745
+ * @param num2: The second operand
2746
+ * @returns The modulus of its operands
2747
+ *
2748
+ * @since v0.1.0
2749
+ */
2504
2750
  @unsafe
2505
- export let (%) = (x: Number, y: Number) => {
2506
- let x = WasmI32.fromGrain(x)
2507
- let y = WasmI32.fromGrain(y)
2751
+ provide let (%) = (num1: Number, num2: Number) => {
2752
+ let x = WasmI32.fromGrain(num1)
2753
+ let y = WasmI32.fromGrain(num2)
2508
2754
  WasmI32.toGrain(numberMod(x, y)): Number
2509
2755
  }
2510
2756
 
2511
2757
  // inc/dec
2512
2758
 
2513
- export let incr = x => {
2514
- x + 1
2759
+ /**
2760
+ * Increments the value by one.
2761
+ *
2762
+ * @param value: The value to increment
2763
+ * @returns The incremented value
2764
+ *
2765
+ * @since v0.1.0
2766
+ */
2767
+ provide let incr = value => {
2768
+ value + 1
2515
2769
  }
2516
2770
 
2517
- export let decr = x => {
2518
- x - 1
2771
+ /**
2772
+ * Decrements the value by one.
2773
+ *
2774
+ * @param value: The value to decrement
2775
+ * @returns The decremented value
2776
+ *
2777
+ * @since v0.1.0
2778
+ */
2779
+ provide let decr = value => {
2780
+ value - 1
2519
2781
  }
2520
2782
 
2521
2783
  @unsafe
2522
- export let isBigInt = x => {
2784
+ provide let isBigInt = x => {
2523
2785
  let x = WasmI32.fromGrain(x)
2524
2786
  isBigInt(x)
2525
2787
  }
@@ -2544,32 +2806,26 @@ export let isBigInt = x => {
2544
2806
  * @since v0.5.4
2545
2807
  */
2546
2808
  @unsafe
2547
- export let scalbn = (x, n) => {
2548
- let (>) = WasmI32.gtS
2549
- let (<) = WasmI32.ltS
2550
- let (*) = WasmF64.mul
2551
- let (-) = WasmI32.sub
2552
- let (+) = WasmI32.add
2553
- let (<<) = WasmI64.shl
2809
+ provide let scalbn = (x, n) => {
2810
+ use WasmI32.{ (>), (<), (-), (+) }
2811
+ use WasmF64.{ (*) }
2812
+ use WasmI64.{ (<<) }
2554
2813
  // Constants
2555
- let const_0x1p1023 = 8.98847e+307W
2556
- let const_0x1p_1022 = 2.22507e-308W
2557
- let const_0x1p53 = 9.0072e+15W
2558
2814
  let mut n = n
2559
2815
  let mut y = x
2560
2816
  if (n > 1023n) {
2561
- y *= const_0x1p1023
2817
+ y *= 0x1p1023W
2562
2818
  n -= 1023n
2563
2819
  if (n > 1023n) {
2564
- y *= const_0x1p1023
2820
+ y *= 0x1p1023W
2565
2821
  n -= 1023n
2566
2822
  if (n > 1023n) n = 1023n
2567
2823
  } else if (n < -1023n) {
2568
2824
  /* make sure final n < -53 to avoid double rounding in the subnormal range */
2569
- y *= const_0x1p_1022 * const_0x1p53
2825
+ y *= 0x1p-1022W * 0x1p53W
2570
2826
  n += 1022n - 53n
2571
2827
  if (n < -1022n) {
2572
- y *= const_0x1p_1022 * const_0x1p53
2828
+ y *= 0x1p-1022W * 0x1p53W
2573
2829
  n += 1022n - 53n
2574
2830
  if (n < -1022n) n = -1022n
2575
2831
  }
@@ -2577,3 +2833,421 @@ export let scalbn = (x, n) => {
2577
2833
  }
2578
2834
  y * WasmF64.reinterpretI64(WasmI64.extendI32S(0x3FFn + n) << 52N)
2579
2835
  }
2836
+
2837
+ // Exponentiation by squaring https://en.wikipedia.org/wiki/Exponentiation_by_squaring special path for int^int
2838
+ let rec expBySquaring = (y, x, n) => {
2839
+ let (==) = numberEq
2840
+ if (n == 0) {
2841
+ 1
2842
+ } else if (n == 1) {
2843
+ x * y
2844
+ } else if (n % 2 == 0) {
2845
+ expBySquaring(y, x * x, n / 2)
2846
+ } else {
2847
+ expBySquaring(x * y, x * x, (n - 1) / 2)
2848
+ }
2849
+ }
2850
+
2851
+ // Math.pow is largely based on https://git.musl-libc.org/cgit/musl/tree/src/math/pow.c
2852
+ /*
2853
+ * ====================================================
2854
+ * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved.
2855
+ *
2856
+ * Permission to use, copy, modify, and distribute this
2857
+ * software is freely granted, provided that this notice
2858
+ * is preserved.
2859
+ * ====================================================
2860
+ */
2861
+ /**
2862
+ * Computes the exponentiation of the given base and power.
2863
+ *
2864
+ * @param base: The base number
2865
+ * @param power: The exponent number
2866
+ * @returns The base raised to the given power
2867
+ *
2868
+ * @since v0.6.0
2869
+ * @history v0.5.4: Originally existed in Number module
2870
+ */
2871
+ @unsafe
2872
+ provide let (**) = (base, power) => {
2873
+ let (==) = numberEq
2874
+ let (!=) = (x, y) => !numberEq(x, y)
2875
+ let basePtr = WasmI32.fromGrain(base)
2876
+ let powerPtr = WasmI32.fromGrain(power)
2877
+ if (base == 1 && power != 0) {
2878
+ return 1
2879
+ } else if (isInteger(basePtr) && isInteger(powerPtr)) {
2880
+ if (power < 0)
2881
+ return expBySquaring(1, 1 / base, power * -1)
2882
+ else
2883
+ return expBySquaring(1, base, power)
2884
+ } else if (isRational(basePtr) && isInteger(powerPtr)) {
2885
+ // Apply expBySquaring to numerator and denominator
2886
+ let numerator = WasmI32.fromGrain(base)
2887
+ Memory.incRef(numerator)
2888
+ let numerator = WasmI32.toGrain(numerator): Rational
2889
+ let numerator = rationalNumerator(numerator)
2890
+ let denominator = WasmI32.fromGrain(base)
2891
+ Memory.incRef(denominator)
2892
+ let denominator = WasmI32.toGrain(denominator): Rational
2893
+ let denominator = rationalDenominator(denominator)
2894
+ let numerator = if (power < 0)
2895
+ expBySquaring(1, 1 / numerator, power * -1)
2896
+ else
2897
+ expBySquaring(1, numerator, power)
2898
+ let denominator = if (power < 0)
2899
+ expBySquaring(1, 1 / denominator, power * -1)
2900
+ else
2901
+ expBySquaring(1, denominator, power)
2902
+ return numerator / denominator
2903
+ } else {
2904
+ // Based on https://git.musl-libc.org/cgit/musl/tree/src/math/pow.c
2905
+ use WasmF64.{ (==), (!=), (<=), (/), (*), (+) }
2906
+ let x = coerceNumberToWasmF64(base)
2907
+ let y = coerceNumberToWasmF64(power)
2908
+ // Fast paths
2909
+ if (WasmF64.abs(y) <= 2.0W) {
2910
+ if (y == 2.0W) {
2911
+ return WasmI32.toGrain(newFloat64(x * x)): Number
2912
+ } else if (y == 0.5W) {
2913
+ if (x != InfinityW) {
2914
+ return WasmI32.toGrain(newFloat64(WasmF64.abs(WasmF64.sqrt(x)))):
2915
+ Number
2916
+ } else {
2917
+ return Infinity
2918
+ }
2919
+ } else if (y == -1.0W) {
2920
+ return WasmI32.toGrain(newFloat64(1.0W / x)): Number
2921
+ } else if (y == 1.0W) {
2922
+ return WasmI32.toGrain(newFloat64(x)): Number
2923
+ } else if (y == 0.0W) {
2924
+ return NaN
2925
+ }
2926
+ }
2927
+ // Full calculation
2928
+ let dp_h1 = WasmF64.reinterpretI64(0x3FE2B80340000000N)
2929
+ let dp_l1 = WasmF64.reinterpretI64(0x3E4CFDEB43CFD006N)
2930
+ let two53 = WasmF64.reinterpretI64(0x4340000000000000N)
2931
+ let huge = WasmF64.reinterpretI64(0x7E37E43C8800759CN)
2932
+ let tiny = WasmF64.reinterpretI64(0x01A56E1FC2F8F359N)
2933
+ let l1 = WasmF64.reinterpretI64(0x3FE3333333333303N)
2934
+ let l2 = WasmF64.reinterpretI64(0x3FDB6DB6DB6FABFFN)
2935
+ let l3 = WasmF64.reinterpretI64(0x3FD55555518F264DN)
2936
+ let l4 = WasmF64.reinterpretI64(0x3FD17460A91D4101N)
2937
+ let l5 = WasmF64.reinterpretI64(0x3FCD864A93C9DB65N)
2938
+ let l6 = WasmF64.reinterpretI64(0x3FCA7E284A454EEFN)
2939
+ let p1 = WasmF64.reinterpretI64(0x3FC555555555553EN)
2940
+ let p2 = WasmF64.reinterpretI64(0xBF66C16C16BEBD93N)
2941
+ let p3 = WasmF64.reinterpretI64(0x3F11566AAF25DE2CN)
2942
+ let p4 = WasmF64.reinterpretI64(0xBEBBBD41C5D26BF1N)
2943
+ let p5 = WasmF64.reinterpretI64(0x3E66376972BEA4D0N)
2944
+ let lg2 = WasmF64.reinterpretI64(0x3FE62E42FEFA39EFN)
2945
+ let lg2_h = WasmF64.reinterpretI64(0x3FE62E4300000000N)
2946
+ let lg2_l = WasmF64.reinterpretI64(0xBE205C610CA86C39N)
2947
+ let ovt = WasmF64.reinterpretI64(0x3C971547652B82FEN)
2948
+ let cp = WasmF64.reinterpretI64(0x3FEEC709DC3A03FDN)
2949
+ let cp_h = WasmF64.reinterpretI64(0x3FEEC709E0000000N)
2950
+ let cp_l = WasmF64.reinterpretI64(0xBE3E2FE0145B01F5N)
2951
+ let ivln2 = WasmF64.reinterpretI64(0x3FF71547652B82FEN)
2952
+ let ivln2_h = WasmF64.reinterpretI64(0x3FF7154760000000N)
2953
+ let ivln2_l = WasmF64.reinterpretI64(0x3E54AE0BF85DDF44N)
2954
+ let inv3 = WasmF64.reinterpretI64(0x3FD5555555555555N)
2955
+ use WasmI32.{
2956
+ (==),
2957
+ (!=),
2958
+ (>=),
2959
+ (<=),
2960
+ (&),
2961
+ (|),
2962
+ (>),
2963
+ (<),
2964
+ (<<),
2965
+ (>>),
2966
+ (-),
2967
+ (+),
2968
+ }
2969
+ use WasmI64.{ (>>) as shrSWasmI64 }
2970
+ let u_ = WasmI64.reinterpretF64(x)
2971
+ let hx = WasmI32.wrapI64(shrSWasmI64(u_, 32N))
2972
+ let lx = WasmI32.wrapI64(u_)
2973
+ let u_ = WasmI64.reinterpretF64(y)
2974
+ let hy = WasmI32.wrapI64(shrSWasmI64(u_, 32N))
2975
+ let ly = WasmI32.wrapI64(u_)
2976
+ let mut ix = hx & 0x7FFFFFFFn
2977
+ let iy = hy & 0x7FFFFFFFn
2978
+ if ((iy | ly) == 0n) { // x**0 = 1, even if x is NaN
2979
+ return 1
2980
+ } else if (
2981
+ // Either Argument is Nan
2982
+ ix > 0x7FF00000n ||
2983
+ ix == 0x7FF00000n && lx != 0n ||
2984
+ iy > 0x7FF00000n ||
2985
+ iy == 0x7FF00000n && ly != 0n
2986
+ ) {
2987
+ use WasmF64.{ (+) }
2988
+ return WasmI32.toGrain(newFloat64(x + y)): Number
2989
+ }
2990
+ let mut yisint = 0n
2991
+ let mut k = 0n
2992
+ if (hx < 0n) {
2993
+ if (iy >= 0x43400000n) {
2994
+ yisint = 2n
2995
+ } else if (iy >= 0x3FF00000n) {
2996
+ k = (iy >> 20n) - 0x3FFn
2997
+ let mut offset = 0n
2998
+ let mut _ly = 0n
2999
+ if (k > 20n) {
3000
+ offset = 52n - k
3001
+ _ly = ly
3002
+ } else {
3003
+ offset = 20n - k
3004
+ _ly = iy
3005
+ }
3006
+ let jj = _ly >> offset
3007
+ if (jj << offset == _ly) yisint = 2n - (jj & 1n)
3008
+ }
3009
+ }
3010
+ if (ly == 0n) {
3011
+ if (iy == 0x7FF00000n) { // y is +- inf
3012
+ if ((ix - 0x3FF00000n | lx) == 0n) { // C: (-1)**+-inf is 1, JS: NaN
3013
+ return NaN
3014
+ } else if (ix >= 0x3FF00000n) { // (|x|>1)**+-inf = inf,0
3015
+ if (hy >= 0n)
3016
+ return WasmI32.toGrain(newFloat64(y)): Number
3017
+ else
3018
+ return 0.0
3019
+ } else { // (|x|<1)**+-inf = 0,inf
3020
+ if (hy >= 0n)
3021
+ return 0.0
3022
+ else
3023
+ return WasmI32.toGrain(newFloat64(y * -1.0W)): Number
3024
+ }
3025
+ } else if (iy == 0x3FF00000n) {
3026
+ if (hy >= 0n)
3027
+ return WasmI32.toGrain(newFloat64(x)): Number
3028
+ else
3029
+ return WasmI32.toGrain(newFloat64(1.0W / x)): Number
3030
+ } else if (hy == 0x3FE00000n) {
3031
+ return WasmI32.toGrain(newFloat64(x * x)): Number
3032
+ } else if (hy == 0x3FE00000n) {
3033
+ if (hx >= 0n) {
3034
+ return WasmI32.toGrain(newFloat64(WasmF64.sqrt(x))): Number
3035
+ }
3036
+ }
3037
+ }
3038
+ let mut ax = WasmF64.abs(x)
3039
+ let mut z = 0.0W
3040
+ if (lx == 0n && (ix == 0n || ix == 0x7FF00000n || ix == 0x3FF00000n)) {
3041
+ z = ax
3042
+ if (hy < 0n) z = 1.0W / z
3043
+ if (hx < 0n) {
3044
+ if ((ix - 0x3FF00000n | yisint) == 0n) {
3045
+ use WasmF64.{ (-) }
3046
+ let d = z - z
3047
+ z = d / d
3048
+ } else if (yisint == 1n) {
3049
+ z *= -1.0W
3050
+ }
3051
+ }
3052
+ return WasmI32.toGrain(newFloat64(z)): Number
3053
+ }
3054
+ let mut s = 1.0W
3055
+ if (hx < 0n) {
3056
+ if (yisint == 0n) {
3057
+ return NaN
3058
+ } else if (yisint == 1n) {
3059
+ s = -1.0W
3060
+ }
3061
+ }
3062
+ let mut t1 = 0.0W
3063
+ and t2 = 0.0W
3064
+ and p_h = 0.0W
3065
+ and p_l = 0.0W
3066
+ and r = 0.0W
3067
+ and t = 0.0W
3068
+ and u = 0.0W
3069
+ and v = 0.0W
3070
+ and w = 0.0W
3071
+ let mut j = 0n
3072
+ and n = 0n
3073
+ if (iy > 0x41E00000n) {
3074
+ if (iy > 0x43F00000n) {
3075
+ if (ix <= 0x3FEFFFFFn) {
3076
+ let output = if (hy < 0n) huge * huge else tiny * tiny
3077
+ return WasmI32.toGrain(newFloat64(output)): Number
3078
+ } else if (ix >= 0x3FF00000n) {
3079
+ let output = if (hy > 0n) huge * huge else tiny * tiny
3080
+ return WasmI32.toGrain(newFloat64(output)): Number
3081
+ }
3082
+ }
3083
+ if (ix < 0x3FEFFFFFn) {
3084
+ if (hy < 0n) {
3085
+ return WasmI32.toGrain(newFloat64(s * huge * huge)): Number
3086
+ } else {
3087
+ return WasmI32.toGrain(newFloat64(s * tiny * tiny)): Number
3088
+ }
3089
+ } else if (ix > 0x3FF00000n) {
3090
+ if (hy > 0n) {
3091
+ return WasmI32.toGrain(newFloat64(s * huge * huge)): Number
3092
+ } else {
3093
+ return WasmI32.toGrain(newFloat64(s * tiny * tiny)): Number
3094
+ }
3095
+ } else {
3096
+ use WasmF64.{ (-), (+) }
3097
+ use WasmI64.{ (&) }
3098
+ t = ax - 1.0W
3099
+ w = t * t * (0.5W - t * (inv3 - t * 0.25W))
3100
+ u = ivln2_h * t
3101
+ v = t * ivln2_l - w * ivln2
3102
+ t1 = u + v
3103
+ t1 = WasmF64.reinterpretI64(
3104
+ WasmI64.reinterpretF64(t1) & 0xFFFFFFFF00000000N
3105
+ )
3106
+ t2 = v - (t1 - u)
3107
+ }
3108
+ } else {
3109
+ let mut ss = 0.0W
3110
+ and s2 = 0.0W
3111
+ and s_h = 0.0W
3112
+ and s_l = 0.0W
3113
+ and t_h = 0.0W
3114
+ and t_l = 0.0W
3115
+ n = 0n
3116
+ if (ix < 0x00100000n) {
3117
+ use WasmI64.{ (>>>) }
3118
+ ax *= two53
3119
+ n -= 53n
3120
+ ix = WasmI32.wrapI64(WasmI64.reinterpretF64(ax) >>> 32N)
3121
+ }
3122
+ n += (ix >> 20n) - 0x3FFn
3123
+ j = ix & 0x000FFFFFn
3124
+ ix = j | 0x3FF00000n
3125
+ if (j <= 0x3988En) {
3126
+ k = 0n
3127
+ } else if (j < 0xBB67An) {
3128
+ k = 1n
3129
+ } else {
3130
+ k = 0n
3131
+ n += 1n
3132
+ ix -= 0x00100000n
3133
+ }
3134
+ use WasmI64.{ (&), (|), (<<) }
3135
+ ax = WasmF64.reinterpretI64(
3136
+ WasmI64.reinterpretF64(ax) & 0xFFFFFFFFN | WasmI64.extendI32S(ix) << 32N
3137
+ )
3138
+ let bp = if (k != 0n) 1.5W else 1.0W
3139
+ use WasmF64.{ (+), (-) }
3140
+ u = ax - bp
3141
+ v = 1.0W / (ax + bp)
3142
+ ss = u * v
3143
+ s_h = ss
3144
+ s_h = WasmF64.reinterpretI64(
3145
+ WasmI64.reinterpretF64(s_h) & 0xFFFFFFFF00000000N
3146
+ )
3147
+ use WasmI32.{ (+), (|), (<<) as shlWasmI64 }
3148
+ t_h = WasmF64.reinterpretI64(
3149
+ WasmI64.extendI32S(
3150
+ (ix >> 1n | 0x20000000n) + 0x00080000n + shlWasmI64(k, 18n)
3151
+ ) <<
3152
+ 32N
3153
+ )
3154
+ use WasmF64.{ (+) }
3155
+ t_l = ax - (t_h - bp)
3156
+ s_l = v * (u - s_h * t_h - s_h * t_l)
3157
+ s2 = ss * ss
3158
+ //formatter-ignore
3159
+ r = s2 * s2 * (l1 + s2 * (l2 + s2 * (l3 + s2 * (l4 + s2 * (l5 + s2 * l6)))))
3160
+ r += s_l * (s_h + ss)
3161
+ s2 = s_h * s_h
3162
+ t_h = 3.0W + s2 + r
3163
+ t_h = WasmF64.reinterpretI64(
3164
+ WasmI64.reinterpretF64(t_h) & 0xFFFFFFFF00000000N
3165
+ )
3166
+ t_l = r - (t_h - 3.0W - s2)
3167
+ u = s_h * t_h
3168
+ v = s_l * t_h + t_l * ss
3169
+ p_h = u + v
3170
+ p_h = WasmF64.reinterpretI64(
3171
+ WasmI64.reinterpretF64(p_h) & 0xFFFFFFFF00000000N
3172
+ )
3173
+ p_l = v - (p_h - u)
3174
+ let z_h = cp_h * p_h
3175
+ let dp_l = if (k != 0n) dp_l1 else 0.0W
3176
+ let z_l = cp_l * p_h + p_l * cp + dp_l
3177
+ t = WasmF64.convertI32S(n)
3178
+ let dp_h = if (k != 0n) dp_h1 else 0.0W
3179
+ t1 = z_h + z_l + dp_h + t
3180
+ t1 = WasmF64.reinterpretI64(
3181
+ WasmI64.reinterpretF64(t1) & 0xFFFFFFFF00000000N
3182
+ )
3183
+ t2 = z_l - (t1 - t - dp_h - z_h)
3184
+ }
3185
+ use WasmF64.{ (>), (-), (+) }
3186
+ use WasmI64.{ (&), (>>), (<<) }
3187
+ let y1 = WasmF64.reinterpretI64(
3188
+ WasmI64.reinterpretF64(y) & 0xFFFFFFFF00000000N
3189
+ )
3190
+ p_l = (y - y1) * t1 + y * t2
3191
+ p_h = y1 * t1
3192
+ z = p_l + p_h
3193
+ let u_ = WasmI64.reinterpretF64(z)
3194
+ let j = WasmI32.wrapI64(u_ >> 32N)
3195
+ let i = WasmI32.wrapI64(u_)
3196
+ use WasmI32.{ (-) as addWasmI32, (&) }
3197
+ if (j >= 0x40900000n) {
3198
+ if ((addWasmI32(j, 0x40900000n) | i) != 0n) {
3199
+ return WasmI32.toGrain(newFloat64(s * huge * huge)): Number
3200
+ } else if (p_l + ovt > z - p_h) {
3201
+ return WasmI32.toGrain(newFloat64(s * huge * huge)): Number
3202
+ }
3203
+ } else if ((j & 0x7FFFFFFFn) >= 0x4090CC00n) {
3204
+ use WasmF64.{ (<=) }
3205
+ if (addWasmI32(j, 0xC090CC00n | i) != 0n) {
3206
+ return WasmI32.toGrain(newFloat64(s * tiny * tiny)): Number
3207
+ } else if (p_l <= z - p_h) {
3208
+ return WasmI32.toGrain(newFloat64(s * tiny * tiny)): Number
3209
+ }
3210
+ }
3211
+ use WasmI32.{ (&), (>>), (-), (+), (>), (*), (<<), (^) }
3212
+ let i = j & 0x7FFFFFFFn
3213
+ k = (i >> 20n) - 0x3FFn
3214
+ n = 0n
3215
+ if (i > 0x3FE00000n) {
3216
+ use WasmI64.{ (<<) }
3217
+ n = j + (0x00100000n >> (k + 1n))
3218
+ k = ((n & 0x7FFFFFFFn) >> 20n) - 0x3FFn
3219
+ t = 0.0W
3220
+ t = WasmF64.reinterpretI64(
3221
+ WasmI64.extendI32S(n & (0x000FFFFFn >> k ^ -1n)) << 32N
3222
+ )
3223
+ n = (n & 0x000FFFFFn | 0x00100000n) >> (20n - k)
3224
+ if (j < 0n) n *= -1n
3225
+ use WasmF64.{ (-) }
3226
+ p_h -= t
3227
+ }
3228
+ use WasmI64.{ (&), (|) }
3229
+ use WasmF64.{ (*), (+), (-) }
3230
+ t = p_l + p_h
3231
+ t = WasmF64.reinterpretI64(WasmI64.reinterpretF64(t) & 0xFFFFFFFF00000000N)
3232
+ u = t * lg2_h
3233
+ v = (p_l - (t - p_h)) * lg2 + t * lg2_l
3234
+ z = u + v
3235
+ w = v - (z - u)
3236
+ t = z * z
3237
+ t1 = z - t * (p1 + t * (p2 + t * (p3 + t * (p4 + t * p5))))
3238
+ r = z * t1 / (t1 - 2.0W) - (w + z * w)
3239
+ z = 1.0W - (r - z)
3240
+ use WasmI32.{ (+) }
3241
+ let j = WasmI32.wrapI64(shrSWasmI64(WasmI64.reinterpretF64(z), 32N)) +
3242
+ (n << 20n)
3243
+ if (j >> 20n <= 0n) {
3244
+ z = scalbn(z, n)
3245
+ } else {
3246
+ use WasmI64.{ (<<) }
3247
+ z = WasmF64.reinterpretI64(
3248
+ WasmI64.reinterpretF64(z) & 0xFFFFFFFFN | WasmI64.extendI32S(j) << 32N
3249
+ )
3250
+ }
3251
+ return WasmI32.toGrain(newFloat64(s * z)): Number
3252
+ }
3253
+ }