More choice impls

This commit is contained in:
Greg Shuflin 2022-10-16 20:16:03 -07:00
parent 4456734134
commit 2dc754c294
2 changed files with 98 additions and 3 deletions

View File

@ -4,9 +4,9 @@ pub fn choice2<P1, P2, I, O, E>(parser1: P1, parser2: P2) -> impl Parser<I, O, E
where where
P1: Parser<I, O, E>, P1: Parser<I, O, E>,
P2: Parser<I, O, E>, P2: Parser<I, O, E>,
I: Copy, I: Clone,
{ {
move |input| match parser1.parse(input) { move |input: I| match parser1.parse(input.clone()) {
ok @ Ok(..) => ok, ok @ Ok(..) => ok,
Err(_e) => parser2.parse(input), Err(_e) => parser2.parse(input),
} }
@ -49,6 +49,101 @@ where
} }
} }
impl<I, O, E, P1, P2, P3> Choice<I, O, E> for (P1, P2, P3)
where
P1: Parser<I, O, E>,
P2: Parser<I, O, E>,
P3: Parser<I, O, E>,
I: Clone,
{
fn parse(&self, input: I) -> ParseResult<I, O, E> {
let parser1 = &self.0;
let parser2 = &self.1;
let parser3 = &self.2;
//TODO need a more principled way to return an error when no choices work
let mut err = None;
for parser in [parser1 as &dyn Parser<I, O, E>, parser2, parser3].iter() {
match parser.parse(input.clone()) {
Ok(result) => return Ok(result),
Err(e) => {
err = Some(e);
}
}
}
Err(err.unwrap())
}
}
impl<I, O, E, P1, P2, P3, P4> 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>,
I: Clone,
{
fn parse(&self, input: I) -> ParseResult<I, O, E> {
let parser1 = &self.0;
let parser2 = &self.1;
let parser3 = &self.2;
let parser4 = &self.3;
//TODO need a more principled way to return an error when no choices work
let mut err = None;
for parser in [parser1 as &dyn Parser<I, O, E>, parser2, parser3, parser4].iter() {
match parser.parse(input.clone()) {
Ok(result) => return Ok(result),
Err(e) => {
err = Some(e);
}
}
}
Err(err.unwrap())
}
}
impl<I, O, E, P1, P2, P3, P4, P5> 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>,
I: Clone,
{
fn parse(&self, input: I) -> ParseResult<I, O, E> {
let parser1 = &self.0;
let parser2 = &self.1;
let parser3 = &self.2;
let parser4 = &self.3;
let parser5 = &self.4;
//TODO need a more principled way to return an error when no choices work
let mut err = None;
for parser in [
parser1 as &dyn Parser<I, O, E>,
parser2,
parser3,
parser4,
parser5,
]
.iter()
{
match parser.parse(input.clone()) {
Ok(result) => return Ok(result),
Err(e) => {
err = Some(e);
}
}
}
Err(err.unwrap())
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;

View File

@ -45,7 +45,7 @@ mod tests {
let json_true = literal("true").to(JsonValue::Bool(true)); let json_true = literal("true").to(JsonValue::Bool(true));
let json_false = literal("false").to(JsonValue::Bool(false)); let json_false = literal("false").to(JsonValue::Bool(false));
let json_value = choice((json_null, choice((json_true, json_false)))); let json_value = choice((json_null, json_true, json_false));
assert_eq!(json_value.parse("true"), Ok((JsonValue::Bool(true), ""))); assert_eq!(json_value.parse("true"), Ok((JsonValue::Bool(true), "")));
} }