diff --git a/src/preprocess/peg.rs b/src/preprocess/peg.rs index e7c7411..9f9bc19 100644 --- a/src/preprocess/peg.rs +++ b/src/preprocess/peg.rs @@ -161,6 +161,37 @@ macro_rules! impl_rule_for_alt { }; } +struct Star(T); + +impl Rule for Star +where + T: Rule, +{ + fn parse(&self, p: &mut Parser) -> Result<()> { + while self.0.parse(p).is_ok() {} + Ok(()) + } +} + +macro_rules! star { + ($($item:tt),+ $(,)?) => { + Star(( + $($item),+, + )) + }; +} + +pub struct EOF; + +impl Rule for EOF { + fn parse(&self, p: &mut Parser) -> Result<()> { + if p.offset < p.input.len() { + bail!("No match"); + } + Ok(()) + } +} + macro_rules! impl_rule_for_many { () => {}; ($head:ident $($tail:ident)*) => { @@ -175,6 +206,12 @@ impl_rule_for_many!(A B C D E F G H I J); mod test { use super::*; + fn parse(rule: &T, input: &str) -> Result<()> { + let mut p = Parser::new(input); + let rule = (Ref(rule), EOF); + rule.parse(&mut p) + } + #[test] fn test_hello() { let mut p = Parser::new("foo"); @@ -200,10 +237,22 @@ mod test { } #[test] - fn test_combinator_alt() { + fn test_combinator_alt() -> Result<()> { let item = Alt(("foo", "bar", "baz")); let rule = (Ref(&item), ", ", Ref(&item)); - let mut p = Parser::new("foo, bar"); - rule.parse(&mut p).unwrap() + parse(&rule, "foo, bar")?; + parse(&rule, "bar, baz")?; + parse(&rule, "baz, foo")?; + Ok(()) + } + + #[test] + fn test_combinator_star() -> Result<()> { + let item = "foo"; + let csv = (item, star!(", ", item)); + parse(&csv, "foo")?; + parse(&csv, "foo, foo")?; + parse(&csv, "foo, foo, foo")?; + Ok(()) } }