Add basic rule definitions to grammar proc macro

This commit is contained in:
2025-05-25 02:21:45 -07:00
parent 1d8c939400
commit 6933ae47b4
2 changed files with 44 additions and 10 deletions
+40 -6
View File
@@ -1,7 +1,7 @@
use proc_macro::TokenStream; use proc_macro::TokenStream;
use quote::quote; use quote::quote;
use syn::{ use syn::{
Ident, Token, Ident, LitStr, Token,
parse::{Parse, ParseStream}, parse::{Parse, ParseStream},
parse_macro_input, parse_macro_input,
punctuated::Punctuated, punctuated::Punctuated,
@@ -13,6 +13,12 @@ struct Grammar {
struct Rule { struct Rule {
name: Ident, name: Ident,
terms: Vec<Term>,
}
enum Term {
Rule(Ident),
Literal(LitStr),
} }
impl Parse for Grammar { impl Parse for Grammar {
@@ -25,10 +31,26 @@ impl Parse for Grammar {
impl Parse for Rule { impl Parse for Rule {
fn parse(input: ParseStream) -> syn::Result<Self> { fn parse(input: ParseStream) -> syn::Result<Self> {
let result = Self { let name = input.parse()?;
name: input.parse()?, input.parse::<Token![=]>()?;
}; let mut terms = vec![];
Ok(result) while !input.peek(Token![;]) {
terms.push(input.parse()?);
}
Ok(Self { name, terms })
}
}
impl Parse for Term {
fn parse(input: ParseStream) -> syn::Result<Self> {
let look = input.lookahead1();
if look.peek(Ident) {
input.parse().map(Term::Rule)
} else if look.peek(LitStr) {
input.parse().map(Term::Literal)
} else {
Err(look.error())
}
} }
} }
@@ -65,9 +87,21 @@ pub fn grammar(ts: TokenStream) -> TokenStream {
.iter() .iter()
.map(|r| { .map(|r| {
let fn_name = &r.name; let fn_name = &r.name;
// Generate a string for debugging
let term_strs: Vec<String> = r
.terms
.iter()
.map(|t| match t {
Term::Rule(ident) => format!("rule {}", ident.to_string()),
Term::Literal(lit_str) => format!("literal \"{}\"", lit_str.value()),
})
.collect();
let text = format!("I'm generated! ({})", term_strs.join(", "));
quote! { quote! {
fn #fn_name() -> String { fn #fn_name() -> String {
"I'm a generated function!".into() #text.into()
} }
} }
}) })
+4 -4
View File
@@ -65,8 +65,8 @@ fn parse_oo(p: &mut ParseState) -> bool {
} }
grammar! { grammar! {
generated_this; generated_this = foo;
generated_that; generated_that = "bar" baz;
} }
#[cfg(test)] #[cfg(test)]
@@ -85,7 +85,7 @@ mod tests {
#[test] #[test]
fn test_generated() { fn test_generated() {
assert_snapshot!(generated_this(), @"I'm a generated function!"); assert_snapshot!(generated_this(), @"I'm generated! (rule foo)");
assert_snapshot!(generated_that(), @"I'm a generated function!"); assert_snapshot!(generated_that(), @r#"I'm generated! (literal "bar", rule baz)"#);
} }
} }