diff --git a/src/branch/mod.rs b/src/branch/mod.rs index 6c0adc742..6109815ae 100644 --- a/src/branch/mod.rs +++ b/src/branch/mod.rs @@ -15,11 +15,37 @@ pub trait Alt { fn choice(&mut self, input: I) -> IResult; } +impl<'a, I: Clone, O, E: ParseError, P: Parser> Alt for &'a mut [P] { + fn choice(&mut self, input: I) -> IResult { + let mut err: Option = None; + for p in self.iter_mut() { + match p.parse(input.clone()) { + Err(Err::Error(e)) => { + err = match err { + Some(curr) => Some(curr.or(e)), + None => Some(e), + } + } + res => return res, + }; + } + match err { + Some(e) => Err(Err::Error(e)), + None => Err(Err::Error(E::from_error_kind( + input.clone(), + ErrorKind::Alt, + ))), + } + } +} + /// Tests a list of parsers one by one until one succeeds. /// /// It takes as argument a tuple of parsers. There is a maximum of 21 /// parsers. If you need more, it is possible to nest them in other `alt` calls, /// like this: `alt(parser_a, alt(parser_b, parser_c))` +/// You can also try: `alt([parser_a, parser_b, parser_c].as_mut())` with limition +/// that parser_a, parser_b, parser_c must be the same type /// /// ```rust /// # #[macro_use] extern crate nom; @@ -44,6 +70,28 @@ pub trait Alt { /// /// With a custom error type, it is possible to have alt return the error of the parser /// that went the farthest in the input data +/// +/// A mutable slice can be used either +/// +/// ```rust +/// # #[macro_use] extern crate nom; +/// # use nom::{Err,error::ErrorKind, Needed, IResult}; +/// use nom::character::complete::{alpha1, digit1}; +/// use nom::branch::alt; +/// # fn main() { +/// fn parser(input: &str) -> IResult<&str, &str> { +/// alt([alpha1, digit1].as_mut())(input) // using a mut slice +/// }; +/// +/// // the first parser, alpha1, recognizes the input +/// assert_eq!(parser("abc"), Ok(("", "abc"))); +/// +/// // the first parser returns an error, so alt tries the second one +/// assert_eq!(parser("123456"), Ok(("", "123456"))); +/// +/// // both parsers failed, and with the default error type, alt will return the last error +/// assert_eq!(parser(" "), Err(Err::Error(error_position!(" ", ErrorKind::Digit)))); +/// # } pub fn alt, List: Alt>( mut l: List, ) -> impl FnMut(I) -> IResult {