@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.
- package/CHANGELOG.md +61 -0
- package/array.gr +65 -57
- package/array.md +54 -6
- package/buffer.gr +71 -1
- package/buffer.md +142 -0
- package/bytes.gr +52 -3
- package/bytes.md +117 -0
- package/char.gr +23 -20
- package/char.md +18 -3
- package/immutablemap.gr +493 -0
- package/immutablemap.md +479 -0
- package/immutablepriorityqueue.gr +44 -16
- package/immutablepriorityqueue.md +44 -1
- package/immutableset.gr +498 -0
- package/immutableset.md +449 -0
- package/int32.gr +39 -37
- package/int32.md +6 -0
- package/int64.gr +39 -37
- package/int64.md +6 -0
- package/list.gr +33 -24
- package/list.md +39 -10
- package/map.gr +19 -28
- package/marshal.gr +4 -4
- package/number.gr +727 -26
- package/number.md +345 -23
- package/option.gr +30 -26
- package/option.md +12 -0
- package/package.json +1 -1
- package/path.gr +787 -0
- package/path.md +727 -0
- package/pervasives.gr +3 -4
- package/pervasives.md +6 -1
- package/priorityqueue.gr +25 -5
- package/priorityqueue.md +30 -0
- package/queue.gr +22 -7
- package/queue.md +18 -1
- package/regex.gr +161 -65
- package/regex.md +70 -0
- package/result.gr +24 -20
- package/result.md +12 -0
- package/runtime/atof/common.gr +198 -0
- package/runtime/atof/common.md +243 -0
- package/runtime/atof/decimal.gr +663 -0
- package/runtime/atof/decimal.md +59 -0
- package/runtime/atof/lemire.gr +264 -0
- package/runtime/atof/lemire.md +6 -0
- package/runtime/atof/parse.gr +615 -0
- package/runtime/atof/parse.md +12 -0
- package/runtime/atof/slow.gr +238 -0
- package/runtime/atof/slow.md +6 -0
- package/runtime/atof/table.gr +2016 -0
- package/runtime/atof/table.md +12 -0
- package/runtime/{stringUtils.gr → atoi/parse.gr} +1 -1
- package/runtime/{stringUtils.md → atoi/parse.md} +1 -1
- package/runtime/bigint.gr +7 -7
- package/runtime/compare.gr +2 -1
- package/runtime/equal.gr +3 -2
- package/runtime/exception.gr +9 -5
- package/runtime/exception.md +8 -2
- package/runtime/gc.gr +2 -1
- package/runtime/malloc.gr +1 -3
- package/runtime/numberUtils.gr +13 -13
- package/runtime/numberUtils.md +6 -0
- package/runtime/numbers.gr +123 -39
- package/runtime/numbers.md +26 -0
- package/runtime/string.gr +4 -2
- package/runtime/unsafe/conv.gr +21 -41
- package/runtime/unsafe/conv.md +0 -3
- package/runtime/unsafe/printWasm.gr +4 -40
- package/runtime/utils/printing.gr +3 -3
- package/set.gr +25 -25
- package/stack.gr +14 -0
- package/stack.md +17 -0
- package/string.gr +313 -39
- package/string.md +99 -0
- package/sys/file.gr +1 -1
- package/sys/time.gr +4 -4
package/pervasives.gr
CHANGED
|
@@ -473,10 +473,11 @@ export primitive ignore: a -> Void = "@ignore"
|
|
|
473
473
|
|
|
474
474
|
/**
|
|
475
475
|
* Assert that the given Boolean condition is `true`.
|
|
476
|
-
* Throws an `AssertionError` if the condition is `false`.
|
|
477
476
|
*
|
|
478
477
|
* @param condition: The condition to assert
|
|
479
478
|
*
|
|
479
|
+
* @throws AssertionError: When the `condition` is false
|
|
480
|
+
*
|
|
480
481
|
* @example assert 3 > 2
|
|
481
482
|
* @example assert true
|
|
482
483
|
*
|
|
@@ -578,7 +579,7 @@ export let cons = (a, b) =>
|
|
|
578
579
|
export let empty = [] // <- for parity with `cons`, but should be deleted as well
|
|
579
580
|
|
|
580
581
|
// Setup exception printing
|
|
581
|
-
@
|
|
582
|
+
@unsafe
|
|
582
583
|
let rec setupExceptions = () => {
|
|
583
584
|
Exception.dangerouslyRegisterPrinter(e => {
|
|
584
585
|
match (e) {
|
|
@@ -589,8 +590,6 @@ let rec setupExceptions = () => {
|
|
|
589
590
|
})
|
|
590
591
|
|
|
591
592
|
Exception.dangerouslyRegisterBasePrinter(e => Some(toString(e)))
|
|
592
|
-
Memory.decRef(WasmI32.fromGrain(setupExceptions))
|
|
593
|
-
void
|
|
594
593
|
}
|
|
595
594
|
|
|
596
595
|
setupExceptions()
|
package/pervasives.md
CHANGED
|
@@ -942,7 +942,6 @@ assert : Bool -> Void
|
|
|
942
942
|
```
|
|
943
943
|
|
|
944
944
|
Assert that the given Boolean condition is `true`.
|
|
945
|
-
Throws an `AssertionError` if the condition is `false`.
|
|
946
945
|
|
|
947
946
|
Parameters:
|
|
948
947
|
|
|
@@ -950,6 +949,12 @@ Parameters:
|
|
|
950
949
|
|-----|----|-----------|
|
|
951
950
|
|`condition`|`Bool`|The condition to assert|
|
|
952
951
|
|
|
952
|
+
Throws:
|
|
953
|
+
|
|
954
|
+
`AssertionError`
|
|
955
|
+
|
|
956
|
+
* When the `condition` is false
|
|
957
|
+
|
|
953
958
|
Examples:
|
|
954
959
|
|
|
955
960
|
```grain
|
package/priorityqueue.gr
CHANGED
|
@@ -219,6 +219,29 @@ export let drain = pq => {
|
|
|
219
219
|
List.reverse(drainRec([]))
|
|
220
220
|
}
|
|
221
221
|
|
|
222
|
+
/**
|
|
223
|
+
* Constructs a new priority queue initialized with the elements in the array
|
|
224
|
+
* using a custom comparator function, which is used to determine priority of
|
|
225
|
+
* elements. The comparator function takes two elements and must return 0 if
|
|
226
|
+
* both share priority, a positive number if the first has greater priority,
|
|
227
|
+
* and a negative number if the first has less priority.
|
|
228
|
+
*
|
|
229
|
+
* @param array: An array of values used to initialize the priority queue
|
|
230
|
+
* @param comp: A comparator function used to assign priority to elements
|
|
231
|
+
* @returns A priority queue containing the elements from the array
|
|
232
|
+
*
|
|
233
|
+
* @since v0.5.4
|
|
234
|
+
*/
|
|
235
|
+
export let fromArray = (array, comp) => {
|
|
236
|
+
let size = Array.length(array)
|
|
237
|
+
let array = Array.map(x => Some(x), array)
|
|
238
|
+
let heap = { size, array, comp }
|
|
239
|
+
for (let mut i = size - 1; i >= 0; i -= 1) {
|
|
240
|
+
siftDown(i, heap)
|
|
241
|
+
}
|
|
242
|
+
heap
|
|
243
|
+
}
|
|
244
|
+
|
|
222
245
|
/**
|
|
223
246
|
* Constructs a new priority queue initialized with the elements in the list
|
|
224
247
|
* using a custom comparator function, which is used to determine priority of
|
|
@@ -233,9 +256,6 @@ export let drain = pq => {
|
|
|
233
256
|
* @since v0.5.3
|
|
234
257
|
*/
|
|
235
258
|
export let fromList = (list, comp) => {
|
|
236
|
-
let
|
|
237
|
-
|
|
238
|
-
push(val, heap)
|
|
239
|
-
}, list)
|
|
240
|
-
heap
|
|
259
|
+
let array = Array.fromList(list)
|
|
260
|
+
fromArray(array, comp)
|
|
241
261
|
}
|
package/priorityqueue.md
CHANGED
|
@@ -247,6 +247,36 @@ Returns:
|
|
|
247
247
|
|----|-----------|
|
|
248
248
|
|`List<a>`|A list of all elements in the priority in priority order|
|
|
249
249
|
|
|
250
|
+
### PriorityQueue.**fromArray**
|
|
251
|
+
|
|
252
|
+
<details disabled>
|
|
253
|
+
<summary tabindex="-1">Added in <code>0.5.4</code></summary>
|
|
254
|
+
No other changes yet.
|
|
255
|
+
</details>
|
|
256
|
+
|
|
257
|
+
```grain
|
|
258
|
+
fromArray : (Array<a>, ((a, a) -> Number)) -> PriorityQueue<a>
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
Constructs a new priority queue initialized with the elements in the array
|
|
262
|
+
using a custom comparator function, which is used to determine priority of
|
|
263
|
+
elements. The comparator function takes two elements and must return 0 if
|
|
264
|
+
both share priority, a positive number if the first has greater priority,
|
|
265
|
+
and a negative number if the first has less priority.
|
|
266
|
+
|
|
267
|
+
Parameters:
|
|
268
|
+
|
|
269
|
+
|param|type|description|
|
|
270
|
+
|-----|----|-----------|
|
|
271
|
+
|`array`|`Array<a>`|An array of values used to initialize the priority queue|
|
|
272
|
+
|`comp`|`(a, a) -> Number`|A comparator function used to assign priority to elements|
|
|
273
|
+
|
|
274
|
+
Returns:
|
|
275
|
+
|
|
276
|
+
|type|description|
|
|
277
|
+
|----|-----------|
|
|
278
|
+
|`PriorityQueue<a>`|A priority queue containing the elements from the array|
|
|
279
|
+
|
|
250
280
|
### PriorityQueue.**fromList**
|
|
251
281
|
|
|
252
282
|
<details disabled>
|
package/queue.gr
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
* @module Queue: An immutable queue implementation. A queue is a FIFO (first-in-first-out) data structure where new values are added to the end and retrieved or removed from the beginning.
|
|
3
3
|
* @example import Queue from "queue"
|
|
4
4
|
* @since v0.2.0
|
|
5
|
+
*
|
|
6
|
+
* @deprecated This module will be renamed to ImmutableQueue in the v0.6.0 release of Grain.
|
|
5
7
|
*/
|
|
6
8
|
import List from "list"
|
|
7
9
|
|
|
@@ -15,13 +17,26 @@ record Queue<a> {
|
|
|
15
17
|
}
|
|
16
18
|
|
|
17
19
|
/**
|
|
18
|
-
* @section Values: Functions for working with queues.
|
|
20
|
+
* @section Values: Functions and constants for working with queues.
|
|
19
21
|
*/
|
|
20
22
|
|
|
23
|
+
/**
|
|
24
|
+
* An empty queue.
|
|
25
|
+
*
|
|
26
|
+
* @since v0.5.4
|
|
27
|
+
*/
|
|
28
|
+
export let empty = {
|
|
29
|
+
let empty = { forwards: [], backwards: [] }
|
|
30
|
+
empty
|
|
31
|
+
}
|
|
32
|
+
|
|
21
33
|
/**
|
|
22
34
|
* Creates an empty queue.
|
|
23
|
-
*
|
|
35
|
+
*
|
|
24
36
|
* @returns An empty queue
|
|
37
|
+
*
|
|
38
|
+
* @deprecated This will be removed in the v0.6.0 release of Grain.
|
|
39
|
+
*
|
|
25
40
|
* @since v0.2.0
|
|
26
41
|
*/
|
|
27
42
|
export let make = () => {
|
|
@@ -30,7 +45,7 @@ export let make = () => {
|
|
|
30
45
|
|
|
31
46
|
/**
|
|
32
47
|
* Checks if the given queue contains any values.
|
|
33
|
-
*
|
|
48
|
+
*
|
|
34
49
|
* @param queue: The queue to check
|
|
35
50
|
* @returns `true` if the given queue is empty or `false` otherwise
|
|
36
51
|
*
|
|
@@ -45,7 +60,7 @@ export let isEmpty = queue => {
|
|
|
45
60
|
|
|
46
61
|
/**
|
|
47
62
|
* Returns the value at the beginning of the queue. It is not removed from the queue.
|
|
48
|
-
*
|
|
63
|
+
*
|
|
49
64
|
* @param queue: The queue to inspect
|
|
50
65
|
* @returns `Some(value)` containing the value at the beginning of the queue, or `None` if the queue is empty
|
|
51
66
|
*
|
|
@@ -63,7 +78,7 @@ export let peek = queue => {
|
|
|
63
78
|
|
|
64
79
|
/**
|
|
65
80
|
* Adds a value to the end of the queue.
|
|
66
|
-
*
|
|
81
|
+
*
|
|
67
82
|
* @param value: The value to append
|
|
68
83
|
* @param queue: The queue to update
|
|
69
84
|
* @returns An updated queue
|
|
@@ -82,7 +97,7 @@ export let push = (value, queue) => {
|
|
|
82
97
|
|
|
83
98
|
/**
|
|
84
99
|
* Dequeues the next value in the queue.
|
|
85
|
-
*
|
|
100
|
+
*
|
|
86
101
|
* @param queue: The queue to change
|
|
87
102
|
* @returns An updated queue
|
|
88
103
|
*
|
|
@@ -106,7 +121,7 @@ export let pop = queue => {
|
|
|
106
121
|
|
|
107
122
|
/**
|
|
108
123
|
* Get the number of values in a queue.
|
|
109
|
-
*
|
|
124
|
+
*
|
|
110
125
|
* @param queue: The queue to inspect
|
|
111
126
|
* @returns The number of values in the queue
|
|
112
127
|
*
|
package/queue.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
title: Queue
|
|
3
3
|
---
|
|
4
4
|
|
|
5
|
+
> **Deprecated:** This module will be renamed to ImmutableQueue in the v0.6.0 release of Grain.
|
|
6
|
+
|
|
5
7
|
An immutable queue implementation. A queue is a FIFO (first-in-first-out) data structure where new values are added to the end and retrieved or removed from the beginning.
|
|
6
8
|
|
|
7
9
|
<details disabled>
|
|
@@ -25,10 +27,25 @@ type Queue<a>
|
|
|
25
27
|
|
|
26
28
|
## Values
|
|
27
29
|
|
|
28
|
-
Functions for working with queues.
|
|
30
|
+
Functions and constants for working with queues.
|
|
31
|
+
|
|
32
|
+
### Queue.**empty**
|
|
33
|
+
|
|
34
|
+
<details disabled>
|
|
35
|
+
<summary tabindex="-1">Added in <code>0.5.4</code></summary>
|
|
36
|
+
No other changes yet.
|
|
37
|
+
</details>
|
|
38
|
+
|
|
39
|
+
```grain
|
|
40
|
+
empty : Queue<a>
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
An empty queue.
|
|
29
44
|
|
|
30
45
|
### Queue.**make**
|
|
31
46
|
|
|
47
|
+
> **Deprecated:** This will be removed in the v0.6.0 release of Grain.
|
|
48
|
+
|
|
32
49
|
<details disabled>
|
|
33
50
|
<summary tabindex="-1">Added in <code>0.2.0</code></summary>
|
|
34
51
|
No other changes yet.
|
package/regex.gr
CHANGED
|
@@ -121,10 +121,10 @@ let withConfig = (buf: RegExBuf, config: RegExParserConfig) => {
|
|
|
121
121
|
|
|
122
122
|
let parseErr = (buf: RegExBuf, msg: String, posShift) => {
|
|
123
123
|
"Invalid Regular Expression: " ++
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
124
|
+
msg ++
|
|
125
|
+
" (position " ++
|
|
126
|
+
toString(unbox(buf.cursor) + posShift) ++
|
|
127
|
+
")"
|
|
128
128
|
}
|
|
129
129
|
|
|
130
130
|
let next = (buf: RegExBuf) => {
|
|
@@ -241,7 +241,8 @@ let rec rangeAdd = (rng: CharRange, v: CharRangeElt) => {
|
|
|
241
241
|
_ when rangeContains(rng, v) => rng,
|
|
242
242
|
_ => rangeUnion(rng, [(v, v)]),
|
|
243
243
|
}
|
|
244
|
-
},
|
|
244
|
+
},
|
|
245
|
+
rangeUnion = (rng1, rng2) => {
|
|
245
246
|
match ((rng1, rng2)) {
|
|
246
247
|
([], _) => rng2,
|
|
247
248
|
(_, []) => rng1,
|
|
@@ -457,7 +458,10 @@ enum ParsedRegularExpression {
|
|
|
457
458
|
), // regex, n-start, num-n, needs-backtrack
|
|
458
459
|
REReference(Number, Bool), // n, case-sensitive
|
|
459
460
|
RERange(RERange),
|
|
460
|
-
REUnicodeCategories(
|
|
461
|
+
REUnicodeCategories(
|
|
462
|
+
List<UnicodeCategory>,
|
|
463
|
+
Bool
|
|
464
|
+
), // symlist, true=match/false=does-not-match
|
|
461
465
|
}
|
|
462
466
|
|
|
463
467
|
let needsBacktrack = (rx: ParsedRegularExpression) => {
|
|
@@ -636,7 +640,8 @@ let rec parseRangeNot = (buf: RegExBuf) => {
|
|
|
636
640
|
Ok(_) => parseRange(buf),
|
|
637
641
|
}
|
|
638
642
|
}
|
|
639
|
-
},
|
|
643
|
+
},
|
|
644
|
+
parseRange = (buf: RegExBuf) => {
|
|
640
645
|
if (!more(buf)) {
|
|
641
646
|
Err(parseErr(buf, "Missing closing `]`", 0))
|
|
642
647
|
} else {
|
|
@@ -659,7 +664,8 @@ let rec parseRangeNot = (buf: RegExBuf) => {
|
|
|
659
664
|
Ok(_) => parseRangeRest(buf, [], None, None),
|
|
660
665
|
}
|
|
661
666
|
}
|
|
662
|
-
},
|
|
667
|
+
},
|
|
668
|
+
parseClass = (buf: RegExBuf) => {
|
|
663
669
|
if (!more(buf)) {
|
|
664
670
|
Err(
|
|
665
671
|
"no chars"
|
|
@@ -694,7 +700,8 @@ let rec parseRangeNot = (buf: RegExBuf) => {
|
|
|
694
700
|
Ok(c) => Err("unknown class: " ++ toString(c)),
|
|
695
701
|
}
|
|
696
702
|
}
|
|
697
|
-
},
|
|
703
|
+
},
|
|
704
|
+
parsePosixCharClass = (buf: RegExBuf) => {
|
|
698
705
|
if (!more(buf)) {
|
|
699
706
|
Err(parseErr(buf, "Missing POSIX character class after `[`", 0))
|
|
700
707
|
} else {
|
|
@@ -810,7 +817,8 @@ let rec parseRangeNot = (buf: RegExBuf) => {
|
|
|
810
817
|
),
|
|
811
818
|
}
|
|
812
819
|
}
|
|
813
|
-
},
|
|
820
|
+
},
|
|
821
|
+
parseRangeRest =
|
|
814
822
|
(
|
|
815
823
|
buf: RegExBuf,
|
|
816
824
|
rng: CharRange,
|
|
@@ -962,7 +970,8 @@ let rec parseRangeNot = (buf: RegExBuf) => {
|
|
|
962
970
|
},
|
|
963
971
|
}
|
|
964
972
|
}
|
|
965
|
-
},
|
|
973
|
+
},
|
|
974
|
+
parseRangeRestSpan =
|
|
966
975
|
(
|
|
967
976
|
buf: RegExBuf,
|
|
968
977
|
c,
|
|
@@ -1213,7 +1222,8 @@ let rec parseAtom = (buf: RegExBuf) => {
|
|
|
1213
1222
|
_ => parseLiteral(buf),
|
|
1214
1223
|
},
|
|
1215
1224
|
}
|
|
1216
|
-
},
|
|
1225
|
+
},
|
|
1226
|
+
parseLook = (buf: RegExBuf) => {
|
|
1217
1227
|
let preNumGroups = unbox(buf.config.groupNumber)
|
|
1218
1228
|
let spanNumGroups = () => unbox(buf.config.groupNumber) - preNumGroups
|
|
1219
1229
|
// (isMatch, isAhead)
|
|
@@ -1279,7 +1289,8 @@ let rec parseAtom = (buf: RegExBuf) => {
|
|
|
1279
1289
|
}
|
|
1280
1290
|
},
|
|
1281
1291
|
}
|
|
1282
|
-
},
|
|
1292
|
+
},
|
|
1293
|
+
parseTest = (buf: RegExBuf) => {
|
|
1283
1294
|
if (!more(buf)) {
|
|
1284
1295
|
Err(parseErr(buf, "Expected test", 0))
|
|
1285
1296
|
} else {
|
|
@@ -1316,7 +1327,8 @@ let rec parseAtom = (buf: RegExBuf) => {
|
|
|
1316
1327
|
),
|
|
1317
1328
|
}
|
|
1318
1329
|
}
|
|
1319
|
-
},
|
|
1330
|
+
},
|
|
1331
|
+
parseInteger = (buf: RegExBuf, n) => {
|
|
1320
1332
|
if (!more(buf)) {
|
|
1321
1333
|
Ok(n)
|
|
1322
1334
|
} else {
|
|
@@ -1331,7 +1343,8 @@ let rec parseAtom = (buf: RegExBuf) => {
|
|
|
1331
1343
|
Ok(_) => Ok(n),
|
|
1332
1344
|
}
|
|
1333
1345
|
}
|
|
1334
|
-
},
|
|
1346
|
+
},
|
|
1347
|
+
parseMode = (buf: RegExBuf) => {
|
|
1335
1348
|
let processState = ((cs, ml)) => {
|
|
1336
1349
|
let withCs = match (cs) {
|
|
1337
1350
|
None => buf.config,
|
|
@@ -1390,7 +1403,8 @@ let rec parseAtom = (buf: RegExBuf) => {
|
|
|
1390
1403
|
}
|
|
1391
1404
|
}
|
|
1392
1405
|
help((None, None))
|
|
1393
|
-
},
|
|
1406
|
+
},
|
|
1407
|
+
parseUnicodeCategories = (buf: RegExBuf, pC: String) => {
|
|
1394
1408
|
if (!more(buf)) {
|
|
1395
1409
|
Err(parseErr(buf, "Expected unicode category", 0))
|
|
1396
1410
|
} else {
|
|
@@ -1558,7 +1572,8 @@ let rec parseAtom = (buf: RegExBuf) => {
|
|
|
1558
1572
|
Ok(_) => Err(parseErr(buf, "Expected `{` after `\\" ++ pC ++ "`", 0)),
|
|
1559
1573
|
}
|
|
1560
1574
|
}
|
|
1561
|
-
},
|
|
1575
|
+
},
|
|
1576
|
+
parseLiteral = (buf: RegExBuf) => {
|
|
1562
1577
|
if (!more(buf)) {
|
|
1563
1578
|
Err(parseErr(buf, "Expected literal", 0))
|
|
1564
1579
|
} else {
|
|
@@ -1592,7 +1607,8 @@ let rec parseAtom = (buf: RegExBuf) => {
|
|
|
1592
1607
|
},
|
|
1593
1608
|
}
|
|
1594
1609
|
}
|
|
1595
|
-
},
|
|
1610
|
+
},
|
|
1611
|
+
parseBackslashLiteral = (buf: RegExBuf) => {
|
|
1596
1612
|
if (!more(buf)) {
|
|
1597
1613
|
// Special case: EOS after backslash matches null
|
|
1598
1614
|
Err(parseErr(buf, "Expected to find escaped value after backslash", 0))
|
|
@@ -1655,7 +1671,8 @@ let rec parseAtom = (buf: RegExBuf) => {
|
|
|
1655
1671
|
},
|
|
1656
1672
|
}
|
|
1657
1673
|
}
|
|
1658
|
-
},
|
|
1674
|
+
},
|
|
1675
|
+
parseNonGreedy = (buf: RegExBuf) => {
|
|
1659
1676
|
let checkNotNested = res => {
|
|
1660
1677
|
if (!more(buf)) {
|
|
1661
1678
|
res
|
|
@@ -1681,7 +1698,8 @@ let rec parseAtom = (buf: RegExBuf) => {
|
|
|
1681
1698
|
Ok(_) => checkNotNested(Ok(false)),
|
|
1682
1699
|
}
|
|
1683
1700
|
}
|
|
1684
|
-
},
|
|
1701
|
+
},
|
|
1702
|
+
parsePCE = (buf: RegExBuf) => {
|
|
1685
1703
|
match (parseAtom(buf)) {
|
|
1686
1704
|
Err(e) => Err(e),
|
|
1687
1705
|
Ok(atom) => {
|
|
@@ -1775,7 +1793,8 @@ let rec parseAtom = (buf: RegExBuf) => {
|
|
|
1775
1793
|
}
|
|
1776
1794
|
},
|
|
1777
1795
|
}
|
|
1778
|
-
},
|
|
1796
|
+
},
|
|
1797
|
+
parsePCEs = (buf: RegExBuf, toplevel: Bool) => {
|
|
1779
1798
|
if (!more(buf)) {
|
|
1780
1799
|
Ok([])
|
|
1781
1800
|
} else {
|
|
@@ -1801,7 +1820,8 @@ let rec parseAtom = (buf: RegExBuf) => {
|
|
|
1801
1820
|
},
|
|
1802
1821
|
}
|
|
1803
1822
|
}
|
|
1804
|
-
},
|
|
1823
|
+
},
|
|
1824
|
+
parseRegex = (buf: RegExBuf) => {
|
|
1805
1825
|
if (!more(buf)) {
|
|
1806
1826
|
Ok(REEmpty)
|
|
1807
1827
|
} else {
|
|
@@ -1836,7 +1856,8 @@ let rec parseAtom = (buf: RegExBuf) => {
|
|
|
1836
1856
|
},
|
|
1837
1857
|
}
|
|
1838
1858
|
}
|
|
1839
|
-
},
|
|
1859
|
+
},
|
|
1860
|
+
parseRegexNonEmpty = (buf: RegExBuf) => {
|
|
1840
1861
|
match (parsePCEs(buf, false)) {
|
|
1841
1862
|
Err(e) => Err(e),
|
|
1842
1863
|
Ok(pces) => {
|
|
@@ -1922,7 +1943,7 @@ let rec isAnchored = (re: ParsedRegularExpression) => {
|
|
|
1922
1943
|
REAlts(a, b) => isAnchored(a) && isAnchored(b),
|
|
1923
1944
|
REConditional(_, rx1, rx2, _, _, _) =>
|
|
1924
1945
|
isAnchored(rx1) &&
|
|
1925
|
-
|
|
1946
|
+
Option.mapWithDefault(isAnchored, false, rx2),
|
|
1926
1947
|
REGroup(rx, _) => isAnchored(rx),
|
|
1927
1948
|
RECut(rx, _, _, _) => isAnchored(rx),
|
|
1928
1949
|
_ => false,
|
|
@@ -2305,10 +2326,10 @@ let charMatcher = (toMatch, next_m) =>
|
|
|
2305
2326
|
if (
|
|
2306
2327
|
{
|
|
2307
2328
|
pos < limit &&
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2329
|
+
match (matchBufChar(buf, pos)) {
|
|
2330
|
+
Err(_) => false,
|
|
2331
|
+
Ok(c) => toMatch == c,
|
|
2332
|
+
}
|
|
2312
2333
|
}
|
|
2313
2334
|
) next_m(buf, pos + 1, start, limit, end, state, stack) else None
|
|
2314
2335
|
}
|
|
@@ -2326,10 +2347,10 @@ let charTailMatcher = toMatch =>
|
|
|
2326
2347
|
if (
|
|
2327
2348
|
{
|
|
2328
2349
|
pos < limit &&
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2350
|
+
match (matchBufChar(buf, pos)) {
|
|
2351
|
+
Err(_) => false,
|
|
2352
|
+
Ok(c) => toMatch == c,
|
|
2353
|
+
}
|
|
2333
2354
|
}
|
|
2334
2355
|
) Some(pos + 1) else None
|
|
2335
2356
|
}
|
|
@@ -2382,13 +2403,13 @@ let stringMatcher = (toMatch, len, next_m) =>
|
|
|
2382
2403
|
if (
|
|
2383
2404
|
{
|
|
2384
2405
|
pos + len <= limit &&
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2406
|
+
subArraysEqual(
|
|
2407
|
+
buf.matchInputExploded,
|
|
2408
|
+
pos,
|
|
2409
|
+
String.explode(toMatch),
|
|
2410
|
+
0,
|
|
2411
|
+
len
|
|
2412
|
+
)
|
|
2392
2413
|
}
|
|
2393
2414
|
) next_m(buf, pos + len, start, limit, end, state, stack) else None
|
|
2394
2415
|
}
|
|
@@ -2406,13 +2427,13 @@ let stringTailMatcher = (toMatch, len) =>
|
|
|
2406
2427
|
if (
|
|
2407
2428
|
{
|
|
2408
2429
|
pos + len <= limit &&
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2430
|
+
subArraysEqual(
|
|
2431
|
+
buf.matchInputExploded,
|
|
2432
|
+
pos,
|
|
2433
|
+
String.explode(toMatch),
|
|
2434
|
+
0,
|
|
2435
|
+
len
|
|
2436
|
+
)
|
|
2416
2437
|
}
|
|
2417
2438
|
) Some(pos + len) else None
|
|
2418
2439
|
}
|
|
@@ -2513,10 +2534,10 @@ let rangeMatcher = (rng: CharRange, next_m) =>
|
|
|
2513
2534
|
if (
|
|
2514
2535
|
{
|
|
2515
2536
|
pos < limit &&
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2537
|
+
match (matchBufChar(buf, pos)) {
|
|
2538
|
+
Err(_) => false,
|
|
2539
|
+
Ok(c) => rangeContains(rng, Char.code(c)),
|
|
2540
|
+
}
|
|
2520
2541
|
}
|
|
2521
2542
|
) next_m(buf, pos + 1, start, limit, end, state, stack) else None
|
|
2522
2543
|
}
|
|
@@ -2534,10 +2555,10 @@ let rangeTailMatcher = (rng: CharRange) =>
|
|
|
2534
2555
|
if (
|
|
2535
2556
|
{
|
|
2536
2557
|
pos < limit &&
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2558
|
+
match (matchBufChar(buf, pos)) {
|
|
2559
|
+
Err(_) => false,
|
|
2560
|
+
Ok(c) => rangeContains(rng, Char.code(c)),
|
|
2561
|
+
}
|
|
2541
2562
|
}
|
|
2542
2563
|
) Some(pos + 1) else None
|
|
2543
2564
|
}
|
|
@@ -2636,7 +2657,7 @@ let isWordChar = c => {
|
|
|
2636
2657
|
|
|
2637
2658
|
let isWordBoundary = (buf, pos, start, limit, end) => {
|
|
2638
2659
|
!((pos == start || !isWordChar(matchBufChar(buf, pos - 1))) ==
|
|
2639
|
-
|
|
2660
|
+
(pos == end || !isWordChar(matchBufChar(buf, pos))))
|
|
2640
2661
|
}
|
|
2641
2662
|
|
|
2642
2663
|
let wordBoundaryMatcher = next_m =>
|
|
@@ -3608,7 +3629,7 @@ export record MatchResult {
|
|
|
3608
3629
|
/**
|
|
3609
3630
|
* Returns the contents of the given group
|
|
3610
3631
|
*/
|
|
3611
|
-
|
|
3632
|
+
group: Number -> Option<String>,
|
|
3612
3633
|
/**
|
|
3613
3634
|
* Returns the position of the given group
|
|
3614
3635
|
*/
|
|
@@ -3672,10 +3693,12 @@ let makeMatchResult = (origString, start, end, state) => {
|
|
|
3672
3693
|
// Helpers for user-facing match functionality
|
|
3673
3694
|
|
|
3674
3695
|
let fastDriveRegexIsMatch = (rx, string, startOffset, endOffset) => {
|
|
3675
|
-
let state =
|
|
3696
|
+
let state =
|
|
3697
|
+
if (rx.reReferences) Array.make(rx.reNumGroups, None)
|
|
3676
3698
|
else Array.make(0, None)
|
|
3677
|
-
let toWrap =
|
|
3678
|
-
|
|
3699
|
+
let toWrap =
|
|
3700
|
+
if (startOffset == 0 && endOffset == String.length(string)) string
|
|
3701
|
+
else String.slice(startOffset, endOffset, string)
|
|
3679
3702
|
let buf = makeMatchBuffer(toWrap)
|
|
3680
3703
|
Option.isSome(
|
|
3681
3704
|
searchMatch(rx, buf, 0, 0, Array.length(buf.matchInputExploded), state)
|
|
@@ -3687,8 +3710,9 @@ let rec fastDriveRegexMatchAll = (rx, string, startOffset, endOffset) => {
|
|
|
3687
3710
|
[]
|
|
3688
3711
|
} else {
|
|
3689
3712
|
let state = Array.make(rx.reNumGroups, None)
|
|
3690
|
-
let toWrap =
|
|
3691
|
-
|
|
3713
|
+
let toWrap =
|
|
3714
|
+
if (startOffset == 0 && endOffset == String.length(string)) string
|
|
3715
|
+
else String.slice(startOffset, endOffset, string)
|
|
3692
3716
|
let buf = makeMatchBuffer(toWrap)
|
|
3693
3717
|
match (searchMatch(
|
|
3694
3718
|
rx,
|
|
@@ -3726,8 +3750,9 @@ let rec fastDriveRegexMatchAll = (rx, string, startOffset, endOffset) => {
|
|
|
3726
3750
|
|
|
3727
3751
|
let fastDriveRegexMatch = (rx, string, startOffset, endOffset) => {
|
|
3728
3752
|
let state = Array.make(rx.reNumGroups, None)
|
|
3729
|
-
let toWrap =
|
|
3730
|
-
|
|
3753
|
+
let toWrap =
|
|
3754
|
+
if (startOffset == 0 && endOffset == String.length(string)) string
|
|
3755
|
+
else String.slice(startOffset, endOffset, string)
|
|
3731
3756
|
let buf = makeMatchBuffer(toWrap)
|
|
3732
3757
|
match (searchMatch(
|
|
3733
3758
|
rx,
|
|
@@ -3951,14 +3976,14 @@ let regexReplaceHelp =
|
|
|
3951
3976
|
all: Bool,
|
|
3952
3977
|
) => {
|
|
3953
3978
|
let buf = makeMatchBuffer(toSearch)
|
|
3954
|
-
let mut out = []
|
|
3955
3979
|
let rec loop = searchPos => {
|
|
3956
3980
|
let state = Array.make(rx.reNumGroups, None)
|
|
3981
|
+
let inStart = max(0, searchPos - rx.reMaxLookbehind)
|
|
3957
3982
|
let poss = searchMatch(
|
|
3958
3983
|
rx,
|
|
3959
3984
|
buf,
|
|
3960
3985
|
searchPos,
|
|
3961
|
-
|
|
3986
|
+
inStart,
|
|
3962
3987
|
Array.length(buf.matchInputExploded),
|
|
3963
3988
|
state
|
|
3964
3989
|
)
|
|
@@ -4044,3 +4069,74 @@ export let replaceAll =
|
|
|
4044
4069
|
) => {
|
|
4045
4070
|
regexReplaceHelp(rx, toSearch, replacement, true)
|
|
4046
4071
|
}
|
|
4072
|
+
|
|
4073
|
+
let regexSplitHelp = (rx: RegularExpression, str: String, all: Bool) => {
|
|
4074
|
+
// Get list of matches
|
|
4075
|
+
let regexMatches = if (all) {
|
|
4076
|
+
findAll(rx, str)
|
|
4077
|
+
} else {
|
|
4078
|
+
match (find(rx, str)) {
|
|
4079
|
+
None => [],
|
|
4080
|
+
Some(m) => [m],
|
|
4081
|
+
}
|
|
4082
|
+
}
|
|
4083
|
+
// Perform replacements
|
|
4084
|
+
let mut out = []
|
|
4085
|
+
let mut currentLocation = 0
|
|
4086
|
+
List.forEach(regexMatch => {
|
|
4087
|
+
let locations = regexMatch.allGroupPositions()
|
|
4088
|
+
Array.forEachi((pos, i) => {
|
|
4089
|
+
match (pos) {
|
|
4090
|
+
Some((start, end)) => {
|
|
4091
|
+
if (i == 0) {
|
|
4092
|
+
// Add the string between this match and the last match
|
|
4093
|
+
out = [String.slice(currentLocation, start, str), ...out]
|
|
4094
|
+
} else {
|
|
4095
|
+
// This adds the groups back in
|
|
4096
|
+
out = [String.slice(start, end, str), ...out]
|
|
4097
|
+
}
|
|
4098
|
+
if (end > currentLocation) currentLocation = end
|
|
4099
|
+
},
|
|
4100
|
+
None => void,
|
|
4101
|
+
}
|
|
4102
|
+
}, locations)
|
|
4103
|
+
}, regexMatches)
|
|
4104
|
+
out = [String.slice(currentLocation, String.length(str), str), ...out]
|
|
4105
|
+
List.reverse(out)
|
|
4106
|
+
}
|
|
4107
|
+
|
|
4108
|
+
/**
|
|
4109
|
+
* Splits the given string at the first match for the given regular expression.
|
|
4110
|
+
*
|
|
4111
|
+
* If the regex pattern contains capture groups, the content of the groups
|
|
4112
|
+
* will be included in the output list.
|
|
4113
|
+
*
|
|
4114
|
+
* @param rx: The regular expression to match
|
|
4115
|
+
* @param str: The string to split
|
|
4116
|
+
* @returns A list of the split segments
|
|
4117
|
+
*
|
|
4118
|
+
* @example assert Regex.split(Result.unwrap(Regex.make(",")), "a,b,c") == [ "a", "b,c" ]
|
|
4119
|
+
*
|
|
4120
|
+
* @since v0.5.5
|
|
4121
|
+
*/
|
|
4122
|
+
export let split = (rx: RegularExpression, str: String) => {
|
|
4123
|
+
regexSplitHelp(rx, str, false)
|
|
4124
|
+
}
|
|
4125
|
+
|
|
4126
|
+
/**
|
|
4127
|
+
* Splits the given string at every match for the given regular expression.
|
|
4128
|
+
*
|
|
4129
|
+
* If the regex pattern contains capture groups, the content of the groups
|
|
4130
|
+
* will be included in the output list.
|
|
4131
|
+
*
|
|
4132
|
+
* @param rx: The regular expression to match
|
|
4133
|
+
* @param str: The string to split
|
|
4134
|
+
* @returns A list of the split segments
|
|
4135
|
+
*
|
|
4136
|
+
* @example assert Regex.splitAll(Result.unwrap(Regex.make(",")), "a,b,c") == [ "a", "b", "c" ]
|
|
4137
|
+
*
|
|
4138
|
+
* @since v0.5.5
|
|
4139
|
+
*/
|
|
4140
|
+
export let splitAll = (rx: RegularExpression, str: String) => {
|
|
4141
|
+
regexSplitHelp(rx, str, true)
|
|
4142
|
+
}
|