From 2ad770734906916e1b018620da1de776e1eafa59 Mon Sep 17 00:00:00 2001 From: Greg Shuflin Date: Sat, 27 Jan 2024 02:20:58 -0800 Subject: [PATCH] Repeat test --- src/combinators.rs | 142 ++++++++++++++++++++++++++++++++++++++++++--- src/lib.rs | 10 ++++ 2 files changed, 144 insertions(+), 8 deletions(-) diff --git a/src/combinators.rs b/src/combinators.rs index 4ffe931..f4913f6 100644 --- a/src/combinators.rs +++ b/src/combinators.rs @@ -2,19 +2,21 @@ use std::marker::PhantomData; use crate::{ParseResult, Parser}; -pub fn repeated(parser: P) -> impl Parser, E> +pub fn repeated(parser: P) -> Repeated where P: Parser, { Repeated::new(parser) } -struct Repeated +pub struct Repeated where P: Parser, { inner_parser: P, phantom: PhantomData<(I, O, E)>, + at_least: Option, + at_most: Option, } impl Repeated @@ -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(self, delimiter: D) -> SeparatedBy + where + D: Parser, + E: Default, + { + SeparatedBy { + inner_repeated: self, + delimiter, + allow_trailing: false, } } } @@ -32,24 +59,123 @@ where impl Parser, E> for Repeated where P: Parser, + E: Default, { - fn parse(&self, input: I) -> ParseResult, E> { - let mut acc = input; + fn parse(&self, mut input: I) -> ParseResult, 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 +where + D: Parser, + P: Parser, + E: Default, +{ + inner_repeated: Repeated, + delimiter: D, + allow_trailing: bool, +} + +impl Parser, E> for SeparatedBy +where + D: Parser, + P: Parser, + E: Default, +{ + fn parse(&self, mut input: I) -> ParseResult, 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)) } } diff --git a/src/lib.rs b/src/lib.rs index 30ca740..f0d0478 100644 --- a/src/lib.rs +++ b/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"]); + } }