diff --git a/src/choice.rs b/src/choice.rs index 1658d5e..18c953d 100644 --- a/src/choice.rs +++ b/src/choice.rs @@ -4,9 +4,9 @@ pub fn choice2(parser1: P1, parser2: P2) -> impl Parser, P2: Parser, - I: Copy, + I: Clone, { - move |input| match parser1.parse(input) { + move |input: I| match parser1.parse(input.clone()) { ok @ Ok(..) => ok, Err(_e) => parser2.parse(input), } @@ -49,6 +49,101 @@ where } } +impl Choice for (P1, P2, P3) +where + P1: Parser, + P2: Parser, + P3: Parser, + I: Clone, +{ + fn parse(&self, input: I) -> ParseResult { + let parser1 = &self.0; + let parser2 = &self.1; + let parser3 = &self.2; + + //TODO need a more principled way to return an error when no choices work + let mut err = None; + + for parser in [parser1 as &dyn Parser, parser2, parser3].iter() { + match parser.parse(input.clone()) { + Ok(result) => return Ok(result), + Err(e) => { + err = Some(e); + } + } + } + Err(err.unwrap()) + } +} + +impl Choice for (P1, P2, P3, P4) +where + P1: Parser, + P2: Parser, + P3: Parser, + P4: Parser, + I: Clone, +{ + fn parse(&self, input: I) -> ParseResult { + let parser1 = &self.0; + let parser2 = &self.1; + let parser3 = &self.2; + let parser4 = &self.3; + + //TODO need a more principled way to return an error when no choices work + let mut err = None; + + for parser in [parser1 as &dyn Parser, parser2, parser3, parser4].iter() { + match parser.parse(input.clone()) { + Ok(result) => return Ok(result), + Err(e) => { + err = Some(e); + } + } + } + Err(err.unwrap()) + } +} + +impl Choice for (P1, P2, P3, P4, P5) +where + P1: Parser, + P2: Parser, + P3: Parser, + P4: Parser, + P5: Parser, + I: Clone, +{ + fn parse(&self, input: I) -> ParseResult { + let parser1 = &self.0; + let parser2 = &self.1; + let parser3 = &self.2; + let parser4 = &self.3; + let parser5 = &self.4; + + //TODO need a more principled way to return an error when no choices work + let mut err = None; + + for parser in [ + parser1 as &dyn Parser, + parser2, + parser3, + parser4, + parser5, + ] + .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::*; diff --git a/src/lib.rs b/src/lib.rs index 941769c..64a623c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -45,7 +45,7 @@ mod tests { let json_true = literal("true").to(JsonValue::Bool(true)); let json_false = literal("false").to(JsonValue::Bool(false)); - let json_value = choice((json_null, choice((json_true, json_false)))); + let json_value = choice((json_null, json_true, json_false)); assert_eq!(json_value.parse("true"), Ok((JsonValue::Bool(true), ""))); }