75 lines
1.9 KiB
Rust
75 lines
1.9 KiB
Rust
use crate::{ParseResult, Parser};
|
|
|
|
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)
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
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])
|
|
}
|
|
}
|
|
|
|
impl<P1, P2, P3, P4, I, O, E> Choice<I, O, E> for (P1, P2, P3, P4)
|
|
where
|
|
P1: Parser<I, O, E>,
|
|
P2: Parser<I, O, E>,
|
|
P3: Parser<I, O, E>,
|
|
P4: Parser<I, O, E>,
|
|
{
|
|
fn parse_choice(&self, input: I) -> Result<(O, I), (E, I)> {
|
|
choice_loop(input, &[&self.0, &self.1, &self.2, &self.3])
|
|
}
|
|
}
|
|
|
|
impl<P1, P2, P3, P4, P5, I, O, E> Choice<I, O, E> for (P1, P2, P3, P4, P5)
|
|
where
|
|
P1: Parser<I, O, E>,
|
|
P2: Parser<I, O, E>,
|
|
P3: Parser<I, O, E>,
|
|
P4: Parser<I, O, E>,
|
|
P5: Parser<I, O, E>,
|
|
{
|
|
fn parse_choice(&self, input: I) -> Result<(O, I), (E, I)> {
|
|
choice_loop(input, &[&self.0, &self.1, &self.2, &self.3, &self.4])
|
|
}
|
|
}
|