Skip to content

Commit 410f8d6

Browse files
authored
Merge pull request #1528 from ianthehenry/til-peg-special
add (til) PEG special
2 parents 6da44bd + 9529062 commit 410f8d6

File tree

3 files changed

+82
-0
lines changed

3 files changed

+82
-0
lines changed

src/core/peg.c

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,42 @@ static const uint8_t *peg_rule(
544544
return window_end;
545545
}
546546

547+
case RULE_TIL: {
548+
const uint32_t *rule_terminus = s->bytecode + rule[1];
549+
const uint32_t *rule_subpattern = s->bytecode + rule[2];
550+
551+
const uint8_t *terminus_start = text;
552+
const uint8_t *terminus_end = NULL;
553+
down1(s);
554+
while (terminus_start <= s->text_end) {
555+
CapState cs2 = cap_save(s);
556+
terminus_end = peg_rule(s, rule_terminus, terminus_start);
557+
cap_load(s, cs2);
558+
if (terminus_end) {
559+
break;
560+
}
561+
terminus_start++;
562+
}
563+
up1(s);
564+
565+
if (!terminus_end) {
566+
return NULL;
567+
}
568+
569+
const uint8_t *saved_end = s->text_end;
570+
s->text_end = terminus_start;
571+
down1(s);
572+
const uint8_t *matched = peg_rule(s, rule_subpattern, text);
573+
up1(s);
574+
s->text_end = saved_end;
575+
576+
if (!matched) {
577+
return NULL;
578+
}
579+
580+
return terminus_end;
581+
}
582+
547583
case RULE_SPLIT: {
548584
const uint8_t *saved_end = s->text_end;
549585
const uint32_t *rule_separator = s->bytecode + rule[1];
@@ -1230,6 +1266,14 @@ static void spec_sub(Builder *b, int32_t argc, const Janet *argv) {
12301266
emit_2(r, RULE_SUB, subrule1, subrule2);
12311267
}
12321268

1269+
static void spec_til(Builder *b, int32_t argc, const Janet *argv) {
1270+
peg_fixarity(b, argc, 2);
1271+
Reserve r = reserve(b, 3);
1272+
uint32_t subrule1 = peg_compile1(b, argv[0]);
1273+
uint32_t subrule2 = peg_compile1(b, argv[1]);
1274+
emit_2(r, RULE_TIL, subrule1, subrule2);
1275+
}
1276+
12331277
static void spec_split(Builder *b, int32_t argc, const Janet *argv) {
12341278
peg_fixarity(b, argc, 2);
12351279
Reserve r = reserve(b, 3);
@@ -1326,6 +1370,7 @@ static const SpecialPair peg_specials[] = {
13261370
{"split", spec_split},
13271371
{"sub", spec_sub},
13281372
{"thru", spec_thru},
1373+
{"til", spec_til},
13291374
{"to", spec_to},
13301375
{"uint", spec_uint_le},
13311376
{"uint-be", spec_uint_be},
@@ -1665,6 +1710,7 @@ static void *peg_unmarshal(JanetMarshalContext *ctx) {
16651710
i += 4;
16661711
break;
16671712
case RULE_SUB:
1713+
case RULE_TIL:
16681714
case RULE_SPLIT:
16691715
/* [rule, rule] */
16701716
if (rule[1] >= blen) goto bad;

src/include/janet.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2182,6 +2182,7 @@ typedef enum {
21822182
RULE_UNREF, /* [rule, tag] */
21832183
RULE_CAPTURE_NUM, /* [rule, tag] */
21842184
RULE_SUB, /* [rule, rule] */
2185+
RULE_TIL, /* [rule, rule] */
21852186
RULE_SPLIT, /* [rule, rule] */
21862187
RULE_NTH, /* [nth, rule, tag] */
21872188
RULE_ONLY_TAGS, /* [rule] */

test/suite-peg.janet

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -713,6 +713,41 @@
713713
"abcdef"
714714
@[])
715715

716+
(test "til: basic matching"
717+
~(til "d" "abc")
718+
"abcdef"
719+
@[])
720+
721+
(test "til: second pattern can't see past the first occurrence of first pattern"
722+
~(til "d" (* "abc" -1))
723+
"abcdef"
724+
@[])
725+
726+
(test "til: fails if first pattern fails"
727+
~(til "x" "abc")
728+
"abcdef"
729+
nil)
730+
731+
(test "til: fails if second pattern fails"
732+
~(til "abc" "x")
733+
"abcdef"
734+
nil)
735+
736+
(test "til: discards captures from initial pattern"
737+
~(til '"d" '"abc")
738+
"abcdef"
739+
@["abc"])
740+
741+
(test "til: positions inside second match are still relative to the entire input"
742+
~(* "one\ntw" (til 0 (* ($) (line) (column))))
743+
"one\ntwo\nthree\n"
744+
@[6 2 3])
745+
746+
(test "til: advances to the end of the first pattern's first occurrence"
747+
~(* (til "d" "ab") "e")
748+
"abcdef"
749+
@[])
750+
716751
(test "split: basic functionality"
717752
~(split "," '1)
718753
"a,b,c"

0 commit comments

Comments
 (0)