@grain/stdlib 0.5.3 → 0.5.5

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 (77) hide show
  1. package/CHANGELOG.md +61 -0
  2. package/array.gr +65 -57
  3. package/array.md +54 -6
  4. package/buffer.gr +71 -1
  5. package/buffer.md +142 -0
  6. package/bytes.gr +52 -3
  7. package/bytes.md +117 -0
  8. package/char.gr +23 -20
  9. package/char.md +18 -3
  10. package/immutablemap.gr +493 -0
  11. package/immutablemap.md +479 -0
  12. package/immutablepriorityqueue.gr +44 -16
  13. package/immutablepriorityqueue.md +44 -1
  14. package/immutableset.gr +498 -0
  15. package/immutableset.md +449 -0
  16. package/int32.gr +39 -37
  17. package/int32.md +6 -0
  18. package/int64.gr +39 -37
  19. package/int64.md +6 -0
  20. package/list.gr +33 -24
  21. package/list.md +39 -10
  22. package/map.gr +19 -28
  23. package/marshal.gr +4 -4
  24. package/number.gr +727 -26
  25. package/number.md +345 -23
  26. package/option.gr +30 -26
  27. package/option.md +12 -0
  28. package/package.json +1 -1
  29. package/path.gr +787 -0
  30. package/path.md +727 -0
  31. package/pervasives.gr +3 -4
  32. package/pervasives.md +6 -1
  33. package/priorityqueue.gr +25 -5
  34. package/priorityqueue.md +30 -0
  35. package/queue.gr +22 -7
  36. package/queue.md +18 -1
  37. package/regex.gr +161 -65
  38. package/regex.md +70 -0
  39. package/result.gr +24 -20
  40. package/result.md +12 -0
  41. package/runtime/atof/common.gr +198 -0
  42. package/runtime/atof/common.md +243 -0
  43. package/runtime/atof/decimal.gr +663 -0
  44. package/runtime/atof/decimal.md +59 -0
  45. package/runtime/atof/lemire.gr +264 -0
  46. package/runtime/atof/lemire.md +6 -0
  47. package/runtime/atof/parse.gr +615 -0
  48. package/runtime/atof/parse.md +12 -0
  49. package/runtime/atof/slow.gr +238 -0
  50. package/runtime/atof/slow.md +6 -0
  51. package/runtime/atof/table.gr +2016 -0
  52. package/runtime/atof/table.md +12 -0
  53. package/runtime/{stringUtils.gr → atoi/parse.gr} +1 -1
  54. package/runtime/{stringUtils.md → atoi/parse.md} +1 -1
  55. package/runtime/bigint.gr +7 -7
  56. package/runtime/compare.gr +2 -1
  57. package/runtime/equal.gr +3 -2
  58. package/runtime/exception.gr +9 -5
  59. package/runtime/exception.md +8 -2
  60. package/runtime/gc.gr +2 -1
  61. package/runtime/malloc.gr +1 -3
  62. package/runtime/numberUtils.gr +13 -13
  63. package/runtime/numberUtils.md +6 -0
  64. package/runtime/numbers.gr +123 -39
  65. package/runtime/numbers.md +26 -0
  66. package/runtime/string.gr +4 -2
  67. package/runtime/unsafe/conv.gr +21 -41
  68. package/runtime/unsafe/conv.md +0 -3
  69. package/runtime/unsafe/printWasm.gr +4 -40
  70. package/runtime/utils/printing.gr +3 -3
  71. package/set.gr +25 -25
  72. package/stack.gr +14 -0
  73. package/stack.md +17 -0
  74. package/string.gr +313 -39
  75. package/string.md +99 -0
  76. package/sys/file.gr +1 -1
  77. package/sys/time.gr +4 -4
