Add basic rule definitions to grammar proc macro
This commit is contained in:
+40
-6
@@ -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
@@ -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)"#);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user