Repeat test

This commit is contained in:
Greg Shuflin 2024-01-27 02:20:58 -08:00
parent 0e26ef1ea6
commit 2ad7707349
2 changed files with 144 additions and 8 deletions

View File

@ -2,19 +2,21 @@ use std::marker::PhantomData;
use crate::{ParseResult, Parser}; use crate::{ParseResult, Parser};
pub fn repeated<P, I, O, E>(parser: P) -> impl Parser<I, Vec<O>, E> pub fn repeated<P, I, O, E>(parser: P) -> Repeated<P, I, O, E>
where where
P: Parser<I, O, E>, P: Parser<I, O, E>,
{ {
Repeated::new(parser) Repeated::new(parser)
} }
struct Repeated<P, I, O, E> pub struct Repeated<P, I, O, E>
where where
P: Parser<I, O, E>, P: Parser<I, O, E>,
{ {
inner_parser: P, inner_parser: P,
phantom: PhantomData<(I, O, E)>, phantom: PhantomData<(I, O, E)>,
at_least: Option<u32>,
at_most: Option<u32>,
} }
impl<P, I, O, E> Repeated<P, I, O, E> impl<P, I, O, E> Repeated<P, I, O, E>
@ -25,6 +27,31 @@ where
Self { Self {
inner_parser, inner_parser,
phantom: PhantomData, phantom: PhantomData,
at_least: None,
at_most: None,
}
}
pub fn at_least(self, at_least: u32) -> Self {
Self {
at_least: Some(at_least),
..self
}
}
pub fn at_most(self, at_most: u32) -> Self {
Self {
at_most: Some(at_most),
..self
}
}
pub fn separated_by<D>(self, delimiter: D) -> SeparatedBy<D, P, I, O, E>
where
D: Parser<I, (), E>,
E: Default,
{
SeparatedBy {
inner_repeated: self,
delimiter,
allow_trailing: false,
} }
} }
} }
@ -32,24 +59,123 @@ where
impl<P, I, O, E> Parser<I, Vec<O>, E> for Repeated<P, I, O, E> impl<P, I, O, E> Parser<I, Vec<O>, E> for Repeated<P, I, O, E>
where where
P: Parser<I, O, E>, P: Parser<I, O, E>,
E: Default,
{ {
fn parse(&self, input: I) -> ParseResult<I, Vec<O>, E> { fn parse(&self, mut input: I) -> ParseResult<I, Vec<O>, E> {
let mut acc = input; let at_least = self.at_least.unwrap_or(0);
let at_most = self.at_most.unwrap_or(u32::MAX);
let mut results = vec![]; let mut results = vec![];
let mut count = 0;
if at_most == 0 {
return Ok((vec![], input));
}
loop { loop {
match self.inner_parser.parse(acc) { match self.inner_parser.parse(input) {
Ok((item, rest)) => { Ok((item, rest)) => {
results.push(item); results.push(item);
acc = rest; input = rest;
count += 1;
if count >= at_most {
break;
}
} }
Err((_err, rest)) => { Err((_err, rest)) => {
acc = rest; input = rest;
break; break;
} }
} }
} }
Ok((results, acc))
if count < at_least {
return Err((Default::default(), input));
}
Ok((results, input))
}
}
pub struct SeparatedBy<D, P, I, O, E>
where
D: Parser<I, (), E>,
P: Parser<I, O, E>,
E: Default,
{
inner_repeated: Repeated<P, I, O, E>,
delimiter: D,
allow_trailing: bool,
}
impl<D, P, I, O, E> Parser<I, Vec<O>, E> for SeparatedBy<D, P, I, O, E>
where
D: Parser<I, (), E>,
P: Parser<I, O, E>,
E: Default,
{
fn parse(&self, mut input: I) -> ParseResult<I, Vec<O>, E> {
let at_least = self.inner_repeated.at_least.unwrap_or(0);
let at_most = self.inner_repeated.at_most.unwrap_or(u32::MAX);
let inner = &self.inner_repeated.inner_parser;
let delimiter = &self.delimiter;
if at_most == 0 {
return Ok((vec![], input));
}
let mut results = Vec::new();
let mut count: u32 = 0;
match inner.parse(input) {
Ok((item, rest)) => {
results.push(item);
input = rest;
}
Err((err, rest)) => {
if at_least > 0 {
return Err((err, rest));
} else {
return Ok((vec![], rest));
}
}
}
loop {
match delimiter.parse(input) {
Ok(((), rest)) => {
input = rest;
count += 1;
}
Err((_err, rest)) => {
input = rest;
break;
}
}
match inner.parse(input) {
Ok((item, rest)) => {
input = rest;
results.push(item);
}
Err((err, rest)) => {
if self.allow_trailing {
input = rest;
break;
} else {
return Err((err, rest));
}
}
}
if count >= at_most {
break;
}
}
if count < at_least {
//return Err(??, rest) <- need to handle errors better
unimplemented!();
}
Ok((results, input))
} }
} }

View File

@ -87,4 +87,14 @@ mod tests {
let output2 = parser.parse("alpha beta").unwrap(); let output2 = parser.parse("alpha beta").unwrap();
assert_eq!(output2.0 .0, Some("alpha")); assert_eq!(output2.0 .0, Some("alpha"));
} }
#[test]
fn test_repeated() {
let spaces = repeated(literal_char(' ')).at_least(1);
let bongo = literal("bongo");
let parser = repeated(bongo).separated_by(map(spaces, |_| ()));
let output = parser.parse("bongo bongo bongo bongo");
let output = output.unwrap();
assert_eq!(output.0, vec!["bongo", "bongo", "bongo", "bongo"]);
}
} }