Skip to content

Commit 324de63

Browse files
committed
yeast: Explicitly warn on nested captured repetitions
This is a weird pattern (that we don't use) that had weird semantics previously. A minimal example would be something like ``` ((item)* (separator))* @Items ``` Here, it's not really clear what @Items should be capturing. The current implementation (post-AST rewrite) simply panics at compile-time, with a message that may or may not be helpful. As the Copilot review correctly points out, this is a regression compared to the previous behaviour (which dealt with the issue by just throwing away the `(item)*` bit). This compiled, but I don't think the old behaviour is particularly sensible either. For that reason, we now explicitly warn that capturing a group containing a nested repetition is an error. At present, we never employ the above pattern in our code. If this changes, then we'll likely want to provide a sensible semantics for this case rather than just panicking.
1 parent 9deb0d7 commit 324de63

1 file changed

Lines changed: 25 additions & 0 deletions

File tree

‎shared/yeast-macros/src/rule_parse.rs‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,18 @@ fn maybe_repeat(tokens: &mut Tokens, pattern: Pattern) -> Result<Pattern> {
213213
});
214214
}
215215

216+
if matches!(
217+
&pattern,
218+
Pattern::Sequence(patterns)
219+
if patterns.iter().any(|pattern| matches!(pattern, Pattern::Repeated { .. }))
220+
) {
221+
return Err(syn::Error::new_spanned(
222+
tokens.peek().unwrap().clone(),
223+
"cannot capture a repeated group containing a nested repetition; \
224+
capture the desired inner patterns explicitly",
225+
));
226+
}
227+
216228
let (name, raw) = consume_capture(tokens)?;
217229
Ok(match pattern {
218230
Pattern::Sequence(patterns) => Pattern::Repeated {
@@ -539,4 +551,17 @@ mod tests {
539551
assert_eq!(*cardinality, Cardinality::ZERO_OR_MORE);
540552
assert!(matches!(captured.as_ref(), Pattern::Node { .. }));
541553
}
554+
555+
#[test]
556+
fn rejects_capture_on_repeated_group_with_nested_repetition() {
557+
let result = parse_pattern(quote!((root ((item)* (separator))* @items)));
558+
let Err(error) = result else {
559+
panic!("expected nested repetition capture to be rejected");
560+
};
561+
assert_eq!(
562+
error.to_string(),
563+
"cannot capture a repeated group containing a nested repetition; \
564+
capture the desired inner patterns explicitly"
565+
);
566+
}
542567
}

0 commit comments

Comments
 (0)