seq for tuples of lengths 2 - 5
This commit is contained in:
parent
750cc23a29
commit
a9f2d4d771
121
src/sequence.rs
121
src/sequence.rs
@ -1,11 +1,37 @@
|
||||
use crate::Parser;
|
||||
use crate::{ParseResult, Parser};
|
||||
|
||||
pub fn tuple2<P1, P2, I, O1, O2, E>(parser1: P1, parser2: P2) -> impl Parser<I, (O1, O2), E>
|
||||
where
|
||||
P1: Parser<I, O1, E>,
|
||||
P2: Parser<I, O2, E>,
|
||||
{
|
||||
move |input| {
|
||||
seq((parser1, parser2))
|
||||
}
|
||||
|
||||
pub fn seq<T, I, O, E>(sequence: T) -> impl Parser<I, O, E>
|
||||
where
|
||||
T: Sequence<I, O, E>,
|
||||
{
|
||||
move |input| sequence.parse(input)
|
||||
}
|
||||
|
||||
/* TODO - eventually rewrite this parser combinator in Schala. Seeing what this
|
||||
* code that makes heavy use of type variables and abstraction over types looks like
|
||||
* in Schala's type system should be educational
|
||||
*/
|
||||
|
||||
pub trait Sequence<I, O, E> {
|
||||
fn parse(&self, input: I) -> ParseResult<I, O, E>;
|
||||
}
|
||||
|
||||
impl<I, O1, O2, E, P1, P2> Sequence<I, (O1, O2), E> for (P1, P2)
|
||||
where
|
||||
P1: Parser<I, O1, E>,
|
||||
P2: Parser<I, O2, E>,
|
||||
{
|
||||
fn parse(&self, input: I) -> ParseResult<I, (O1, O2), E> {
|
||||
let parser1 = &self.0;
|
||||
let parser2 = &self.1;
|
||||
parser1.parse(input).and_then(|(result1, rest1)| {
|
||||
parser2
|
||||
.parse(rest1)
|
||||
@ -14,10 +40,77 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, O1, O2, O3, E, P1, P2, P3> Sequence<I, (O1, O2, O3), E> for (P1, P2, P3)
|
||||
where
|
||||
P1: Parser<I, O1, E>,
|
||||
P2: Parser<I, O2, E>,
|
||||
P3: Parser<I, O3, E>,
|
||||
{
|
||||
fn parse(&self, input: I) -> ParseResult<I, (O1, O2, O3), E> {
|
||||
let parser1 = &self.0;
|
||||
let parser2 = &self.1;
|
||||
let parser3 = &self.2;
|
||||
|
||||
let (result1, rest1) = parser1.parse(input)?;
|
||||
let (result2, rest2) = parser2.parse(rest1)?;
|
||||
let (result3, rest3) = parser3.parse(rest2)?;
|
||||
|
||||
Ok(((result1, result2, result3), rest3))
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, O1, O2, O3, O4, E, P1, P2, P3, P4> Sequence<I, (O1, O2, O3, O4), E> for (P1, P2, P3, P4)
|
||||
where
|
||||
P1: Parser<I, O1, E>,
|
||||
P2: Parser<I, O2, E>,
|
||||
P3: Parser<I, O3, E>,
|
||||
P4: Parser<I, O4, E>,
|
||||
{
|
||||
fn parse(&self, input: I) -> ParseResult<I, (O1, O2, O3, O4), E> {
|
||||
let parser1 = &self.0;
|
||||
let parser2 = &self.1;
|
||||
let parser3 = &self.2;
|
||||
let parser4 = &self.3;
|
||||
|
||||
let (result1, rest1) = parser1.parse(input)?;
|
||||
let (result2, rest2) = parser2.parse(rest1)?;
|
||||
let (result3, rest3) = parser3.parse(rest2)?;
|
||||
let (result4, rest4) = parser4.parse(rest3)?;
|
||||
|
||||
Ok(((result1, result2, result3, result4), rest4))
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, O1, O2, O3, O4, O5, E, P1, P2, P3, P4, P5> Sequence<I, (O1, O2, O3, O4, O5), E>
|
||||
for (P1, P2, P3, P4, P5)
|
||||
where
|
||||
P1: Parser<I, O1, E>,
|
||||
P2: Parser<I, O2, E>,
|
||||
P3: Parser<I, O3, E>,
|
||||
P4: Parser<I, O4, E>,
|
||||
P5: Parser<I, O5, E>,
|
||||
{
|
||||
fn parse(&self, input: I) -> ParseResult<I, (O1, O2, O3, O4, O5), E> {
|
||||
let parser1 = &self.0;
|
||||
let parser2 = &self.1;
|
||||
let parser3 = &self.2;
|
||||
let parser4 = &self.3;
|
||||
let parser5 = &self.4;
|
||||
|
||||
let (result1, rest1) = parser1.parse(input)?;
|
||||
let (result2, rest2) = parser2.parse(rest1)?;
|
||||
let (result3, rest3) = parser3.parse(rest2)?;
|
||||
let (result4, rest4) = parser4.parse(rest3)?;
|
||||
let (result5, rest5) = parser5.parse(rest4)?;
|
||||
|
||||
Ok(((result1, result2, result3, result4, result5), rest5))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::{identifier, literal};
|
||||
use crate::{identifier, literal, zero_or_more};
|
||||
use std::assert_matches::assert_matches;
|
||||
|
||||
#[test]
|
||||
@ -28,4 +121,26 @@ mod test {
|
||||
let p = identifier.then(literal(" ")).then(literal("ruts"));
|
||||
assert_matches!(p.parse("fort1 ruts"), Ok((r, "")) if r.0.0 == "fort1" && r.0.1== " " && r.1 == "ruts");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seq() {
|
||||
let p = seq((
|
||||
literal("bong").to(10),
|
||||
zero_or_more(literal(" ")).to(()),
|
||||
literal("hits").to(20),
|
||||
));
|
||||
assert_eq!(p.parse("bong hits").unwrap(), ((10, (), 20), ""));
|
||||
|
||||
let p = seq((
|
||||
literal("alpha").to(10),
|
||||
zero_or_more(literal(" ")).to(()),
|
||||
zero_or_more(literal("-")).to(()),
|
||||
zero_or_more(literal(" ")),
|
||||
literal("beta"),
|
||||
));
|
||||
assert_eq!(
|
||||
p.parse("alpha ------ beta gamma").unwrap(),
|
||||
((10, (), (), vec![" ", " ", " "], "beta"), " gamma")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user