@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
package/list.gr CHANGED
@@ -230,10 +230,12 @@ export let rec flatMap = (fn, list) => {
230
230
  *
231
231
  * @since v0.1.0
232
232
  */
233
- export let every = (fn, list) => {
234
- reduce((acc, value) => {
235
- acc && fn(value)
236
- }, true, list)
233
+ export let rec every = (fn, list) => {
234
+ match (list) {
235
+ [] => true,
236
+ // The short-circuiting of `&&` makes this tail-recursive
237
+ [first, ...rest] => fn(first) && every(fn, rest),
238
+ }
237
239
  }
238
240
 
239
241
  /**
@@ -246,10 +248,12 @@ export let every = (fn, list) => {
246
248
  *
247
249
  * @since v0.1.0
248
250
  */
249
- export let some = (fn, list) => {
250
- reduce((acc, value) => {
251
- acc || fn(value)
252
- }, false, list)
251
+ export let rec some = (fn, list) => {
252
+ match (list) {
253
+ [] => false,
254
+ // The short-circuiting of `||` makes this tail-recursive
255
+ [first, ...rest] => fn(first) || some(fn, rest),
256
+ }
253
257
  }
254
258
 
255
259
  /**
@@ -433,13 +437,15 @@ export let rec flatten = list => {
433
437
 
434
438
  /**
435
439
  * Inserts a new value into a list at the specified index.
436
- * Fails if the index is out-of-bounds.
437
440
  *
438
441
  * @param value: The value to insert
439
442
  * @param index: The index to update
440
443
  * @param list: The list to update
441
444
  * @returns The new list
442
445
  *
446
+ * @throws Failure(String): When `index` is negative
447
+ * @throws Failure(String): When `index` is more than 0 and greater than the list size
448
+ *
443
449
  * @since v0.1.0
444
450
  */
445
451
  export let rec insert = (value, index, list) => {
@@ -477,12 +483,14 @@ export let count = (fn, list) => {
477
483
 
478
484
  /**
479
485
  * Split a list into two, with the first list containing the required number of elements.
480
- * Fails if the input list doesn't contain at least the required amount of elements.
481
486
  *
482
487
  * @param count: The number of elements required
483
488
  * @param list: The list to split
484
489
  * @returns Two lists where the first contains exactly the required amount of elements and the second contains any remaining elements
485
490
  *
491
+ * @throws Failure(String): When `count` is negative
492
+ * @throws Failure(String): When the list doesn't contain at least the required amount of elements
493
+ *
486
494
  * @since v0.1.0
487
495
  */
488
496
  export let part = (count, list) => {
@@ -509,19 +517,19 @@ export let part = (count, list) => {
509
517
  * If value is negative, list elements will be rotated by the
510
518
  * specified amount to the right. See examples.
511
519
  *
512
- * Fails if the input list doesn't contain at least the required amount of elements.
513
- *
514
520
  * @param count: The number of elements to rotate by
515
521
  * @param list: The list to be rotated
516
522
  *
517
523
  * @example List.rotate(2, [1, 2, 3, 4, 5]) // [3, 4, 5, 1, 2]
518
524
  * @example List.rotate(-1, [1, 2, 3, 4, 5]) // [5, 1, 2, 3, 4]
519
525
  *
526
+ * @throws Failure(String): When the list doesn't contain at least the required amount of elements
527
+ *
520
528
  * @since v0.1.0
521
529
  */
522
530
  export let rotate = (count, list) => {
523
- let (beginning, end) = if (count >= 0) part(count, list)
524
- else part(length(list) + count, list)
531
+ let (beginning, end) =
532
+ if (count >= 0) part(count, list) else part(length(list) + count, list)
525
533
  append(end, beginning)
526
534
  }
527
535
 
@@ -552,7 +560,7 @@ export let unique = list => {
552
560
  * Produces a new list filled with tuples of elements from both given lists.
553
561
  * The first tuple will contain the first item of each list, the second tuple
554
562
  * will contain the second item of each list, and so on.
555
- *
563
+ *
556
564
  * Calling this function with lists of different sizes will cause the returned
557
565
  * list to have the length of the smaller list.
558
566
  *
@@ -562,7 +570,7 @@ export let unique = list => {
562
570
  *
563
571
  * @example List.zip([1, 2, 3], [4, 5, 6]) // [(1, 4), (2, 5), (3, 6)]
564
572
  * @example List.zip([1, 2, 3], [4, 5]) // [(1, 4), (2, 5)]
565
- *
573
+ *
566
574
  * @since v0.5.3
567
575
  */
568
576
  export let zip = (list1, list2) => {
@@ -582,7 +590,7 @@ export let zip = (list1, list2) => {
582
590
  * applying the function to the first elements of each list, the second element
583
591
  * will contain the result of applying the function to the second elements of
584
592
  * each list, and so on.
585
- *
593
+ *
586
594
  * Calling this function with lists of different sizes will cause the returned
587
595
  * list to have the length of the smaller list.
588
596
  *
@@ -593,7 +601,7 @@ export let zip = (list1, list2) => {
593
601
  *
594
602
  * @example List.zipWith((a, b) => a + b, [1, 2, 3], [4, 5, 6]) // [5, 7, 9]
595
603
  * @example List.zipWith((a, b) => a * b, [1, 2, 3], [4, 5]) // [4, 10]
596
- *
604
+ *
597
605
  * @since v0.5.3
598
606
  */
599
607
  export let zipWith = (fn, list1, list2) => {
@@ -625,12 +633,12 @@ export let unzip = list => {
625
633
  * Produces a new list with the specified number of elements removed from
626
634
  * the beginning of the input list.
627
635
  *
628
- * Fails if the specified amount is a negative number.
629
- *
630
636
  * @param count: The amount of elements to remove
631
637
  * @param list: The input list
632
638
  * @returns The new list without the dropped elements
633
639
  *
640
+ * @throws Failure(String): When `count` is negative
641
+ *
634
642
  * @since v0.2.0
635
643
  */
636
644
  export let rec drop = (count, list) => {
@@ -667,12 +675,12 @@ export let rec dropWhile = (fn, list) => {
667
675
  * Produces a new list with–at most—the specified amount elements from
668
676
  * the beginning of the input list.
669
677
  *
670
- * Fails if the specified amount is a negative number.
671
- *
672
678
  * @param count: The amount of elements to keep
673
679
  * @param list: The input list
674
680
  * @returns The new list containing the taken elements
675
681
  *
682
+ * @throws Failure(String): When `count` is negative
683
+ *
676
684
  * @since v0.2.0
677
685
  */
678
686
  export let rec take = (count, list) => {
@@ -769,13 +777,14 @@ export let product = (list1, list2) => {
769
777
  * Provides the subset of a list given zero-based start index and amount of elements
770
778
  * to include.
771
779
  *
772
- * Fails if the start index or amount of elements are negative numbers.
773
- *
774
780
  * @param start: The index of the list where the subset will begin (inclusive)
775
781
  * @param length: The amount of elements to be included in the subset
776
782
  * @param list: The input list
777
783
  * @returns The subset of the list
778
784
  *
785
+ * @throws Failure(String): When `start` is negative
786
+ * @throws Failure(String): When `length` is negative
787
+ *
779
788
  * @since v0.2.0
780
789
  */
781
790
  export let sub = (start, length, list) => {
package/list.md CHANGED
@@ -674,7 +674,6 @@ insert : (a, Number, List<a>) -> List<a>
674
674
  ```
675
675
 
676
676
  Inserts a new value into a list at the specified index.
677
- Fails if the index is out-of-bounds.
678
677
 
679
678
  Parameters:
680
679
 
@@ -690,6 +689,13 @@ Returns:
690
689
  |----|-----------|
691
690
  |`List<a>`|The new list|
692
691
 
692
+ Throws:
693
+
694
+ `Failure(String)`
695
+
696
+ * When `index` is negative
697
+ * When `index` is more than 0 and greater than the list size
698
+
693
699
  ### List.**count**
694
700
 
695
701
  <details>
@@ -735,7 +741,6 @@ part : (Number, List<a>) -> (List<a>, List<a>)
735
741
  ```
736
742
 
737
743
  Split a list into two, with the first list containing the required number of elements.
738
- Fails if the input list doesn't contain at least the required amount of elements.
739
744
 
740
745
  Parameters:
741
746
 
@@ -750,6 +755,13 @@ Returns:
750
755
  |----|-----------|
751
756
  |`(List<a>, List<a>)`|Two lists where the first contains exactly the required amount of elements and the second contains any remaining elements|
752
757
 
758
+ Throws:
759
+
760
+ `Failure(String)`
761
+
762
+ * When `count` is negative
763
+ * When the list doesn't contain at least the required amount of elements
764
+
753
765
  ### List.**rotate**
754
766
 
755
767
  <details disabled>
@@ -766,8 +778,6 @@ Rotates list elements by the specified amount to the left.
766
778
  If value is negative, list elements will be rotated by the
767
779
  specified amount to the right. See examples.
768
780
 
769
- Fails if the input list doesn't contain at least the required amount of elements.
770
-
771
781
  Parameters:
772
782
 
773
783
  |param|type|description|
@@ -775,6 +785,12 @@ Parameters:
775
785
  |`count`|`Number`|The number of elements to rotate by|
776
786
  |`list`|`List<a>`|The list to be rotated|
777
787
 
788
+ Throws:
789
+
790
+ `Failure(String)`
791
+
792
+ * When the list doesn't contain at least the required amount of elements
793
+
778
794
  Examples:
779
795
 
780
796
  ```grain
@@ -943,8 +959,6 @@ drop : (Number, List<a>) -> List<a>
943
959
  Produces a new list with the specified number of elements removed from
944
960
  the beginning of the input list.
945
961
 
946
- Fails if the specified amount is a negative number.
947
-
948
962
  Parameters:
949
963
 
950
964
  |param|type|description|
@@ -958,6 +972,12 @@ Returns:
958
972
  |----|-----------|
959
973
  |`List<a>`|The new list without the dropped elements|
960
974
 
975
+ Throws:
976
+
977
+ `Failure(String)`
978
+
979
+ * When `count` is negative
980
+
961
981
  ### List.**dropWhile**
962
982
 
963
983
  <details disabled>
@@ -1000,8 +1020,6 @@ take : (Number, List<a>) -> List<a>
1000
1020
  Produces a new list with–at most—the specified amount elements from
1001
1021
  the beginning of the input list.
1002
1022
 
1003
- Fails if the specified amount is a negative number.
1004
-
1005
1023
  Parameters:
1006
1024
 
1007
1025
  |param|type|description|
@@ -1015,6 +1033,12 @@ Returns:
1015
1033
  |----|-----------|
1016
1034
  |`List<a>`|The new list containing the taken elements|
1017
1035
 
1036
+ Throws:
1037
+
1038
+ `Failure(String)`
1039
+
1040
+ * When `count` is negative
1041
+
1018
1042
  ### List.**takeWhile**
1019
1043
 
1020
1044
  <details disabled>
@@ -1152,8 +1176,6 @@ sub : (Number, Number, List<a>) -> List<a>
1152
1176
  Provides the subset of a list given zero-based start index and amount of elements
1153
1177
  to include.
1154
1178
 
1155
- Fails if the start index or amount of elements are negative numbers.
1156
-
1157
1179
  Parameters:
1158
1180
 
1159
1181
  |param|type|description|
@@ -1168,6 +1190,13 @@ Returns:
1168
1190
  |----|-----------|
1169
1191
  |`List<a>`|The subset of the list|
1170
1192
 
1193
+ Throws:
1194
+
1195
+ `Failure(String)`
1196
+
1197
+ * When `start` is negative
1198
+ * When `length` is negative
1199
+
1171
1200
  ### List.**join**
1172
1201
 
1173
1202
  <details disabled>
package/map.gr CHANGED
@@ -9,7 +9,7 @@ import Array from "array"
9
9
  import { hash } from "hash"
10
10
  import Memory from "runtime/unsafe/memory"
11
11
  import WasmI32 from "runtime/unsafe/wasmi32"
12
- import { allocateArray } from "runtime/dataStructures"
12
+ import { allocateArray, untagSimpleNumber } from "runtime/dataStructures"
13
13
 
14
14
  // TODO: Consider implementing this as List<(Box<k>, Box<v>)>
15
15
  record Bucket<k, v> {
@@ -418,19 +418,6 @@ export let fromList = list => {
418
418
  map
419
419
  }
420
420
 
421
- let setInArray = array => {
422
- @disableGC
423
- let rec iter = (i, key, value) => {
424
- array[i] = (key, value)
425
- // no decRef on key and value, since they are stored in array
426
- Memory.decRef(WasmI32.fromGrain(iter))
427
- Memory.incRef(WasmI32.fromGrain((+)))
428
- Memory.incRef(WasmI32.fromGrain(i))
429
- i + 1
430
- }
431
- iter
432
- }
433
-
434
421
  /**
435
422
  * Converts a map into an array of its key-value pairs.
436
423
  *
@@ -439,20 +426,24 @@ let setInArray = array => {
439
426
  *
440
427
  * @since v0.2.0
441
428
  */
442
- @disableGC
443
- export let rec toArray = map => {
444
- let length = WasmI32.shrS(WasmI32.fromGrain(map.size), 1n)
445
- let array = WasmI32.toGrain(allocateArray(length)): Array<a>
446
- Memory.incRef(WasmI32.fromGrain(setInArray))
447
- Memory.incRef(WasmI32.fromGrain(array))
448
- let setInArray = setInArray(array)
449
- Memory.incRef(WasmI32.fromGrain(reduce))
450
- Memory.incRef(WasmI32.fromGrain(setInArray))
451
- Memory.incRef(WasmI32.fromGrain(map))
452
- reduce(setInArray, 0, map)
453
- Memory.decRef(WasmI32.fromGrain(setInArray))
454
- Memory.decRef(WasmI32.fromGrain(map))
455
- Memory.decRef(WasmI32.fromGrain(toArray))
429
+ @unsafe
430
+ export let toArray: Map<a, b> -> Array<(a, b)> = map => {
431
+ let length = untagSimpleNumber(map.size)
432
+ let array = WasmI32.toGrain(allocateArray(length))
433
+ @unsafe
434
+ let reducer = (i, key, value) => {
435
+ // Assign the values into the array.
436
+ // We store them directly to prevent GC on uninitialized array data.
437
+ let array = WasmI32.fromGrain(array)
438
+ let item = (key, value)
439
+ WasmI32.store(
440
+ WasmI32.add(array, WasmI32.mul(untagSimpleNumber(i), 4n)),
441
+ Memory.incRef(WasmI32.fromGrain(item)),
442
+ 8n
443
+ )
444
+ i + 1
445
+ }
446
+ reduce(reducer, 0, map)
456
447
  array
457
448
  }
458
449
 
package/marshal.gr CHANGED
@@ -54,7 +54,7 @@ let roundTo8 = n => {
54
54
  @unsafe
55
55
  let isHeapPtr = value =>
56
56
  (value & Tags._GRAIN_GENERIC_TAG_MASK) ==
57
- Tags._GRAIN_GENERIC_HEAP_TAG_TYPE
57
+ Tags._GRAIN_GENERIC_HEAP_TAG_TYPE
58
58
 
59
59
  @unsafe
60
60
  let rec size = (value, acc, valuesSeen, toplevel) => {
@@ -157,9 +157,9 @@ let rec size = (value, acc, valuesSeen, toplevel) => {
157
157
  },
158
158
  t when t == Tags._GRAIN_RATIONAL_BOXED_NUM_TAG => {
159
159
  acc +
160
- 16n +
161
- size(load(value, 8n), 0n, valuesSeen, false) +
162
- size(load(value, 12n), 0n, valuesSeen, false)
160
+ 16n +
161
+ size(load(value, 8n), 0n, valuesSeen, false) +
162
+ size(load(value, 12n), 0n, valuesSeen, false)
163
163
  },
164
164
  _ => {
165
165
  fail "Unknown number type"