From 2c96e1c6de13821558b5aa40212a0eb7b1b6856f Mon Sep 17 00:00:00 2001 From: John Turner Date: Fri, 31 Oct 2025 22:00:42 +0000 Subject: create ParserIter trait --- src/lib.rs | 354 ++++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 235 insertions(+), 119 deletions(-) (limited to 'src/lib.rs') diff --git a/src/lib.rs b/src/lib.rs index 250ce9f..7221769 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,7 +6,7 @@ use core::{ fmt, iter::{IntoIterator, Iterator}, marker::Sized, - ops::{Bound, Range, RangeBounds}, + ops::Range, }; use crate::{ @@ -153,16 +153,6 @@ pub trait Parser: Sized { Recognize { parser: self } } - fn repeated(self, range: R) -> impl Parser> - where - R: RangeBounds, - { - Repeated { - parser: self, - range, - } - } - fn verify_input(self, checker: C) -> impl Parser where C: Parser, @@ -195,23 +185,228 @@ pub trait Parser: Sized { Not { parser: self } } - fn separated_by( - self, - delimiter: P, - range: R, - ) -> impl Parser> + fn repeated(self) -> impl ParserIter { + Repeated { parser: self } + } + + fn separated_by

(self, delimiter: P) -> impl ParserIter where P: Parser, - R: RangeBounds, { SeparatedBy { parser: self, delimiter, - range, } } } +pub trait ParserIter { + type Item; + + fn next( + &self, + it: InputIter, + ) -> Option>; + + fn many(self) -> impl Parser> + where + Self: Sized, + { + Many { parser: self } + } + + fn at_least(self, count: usize) -> impl Parser> + where + Self: Sized, + { + AtLeast { + parser: self, + count, + } + } + + fn at_most(self, count: usize) -> impl Parser> + where + Self: Sized, + { + AtMost { + parser: self, + count, + } + } +} + +struct Repeated

{ + parser: P, +} + +impl ParserIter for Repeated

+where + I: Input, + P: Parser, +{ + type Item = P::Output; + + fn next( + &self, + it: InputIter, + ) -> Option> { + if it.is_finished() { + None + } else { + match self.parser.run::(it) { + Ok((rest, output)) => Some(Ok((rest, output))), + Err(rest) => Some(Err(rest)), + } + } + } +} + +struct SeparatedBy { + parser: P1, + delimiter: P2, +} + +impl ParserIter for SeparatedBy +where + I: Input, + P1: Parser, + P2: Parser, +{ + type Item = P1::Output; + + fn next( + &self, + it: InputIter, + ) -> Option> { + if it.is_finished() { + None + } else { + let (rest, output) = match self.parser.run::(it) { + Ok((rest, output)) => (rest, output), + Err(rest) => return Some(Err(rest)), + }; + + let rest = match self.delimiter.check(rest.clone()) { + Ok((rest, _)) => rest, + _ => rest, + }; + + Some(Ok((rest, output))) + } + } +} + +struct AtLeast

{ + parser: P, + count: usize, +} + +impl Parser for AtLeast

+where + I: Input, + P: ParserIter, +{ + type Output = Vec; + + fn run>( + &self, + mut it: InputIter, + ) -> ParserResult { + let mut outputs = OM::bind(|| Vec::new()); + let mut i = 0; + + while !it.is_finished() { + it = match self.parser.next::(it.clone()) { + Some(Ok((rest, output))) => { + outputs = OM::combine(outputs, output, |mut acc, e| { + acc.push(e); + acc + }); + rest + } + Some(Err(_)) if i >= self.count => break, + Some(Err(rest)) => return Err(rest), + None if i >= self.count => break, + None => return Err(EM::bind(|| it)), + }; + + i += 1; + } + + Ok((it, outputs)) + } +} + +struct AtMost

{ + parser: P, + count: usize, +} + +impl Parser for AtMost

+where + I: Input, + P: ParserIter, +{ + type Output = Vec; + + fn run>( + &self, + mut it: InputIter, + ) -> ParserResult { + let mut outputs = OM::bind(|| Vec::new()); + + for _ in 0..self.count { + it = match self.parser.next::(it.clone()) { + Some(Ok((rest, output))) => { + outputs = OM::combine(outputs, output, |mut acc, e| { + acc.push(e); + acc + }); + rest + } + _ => break, + } + } + + Ok((it, outputs)) + } +} + +struct Many

{ + parser: P, +} + +impl Parser for Many

