Skip to content

Alt trait for array #1269

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions src/branch/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,37 @@ pub trait Alt<I, O, E> {
fn choice(&mut self, input: I) -> IResult<I, O, E>;
}

impl<'a, I: Clone, O, E: ParseError<I>, P: Parser<I, O, E>> Alt<I, O, E> for &'a mut [P] {
fn choice(&mut self, input: I) -> IResult<I, O, E> {
let mut err: Option<E> = 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;
Expand All @@ -44,6 +70,28 @@ pub trait Alt<I, O, E> {
///
/// 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<I: Clone, O, E: ParseError<I>, List: Alt<I, O, E>>(
mut l: List,
) -> impl FnMut(I) -> IResult<I, O, E> {
Expand Down