Repeat test
This commit is contained in:
parent
0e26ef1ea6
commit
2ad7707349
@ -2,19 +2,21 @@ use std::marker::PhantomData;
|
||||
|
||||
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
|
||||
P: Parser<I, O, E>,
|
||||
{
|
||||
Repeated::new(parser)
|
||||
}
|
||||
|
||||
struct Repeated<P, I, O, E>
|
||||
pub struct Repeated<P, I, O, E>
|
||||
where
|
||||
P: Parser<I, O, E>,
|
||||
{
|
||||
inner_parser: P,
|
||||
phantom: PhantomData<(I, O, E)>,
|
||||
at_least: Option<u32>,
|
||||
at_most: Option<u32>,
|
||||
}
|
||||
|
||||
impl<P, I, O, E> Repeated<P, I, O, E>
|
||||
@ -25,6 +27,31 @@ where
|
||||
Self {
|
||||
inner_parser,
|
||||
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>
|
||||
where
|
||||
P: Parser<I, O, E>,
|
||||
E: Default,
|
||||
{
|
||||
fn parse(&self, input: I) -> ParseResult<I, Vec<O>, E> {
|
||||
let mut acc = input;
|
||||
fn parse(&self, mut input: I) -> ParseResult<I, Vec<O>, E> {
|
||||
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 count = 0;
|
||||
|
||||
if at_most == 0 {
|
||||
return Ok((vec![], input));
|
||||
}
|
||||
|
||||
loop {
|
||||
match self.inner_parser.parse(acc) {
|
||||
match self.inner_parser.parse(input) {
|
||||
Ok((item, rest)) => {
|
||||
results.push(item);
|
||||
acc = rest;
|
||||
input = rest;
|
||||
count += 1;
|
||||
if count >= at_most {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Err((_err, rest)) => {
|
||||
acc = rest;
|
||||
input = rest;
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
|
10
src/lib.rs
10
src/lib.rs
@ -87,4 +87,14 @@ mod tests {
|
||||
let output2 = parser.parse("alpha beta").unwrap();
|
||||
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"]);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user