Skip to content

Commit cafada6

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 2853b34 commit cafada6

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
@@ -230,6 +230,18 @@ fn capture_repeated_pattern(tokens: &mut Tokens, pattern: Pattern) -> Result<Pat
230230
return Ok(pattern);
231231
}
232232

233+
if matches!(
234+
&pattern,
235+
Pattern::Sequence(patterns)
236+
if patterns.iter().any(|pattern| matches!(pattern, Pattern::Repeated { .. }))
237+
) {
238+
return Err(syn::Error::new_spanned(
239+
tokens.peek().unwrap().clone(),
240+
"cannot capture a repeated group containing a nested repetition; \
241+
capture the desired inner patterns explicitly",
242+
));
243+
}
244+
233245
let capture = consume_capture(tokens)?;
234246
Ok(match pattern {
235247
Pattern::Sequence(patterns) => Pattern::Sequence(
@@ -525,4 +537,17 @@ mod tests {
525537
assert!(rule.guard.is_none());
526538
assert!(matches!(rule.replacement, Replacement::Templates(_)));
527539
}
540+
541+
#[test]
542+
fn rejects_capture_on_repeated_group_with_nested_repetition() {
543+
let result = parse_pattern(quote!((root ((item)* (separator))* @items)));
544+
let Err(error) = result else {
545+
panic!("expected nested repetition capture to be rejected");
546+
};
547+
assert_eq!(
548+
error.to_string(),
549+
"cannot capture a repeated group containing a nested repetition; \
550+
capture the desired inner patterns explicitly"
551+
);
552+
}
528553
}

0 commit comments

Comments
 (0)