Add combinator NoCase

This commit is contained in:
2025-05-11 01:27:05 -07:00
parent b685e4e657
commit 0c5bacc341
+47 -2
View File
@@ -7,6 +7,7 @@ pub struct Parser {
input: String,
offset: usize,
captures: Vec<RawCapture>,
case_sensitive: bool,
}
impl Parser {
@@ -15,6 +16,7 @@ impl Parser {
input: input.into(),
offset: 0,
captures: Vec::new(),
case_sensitive: true,
}
}
@@ -127,7 +129,12 @@ where
impl Rule for &str {
fn parse(&self, p: &mut Parser) -> bool {
if p.input[p.offset..].starts_with(self) {
let matches = if p.case_sensitive {
p.input[p.offset..].starts_with(self)
} else {
p.input[p.offset..(p.offset + self.len())].eq_ignore_ascii_case(self)
};
if matches {
p.offset += self.len();
true
} else {
@@ -139,7 +146,12 @@ impl Rule for &str {
impl Rule for RangeInclusive<char> {
fn parse(&self, p: &mut Parser) -> bool {
if let Some(c) = p.input[p.offset..].chars().next() {
if self.contains(&c) {
let matches = if p.case_sensitive {
self.contains(&c)
} else {
self.contains(&c.to_ascii_uppercase()) || self.contains(&c.to_ascii_lowercase())
};
if matches {
p.offset += c.len_utf8();
return true;
}
@@ -218,6 +230,21 @@ impl Rule for Dot {
}
}
pub struct NoCase<T>(pub T);
impl<T> Rule for NoCase<T>
where
T: Rule,
{
fn parse(&self, p: &mut Parser) -> bool {
let old_value = p.case_sensitive;
p.case_sensitive = false;
let result = self.0.parse(p);
p.case_sensitive = old_value;
result
}
}
pub struct Not<T>(pub T);
impl<T> Rule for Not<T>
@@ -406,6 +433,24 @@ mod test {
parse(&rule, "foo\nbar");
}
#[test]
fn test_combinator_nocase() {
let rule = NoCase(("foo-", 'a'..='z', 'A'..='Z'));
parse(&rule, "foo-ab");
parse(&rule, "fOO-cD");
parse(&rule, "Foo-Ef");
parse(&rule, "FOO-GH");
}
#[test]
fn test_mixed_case() {
let rule = ("foo ", NoCase("bar"), " baz");
parse(&rule, "foo bar baz");
parse(&rule, "foo BAR baz");
parse_err(&rule, "FOO bar baz");
parse_err(&rule, "foo bar BAZ");
}
#[test]
fn test_combinator_not() {
let rule = (Not("foo"), star!(Dot));