nomen-lang 0.6.0 → 0.6.2
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/core/System/List.nm +12 -0
- package/core/System/StringBuilder.nm +126 -3
- package/core/System/Text/Regex.nm +345 -91
- package/dist/index.mjs +492 -62
- package/package.json +1 -1
- package/src/test.ts +45 -5
|
@@ -255,12 +255,13 @@ func fold_pattern = (string pattern, move out string) {
|
|
|
255
255
|
while i < n; i += 1 {
|
|
256
256
|
var char c = pattern.at(i)
|
|
257
257
|
if (c as int) == 92 {
|
|
258
|
-
// Escaped char: shorthands
|
|
259
|
-
//
|
|
260
|
-
// punctuation is copied
|
|
258
|
+
// Escaped char: shorthands, backrefs, and control escapes
|
|
259
|
+
// (\n \r \t) keep their backslash; other escaped letters
|
|
260
|
+
// become both-case classes; escaped punctuation is copied
|
|
261
|
+
// literally.
|
|
261
262
|
if i + 1 < n {
|
|
262
263
|
var char e = pattern.at(i + 1)
|
|
263
|
-
if is_shorthand(e) || is_backref_digit(e) {
|
|
264
|
+
if is_shorthand(e) || is_backref_digit(e) || is_control_escape(e) {
|
|
264
265
|
sb.append_char(c)
|
|
265
266
|
sb.append_char(e)
|
|
266
267
|
} else {
|
|
@@ -317,9 +318,10 @@ func fold_class = (string pattern, int cs, int ce, ref StringBuilder dst) {
|
|
|
317
318
|
if i + 1 < content_end {
|
|
318
319
|
var char e = pattern.at(i + 1)
|
|
319
320
|
dst.append_char(e)
|
|
320
|
-
// A shorthand
|
|
321
|
-
// gain their case
|
|
322
|
-
|
|
321
|
+
// A shorthand or control escape (\n \r \t) keeps its
|
|
322
|
+
// backslash; other escaped letters gain their case
|
|
323
|
+
// counterpart.
|
|
324
|
+
if is_alpha_byte(e) && !is_shorthand(e) && !is_control_escape(e) {
|
|
323
325
|
dst.append_char(swap_case_byte(e))
|
|
324
326
|
}
|
|
325
327
|
i += 1
|
|
@@ -469,18 +471,20 @@ func collect_first_bytes = (
|
|
|
469
471
|
//
|
|
470
472
|
// Handles the shapes the engine's matcher can produce: a leading anchor is
|
|
471
473
|
// zero-width (skipped), a leading group contributes its CONTENT's first bytes
|
|
472
|
-
// (recursively over the group's own top-level alternatives), and
|
|
473
|
-
// quantified with '?'/'*' is
|
|
474
|
-
//
|
|
475
|
-
// set indeterminable.
|
|
474
|
+
// (recursively over the group's own top-level alternatives), and ANY leading
|
|
475
|
+
// atom — literal, escaped, class, or group — quantified with '?'/'*' is
|
|
476
|
+
// nullable: what FOLLOWS it can also be first, so the scan continues past it.
|
|
477
|
+
// A wildcard '.' or an empty alternative makes the set indeterminable.
|
|
476
478
|
func alt_first_bytes = (string pattern, int start, int end, ref StringBuilder sb, out int) {
|
|
477
479
|
var int i = start
|
|
478
480
|
while i < end {
|
|
479
481
|
var char c = pattern.at(i)
|
|
480
482
|
if (c as int) == 92 {
|
|
481
|
-
// escaped literal: first byte is the
|
|
482
|
-
//
|
|
483
|
-
//
|
|
483
|
+
// escaped literal: first byte is the byte the escape names
|
|
484
|
+
// (\n is LF, \r is CR, \t is TAB; any other escaped character
|
|
485
|
+
// is its own literal byte) — unless it's a backreference
|
|
486
|
+
// (depends on a capture) or a complement shorthand (not an
|
|
487
|
+
// inclusion set), which disable the prefilter.
|
|
484
488
|
if i + 1 < end {
|
|
485
489
|
var char e = pattern.at(i + 1)
|
|
486
490
|
if is_backref_digit(e) {
|
|
@@ -490,9 +494,17 @@ func alt_first_bytes = (string pattern, int start, int end, ref StringBuilder sb
|
|
|
490
494
|
if shorthand_members(e, ref sb) < 0 {
|
|
491
495
|
return -1
|
|
492
496
|
}
|
|
497
|
+
} else {
|
|
498
|
+
sb.append_char(escaped_byte_value(e) as char)
|
|
499
|
+
}
|
|
500
|
+
// A '?'/'*' quantifier makes the atom nullable — the first
|
|
501
|
+
// byte can also come from whatever follows it.
|
|
502
|
+
var int cont = nullable_quant_after(pattern, i + 2, end)
|
|
503
|
+
if cont < 0 {
|
|
493
504
|
return 0
|
|
494
505
|
}
|
|
495
|
-
|
|
506
|
+
i = cont
|
|
507
|
+
continue
|
|
496
508
|
}
|
|
497
509
|
return 0
|
|
498
510
|
}
|
|
@@ -509,7 +521,12 @@ func alt_first_bytes = (string pattern, int start, int end, ref StringBuilder sb
|
|
|
509
521
|
}
|
|
510
522
|
}
|
|
511
523
|
add_class_chars(pattern, i + 1, a_end - 1, ref sb)
|
|
512
|
-
|
|
524
|
+
var int cont = nullable_quant_after(pattern, a_end, end)
|
|
525
|
+
if cont < 0 {
|
|
526
|
+
return 0
|
|
527
|
+
}
|
|
528
|
+
i = cont
|
|
529
|
+
continue
|
|
513
530
|
}
|
|
514
531
|
if c == '(' {
|
|
515
532
|
var int a_end = atom_end_pos(pattern, i, end)
|
|
@@ -518,27 +535,11 @@ func alt_first_bytes = (string pattern, int start, int end, ref StringBuilder sb
|
|
|
518
535
|
if collect_first_bytes(pattern, i + 1, a_end - 1, ref sb) < 0 {
|
|
519
536
|
return -1
|
|
520
537
|
}
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
// quantifier lazy and is skipped either way.
|
|
524
|
-
var int after = a_end
|
|
525
|
-
var nullable = 0
|
|
526
|
-
if after < end {
|
|
527
|
-
var char q = pattern.at(after)
|
|
528
|
-
if q == '?' || q == '*' {
|
|
529
|
-
nullable = 1
|
|
530
|
-
after += 1
|
|
531
|
-
if after < end {
|
|
532
|
-
if pattern.at(after) == '?' {
|
|
533
|
-
after += 1
|
|
534
|
-
}
|
|
535
|
-
}
|
|
536
|
-
}
|
|
537
|
-
}
|
|
538
|
-
if nullable == 0 {
|
|
538
|
+
var int cont = nullable_quant_after(pattern, a_end, end)
|
|
539
|
+
if cont < 0 {
|
|
539
540
|
return 0
|
|
540
541
|
}
|
|
541
|
-
i =
|
|
542
|
+
i = cont
|
|
542
543
|
continue
|
|
543
544
|
}
|
|
544
545
|
if c == '^' || c == '$' {
|
|
@@ -552,9 +553,40 @@ func alt_first_bytes = (string pattern, int start, int end, ref StringBuilder sb
|
|
|
552
553
|
return -1
|
|
553
554
|
}
|
|
554
555
|
sb.append_char(c)
|
|
555
|
-
|
|
556
|
+
var int cont = nullable_quant_after(pattern, i + 1, end)
|
|
557
|
+
if cont < 0 {
|
|
558
|
+
return 0
|
|
559
|
+
}
|
|
560
|
+
i = cont
|
|
561
|
+
continue
|
|
562
|
+
}
|
|
563
|
+
// An empty alternative (nothing left after nullable atoms — or nothing at
|
|
564
|
+
// all) can match at any position — indeterminable.
|
|
565
|
+
return -1
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
// If the atom ending at `after` carries a nullable quantifier ('?' or '*',
|
|
569
|
+
// optionally marked lazy by a second '?'), return the position just past the
|
|
570
|
+
// quantifier; otherwise return -1. Callers keep scanning from the returned
|
|
571
|
+
// position: a nullable leading atom means the alternative's match can also
|
|
572
|
+
// START with whatever follows, so those bytes belong in the first-byte set
|
|
573
|
+
// too. ('+' is NOT nullable — the atom must match once — so it leaves the
|
|
574
|
+
// atom's own bytes as the whole first set.)
|
|
575
|
+
func nullable_quant_after = (string pattern, int after, int end, out int) {
|
|
576
|
+
var int j = after
|
|
577
|
+
if j >= end {
|
|
578
|
+
return -1
|
|
579
|
+
}
|
|
580
|
+
var char q = pattern.at(j)
|
|
581
|
+
if q == '?' || q == '*' {
|
|
582
|
+
j += 1
|
|
583
|
+
if j < end {
|
|
584
|
+
if pattern.at(j) == '?' {
|
|
585
|
+
j += 1
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
return j
|
|
556
589
|
}
|
|
557
|
-
// An empty alternative can match at any position — indeterminable.
|
|
558
590
|
return -1
|
|
559
591
|
}
|
|
560
592
|
|
|
@@ -569,22 +601,34 @@ func add_class_chars = (string pattern, int start, int end, ref StringBuilder sb
|
|
|
569
601
|
}
|
|
570
602
|
var int i = cs
|
|
571
603
|
while i < end {
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
604
|
+
var char c = pattern.at(i)
|
|
605
|
+
if (c as int) == 92 {
|
|
606
|
+
// Escaped byte: contribute the byte the escape names (\n is
|
|
607
|
+
// LF, \r is CR, \t is TAB; any other escaped character is its
|
|
608
|
+
// own literal byte) so the prefilter stays a superset of the
|
|
609
|
+
// matcher's first bytes.
|
|
610
|
+
if i + 1 < end {
|
|
611
|
+
sb.append_char(escaped_byte_value(pattern.at(i + 1)) as char)
|
|
612
|
+
}
|
|
613
|
+
i += 2
|
|
614
|
+
} else {
|
|
615
|
+
if i + 2 < end {
|
|
616
|
+
if pattern.at(i + 1) == '-' {
|
|
617
|
+
var int lo = pattern.at(i) as int
|
|
618
|
+
var int hi = pattern.at(i + 2) as int
|
|
619
|
+
while lo <= hi {
|
|
620
|
+
sb.append_char(lo as char)
|
|
621
|
+
lo += 1
|
|
622
|
+
}
|
|
623
|
+
i += 3
|
|
624
|
+
} else {
|
|
625
|
+
sb.append_char(c)
|
|
626
|
+
i += 1
|
|
579
627
|
}
|
|
580
|
-
i += 3
|
|
581
628
|
} else {
|
|
582
|
-
sb.append_char(
|
|
629
|
+
sb.append_char(c)
|
|
583
630
|
i += 1
|
|
584
631
|
}
|
|
585
|
-
} else {
|
|
586
|
-
sb.append_char(pattern.at(i))
|
|
587
|
-
i += 1
|
|
588
632
|
}
|
|
589
633
|
}
|
|
590
634
|
}
|
|
@@ -732,7 +776,23 @@ func match_here = (
|
|
|
732
776
|
}
|
|
733
777
|
}
|
|
734
778
|
|
|
735
|
-
// No quantifier: match the atom once, then the rest of the pattern.
|
|
779
|
+
// No quantifier: match the atom once, then the rest of the pattern. A
|
|
780
|
+
// GROUP atom goes through the continuation-aware path: its inner
|
|
781
|
+
// alternatives retry when the rest fails on an earlier one (JS-style
|
|
782
|
+
// backtracking — `(head|header)(\s|$|>)` must still match "header>").
|
|
783
|
+
if pc == '(' {
|
|
784
|
+
return match_group_then_rest(
|
|
785
|
+
pattern,
|
|
786
|
+
pat_pos,
|
|
787
|
+
a_end,
|
|
788
|
+
a_end,
|
|
789
|
+
pat_end,
|
|
790
|
+
input,
|
|
791
|
+
in_pos,
|
|
792
|
+
in_len,
|
|
793
|
+
ref caps,
|
|
794
|
+
)
|
|
795
|
+
}
|
|
736
796
|
var int next = match_single_atom(pattern, pat_pos, a_end, input, in_pos, in_len, ref caps)
|
|
737
797
|
if next < 0 {
|
|
738
798
|
return -1
|
|
@@ -740,6 +800,97 @@ func match_here = (
|
|
|
740
800
|
return match_here(pattern, a_end, pat_end, input, next, in_len, ref caps)
|
|
741
801
|
}
|
|
742
802
|
|
|
803
|
+
// The position of the first top-level '|' in [start, end), or -1. Escapes,
|
|
804
|
+
// character classes, and nested groups are skipped so only depth-0
|
|
805
|
+
// alternation operators count (same scanning discipline as match_here).
|
|
806
|
+
func next_top_level_alt = (string pattern, int start, int end, out int) {
|
|
807
|
+
var depth = 0
|
|
808
|
+
var int i = start
|
|
809
|
+
while i < end {
|
|
810
|
+
var char c = pattern.at(i)
|
|
811
|
+
if (c as int) == 92 {
|
|
812
|
+
i += 2
|
|
813
|
+
} else {
|
|
814
|
+
if c == '[' {
|
|
815
|
+
i = atom_end_pos(pattern, i, end)
|
|
816
|
+
} else {
|
|
817
|
+
if c == '(' {
|
|
818
|
+
depth += 1
|
|
819
|
+
}
|
|
820
|
+
if c == ')' {
|
|
821
|
+
if depth > 0 {
|
|
822
|
+
depth -= 1
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
if (c as int) == 124 {
|
|
826
|
+
if depth == 0 {
|
|
827
|
+
return i
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
i += 1
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
return -1
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
// Match the group atom spanning [atom_start, atom_end) ('(' at atom_start)
|
|
838
|
+
// and then the continuation [rest, pat_end), retrying the group's LATER
|
|
839
|
+
// alternatives whenever the continuation fails on an earlier one. Without
|
|
840
|
+
// this, a group commits to the first alternative that matches the group
|
|
841
|
+
// ALONE and a failing continuation aborts the whole match — the engine had
|
|
842
|
+
// no backtracking into a group's alternatives (PORT.md: `(head|header)`
|
|
843
|
+
// never reached `header` when `(\s|$|>)` rejected what `head` left behind).
|
|
844
|
+
// A group without a top-level '|' behaves exactly like the old
|
|
845
|
+
// match-atom-then-continue path, and a failed trial restores the group's
|
|
846
|
+
// previous capture span before the next attempt.
|
|
847
|
+
func match_group_then_rest = (
|
|
848
|
+
string pattern,
|
|
849
|
+
int atom_start,
|
|
850
|
+
int atom_end,
|
|
851
|
+
int rest,
|
|
852
|
+
int pat_end,
|
|
853
|
+
string input,
|
|
854
|
+
int in_pos,
|
|
855
|
+
int in_len,
|
|
856
|
+
ref List<int> caps,
|
|
857
|
+
out int
|
|
858
|
+
) {
|
|
859
|
+
var int g = group_index_at(pattern, atom_start)
|
|
860
|
+
var int at = last_capture_index(caps, g)
|
|
861
|
+
var int old_start = -1
|
|
862
|
+
var int old_end = -1
|
|
863
|
+
if at >= 0 {
|
|
864
|
+
old_start = caps.at(at + 1)
|
|
865
|
+
old_end = caps.at(at + 2)
|
|
866
|
+
}
|
|
867
|
+
var int inner_start = atom_start + 1
|
|
868
|
+
var int inner_end = atom_end - 1
|
|
869
|
+
var int s = inner_start
|
|
870
|
+
while s <= inner_end {
|
|
871
|
+
var int bar = next_top_level_alt(pattern, s, inner_end)
|
|
872
|
+
var int e = inner_end
|
|
873
|
+
if bar >= 0 {
|
|
874
|
+
e = bar
|
|
875
|
+
}
|
|
876
|
+
var int next = match_here(pattern, s, e, input, in_pos, in_len, ref caps)
|
|
877
|
+
if next >= 0 {
|
|
878
|
+
record_capture(ref caps, g, in_pos, next)
|
|
879
|
+
var int r = match_here(pattern, rest, pat_end, input, next, in_len, ref caps)
|
|
880
|
+
if r >= 0 {
|
|
881
|
+
return r
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
record_capture(ref caps, g, old_start, old_end)
|
|
885
|
+
if bar >= 0 {
|
|
886
|
+
s = bar + 1
|
|
887
|
+
} else {
|
|
888
|
+
s = inner_end + 1
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
return -1
|
|
892
|
+
}
|
|
893
|
+
|
|
743
894
|
// Return the position just past the atom that starts at pat_pos. Handles
|
|
744
895
|
// character classes [...], groups (...), and escaped characters (\x).
|
|
745
896
|
func atom_end_pos = (string pattern, int pat_pos, int pat_end, out int) {
|
|
@@ -860,7 +1011,7 @@ func match_single_atom = (
|
|
|
860
1011
|
return -1
|
|
861
1012
|
}
|
|
862
1013
|
if in_pos < in_len {
|
|
863
|
-
if input.at(in_pos) == ec {
|
|
1014
|
+
if (input.at(in_pos) as int) == escaped_byte_value(ec) {
|
|
864
1015
|
return in_pos + 1
|
|
865
1016
|
}
|
|
866
1017
|
}
|
|
@@ -908,7 +1059,7 @@ func char_matches_atom = (
|
|
|
908
1059
|
if is_shorthand(ec) {
|
|
909
1060
|
return matches_shorthand(ec, ic)
|
|
910
1061
|
}
|
|
911
|
-
return ic == ec
|
|
1062
|
+
return (ic as int) == escaped_byte_value(ec)
|
|
912
1063
|
}
|
|
913
1064
|
return false
|
|
914
1065
|
}
|
|
@@ -1018,29 +1169,99 @@ func match_star_group = (
|
|
|
1018
1169
|
) {
|
|
1019
1170
|
if lazy > 0 {
|
|
1020
1171
|
// Lazy: stop repeating first (minimum met), then try one more
|
|
1021
|
-
// iteration before giving up.
|
|
1172
|
+
// iteration before giving up. The iteration retries the group's
|
|
1173
|
+
// top-level alternatives (see match_group_iteration).
|
|
1022
1174
|
if min_count <= 0 {
|
|
1023
1175
|
var int stop = match_here(pattern, rest, pat_end, input, in_pos, in_len, ref caps)
|
|
1024
1176
|
if stop >= 0 {
|
|
1025
1177
|
return stop
|
|
1026
1178
|
}
|
|
1027
1179
|
}
|
|
1028
|
-
|
|
1180
|
+
return match_group_iteration(
|
|
1029
1181
|
pattern,
|
|
1030
1182
|
atom_start,
|
|
1031
1183
|
atom_end,
|
|
1184
|
+
rest,
|
|
1185
|
+
pat_end,
|
|
1032
1186
|
input,
|
|
1033
1187
|
in_pos,
|
|
1188
|
+
min_count,
|
|
1189
|
+
lazy,
|
|
1034
1190
|
in_len,
|
|
1035
1191
|
ref caps,
|
|
1036
1192
|
)
|
|
1193
|
+
}
|
|
1194
|
+
// Try matching the group one more time (greedy) — each top-level
|
|
1195
|
+
// alternative in turn — before stopping.
|
|
1196
|
+
var int r = match_group_iteration(
|
|
1197
|
+
pattern,
|
|
1198
|
+
atom_start,
|
|
1199
|
+
atom_end,
|
|
1200
|
+
rest,
|
|
1201
|
+
pat_end,
|
|
1202
|
+
input,
|
|
1203
|
+
in_pos,
|
|
1204
|
+
min_count,
|
|
1205
|
+
lazy,
|
|
1206
|
+
in_len,
|
|
1207
|
+
ref caps,
|
|
1208
|
+
)
|
|
1209
|
+
if r >= 0 {
|
|
1210
|
+
return r
|
|
1211
|
+
}
|
|
1212
|
+
// Stop repeating and try the rest of the pattern, if the minimum is met.
|
|
1213
|
+
if min_count <= 0 {
|
|
1214
|
+
return match_here(pattern, rest, pat_end, input, in_pos, in_len, ref caps)
|
|
1215
|
+
}
|
|
1216
|
+
return -1
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1219
|
+
// Try ONE further iteration of a quantified group at in_pos, retrying the
|
|
1220
|
+
// group's top-level alternatives while the remaining star recursion fails.
|
|
1221
|
+
// Returns the recursion's result, or -1 when no alternative leads to a
|
|
1222
|
+
// match. An alternative that matches the empty string is not recursed into
|
|
1223
|
+
// (an empty iteration cannot make progress; the caller's stop path covers
|
|
1224
|
+
// it), and every failed trial restores the group's previous capture span.
|
|
1225
|
+
func match_group_iteration = (
|
|
1226
|
+
string pattern,
|
|
1227
|
+
int atom_start,
|
|
1228
|
+
int atom_end,
|
|
1229
|
+
int rest,
|
|
1230
|
+
int pat_end,
|
|
1231
|
+
string input,
|
|
1232
|
+
int in_pos,
|
|
1233
|
+
int min_count,
|
|
1234
|
+
int lazy,
|
|
1235
|
+
int in_len,
|
|
1236
|
+
ref List<int> caps,
|
|
1237
|
+
out int
|
|
1238
|
+
) {
|
|
1239
|
+
var int g = group_index_at(pattern, atom_start)
|
|
1240
|
+
var int at = last_capture_index(caps, g)
|
|
1241
|
+
var int old_start = -1
|
|
1242
|
+
var int old_end = -1
|
|
1243
|
+
if at >= 0 {
|
|
1244
|
+
old_start = caps.at(at + 1)
|
|
1245
|
+
old_end = caps.at(at + 2)
|
|
1246
|
+
}
|
|
1247
|
+
var int inner_start = atom_start + 1
|
|
1248
|
+
var int inner_end = atom_end - 1
|
|
1249
|
+
var int s = inner_start
|
|
1250
|
+
while s <= inner_end {
|
|
1251
|
+
var int bar = next_top_level_alt(pattern, s, inner_end)
|
|
1252
|
+
var int e = inner_end
|
|
1253
|
+
if bar >= 0 {
|
|
1254
|
+
e = bar
|
|
1255
|
+
}
|
|
1256
|
+
var int next = match_here(pattern, s, e, input, in_pos, in_len, ref caps)
|
|
1037
1257
|
if next >= 0 {
|
|
1258
|
+
record_capture(ref caps, g, in_pos, next)
|
|
1038
1259
|
if next != in_pos {
|
|
1039
1260
|
var new_min = 0
|
|
1040
1261
|
if min_count > 0 {
|
|
1041
1262
|
new_min = min_count - 1
|
|
1042
1263
|
}
|
|
1043
|
-
|
|
1264
|
+
var int r = match_star_group(
|
|
1044
1265
|
pattern,
|
|
1045
1266
|
atom_start,
|
|
1046
1267
|
atom_end,
|
|
@@ -1053,40 +1274,18 @@ func match_star_group = (
|
|
|
1053
1274
|
in_len,
|
|
1054
1275
|
ref caps,
|
|
1055
1276
|
)
|
|
1277
|
+
if r >= 0 {
|
|
1278
|
+
return r
|
|
1279
|
+
}
|
|
1056
1280
|
}
|
|
1057
1281
|
}
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
if next != in_pos {
|
|
1064
|
-
var new_min = 0
|
|
1065
|
-
if min_count > 0 {
|
|
1066
|
-
new_min = min_count - 1
|
|
1067
|
-
}
|
|
1068
|
-
var int r = match_star_group(
|
|
1069
|
-
pattern,
|
|
1070
|
-
atom_start,
|
|
1071
|
-
atom_end,
|
|
1072
|
-
rest,
|
|
1073
|
-
pat_end,
|
|
1074
|
-
input,
|
|
1075
|
-
next,
|
|
1076
|
-
new_min,
|
|
1077
|
-
lazy,
|
|
1078
|
-
in_len,
|
|
1079
|
-
ref caps,
|
|
1080
|
-
)
|
|
1081
|
-
if r >= 0 {
|
|
1082
|
-
return r
|
|
1083
|
-
}
|
|
1282
|
+
record_capture(ref caps, g, old_start, old_end)
|
|
1283
|
+
if bar >= 0 {
|
|
1284
|
+
s = bar + 1
|
|
1285
|
+
} else {
|
|
1286
|
+
s = inner_end + 1
|
|
1084
1287
|
}
|
|
1085
1288
|
}
|
|
1086
|
-
// Stop repeating and try the rest of the pattern, if the minimum is met.
|
|
1087
|
-
if min_count <= 0 {
|
|
1088
|
-
return match_here(pattern, rest, pat_end, input, in_pos, in_len, ref caps)
|
|
1089
|
-
}
|
|
1090
1289
|
return -1
|
|
1091
1290
|
}
|
|
1092
1291
|
|
|
@@ -1110,6 +1309,21 @@ func match_optional = (
|
|
|
1110
1309
|
if skip >= 0 {
|
|
1111
1310
|
return skip
|
|
1112
1311
|
}
|
|
1312
|
+
// A group atom includes continuation-aware alternative retries (see
|
|
1313
|
+
// match_group_then_rest) in both moods.
|
|
1314
|
+
if pattern.at(atom_start) == '(' {
|
|
1315
|
+
return match_group_then_rest(
|
|
1316
|
+
pattern,
|
|
1317
|
+
atom_start,
|
|
1318
|
+
atom_end,
|
|
1319
|
+
rest,
|
|
1320
|
+
pat_end,
|
|
1321
|
+
input,
|
|
1322
|
+
in_pos,
|
|
1323
|
+
in_len,
|
|
1324
|
+
ref caps,
|
|
1325
|
+
)
|
|
1326
|
+
}
|
|
1113
1327
|
var int next = match_single_atom(
|
|
1114
1328
|
pattern,
|
|
1115
1329
|
atom_start,
|
|
@@ -1124,11 +1338,28 @@ func match_optional = (
|
|
|
1124
1338
|
}
|
|
1125
1339
|
return -1
|
|
1126
1340
|
}
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1341
|
+
if pattern.at(atom_start) == '(' {
|
|
1342
|
+
var int grouped = match_group_then_rest(
|
|
1343
|
+
pattern,
|
|
1344
|
+
atom_start,
|
|
1345
|
+
atom_end,
|
|
1346
|
+
rest,
|
|
1347
|
+
pat_end,
|
|
1348
|
+
input,
|
|
1349
|
+
in_pos,
|
|
1350
|
+
in_len,
|
|
1351
|
+
ref caps,
|
|
1352
|
+
)
|
|
1353
|
+
if grouped >= 0 {
|
|
1354
|
+
return grouped
|
|
1355
|
+
}
|
|
1356
|
+
} else {
|
|
1357
|
+
var int next = match_single_atom(pattern, atom_start, atom_end, input, in_pos, in_len, ref caps)
|
|
1358
|
+
if next >= 0 {
|
|
1359
|
+
var int r = match_here(pattern, rest, pat_end, input, next, in_len, ref caps)
|
|
1360
|
+
if r >= 0 {
|
|
1361
|
+
return r
|
|
1362
|
+
}
|
|
1132
1363
|
}
|
|
1133
1364
|
}
|
|
1134
1365
|
return match_here(pattern, rest, pat_end, input, in_pos, in_len, ref caps)
|
|
@@ -1173,7 +1404,7 @@ func char_in_class = (
|
|
|
1173
1404
|
found = true
|
|
1174
1405
|
}
|
|
1175
1406
|
} else {
|
|
1176
|
-
if ic == e {
|
|
1407
|
+
if (ic as int) == escaped_byte_value(e) {
|
|
1177
1408
|
found = true
|
|
1178
1409
|
}
|
|
1179
1410
|
}
|
|
@@ -1428,6 +1659,29 @@ func is_shorthand = (char c, out bool) {
|
|
|
1428
1659
|
return code == 100 || code == 68 || code == 119 || code == 87 || code == 115 || code == 83
|
|
1429
1660
|
}
|
|
1430
1661
|
|
|
1662
|
+
// Whether the escaped character c names a control-character shorthand
|
|
1663
|
+
// (\n \r \t) that the engine maps to its real control byte.
|
|
1664
|
+
func is_control_escape = (char c, out bool) {
|
|
1665
|
+
var int code = c as int
|
|
1666
|
+
return code == 110 || code == 114 || code == 116
|
|
1667
|
+
}
|
|
1668
|
+
|
|
1669
|
+
// The byte an escaped atom names: \n is LF (10), \r is CR (13), \t is TAB
|
|
1670
|
+
// (9); every other escaped character is the literal byte of that character.
|
|
1671
|
+
func escaped_byte_value = (char c, out int) {
|
|
1672
|
+
var int code = c as int
|
|
1673
|
+
if code == 110 {
|
|
1674
|
+
return 10
|
|
1675
|
+
}
|
|
1676
|
+
if code == 114 {
|
|
1677
|
+
return 13
|
|
1678
|
+
}
|
|
1679
|
+
if code == 116 {
|
|
1680
|
+
return 9
|
|
1681
|
+
}
|
|
1682
|
+
return code
|
|
1683
|
+
}
|
|
1684
|
+
|
|
1431
1685
|
// Whether byte b belongs to the shorthand class named by c. Uppercase names
|
|
1432
1686
|
// are the complements (S/D/W match anything the lowercase set excludes).
|
|
1433
1687
|
func matches_shorthand = (char c, char b, out bool) {
|