Use trait in choice
This commit is contained in:
parent
3669d5d2cc
commit
56042dbbe2
@ -1,19 +1,49 @@
|
|||||||
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)>;
|
||||||
//TODO need a more principled way to return an error when no choices work
|
}
|
||||||
let mut err = None;
|
|
||||||
|
|
||||||
for parser in parsers.iter() {
|
pub fn choice<C: Choice<I, O, E>, I, O, E>(choices: C) -> impl Parser<I, O, E> {
|
||||||
match parser.parse(input) {
|
move |input| choices.parse_choice(input)
|
||||||
Ok(res) => return Ok(res),
|
}
|
||||||
Err((e, rest)) => {
|
|
||||||
err = Some(e);
|
fn choice_loop<'a, I, O, E>(
|
||||||
input = rest;
|
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))
|
}
|
||||||
|
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])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
@ -53,7 +49,7 @@ fn test_optional() {
|
|||||||
let parser = seq2(
|
let parser = seq2(
|
||||||
optional(literal("alpha")),
|
optional(literal("alpha")),
|
||||||
seq2(repeated(literal(" ")), literal("beta")),
|
seq2(repeated(literal(" ")), literal("beta")),
|
||||||
);
|
);
|
||||||
|
|
||||||
let output1 = parser.parse(" beta").unwrap();
|
let output1 = parser.parse(" beta").unwrap();
|
||||||
assert_eq!(output1.0 .0, None);
|
assert_eq!(output1.0 .0, None);
|
||||||
|
Loading…
Reference in New Issue
Block a user