use crate::bnf::Bnf; use crate::parser::{ParseResult, Parser, ParserInput}; pub fn choice2(parser1: P1, parser2: P2) -> impl Parser where P1: Parser, P2: Parser, I: ParserInput + Clone, { move |input: I| match parser1.parse(input.clone()) { ok @ Ok(..) => ok, Err(_e) => parser2.parse(input), } } pub fn choice(choices: C) -> (impl Parser, Bnf) where C: Choice, I: ParserInput + Clone, { let bnf = choices.bnf(); (move |input| choices.parse(input), bnf) } pub trait Choice { fn parse(&self, input: I) -> ParseResult; fn bnf(&self) -> Bnf; } impl Choice for (P1, P2) where P1: Parser, P2: Parser, I: ParserInput + Clone, { fn parse(&self, input: I) -> ParseResult { let parsers = vec![&self.0 as &dyn Parser, &self.1]; choice_loop(input, parsers) } fn bnf(&self) -> Bnf { let parsers = vec![&self.0 as &dyn Parser, &self.1]; Bnf::Choice( parsers .into_iter() .map(|p| p.bnf().unwrap_or(Bnf::Unknown)) .collect(), ) } } impl Choice for (P1, P2, P3) where P1: Parser, P2: Parser, P3: Parser, I: ParserInput + Clone, { fn parse(&self, input: I) -> ParseResult { let parsers = vec![&self.0 as &dyn Parser, &self.1, &self.2]; choice_loop(input, parsers) } fn bnf(&self) -> Bnf { let parsers = vec![&self.0 as &dyn Parser, &self.1, &self.2]; Bnf::Choice( parsers .into_iter() .map(|p| p.bnf().unwrap_or(Bnf::Unknown)) .collect(), ) } } impl Choice for (P1, P2, P3, P4) where P1: Parser, P2: Parser, P3: Parser, P4: Parser, I: ParserInput + Clone, { fn parse(&self, input: I) -> ParseResult { let parsers = vec![&self.0 as &dyn Parser, &self.1, &self.2, &self.3]; choice_loop(input, parsers) } fn bnf(&self) -> Bnf { let parsers = vec![&self.0 as &dyn Parser, &self.1, &self.2, &self.3]; Bnf::Choice( parsers .into_iter() .map(|p| p.bnf().unwrap_or(Bnf::Unknown)) .collect(), ) } } impl Choice for (P1, P2, P3, P4, P5) where P1: Parser, P2: Parser, P3: Parser, P4: Parser, P5: Parser, I: ParserInput + Clone, { fn parse(&self, input: I) -> ParseResult { let parsers = vec![ &self.0 as &dyn Parser, &self.1, &self.2, &self.3, &self.4, ]; choice_loop(input, parsers) } fn bnf(&self) -> Bnf { let parsers = vec![ &self.0 as &dyn Parser, &self.1, &self.2, &self.3, &self.4, ]; Bnf::Choice( parsers .into_iter() .map(|p| p.bnf().unwrap_or(Bnf::Unknown)) .collect(), ) } } impl Choice for (P1, P2, P3, P4, P5, P6) where P1: Parser, P2: Parser, P3: Parser, P4: Parser, P5: Parser, P6: Parser, I: ParserInput + Clone, { fn parse(&self, input: I) -> ParseResult { let parsers = vec![ &self.0 as &dyn Parser, &self.1, &self.2, &self.3, &self.4, &self.5, ]; choice_loop(input, parsers) } fn bnf(&self) -> Bnf { let parsers = vec![ &self.0 as &dyn Parser, &self.1, &self.2, &self.3, &self.4, &self.5, ]; Bnf::Choice( parsers .into_iter() .map(|p| p.bnf().unwrap_or(Bnf::Unknown)) .collect(), ) } } fn choice_loop(input: I, parsers: Vec<&dyn Parser>) -> ParseResult where I: ParserInput + Clone, { //TODO need a more principled way to return an error when no choices work let mut err = None; for parser in parsers.iter() { match parser.parse(input.clone()) { Ok(result) => return Ok(result), Err(e) => { err = Some(e); } } } Err(err.unwrap()) } #[cfg(test)] mod tests { use super::*; use crate::combinators::repeated; use crate::primitives::literal; #[test] fn test_choice() { let p = choice2( literal("gnostika").to(1), repeated(literal(" ")).at_least(1).to(2), ); assert_eq!(p.parse("gnostika twentynine"), Ok((1, " twentynine"))); } #[test] fn test_several_choices() { let p = choice(( literal("a").to(1), literal("q").to(10), repeated(literal("chutney")).to(200), literal("banana").to(10000), )); assert_eq!(p.parse("q drugs").unwrap(), (10, " drugs")); } }