Skip to content

Commit d30fd27

Browse files
committed
Address #1554 - capture first 0-width match in repeating rules and
optionals. This fixes some undesirable interplay between lookaheads and looping (repeating) rules where lookaheads caused the loop to immediately terminate _and_ discard any captures. This change adds an exception if there is a 0-width match at the first iteration of the loop, in which case captures will be kept, although the loop will still be terminated (any further iteration of the loop would possibly cause an infinite loop). This allows optionals to work as expected when combined with lookahead. There is also a question of whether or not optional should be implemented as separate rule rather than as `(between 0 1 subrule)`.
1 parent 1b278fc commit d30fd27

File tree

2 files changed

+9
-1
lines changed

2 files changed

+9
-1
lines changed

src/core/peg.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,7 @@ static const uint8_t *peg_rule(
343343
CapState cs2 = cap_save(s);
344344
next_text = peg_rule(s, rule_a, text);
345345
if (!next_text || next_text == text) {
346-
cap_load(s, cs2);
346+
if (!next_text || captured > 0) cap_load(s, cs2);
347347
break;
348348
}
349349
captured++;

test/suite-peg.janet

+8
Original file line numberDiff line numberDiff line change
@@ -789,5 +789,13 @@
789789
"abc123"
790790
@["abc123"])
791791

792+
# Issue 1554
793+
(test "issue 1554 case 1" '(any (> '1)) "abc" @["a"])
794+
(test "issue 1554 case 2" '(any (? (> '1))) "abc" @["a"])
795+
(test "issue 1554 case 3" '(any (> (? '1))) "abc" @["a"])
796+
(test "issue 1554 case 4" '(* "a" (> '1)) "abc" @["b"])
797+
(test "issue 1554 case 5" '(* "a" (? (> '1))) "abc" @["b"])
798+
(test "issue 1554 case 6" '(* "a" (> (? '1))) "abc" @["b"])
799+
792800
(end-suite)
793801

0 commit comments

Comments
 (0)