git-subtree-dir: subtrees/parser-combinator git-subtree-split: 5526ce7bd17beda52047fbc3442e23e0174b79a7
199 lines
5.0 KiB
Rust
199 lines
5.0 KiB
Rust
use crate::parser::{ParseResult, Parser, ParserInput, Representation};
|
|
|
|
pub fn choice2<P1, P2, I, O, E>(parser1: P1, parser2: P2) -> impl Parser<I, O, E>
|
|
where
|
|
P1: Parser<I, O, E>,
|
|
P2: Parser<I, O, E>,
|
|
I: ParserInput + Clone,
|
|
{
|
|
choice((parser1, parser2))
|
|
}
|
|
|
|
pub fn choice<C, I, O, E>(choices: C) -> impl Parser<I, O, E>
|
|
where
|
|
C: Choice<I, O, E>,
|
|
I: ParserInput + Clone,
|
|
{
|
|
let rep = choices.representation();
|
|
(move |input| choices.parse(input), rep)
|
|
}
|
|
|
|
pub trait Choice<I: Clone, O, E> {
|
|
fn parse(&self, input: I) -> ParseResult<I, O, E>;
|
|
fn representation(&self) -> Representation;
|
|
}
|
|
|
|
impl<I, O, E, P1, P2> Choice<I, O, E> for (P1, P2)
|
|
where
|
|
P1: Parser<I, O, E>,
|
|
P2: Parser<I, O, E>,
|
|
I: ParserInput + Clone,
|
|
{
|
|
fn parse(&self, input: I) -> ParseResult<I, O, E> {
|
|
let parsers = vec![&self.0 as &dyn Parser<I, O, E>, &self.1];
|
|
choice_loop(input, parsers)
|
|
}
|
|
|
|
fn representation(&self) -> Representation {
|
|
let parsers = vec![&self.0 as &dyn Parser<I, O, E>, &self.1];
|
|
repr_loop(parsers)
|
|
}
|
|
}
|
|
|
|
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: ParserInput + Clone,
|
|
{
|
|
fn parse(&self, input: I) -> ParseResult<I, O, E> {
|
|
let parsers = vec![&self.0 as &dyn Parser<I, O, E>, &self.1, &self.2];
|
|
choice_loop(input, parsers)
|
|
}
|
|
|
|
fn representation(&self) -> Representation {
|
|
let parsers = vec![&self.0 as &dyn Parser<I, O, E>, &self.1, &self.2];
|
|
repr_loop(parsers)
|
|
}
|
|
}
|
|
|
|
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: ParserInput + Clone,
|
|
{
|
|
fn parse(&self, input: I) -> ParseResult<I, O, E> {
|
|
let parsers = vec![&self.0 as &dyn Parser<I, O, E>, &self.1, &self.2, &self.3];
|
|
choice_loop(input, parsers)
|
|
}
|
|
|
|
fn representation(&self) -> Representation {
|
|
let parsers = vec![&self.0 as &dyn Parser<I, O, E>, &self.1, &self.2, &self.3];
|
|
repr_loop(parsers)
|
|
}
|
|
}
|
|
|
|
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: ParserInput + Clone,
|
|
{
|
|
fn parse(&self, input: I) -> ParseResult<I, O, E> {
|
|
let parsers = vec![
|
|
&self.0 as &dyn Parser<I, O, E>,
|
|
&self.1,
|
|
&self.2,
|
|
&self.3,
|
|
&self.4,
|
|
];
|
|
choice_loop(input, parsers)
|
|
}
|
|
|
|
fn representation(&self) -> Representation {
|
|
let parsers = vec![
|
|
&self.0 as &dyn Parser<I, O, E>,
|
|
&self.1,
|
|
&self.2,
|
|
&self.3,
|
|
&self.4,
|
|
];
|
|
repr_loop(parsers)
|
|
}
|
|
}
|
|
|
|
impl<I, O, E, P1, P2, P3, P4, P5, P6> Choice<I, O, E> for (P1, P2, P3, P4, P5, P6)
|
|
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>,
|
|
P6: Parser<I, O, E>,
|
|
I: ParserInput + Clone,
|
|
{
|
|
fn parse(&self, input: I) -> ParseResult<I, O, E> {
|
|
let parsers = vec![
|
|
&self.0 as &dyn Parser<I, O, E>,
|
|
&self.1,
|
|
&self.2,
|
|
&self.3,
|
|
&self.4,
|
|
&self.5,
|
|
];
|
|
choice_loop(input, parsers)
|
|
}
|
|
fn representation(&self) -> Representation {
|
|
let parsers = vec![
|
|
&self.0 as &dyn Parser<I, O, E>,
|
|
&self.1,
|
|
&self.2,
|
|
&self.3,
|
|
&self.4,
|
|
&self.5,
|
|
];
|
|
repr_loop(parsers)
|
|
}
|
|
}
|
|
|
|
fn choice_loop<I, O, E>(input: I, parsers: Vec<&dyn Parser<I, O, E>>) -> ParseResult<I, O, E>
|
|
where
|
|
I: ParserInput + Clone,
|
|
{
|
|
//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.clone()) {
|
|
Ok(result) => return Ok(result),
|
|
Err(e) => {
|
|
err = Some(e);
|
|
}
|
|
}
|
|
}
|
|
Err(err.unwrap())
|
|
}
|
|
|
|
fn repr_loop<I, O, E>(parsers: Vec<&dyn Parser<I, O, E>>) -> Representation
|
|
where
|
|
I: ParserInput + Clone,
|
|
{
|
|
let mut iter = parsers.iter().map(|p| p.representation());
|
|
Representation::from_choice(&mut iter)
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use crate::combinators::repeated;
|
|
use crate::primitives::literal;
|
|
|
|
#[test]
|
|
fn test_choice() {
|
|
let p = choice2(
|
|
literal("gnostika").to(1),
|
|
repeated(literal(" ")).at_least(1).to(2),
|
|
);
|
|
assert_eq!(p.parse("gnostika twentynine"), Ok((1, " twentynine")));
|
|
}
|
|
|
|
#[test]
|
|
fn test_several_choices() {
|
|
let p = choice((
|
|
literal("a").to(1),
|
|
literal("q").to(10),
|
|
repeated(literal("chutney")).to(200),
|
|
literal("banana").to(10000),
|
|
));
|
|
|
|
assert_eq!(p.parse("q drugs").unwrap(), (10, " drugs"));
|
|
}
|
|
}
|