seq for tuples of lengths 2 - 5

This commit is contained in:
Greg Shuflin 2022-10-16 18:51:14 -07:00
parent 750cc23a29
commit a9f2d4d771

View File

@ -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")
);
}
}