@@ -79,7 +79,7 @@ export let isFloat = x => {
79
79
  if (isBoxedNumber(x)) {
80
80
  let tag = WasmI32.load(x, 4n)
81
81
  WasmI32.eq(tag, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) ||
82
- WasmI32.eq(tag, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG)
82
+ WasmI32.eq(tag, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG)
83
83
  } else {
84
84
  false
85
85
  }
@@ -90,8 +90,8 @@ export let isInteger = x => {
90
90
  if (isBoxedNumber(x)) {
91
91
  let tag = WasmI32.load(x, 4n)
92
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)
93
+ WasmI32.eq(tag, Tags._GRAIN_INT64_BOXED_NUM_TAG) ||
94
+ WasmI32.eq(tag, Tags._GRAIN_BIGINT_BOXED_NUM_TAG)
95
95
  } else {
96
96
  true
97
97
  }
@@ -518,13 +518,13 @@ let isIntegerF64 = value => {
518
518
  @unsafe
519
519
  let isSafeIntegerF32 = value => {
520
520
  WasmF32.le(WasmF32.abs(value), _F32_MAX_SAFE_INTEGER) &&
521
- WasmF32.eq(WasmF32.trunc(value), value)
521
+ WasmF32.eq(WasmF32.trunc(value), value)
522
522
  }
523
523
 
524
524
  @unsafe
525
525
  let isSafeIntegerF64 = value => {
526
526
  WasmF64.le(WasmF64.abs(value), _F64_MAX_SAFE_INTEGER) &&
527
- WasmF64.eq(WasmF64.trunc(value), value)
527
+ WasmF64.eq(WasmF64.trunc(value), value)
528
528
  }
529
529
 
530
530
  /** Number-aware equality checking
@@ -564,12 +564,12 @@ let numberEqualSimpleHelp = (x, y) => {
564
564
  t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
565
565
  let yBoxedVal = boxedFloat32Number(y)
566
566
  isSafeIntegerF32(yBoxedVal) &&
567
- WasmF32.eq(WasmF32.convertI32S(xval), yBoxedVal)
567
+ WasmF32.eq(WasmF32.convertI32S(xval), yBoxedVal)
568
568
  },
569
569
  t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
570
570
  let yBoxedVal = boxedFloat64Number(y)
571
571
  isSafeIntegerF64(yBoxedVal) &&
572
- WasmF64.eq(WasmF64.convertI32S(xval), yBoxedVal)
572
+ WasmF64.eq(WasmF64.convertI32S(xval), yBoxedVal)
573
573
  },
574
574
  _ => {
575
575
  throw UnknownNumberTag
@@ -606,12 +606,12 @@ let numberEqualInt64Help = (xBoxedVal, y) => {
606
606
  t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
607
607
  let yBoxedVal = boxedFloat32Number(y)
608
608
  isSafeIntegerF32(yBoxedVal) &&
609
- WasmI64.eq(xBoxedVal, WasmI64.truncF32S(yBoxedVal))
609
+ WasmI64.eq(xBoxedVal, WasmI64.truncF32S(yBoxedVal))
610
610
  },
611
611
  t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
612
612
  let yBoxedVal = boxedFloat64Number(y)
613
613
  isSafeIntegerF64(yBoxedVal) &&
614
- WasmI64.eq(xBoxedVal, WasmI64.truncF64S(yBoxedVal))
614
+ WasmI64.eq(xBoxedVal, WasmI64.truncF64S(yBoxedVal))
615
615
  },
616
616
  _ => {
617
617
  throw UnknownNumberTag
@@ -843,14 +843,16 @@ let numberAddSubSimpleHelp = (x, y, isSub) => {
843
843
  t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => {
844
844
  let xval = WasmI64.extendI32S(xval)
845
845
  let yBoxedVal = WasmI64.extendI32S(boxedInt32Number(y))
846
- let result = if (isSub) WasmI64.sub(xval, yBoxedVal)
846
+ let result =
847
+ if (isSub) WasmI64.sub(xval, yBoxedVal)
847
848
  else WasmI64.add(xval, yBoxedVal)
848
849
  reducedInteger(result)
849
850
  },
850
851
  t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
851
852
  let yBoxedVal = boxedInt64Number(y)
852
853
  let xval64 = WasmI64.extendI32S(xval)
853
- let result = if (isSub) WasmI64.sub(xval64, yBoxedVal)
854
+ let result =
855
+ if (isSub) WasmI64.sub(xval64, yBoxedVal)
854
856
  else WasmI64.add(xval64, yBoxedVal)
855
857
  if (
856
858
  WasmI64.geS(yBoxedVal, 0N) && WasmI64.ltS(result, xval64) ||
@@ -884,7 +886,8 @@ let numberAddSubSimpleHelp = (x, y, isSub) => {
884
886
  let yDenominator = boxedRationalDenominator(y)
885
887
  let expandedXNumerator = BI.mul(xBig, yDenominator)
886
888
  Memory.decRef(xBig)
887
- let result = if (isSub) BI.sub(expandedXNumerator, yNumerator)
889
+ let result =
890
+ if (isSub) BI.sub(expandedXNumerator, yNumerator)
888
891
  else BI.add(expandedXNumerator, yNumerator)
889
892
  let ret = reducedFractionBigInt(result, yDenominator)
890
893
  Memory.decRef(expandedXNumerator)
@@ -894,14 +897,16 @@ let numberAddSubSimpleHelp = (x, y, isSub) => {
894
897
  t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
895
898
  let yBoxedVal = boxedFloat32Number(y)
896
899
  let xval = WasmF32.convertI32S(xval)
897
- let result = if (isSub) WasmF32.sub(xval, yBoxedVal)
900
+ let result =
901
+ if (isSub) WasmF32.sub(xval, yBoxedVal)
898
902
  else WasmF32.add(xval, yBoxedVal)
899
903
  newFloat32(result)
900
904
  },
901
905
  t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
902
906
  let yBoxedVal = boxedFloat64Number(y)
903
907
  let xval = WasmF64.convertI32S(xval)
904
- let result = if (isSub) WasmF64.sub(xval, yBoxedVal)
908
+ let result =
909
+ if (isSub) WasmF64.sub(xval, yBoxedVal)
905
910
  else WasmF64.add(xval, yBoxedVal)
906
911
  newFloat64(result)
907
912
  },
@@ -940,14 +945,16 @@ let numberAddSubInt64Help = (xval, y, isSub) => {
940
945
  match (yBoxedNumberTag) {
941
946
  t when WasmI32.eq(t, Tags._GRAIN_INT32_BOXED_NUM_TAG) => {
942
947
  let yBoxedVal = WasmI64.extendI32S(boxedInt32Number(y))
943
- let result = if (isSub) WasmI64.sub(xval, yBoxedVal)
948
+ let result =
949
+ if (isSub) WasmI64.sub(xval, yBoxedVal)
944
950
  else WasmI64.add(xval, yBoxedVal)
945
951
  reducedInteger(result)
946
952
  },
947
953
  t when WasmI32.eq(t, Tags._GRAIN_INT64_BOXED_NUM_TAG) => {
948
954
  let yBoxedVal = boxedInt64Number(y)
949
955
  let xval64 = xval
950
- let result = if (isSub) WasmI64.sub(xval64, yBoxedVal)
956
+ let result =
957
+ if (isSub) WasmI64.sub(xval64, yBoxedVal)
951
958
  else WasmI64.add(xval64, yBoxedVal)
952
959
  if (
953
960
  WasmI64.geS(yBoxedVal, 0N) && WasmI64.ltS(result, xval64) ||
@@ -981,7 +988,8 @@ let numberAddSubInt64Help = (xval, y, isSub) => {
981
988
  let yDenominator = boxedRationalDenominator(y)
982
989
  let expandedXNumerator = BI.mul(xBig, yDenominator)
983
990
  Memory.decRef(xBig)
984
- let result = if (isSub) BI.sub(expandedXNumerator, yNumerator)
991
+ let result =
992
+ if (isSub) BI.sub(expandedXNumerator, yNumerator)
985
993
  else BI.add(expandedXNumerator, yNumerator)
986
994
  let ret = reducedFractionBigInt(result, yDenominator)
987
995
  Memory.decRef(expandedXNumerator)
@@ -991,14 +999,16 @@ let numberAddSubInt64Help = (xval, y, isSub) => {
991
999
  t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
992
1000
  let xval = WasmF32.convertI64S(xval)
993
1001
  let yBoxedVal = boxedFloat32Number(y)
994
- let result = if (isSub) WasmF32.sub(xval, yBoxedVal)
1002
+ let result =
1003
+ if (isSub) WasmF32.sub(xval, yBoxedVal)
995
1004
  else WasmF32.add(xval, yBoxedVal)
996
1005
  newFloat32(result)
997
1006
  },
998
1007
  t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
999
1008
  let xval = WasmF64.convertI64S(xval)
1000
1009
  let yBoxedVal = boxedFloat64Number(y)
1001
- let result = if (isSub) WasmF64.sub(xval, yBoxedVal)
1010
+ let result =
1011
+ if (isSub) WasmF64.sub(xval, yBoxedVal)
1002
1012
  else WasmF64.add(xval, yBoxedVal)
1003
1013
  newFloat64(result)
1004
1014
  },
@@ -1092,7 +1102,8 @@ let numberAddSubBigIntHelp = (x, y, isSub) => {
1092
1102
  let yNumerator = boxedRationalNumerator(y)
1093
1103
  let yDenominator = boxedRationalDenominator(y)
1094
1104
  let expandedXNumerator = BI.mul(x, yDenominator)
1095
- let result = if (isSub) BI.sub(expandedXNumerator, yNumerator)
1105
+ let result =
1106
+ if (isSub) BI.sub(expandedXNumerator, yNumerator)
1096
1107
  else BI.add(expandedXNumerator, yNumerator)
1097
1108
  Memory.decRef(expandedXNumerator)
1098
1109
  let ret = reducedFractionBigInt(result, yDenominator)
@@ -1102,14 +1113,16 @@ let numberAddSubBigIntHelp = (x, y, isSub) => {
1102
1113
  t when WasmI32.eq(t, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG) => {
1103
1114
  let xval = BI.toFloat32(x)
1104
1115
  let yBoxedVal = boxedFloat32Number(y)
1105
- let result = if (isSub) WasmF32.sub(xval, yBoxedVal)
1116
+ let result =
1117
+ if (isSub) WasmF32.sub(xval, yBoxedVal)
1106
1118
  else WasmF32.add(xval, yBoxedVal)
1107
1119
  newFloat32(result)
1108
1120
  },
1109
1121
  t when WasmI32.eq(t, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG) => {
1110
1122
  let xval = BI.toFloat64(x)
1111
1123
  let yBoxedVal = boxedFloat64Number(y)
1112
- let result = if (isSub) WasmF64.sub(xval, yBoxedVal)
1124
+ let result =
1125
+ if (isSub) WasmF64.sub(xval, yBoxedVal)
1113
1126
  else WasmF64.add(xval, yBoxedVal)
1114
1127
  newFloat64(result)
1115
1128
  },
@@ -1128,7 +1141,8 @@ let numberAddSubRationalHelp = (x, y, isSub) => {
1128
1141
  let yval = untagSimple(y)
1129
1142
  let yBig = BI.makeWrappedInt32(yval)
1130
1143
  let expandedYNumerator = BI.mul(xDenominator, yBig)
1131
- let result = if (isSub) BI.sub(xNumerator, expandedYNumerator)
1144
+ let result =
1145
+ if (isSub) BI.sub(xNumerator, expandedYNumerator)
1132
1146
  else BI.add(xNumerator, expandedYNumerator)
1133
1147
  Memory.decRef(expandedYNumerator)
1134
1148
  Memory.decRef(yBig)
@@ -1145,7 +1159,8 @@ let numberAddSubRationalHelp = (x, y, isSub) => {
1145
1159
  let yNumerator = boxedRationalNumerator(y)
1146
1160
  let yDenominator = boxedRationalDenominator(y)
1147
1161
  if (BI.eq(xDenominator, yDenominator)) {
1148
- let newNumerator = if (isSub) BI.sub(xNumerator, yNumerator)
1162
+ let newNumerator =
1163
+ if (isSub) BI.sub(xNumerator, yNumerator)
1149
1164
  else BI.add(xNumerator, yNumerator)
1150
1165
  let ret = reducedFractionBigInt(newNumerator, xDenominator)
1151
1166
  Memory.decRef(newNumerator)
@@ -1153,7 +1168,8 @@ let numberAddSubRationalHelp = (x, y, isSub) => {
1153
1168
  } else {
1154
1169
  let numerator1 = BI.mul(xNumerator, yDenominator)
1155
1170
  let numerator2 = BI.mul(yNumerator, xDenominator)
1156
- let numerator = if (isSub) BI.sub(numerator1, numerator2)
1171
+ let numerator =
1172
+ if (isSub) BI.sub(numerator1, numerator2)
1157
1173
  else BI.add(numerator1, numerator2)
1158
1174
  let denominator = BI.mul(xDenominator, yDenominator)
1159
1175
  let ret = reducedFractionBigInt(numerator, denominator)
@@ -1167,7 +1183,8 @@ let numberAddSubRationalHelp = (x, y, isSub) => {
1167
1183
  let yBig = BI.makeWrappedInt32(boxedInt32Number(y))
1168
1184
  let expandedYNumerator = BI.mul(yBig, xDenominator)
1169
1185
  Memory.decRef(yBig)
1170
- let result = if (isSub) BI.sub(xNumerator, expandedYNumerator)
1186
+ let result =
1187
+ if (isSub) BI.sub(xNumerator, expandedYNumerator)
1171
1188
  else BI.add(xNumerator, expandedYNumerator)
1172
1189
  let ret = reducedFractionBigInt(result, xDenominator)
1173
1190
  Memory.decRef(expandedYNumerator)
@@ -1178,7 +1195,8 @@ let numberAddSubRationalHelp = (x, y, isSub) => {
1178
1195
  let yBig = BI.makeWrappedInt64(boxedInt64Number(y))
1179
1196
  let expandedYNumerator = BI.mul(yBig, xDenominator)
1180
1197
  Memory.decRef(yBig)
1181
- let result = if (isSub) BI.sub(xNumerator, expandedYNumerator)
1198
+ let result =
1199
+ if (isSub) BI.sub(xNumerator, expandedYNumerator)
1182
1200
  else BI.add(xNumerator, expandedYNumerator)
1183
1201
  let ret = reducedFractionBigInt(result, xDenominator)
1184
1202
  Memory.decRef(expandedYNumerator)
@@ -1187,7 +1205,8 @@ let numberAddSubRationalHelp = (x, y, isSub) => {
1187
1205
  },
1188
1206
  t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
1189
1207
  let expandedYNumerator = BI.mul(xDenominator, y)
1190
- let result = if (isSub) BI.sub(xNumerator, expandedYNumerator)
1208
+ let result =
1209
+ if (isSub) BI.sub(xNumerator, expandedYNumerator)
1191
1210
  else BI.add(xNumerator, expandedYNumerator)
1192
1211
  Memory.decRef(expandedYNumerator)
1193
1212
  let ret = reducedFractionBigInt(result, xDenominator)
@@ -1199,7 +1218,8 @@ let numberAddSubRationalHelp = (x, y, isSub) => {
1199
1218
  BI.toFloat32(xNumerator),
1200
1219
  BI.toFloat32(xDenominator)
1201
1220
  )
1202
- let result = if (isSub) WasmF32.sub(xval, boxedFloat32Number(y))
1221
+ let result =
1222
+ if (isSub) WasmF32.sub(xval, boxedFloat32Number(y))
1203
1223
  else WasmF32.add(xval, boxedFloat32Number(y))
1204
1224
  newFloat32(result)
1205
1225
  },
@@ -1208,8 +1228,8 @@ let numberAddSubRationalHelp = (x, y, isSub) => {
1208
1228
  let xdenfloat = BI.toFloat64(xDenominator)
1209
1229
  let xval = WasmF64.div(xnumfloat, xdenfloat)
1210
1230
  let yval = boxedFloat64Number(y)
1211
- let result = if (isSub) WasmF64.sub(xval, yval)
1212
- else WasmF64.add(xval, yval)
1231
+ let result =
1232
+ if (isSub) WasmF64.sub(xval, yval) else WasmF64.add(xval, yval)
1213
1233
  let ret = newFloat64(result)
1214
1234
  ret
1215
1235
  },
@@ -1404,6 +1424,13 @@ let numberTimesDivideBigIntHelp = (x, y, isDivide) => {
1404
1424
  Memory.decRef(yBig)
1405
1425
  ret
1406
1426
  },
1427
+ t when WasmI32.eq(t, Tags._GRAIN_BIGINT_BOXED_NUM_TAG) => {
1428
+ if (isDivide) {
1429
+ reducedFractionBigInt(x, y)
1430
+ } else {
1431
+ reducedBigInteger(BI.mul(x, y))
1432
+ }
1433
+ },
1407
1434
  t when WasmI32.eq(t, Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) => {
1408
1435
  let yNumerator = boxedRationalNumerator(y)
1409
1436
  let yDenominator = boxedRationalDenominator(y)
@@ -1548,9 +1575,11 @@ let numberTimesDivideRationalHelp = (x, y, isDivide) => {
1548
1575
  let yDenominator = boxedRationalDenominator(y)
1549
1576
  // (a / b) * (c / d) == (a * c) / (b * d)
1550
1577
  // (a / b) / (c / d) == (a * d) / (b * c)
1551
- let numerator = if (isDivide) BI.mul(xNumerator, yDenominator)
1578
+ let numerator =
1579
+ if (isDivide) BI.mul(xNumerator, yDenominator)
1552
1580
  else BI.mul(xNumerator, yNumerator)
1553
- let denominator = if (isDivide) BI.mul(xDenominator, yNumerator)
1581
+ let denominator =
1582
+ if (isDivide) BI.mul(xDenominator, yNumerator)
1554
1583
  else BI.mul(xDenominator, yDenominator)
1555
1584
  reducedFractionBigInt(numerator, denominator)
1556
1585
  },
@@ -1686,7 +1715,8 @@ let numberMod = (x, y) => {
1686
1715
  WasmI64.gtS(xval, 0N) && WasmI64.ltS(yval, 0N)
1687
1716
  ) {
1688
1717
  let modval = WasmI64.remS(i64abs(xval), i64abs(yval))
1689
- let result = if (WasmI64.ne(modval, 0N))
1718
+ let result =
1719
+ if (WasmI64.ne(modval, 0N))
1690
1720
  WasmI64.mul(
1691
1721
  WasmI64.sub(i64abs(yval), modval),
1692
1722
  if (WasmI64.ltS(yval, 0N)) -1N else 1N
@@ -1702,9 +1732,9 @@ let numberMod = (x, y) => {
1702
1732
  * Int/int and float/float comparisons are always accurate.
1703
1733
  * Rational/rational comparisons are approximations with the exception of
1704
1734
  * equality, which is always accurate.
1705
- *
1735
+ *
1706
1736
  * Values compared to floats or rationals are first converted to floats.
1707
- *
1737
+ *
1708
1738
  * All comparison operators consider NaN not equal to, less than, or greater
1709
1739
  * than NaN, with the exception of `compare`, which considers NaN equal to
1710
1740
  * itself and otherwise smaller than any other float value. This provides a
@@ -2190,7 +2220,7 @@ export let (>>) = (x: Number, y: Number) => {
2190
2220
  // we will fail if attempting to coerce to an int!
2191
2221
 
2192
2222
  @unsafe
2193
- export let rec coerceNumberToInt32 = (x: Number) => {
2223
+ export let coerceNumberToInt32 = (x: Number) => {
2194
2224
  let x = WasmI32.fromGrain(x)
2195
2225
  let result = if (
2196
2226
  !isSimpleNumber(x) &&
@@ -2209,7 +2239,7 @@ export let rec coerceNumberToInt32 = (x: Number) => {
2209
2239
  }
2210
2240
 
2211
2241
  @unsafe
2212
- export let rec coerceNumberToInt64 = (x: Number) => {
2242
+ export let coerceNumberToInt64 = (x: Number) => {
2213
2243
  let x = WasmI32.fromGrain(x)
2214
2244
  let result = if (
2215
2245
  !isSimpleNumber(x) &&
@@ -2227,7 +2257,7 @@ export let rec coerceNumberToInt64 = (x: Number) => {
2227
2257
  }
2228
2258
 
2229
2259
  @unsafe
2230
- export let rec coerceNumberToBigInt = (x: Number) => {
2260
+ export let coerceNumberToBigInt = (x: Number) => {
2231
2261
  let x = WasmI32.fromGrain(x)
2232
2262
  let result = if (isBigInt(x)) {
2233
2263
  // avoid extra malloc and prevent x from being freed
@@ -2459,3 +2489,57 @@ export let isBigInt = x => {
2459
2489
  let x = WasmI32.fromGrain(x)
2460
2490
  isBigInt(x)
2461
2491
  }
2492
+
2493
+ // Scalbn is based on https://git.musl-libc.org/cgit/musl/tree/src/math/scalbn.c
2494
+ /*
2495
+ * ====================================================
2496
+ * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved.
2497
+ *
2498
+ * Permission to use, copy, modify, and distribute this
2499
+ * software is freely granted, provided that this notice
2500
+ * is preserved.
2501
+ * ====================================================
2502
+ */
2503
+ /**
2504
+ * Multiplies a floating-point number by an integral power of 2.
2505
+ *
2506
+ * @param x: The floating-point value
2507
+ * @param n: The Integer exponent
2508
+ * @returns The result of x * 2^n
2509
+ *
2510
+ * @since v0.5.4
2511
+ */
2512
+ @unsafe
2513
+ export let scalbn = (x, n) => {
2514
+ let (>) = WasmI32.gtS
2515
+ let (<) = WasmI32.ltS
2516
+ let (*) = WasmF64.mul
2517
+ let (-) = WasmI32.sub
2518
+ let (+) = WasmI32.add
2519
+ let (<<) = WasmI64.shl
2520
+ // Constants
2521
+ let const_0x1p1023 = 8.98847e+307W
2522
+ let const_0x1p_1022 = 2.22507e-308W
2523
+ let const_0x1p53 = 9.0072e+15W
2524
+ let mut n = n
2525
+ let mut y = x
2526
+ if (n > 1023n) {
2527
+ y *= const_0x1p1023
2528
+ n -= 1023n
2529
+ if (n > 1023n) {
2530
+ y *= const_0x1p1023
2531
+ n -= 1023n
2532
+ if (n > 1023n) n = 1023n
2533
+ } else if (n < -1023n) {
2534
+ /* make sure final n < -53 to avoid double rounding in the subnormal range */
2535
+ y *= const_0x1p_1022 * const_0x1p53
2536
+ n += 1022n - 53n
2537
+ if (n < -1022n) {
2538
+ y *= const_0x1p_1022 * const_0x1p53
2539
+ n += 1022n - 53n
2540
+ if (n < -1022n) n = -1022n
2541
+ }
2542
+ }
2543
+ }
2544
+ y * WasmF64.reinterpretI64(WasmI64.extendI32S(0x3FFn + n) << 52N)
2545
+ }
@@ -322,3 +322,29 @@ decr : Number -> Number
322
322
  isBigInt : a -> Bool
323
323
  ```
324
324
 
325
+ ### Numbers.**scalbn**
326
+
327
+ <details disabled>
328
+ <summary tabindex="-1">Added in <code>0.5.4</code></summary>
329
+ No other changes yet.
330
+ </details>
331
+
332
+ ```grain
333
+ scalbn : (WasmF64, WasmI32) -> WasmF64
334
+ ```
335
+
336
+ Multiplies a floating-point number by an integral power of 2.
337
+
338
+ Parameters:
339
+
340
+ |param|type|description|
341
+ |-----|----|-----------|
342
+ |`x`|`WasmF64`|The floating-point value|
343
+ |`n`|`WasmI32`|The Integer exponent|
344
+
345
+ Returns:
346
+
347
+ |type|description|
348
+ |----|-----------|
349
+ |`WasmF64`|The result of x * 2^n|
350
+
package/runtime/string.gr CHANGED
@@ -547,7 +547,8 @@ let rec heapValueToString = (ptr, extraIndents, toplevel) => {
547
547
  join(strings)
548
548
  },
549
549
  }
550
- }, toStringHelp = (grainValue, extraIndents, toplevel) => {
550
+ },
551
+ toStringHelp = (grainValue, extraIndents, toplevel) => {
551
552
  if ((grainValue & 1n) != 0n) {
552
553
  // Simple (unboxed) numbers
553
554
  NumberUtils.itoa32(grainValue >> 1n, 10n)
@@ -572,7 +573,8 @@ let rec heapValueToString = (ptr, extraIndents, toplevel) => {
572
573
  "<unknown value>"
573
574
  }
574
575
  }
575
- }, listToString = (ptr, extraIndents) => {
576
+ },
577
+ listToString = (ptr, extraIndents) => {
576
578
  let mut cur = ptr
577
579
  let mut isFirst = true
578
580
 
@@ -1,69 +1,53 @@
1
- import Memory from "runtime/unsafe/memory"
2
1
  import WasmI32 from "runtime/unsafe/wasmi32"
3
2
  import WasmI64 from "runtime/unsafe/wasmi64"
4
3
  import WasmF32 from "runtime/unsafe/wasmf32"
5
4
  import WasmF64 from "runtime/unsafe/wasmf64"
6
- import Tags from "runtime/unsafe/tags"
7
-
8
- @disableGC
5
+ import {
6
+ newInt32,
7
+ newInt64,
8
+ newFloat32,
9
+ newFloat64,
10
+ } from "runtime/dataStructures"
11
+
12
+ @unsafe
9
13
  export let toInt32 = n => {
10
- let ptr = Memory.malloc(12n)
11
- WasmI32.store(ptr, Tags._GRAIN_BOXED_NUM_HEAP_TAG, 0n)
12
- WasmI32.store(ptr, Tags._GRAIN_INT32_BOXED_NUM_TAG, 4n)
13
- WasmI32.store(ptr, n, 8n)
14
-
15
- WasmI32.toGrain(ptr): Int32
14
+ WasmI32.toGrain(newInt32(n)): Int32
16
15
  }
17
16
 
18
- @disableGC
17
+ @unsafe
19
18
  export let fromInt32 = (n: Int32) => {
20
19
  let ptr = WasmI32.fromGrain(n)
21
20
  WasmI32.load(ptr, 8n)
22
21
  }
23
22
 
24
- @disableGC
23
+ @unsafe
25
24
  export let toInt64 = n => {
26
- let ptr = Memory.malloc(16n)
27
- WasmI32.store(ptr, Tags._GRAIN_BOXED_NUM_HEAP_TAG, 0n)
28
- WasmI32.store(ptr, Tags._GRAIN_INT64_BOXED_NUM_TAG, 4n)
29
- WasmI64.store(ptr, n, 8n)
30
-
31
- WasmI32.toGrain(ptr): Int64
25
+ WasmI32.toGrain(newInt64(n)): Int64
32
26
  }
33
27
 
34
- @disableGC
28
+ @unsafe
35
29
  export let fromInt64 = (n: Int64) => {
36
30
  let ptr = WasmI32.fromGrain(n)
37
31
  WasmI64.load(ptr, 8n)
38
32
  }
39
33
 
40
- @disableGC
34
+ @unsafe
41
35
  export let toFloat32 = n => {
42
- let ptr = Memory.malloc(12n)
43
- WasmI32.store(ptr, Tags._GRAIN_BOXED_NUM_HEAP_TAG, 0n)
44
- WasmI32.store(ptr, Tags._GRAIN_FLOAT32_BOXED_NUM_TAG, 4n)
45
- WasmF32.store(ptr, n, 8n)
46
-
47
- WasmI32.toGrain(ptr): Float32
36
+ WasmI32.toGrain(newFloat32(n)): Float32
48
37
  }
49
38
 
50
- @disableGC
39
+ @unsafe
51
40
  export let fromFloat32 = (n: Float32) => {
52
41
  let ptr = WasmI32.fromGrain(n)
53
42
  WasmF32.load(ptr, 8n)
54
43
  }
55
44
 
56
- @disableGC
45
+ @unsafe
57
46
  export let toFloat64 = n => {
58
- let ptr = Memory.malloc(16n)
59
- WasmI32.store(ptr, Tags._GRAIN_BOXED_NUM_HEAP_TAG, 0n)
60
- WasmI32.store(ptr, Tags._GRAIN_FLOAT64_BOXED_NUM_TAG, 4n)
61
- WasmF64.store(ptr, n, 8n)
62
-
63
- WasmI32.toGrain(ptr): Float64
47
+ WasmI32.toGrain(newFloat64(n)): Float64
64
48
  }
65
49
 
66
- @disableGC
50
+ @unsafe
67
51
  export let fromFloat64 = (n: Float64) => {
68
52
  let ptr = WasmI32.fromGrain(n)
69
53
  WasmF64.load(ptr, 8n)
@@ -72,13 +56,10 @@ export let fromFloat64 = (n: Float64) => {
72
56
  /**
73
57
  * Converts a WasmI32 value to Number.
74
58
  *
75
- * This function is meant to be called from a `@disableGC` context without
76
- * need to call incRef on the function.
77
- *
78
59
  * @param n: The WasmI32 to convert
79
60
  * @returns The value converted to either a simple or a 32 bit heap allocated number.
80
61
  */
81
- @disableGC
62
+ @unsafe
82
63
  export let wasmI32ToNumber = (n: WasmI32) => {
83
64
  // Follows a little optimization. Instead of testing if n is range of allowed
84
65
  // non heap allocated simple numbers (-1073741824n..1073741823n), actually
@@ -106,8 +87,7 @@ export let wasmI32ToNumber = (n: WasmI32) => {
106
87
  // If it did overflow, then the value differs and we need to discard it and
107
88
  // allocate the number on the heap. A boxed 32 bit number actually is the
108
89
  // same thing as an Int32. It only needs to be cast into Number.
109
- let asInt32 = toInt32(n)
110
- WasmI32.toGrain(WasmI32.fromGrain(asInt32)): Number
90
+ WasmI32.toGrain(newInt32(n)): Number
111
91
  }
112
92
  result
113
93
  }
@@ -54,9 +54,6 @@ wasmI32ToNumber : WasmI32 -> Number
54
54
 
55
55
  Converts a WasmI32 value to Number.
56
56
 
57
- This function is meant to be called from a `@disableGC` context without
58
- need to call incRef on the function.
59
-
60
57
  Parameters:
61
58
 
62
59
  |param|type|description|
@@ -4,74 +4,38 @@ import Memory from "runtime/unsafe/memory"
4
4
 
5
5
  // [FIXME] These all leak ATM (grain-lang/grain#791)
6
6
 
7
- @disableGC
7
+ @unsafe
8
8
  export let printI32 = val => {
9
- Memory.incRef(WasmI32.fromGrain(print))
10
- Memory.incRef(WasmI32.fromGrain(toString))
11
9
  let conv = Conv.toInt32(val)
12
- Memory.incRef(WasmI32.fromGrain(conv))
13
- Memory.incRef(WasmI32.fromGrain(toString))
14
10
  let s1 = toString(conv)
15
11
  let s2 = "n"
16
- Memory.incRef(WasmI32.fromGrain(s1))
17
- Memory.incRef(WasmI32.fromGrain(s2))
18
- Memory.incRef(WasmI32.fromGrain((++)))
19
12
  let s = s1 ++ s2
20
- Memory.incRef(WasmI32.fromGrain(print))
21
- Memory.incRef(WasmI32.fromGrain(s))
22
13
  print(s)
23
14
  }
24
15
 
25
- @disableGC
16
+ @unsafe
26
17
  export let printI64 = val => {
27
- Memory.incRef(WasmI32.fromGrain(print))
28
- Memory.incRef(WasmI32.fromGrain(toString))
29
18
  let conv = Conv.toInt64(val)
30
- Memory.incRef(WasmI32.fromGrain(conv))
31
- Memory.incRef(WasmI32.fromGrain(toString))
32
19
  let s1 = toString(conv)
33
20
  let s2 = "N"
34
- Memory.incRef(WasmI32.fromGrain(s1))
35
- Memory.incRef(WasmI32.fromGrain(s2))
36
- Memory.incRef(WasmI32.fromGrain((++)))
37
21
  let s = s1 ++ s2
38
- Memory.incRef(WasmI32.fromGrain(print))
39
- Memory.incRef(WasmI32.fromGrain(s))
40
22
  print(s)
41
23
  }
42
24
 
43
- @disableGC
25
+ @unsafe
44
26
  export let printF32 = val => {
45
- Memory.incRef(WasmI32.fromGrain(print))
46
- Memory.incRef(WasmI32.fromGrain(toString))
47
27
  let conv = Conv.toFloat32(val)
48
- Memory.incRef(WasmI32.fromGrain(conv))
49
- Memory.incRef(WasmI32.fromGrain(toString))
50
28
  let s1 = toString(conv)
51
29
  let s2 = "w"
52
- Memory.incRef(WasmI32.fromGrain(s1))
53
- Memory.incRef(WasmI32.fromGrain(s2))
54
- Memory.incRef(WasmI32.fromGrain((++)))
55
30
  let s = s1 ++ s2
56
- Memory.incRef(WasmI32.fromGrain(print))
57
- Memory.incRef(WasmI32.fromGrain(s))
58
31
  print(s)
59
32
  }
60
33
 
61
- @disableGC
34
+ @unsafe
62
35
  export let printF64 = val => {
63
- Memory.incRef(WasmI32.fromGrain(print))
64
- Memory.incRef(WasmI32.fromGrain(toString))
65
36
  let conv = Conv.toFloat64(val)
66
- Memory.incRef(WasmI32.fromGrain(conv))
67
- Memory.incRef(WasmI32.fromGrain(toString))
68
37
  let s1 = toString(conv)
69
38
  let s2 = "W"
70
- Memory.incRef(WasmI32.fromGrain(s1))
71
- Memory.incRef(WasmI32.fromGrain(s2))
72
- Memory.incRef(WasmI32.fromGrain((++)))
73
39
  let s = s1 ++ s2
74
- Memory.incRef(WasmI32.fromGrain(print))
75
- Memory.incRef(WasmI32.fromGrain(s))
76
40
  print(s)
77
41
  }
@@ -12,12 +12,12 @@ import foreign wasm fd_write: (
12
12
  ) -> WasmI32 from "wasi_snapshot_preview1"
13
13
 
14
14
  @unsafe
15
- export let rec numberToString = (n: WasmI64) => {
15
+ export let numberToString = (n: WasmI64) => {
16
16
  NumberUtils.itoa64(n, 10n)
17
17
  }
18
18
 
19
19
  @unsafe
20
- export let rec printNumber = (n: WasmI64) => {
20
+ export let printNumber = (n: WasmI64) => {
21
21
  // like print(), but `s` should be a Grain string
22
22
  let (+) = WasmI32.add
23
23
  let s = numberToString(n)
@@ -40,7 +40,7 @@ export let rec printNumber = (n: WasmI64) => {
40
40
  }
41
41
 
42
42
  @unsafe
43
- export let rec printString = (s: String) => {
43
+ export let printString = (s: String) => {
44
44
  // like print(), but `s` should be a Grain string
45
45
  let (+) = WasmI32.add
46
46
  let ptr = WasmI32.fromGrain(s)