use crate::{Error, InputToken, Parser};
pub fn choice<'a, P, IT, O, PI>(parsers: &'a PI) -> impl Parser<IT, O>
where
P: Parser<IT, O> + 'a,
IT: InputToken,
&'a PI: IntoIterator<Item = &'a P>,
{
move |input| {
let mut first_error: Option<Error> = None;
for parser in parsers {
match parser(input) {
Ok(output) => return Ok(output), Err(e) => first_error = first_error.or(Some(e)), }
}
match first_error {
Some(error) => Err(error),
None => {
let fallback = Error::UnexpectedToken(input.source_name(), input.position(), None);
Err(fallback)
}
}
}
}
#[cfg(test)]
mod tests {
use crate::input::Position;
use crate::*;
#[test]
fn success() {
let parser1 = is('h');
let parser2 = is('e');
let parser3 = is('l');
let parsers: Vec<Box<dyn Parser<_, _>>> =
vec![Box::new(parser1), Box::new(parser2), Box::new(parser3)];
let parser_choice = choice(&parsers);
let mut input = Input::new_from_chars("h".chars(), None);
let output = parser_choice(&mut input).unwrap();
assert_eq!(output, 'h');
assert!(end_of_input()(&mut input).is_ok()); let mut input = Input::new_from_chars("e".chars(), None);
let output = parser_choice(&mut input).unwrap();
assert_eq!(output, 'e');
assert!(end_of_input()(&mut input).is_ok()); let mut input = Input::new_from_chars("l".chars(), None);
let output = parser_choice(&mut input).unwrap();
assert_eq!(output, 'l');
assert!(end_of_input()(&mut input).is_ok()); let mut input = Input::new_from_chars("u".chars(), None);
let mismatch = Mismatch::new('h', 'u');
assert_eq!(
parser_choice(&mut input),
Err(Error::UnexpectedToken(
None,
Position::new(1, 1),
Some(mismatch)
))
);
assert!(end_of_input()(&mut input).is_err()); }
#[test]
fn fail() {
let parser1 = is('h');
let parser2 = is('e');
let parser3 = is('l');
let parsers: Vec<Box<dyn Parser<_, _>>> =
vec![Box::new(parser1), Box::new(parser2), Box::new(parser3)];
let parser_choice = choice(&parsers);
let mut input = Input::new_from_chars("x".chars(), None);
let output = parser_choice(&mut input);
let mismatch = Mismatch::new('h', 'x');
assert_eq!(
output,
Err(Error::UnexpectedToken(
None,
Position::new(1, 1),
Some(mismatch)
))
);
assert!(end_of_input()(&mut input).is_err()); }
#[test]
fn empty() {
let parser1 = is('h');
let parser2 = is('e');
let parser3 = is('l');
let parsers: Vec<Box<dyn Parser<_, _>>> =
vec![Box::new(parser1), Box::new(parser2), Box::new(parser3)];
let parser_choice = choice(&parsers);
let mut input = Input::new_from_chars("".chars(), None);
let output = parser_choice(&mut input);
assert_eq!(output, Err(Error::EndOfInput(Some(Box::new('h')))));
}
#[test]
fn fail_consuming_input_no_attempt() {
let parser1 = |input: &mut StringInput| {
is('h')(input)?;
is('a')(input)
};
let parser2 = is('j');
let parser3 = is('k');
let parsers: Vec<Box<dyn Parser<_, _>>> =
vec![Box::new(parser1), Box::new(parser2), Box::new(parser3)];
let parser_choice = choice(&parsers);
let mut input = Input::new_from_chars("hello".chars(), None);
let output = parser_choice(&mut input);
let mismatch = Mismatch::new('a', 'e');
assert_eq!(
output,
Err(Error::UnexpectedToken(
None,
Position::new(1, 2),
Some(mismatch)
))
);
assert_eq!(any()(&mut input), Ok('e')); }
#[test]
fn fail_consuming_input_attempt() {
let parser1 = |input: &mut StringInput| {
is('h')(input)?;
is('a')(input)
};
let parser2 = is('j');
let parser3 = is('k');
let parsers: Vec<Box<dyn Parser<_, _>>> = vec![
Box::new(parser1.attempt()),
Box::new(parser2.attempt()),
Box::new(parser3.attempt()),
];
let parser_choice = choice(&parsers);
let mut input = Input::new_from_chars("hello".chars(), None);
let output = parser_choice(&mut input);
let mismatch = Mismatch::new('a', 'e');
assert_eq!(
output,
Err(Error::UnexpectedToken(
None,
Position::new(1, 2),
Some(mismatch)
))
);
assert_eq!(any()(&mut input), Ok('h')); }
}