+where + I: Input, + P: ParserIter, +{ + type Output = Vec; + + fn run>( + &self, + mut it: InputIter, + ) -> ParserResult { + let mut outputs = OM::bind(|| Vec::new()); + + while !it.is_finished() { + it = match self.parser.next::(it.clone()) { + Some(Ok((rest, output))) => { + outputs = OM::combine(outputs, output, |mut acc, e| { + acc.push(e); + acc + }); + rest + } + _ => break, + }; + } + + Ok((it, outputs)) + } +} + impl Parser for F where I: Input, @@ -387,98 +582,6 @@ where Take { amt } } -struct Repeated { - parser: P, - range: R, -} - -impl Parser for Repeated -where - I: Input, - P: Parser, - R: RangeBounds, -{ - type Output = Vec; - - fn run>( - &self, - mut it: InputIter, - ) -> ParserResult { - Tracer::trace("list", it.clone()); - - let mut outputs = OM::bind(|| Vec::new()); - let mut i = 0; - - while (Bound::Unbounded, self.range.end_bound()).contains(&i) { - it = match self.parser.run::(it.clone()) { - Ok((rest, output)) => { - outputs = OM::combine(outputs, output, |mut acc, e| { - acc.push(e); - acc - }); - rest - } - Err(_) if self.range.contains(&i) => break, - Err(rest) => return Err(rest), - }; - - i += 1; - } - - Ok((it, outputs)) - } -} - -struct SeparatedBy { - parser: P1, - delimiter: P2, - range: R, -} - -impl Parser for SeparatedBy -where - I: Input, - P1: Parser, - P2: Parser, - R: RangeBounds, -{ - type Output = Vec; - - fn run>( - &self, - mut it: InputIter, - ) -> ParserResult { - Tracer::trace("separated list", it.clone()); - - let mut outputs = OM::bind(|| Vec::new()); - let mut i = 0usize; - - while (Bound::Unbounded, self.range.end_bound()).contains(&i) { - it = match self.parser.run::(it.clone()) { - Ok((rest, output)) => { - outputs = OM::combine(outputs, output, |mut acc, e| { - acc.push(e); - acc - }); - rest - } - _ if self.range.contains(&i) => break, - _ => return Err(EM::bind(|| it)), - }; - - i += 1; - - it = match self.delimiter.check(it.clone()) { - Ok((rest, _)) => rest, - _ if self.range.contains(&i) => break, - _ => return Err(EM::bind(|| it)), - }; - } - - Ok((it, outputs)) - } -} - pub struct OneOf { it: It, } @@ -861,7 +964,8 @@ where I::Item: Character, { r#if(|c: &I::Item| c.is_alphabetic()) - .repeated(0..) + .repeated() + .many() .recognize() } @@ -871,7 +975,8 @@ where I::Item: Character, { r#if(|c: &I::Item| c.is_alphabetic()) - .repeated(1..) + .repeated() + .at_least(1) .recognize() } @@ -880,7 +985,10 @@ where I: Input, I::Item: Character, { - r#if(|c: &I::Item| c.is_numeric()).repeated(0..).recognize() + r#if(|c: &I::Item| c.is_numeric()) + .repeated() + .many() + .recognize() } pub fn numeric1() -> impl Parser @@ -888,7 +996,10 @@ where I: Input, I::Item: Character, { - r#if(|c: &I::Item| c.is_numeric()).repeated(1..).recognize() + r#if(|c: &I::Item| c.is_numeric()) + .repeated() + .at_least(1) + .recognize() } pub fn alphanumeric() -> impl Parser @@ -897,7 +1008,8 @@ where I::Item: Character, { r#if(|c: &I::Item| c.is_alphanumeric()) - .repeated(0..) + .repeated() + .many() .recognize() } @@ -907,7 +1019,8 @@ where I::Item: Character, { r#if(|c: &I::Item| c.is_alphanumeric()) - .repeated(1..) + .repeated() + .at_least(1) .recognize() } @@ -917,7 +1030,8 @@ where I::Item: Character, { r#if(|c: &I::Item| c.is_whitespace()) - .repeated(0..) + .repeated() + .many() .recognize() } @@ -927,7 +1041,8 @@ where I::Item: Character, { r#if(|c: &I::Item| c.is_whitespace()) - .repeated(1..) + .repeated() + .at_least(1) .recognize() } @@ -977,7 +1092,8 @@ mod test { let it = InputIter::new(input); alpha1() - .separated_by(whitespace(), 1..) + .separated_by(whitespace()) + .at_least(1) .check_finished(it) .unwrap(); } -- cgit v1.2.3