Add @icase decorator

This commit is contained in:
2025-06-01 10:50:53 -07:00
parent 4a065db1e6
commit 96b6733dcb
2 changed files with 47 additions and 1 deletions
+35 -1
View File
@@ -38,6 +38,7 @@ enum Term {
mod kw { mod kw {
syn::custom_keyword!(ANY); syn::custom_keyword!(ANY);
syn::custom_keyword!(EOI); syn::custom_keyword!(EOI);
syn::custom_keyword!(icase);
} }
impl Parse for Grammar { impl Parse for Grammar {
@@ -50,9 +51,23 @@ 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 mut icase = false;
if input.parse::<Token![@]>().is_ok() {
let look = input.lookahead1();
if look.peek(kw::icase) {
input.parse::<kw::icase>()?;
icase = true;
} else {
return Err(look.error());
}
}
let name = input.parse()?; let name = input.parse()?;
input.parse::<Token![=]>()?; input.parse::<Token![=]>()?;
let definition = input.parse()?; let mut definition: Term = input.parse()?;
if icase {
definition.set_icase();
}
Ok(Self { name, definition }) 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] #[proc_macro]
+12
View File
@@ -106,6 +106,10 @@ mod tests {
quoted = dq ("\\" ANY / !dq ANY)* dq; quoted = dq ("\\" ANY / !dq ANY)* dq;
case_sensitivity = "Strict " ('a'..'z')+ ", loose "i ('a'..'z'i)+; 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<T: Fn(&mut ParseState) -> bool>(rule: T, s: &str) -> bool { fn parse<T: Fn(&mut ParseState) -> 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"));
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"));
}
} }