Skip to content

Commit c78bf07

Browse files
committed
yeast-macros: Analyse explicit rule!s inside of rules!
The `rules!` macro needs to inspect every rule before expansion so it can apply schema-aware transformations consistently. When we encounter an embedded `rule!` macro inside of `rules!`, we now unwrap it and lower it as if it were an inline rule.
1 parent 3c6fc14 commit c78bf07

1 file changed

Lines changed: 26 additions & 2 deletions

File tree

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

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,13 @@ pub fn parse_rules_top(input: TokenStream) -> Result<TokenStream> {
6363
let emitted_items = split_top_level_commas(list.stream())
6464
.into_iter()
6565
.map(|item| {
66-
if has_top_level_arrow(&item) {
67-
Ok(crate::rule_parse::parse_rule(item)?.lower())
66+
let rule_body = if has_top_level_arrow(&item) {
67+
Some(item.clone())
68+
} else {
69+
explicit_rule_body(&item)
70+
};
71+
if let Some(rule_body) = rule_body {
72+
Ok(crate::rule_parse::parse_rule(rule_body)?.lower())
6873
} else {
6974
Ok(item)
7075
}
@@ -152,6 +157,17 @@ fn has_top_level_arrow(stream: &TokenStream) -> bool {
152157
})
153158
}
154159

160+
fn explicit_rule_body(stream: &TokenStream) -> Option<TokenStream> {
161+
let expression = syn::parse2::<syn::ExprMacro>(stream.clone()).ok()?;
162+
let is_rule = expression
163+
.mac
164+
.path
165+
.segments
166+
.last()
167+
.is_some_and(|segment| segment.ident == "rule");
168+
is_rule.then_some(expression.mac.tokens)
169+
}
170+
155171
type Tokens = std::iter::Peekable<proc_macro2::token_stream::IntoIter>;
156172

157173
fn expect_ident(tokens: &mut Tokens, message: &str) -> Result<syn::Ident> {
@@ -212,4 +228,12 @@ mod tests {
212228
&quote! { { match x { 1 => 2, _ => 3 } } }
213229
));
214230
}
231+
232+
#[test]
233+
fn recognizes_explicit_rule_macros() {
234+
assert!(explicit_rule_body(&quote! { rule!((a) => (b)) }).is_some());
235+
assert!(explicit_rule_body(&quote! { yeast::rule!((a) => (b)) }).is_some());
236+
assert!(explicit_rule_body(&quote! { other!((a) => (b)) }).is_none());
237+
assert!(explicit_rule_body(&quote! { make_rule() }).is_none());
238+
}
215239
}

0 commit comments

Comments
 (0)