rust-parser-combinator/src/choice.rs

50 lines
1.2 KiB
Rust
Raw Normal View History

2024-01-28 02:53:13 -08:00
use crate::{ParseResult, Parser};
2024-01-26 00:07:52 -08:00
2024-01-28 02:53:13 -08:00
pub trait Choice<I, O, E> {
fn parse_choice(&self, input: I) -> Result<(O, I), (E, I)>;
}
pub fn choice<C: Choice<I, O, E>, I, O, E>(choices: C) -> impl Parser<I, O, E> {
move |input| choices.parse_choice(input)
}
2024-01-26 00:07:52 -08:00
2024-01-28 02:53:13 -08:00
fn choice_loop<'a, I, O, E>(
mut input: I,
parsers: &'a [&'a dyn Parser<I, O, E>],
) -> ParseResult<I, O, E> {
//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) {
Ok(res) => return Ok(res),
Err((e, rest)) => {
err = Some(e);
input = rest;
2024-01-26 00:07:52 -08:00
}
}
2024-01-28 02:53:13 -08:00
}
Err((err.unwrap(), input))
}
impl<P1, P2, I, O, E> Choice<I, O, E> for (P1, P2)
where
P1: Parser<I, O, E>,
P2: Parser<I, O, E>,
{
fn parse_choice(&self, input: I) -> Result<(O, I), (E, I)> {
choice_loop(input, &[&self.0, &self.1])
}
}
impl<P1, P2, P3, I, O, E> Choice<I, O, E> for (P1, P2, P3)
where
P1: Parser<I, O, E>,
P2: Parser<I, O, E>,
P3: Parser<I, O, E>,
{
fn parse_choice(&self, input: I) -> Result<(O, I), (E, I)> {
choice_loop(input, &[&self.0, &self.1, &self.2])
2024-01-26 00:07:52 -08:00
}
}