Refactor Term to allow sequences

This commit is contained in:
2025-05-25 20:35:09 -07:00
parent 2305e6453f
commit 63dc9790ed
2 changed files with 36 additions and 25 deletions
+35 -24
View File
@@ -13,7 +13,7 @@ struct Grammar {
struct Rule { struct Rule {
name: Ident, name: Ident,
terms: Vec<Term>, definition: Term,
} }
enum Term { enum Term {
@@ -34,23 +34,32 @@ impl Parse for Rule {
fn parse(input: ParseStream) -> syn::Result<Self> { fn parse(input: ParseStream) -> syn::Result<Self> {
let name = input.parse()?; let name = input.parse()?;
input.parse::<Token![=]>()?; input.parse::<Token![=]>()?;
let mut terms = vec![]; let definition = input.parse()?;
while !input.peek(Token![;]) { Ok(Self { name, definition })
terms.push(input.parse()?);
}
Ok(Self { name, terms })
} }
} }
impl Parse for Term { impl Parse for Term {
fn parse(input: ParseStream) -> syn::Result<Self> { fn parse(input: ParseStream) -> syn::Result<Self> {
let look = input.lookahead1(); let mut terms = vec![];
if look.peek(Ident) { let parse_one = || {
input.parse().map(Term::Rule) let look = input.lookahead1();
} else if look.peek(LitStr) { if look.peek(Ident) {
input.parse().map(Term::Literal) input.parse().map(Term::Rule)
} else if look.peek(LitStr) {
input.parse().map(Term::Literal)
} else {
Err(look.error())
}
};
terms.push(parse_one()?);
while !input.is_empty() && !input.peek(Token![;]) {
terms.push(parse_one()?);
}
if terms.len() == 1 {
Ok(terms.pop().unwrap())
} else { } else {
Err(look.error()) Ok(Term::Sequence(terms))
} }
} }
} }
@@ -66,7 +75,9 @@ impl Term {
println!("parse literal"); println!("parse literal");
// call p.literal() // call p.literal()
}, },
Term::Sequence(terms) => todo!(), Term::Sequence(terms) => quote! {
println!("sequence");
},
} }
} }
} }
@@ -106,22 +117,22 @@ pub fn grammar(ts: TokenStream) -> TokenStream {
let fn_name = &r.name; let fn_name = &r.name;
// Generate a string for debugging // Generate a string for debugging
let term_strs: Vec<String> = r fn term2str(t: &Term) -> String {
.terms match t {
.iter()
.map(|t| match t {
Term::Rule(ident) => format!("rule {}", ident.to_string()), Term::Rule(ident) => format!("rule {}", ident.to_string()),
Term::Literal(lit_str) => format!("literal \"{}\"", lit_str.value()), Term::Literal(lit_str) => format!("literal \"{}\"", lit_str.value()),
Term::Sequence(terms) => todo!(), Term::Sequence(terms) => {
}) let parts: Vec<_> = terms.iter().map(term2str).collect();
.collect(); format!("sequence [{}]", parts.join(", "))
let text = format!("I'm generated! ({})", term_strs.join(", ")); }
}
let generated: Vec<_> = r.terms.iter().map(|t| t.generate_code()).collect(); }
let text = format!("I'm generated! ({})", term2str(&r.definition));
let generated = r.definition.generate_code();
quote! { quote! {
fn #fn_name(p: &mut crate::peg::ParseState) -> String { fn #fn_name(p: &mut crate::peg::ParseState) -> String {
#(#generated)* #generated
#text.into() #text.into()
} }
} }
+1 -1
View File
@@ -87,6 +87,6 @@ mod tests {
fn test_generated() { fn test_generated() {
let mut p = ParseState::new(""); let mut p = ParseState::new("");
assert_snapshot!(generated_this(&mut p), @"I'm generated! (rule foo)"); assert_snapshot!(generated_this(&mut p), @"I'm generated! (rule foo)");
assert_snapshot!(generated_that(&mut p), @r#"I'm generated! (literal "bar", rule baz)"#); assert_snapshot!(generated_that(&mut p), @r#"I'm generated! (sequence [literal "bar", rule baz])"#);
} }
} }