Use trait in choice

This commit is contained in:
Greg Shuflin 2024-01-28 02:53:13 -08:00
parent 3669d5d2cc
commit 56042dbbe2
2 changed files with 45 additions and 19 deletions

View File

@ -1,7 +1,17 @@
use crate::Parser; use crate::{ParseResult, Parser};
pub fn choice<'a, I, O, E>(parsers: &'a [&'a dyn Parser<I, O, E>]) -> impl Parser<I, O, E> + 'a { pub trait Choice<I, O, E> {
move |mut input: I| { 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 //TODO need a more principled way to return an error when no choices work
let mut err = None; let mut err = None;
@ -16,4 +26,24 @@ pub fn choice<'a, I, O, E>(parsers: &'a [&'a dyn Parser<I, O, E>]) -> impl Parse
} }
Err((err.unwrap(), input)) 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])
}
} }

View File

@ -18,11 +18,7 @@ fn test_sequence() {
#[test] #[test]
fn test_choice() { fn test_choice() {
let a = literal("bongo"); let parser = choice((literal("bongo"), literal("sucy"), literal("ara")));
let b = literal("sucy");
let c = literal("ara");
let inputs = [&a as &dyn Parser<&str, &str, ()>, &b, &c];
let parser = choice(&inputs);
let output = parser.parse("ara hajimete").unwrap(); let output = parser.parse("ara hajimete").unwrap();
assert_eq!(("ara", " hajimete"), output); assert_eq!(("ara", " hajimete"), output);