diff options
| author | John Turner <jturner.usa@gmail.com> | 2025-10-27 01:37:29 -0400 |
|---|---|---|
| committer | John Turner <jturner.usa@gmail.com> | 2025-10-27 01:37:29 -0400 |
| commit | b8250a0f3975b63f54eea370d9d0907e92252984 (patch) | |
| tree | aa0fb7a46e89e18d7230e84923dfc11ea78a4a86 /src | |
| parent | 4d28f32d78c68558bb838060af515074af9c2c5e (diff) | |
| download | mon-b8250a0f3975b63f54eea370d9d0907e92252984.tar.gz | |
bring back separated_list but with a range parameter
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib.rs | 79 |
1 files changed, 79 insertions, 0 deletions
@@ -7,6 +7,8 @@ use core::{ ops::{Bound, Range, RangeBounds}, }; +use regex::Replacer; + use crate::{ input::{Character, Input, InputIter}, mode::{Check, Emit, Mode}, @@ -192,6 +194,22 @@ pub trait Parser<I: Input>: Sized { fn not(self) -> impl Parser<I, Output = ()> { Not { parser: self } } + + fn separated_list<P, R>( + self, + delimiter: P, + range: R, + ) -> impl Parser<I, Output = Vec<Self::Output>> + where + P: Parser<I>, + R: RangeBounds<usize>, + { + SeparatedList { + parser: self, + delimiter, + range, + } + } } impl<I, O, F> Parser<I> for F @@ -411,6 +429,56 @@ where } } +struct SeparatedList<P1, P2, R> { + parser: P1, + delimiter: P2, + range: R, +} + +impl<I, P1, P2, R> Parser<I> for SeparatedList<P1, P2, R> +where + I: Input, + P1: Parser<I>, + P2: Parser<I>, + R: RangeBounds<usize>, +{ + type Output = Vec<P1::Output>; + + fn run<OM: Mode, EM: Mode, Tracer: Trace<I>>( + &self, + mut it: InputIter<I>, + ) -> ParserResult<I, Self::Output, OM, EM> { + 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::<OM, EM, Tracer>(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)), + }; + + it = match self.delimiter.check(it.clone()) { + Ok((rest, _)) => rest, + _ if self.range.contains(&i) => break, + _ => return Err(EM::bind(|| it)), + }; + + i += 1; + } + + Ok((it, outputs)) + } +} + pub struct OneOf<It> { it: It, } @@ -889,6 +957,17 @@ mod test { use super::*; #[test] + fn test_separated_list() { + let input = "a b c"; + let it = InputIter::new(input); + + alpha1() + .separated_list(whitespace(), 1..) + .check_finished(it) + .unwrap(); + } + + #[test] fn test_regex_parser() { let it = InputIter::new("abc 123"); |
