diff --git a/peg_macro/src/lib.rs b/peg_macro/src/lib.rs index 9bec687..f0dba6a 100644 --- a/peg_macro/src/lib.rs +++ b/peg_macro/src/lib.rs @@ -38,6 +38,7 @@ enum Term { mod kw { syn::custom_keyword!(ANY); syn::custom_keyword!(EOI); + syn::custom_keyword!(icase); } impl Parse for Grammar { @@ -50,9 +51,23 @@ impl Parse for Grammar { impl Parse for Rule { fn parse(input: ParseStream) -> syn::Result { + let mut icase = false; + if input.parse::().is_ok() { + let look = input.lookahead1(); + if look.peek(kw::icase) { + input.parse::()?; + icase = true; + } else { + return Err(look.error()); + } + } + let name = input.parse()?; input.parse::()?; - let definition = input.parse()?; + let mut definition: Term = input.parse()?; + if icase { + definition.set_icase(); + } Ok(Self { name, definition }) } } @@ -264,6 +279,25 @@ impl Term { } } } + + fn set_icase(&mut self) { + match self { + Term::Literal(_, icase) | Term::Range(_, icase) => { + *icase = true; + } + Term::Choice(terms) | Term::Sequence(terms) => { + terms.iter_mut().for_each(|x| x.set_icase()); + } + Term::NegLookahead(term) + | Term::Optional(term) + | Term::Plus(term) + | Term::PosLookahead(term) + | Term::Star(term) => { + term.set_icase(); + } + Term::AnyChar | Term::EOI | Term::Rule(_) => {} + } + } } #[proc_macro] diff --git a/src/peg/peg.rs b/src/peg/peg.rs index bd24e63..862db47 100644 --- a/src/peg/peg.rs +++ b/src/peg/peg.rs @@ -106,6 +106,10 @@ mod tests { quoted = dq ("\\" ANY / !dq ANY)* dq; case_sensitivity = "Strict " ('a'..'z')+ ", loose "i ('a'..'z'i)+; + + @icase + hex_config = "let " var_name " = 0x" ('a'..'f' / '0'..'9')+; + var_name = "foo" / "bar"; // case must match } fn parse bool>(rule: T, s: &str) -> bool { @@ -194,4 +198,12 @@ mod tests { assert!(parse(case_sensitivity, "Strict abc, loose XYZ")); assert!(parse(case_sensitivity, "Strict abc, LoOsE XyZ")); } + + #[test] + fn test_icase_decorator() { + assert!(parse(hex_config, "let foo = 0xc0ffee")); + assert!(parse(hex_config, "LET bar = 0XCAFE")); + assert!(!parse(hex_config, "let Foo = 0xc0ffee")); + assert!(!parse(hex_config, "let BAR = 0xcafe")); + } }