diff options
| author | John Turner <jturner.usa@gmail.com> | 2025-10-31 22:00:42 +0000 |
|---|---|---|
| committer | John Turner <jturner.usa@gmail.com> | 2025-11-01 17:13:21 +0000 |
| commit | 2c96e1c6de13821558b5aa40212a0eb7b1b6856f (patch) | |
| tree | 66f2b6bdc5dec5b6c00f3e9a32d4ee93fdb3a4de | |
| parent | 821f132bd5c8678327c2ab8764bd7d172a7b7ee4 (diff) | |
| download | mon-2c96e1c6de13821558b5aa40212a0eb7b1b6856f.tar.gz | |
create ParserIter trait
| -rw-r--r-- | .dir-locals.el | 2 | ||||
| -rw-r--r-- | src/lib.rs | 354 | ||||
| -rw-r--r-- | tests/sexpr.rs | 5 |
3 files changed, 239 insertions, 122 deletions
diff --git a/.dir-locals.el b/.dir-locals.el index 50970c5..be0d841 100644 --- a/.dir-locals.el +++ b/.dir-locals.el @@ -1,5 +1,5 @@ ((rust-ts-mode . ((fmt-executable . "rustfmt") - (fmt-args . ("--edition=2021")) + (fmt-args . ("--edition=2024")) (eval . (eglot-ensure)) (eval . (company-mode 1)) (eval . (add-hook 'before-save-hook 'fmt-current-buffer nil t)) @@ -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<I: Input>: Sized { Recognize { parser: self } } - fn repeated<R>(self, range: R) -> impl Parser<I, Output = Vec<Self::Output>> - where - R: RangeBounds<usize>, - { - Repeated { - parser: self, - range, - } - } - fn verify_input<C>(self, checker: C) -> impl Parser<I, Output = Self::Output> where C: Parser<I>, @@ -195,23 +185,228 @@ pub trait Parser<I: Input>: Sized { Not { parser: self } } - fn separated_by<P, R>( - self, - delimiter: P, - range: R, - ) -> impl Parser<I, Output = Vec<Self::Output>> + fn repeated(self) -> impl ParserIter<I, Item = Self::Output> { + Repeated { parser: self } + } + + fn separated_by<P>(self, delimiter: P) -> impl ParserIter<I, Item = Self::Output> where P: Parser<I>, - R: RangeBounds<usize>, { SeparatedBy { parser: self, delimiter, - range, } } } +pub trait ParserIter<I: Input> { + type Item; + + fn next<OM: Mode, EM: Mode>( + &self, + it: InputIter<I>, + ) -> Option<ParserResult<I, Self::Item, OM, EM>>; + + fn many(self) -> impl Parser<I, Output = Vec<Self::Item>> + where + Self: Sized, + { + Many { parser: self } + } + + fn at_least(self, count: usize) -> impl Parser<I, Output = Vec<Self::Item>> + where + Self: Sized, + { + AtLeast { + parser: self, + count, + } + } + + fn at_most(self, count: usize) -> impl Parser<I, Output = Vec<Self::Item>> + where + Self: Sized, + { + AtMost { + parser: self, + count, + } + } +} + +struct Repeated<P> { + parser: P, +} + +impl<I, P> ParserIter<I> for Repeated<P> +where + I: Input, + P: Parser<I>, +{ + type Item = P::Output; + + fn next<OM: Mode, EM: Mode>( + &self, + it: InputIter<I>, + ) -> Option<ParserResult<I, Self::Item, OM, EM>> { + if it.is_finished() { + None + } else { + match self.parser.run::<OM, EM, ()>(it) { + Ok((rest, output)) => Some(Ok((rest, output))), + Err(rest) => Some(Err(rest)), + } + } + } +} + +struct SeparatedBy<P1, P2> { + parser: P1, + delimiter: P2, +} + +impl<I, P1, P2> ParserIter<I> for SeparatedBy<P1, P2> +where + I: Input, + P1: Parser<I>, + P2: Parser<I>, +{ + type Item = P1::Output; + + fn next<OM: Mode, EM: Mode>( + &self, + it: InputIter<I>, + ) -> Option<ParserResult<I, Self::Item, OM, EM>> { + if it.is_finished() { + None + } else { + let (rest, output) = match self.parser.run::<OM, EM, ()>(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<P> { + parser: P, + count: usize, +} + +impl<I, P> Parser<I> for AtLeast<P> +where + I: Input, + P: ParserIter<I>, +{ + type Output = Vec<P::Item>; + + fn run<OM: Mode, EM: Mode, Tracer: Trace<I>>( + &self, + mut it: InputIter<I>, + ) -> ParserResult<I, Self::Output, OM, EM> { + let mut outputs = OM::bind(|| Vec::new()); + let mut i = 0; + + while !it.is_finished() { + it = match self.parser.next::<OM, EM>(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<P> { + parser: P, + count: usize, +} + +impl<I, P> Parser<I> for AtMost<P> +where + I: Input, + P: ParserIter<I>, +{ + type Output = Vec<P::Item>; + + fn run<OM: Mode, EM: Mode, Tracer: Trace<I>>( + &self, + mut it: InputIter<I>, + ) -> ParserResult<I, Self::Output, OM, EM> { + let mut outputs = OM::bind(|| Vec::new()); + + for _ in 0..self.count { + it = match self.parser.next::<OM, EM>(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<P> { + parser: P, +} + +impl<I, P> Parser<I> for Many<P> +where + I: Input, + P: ParserIter<I>, +{ + type Output = Vec<P::Item>; + + fn run<OM: Mode, EM: Mode, Tracer: Trace<I>>( + &self, + mut it: InputIter<I>, + ) -> ParserResult<I, Self::Output, OM, EM> { + let mut outputs = OM::bind(|| Vec::new()); + + while !it.is_finished() { + it = match self.parser.next::<OM, EM>(it.clone()) { + Some(Ok((rest, output))) => { + outputs = OM::combine(outputs, output, |mut acc, e| { + acc.push(e); + acc + }); + rest + } + _ => break, + }; + } + + Ok((it, outputs)) + } +} + impl<I, O, F> Parser<I> for F where I: Input, @@ -387,98 +582,6 @@ where Take { amt } } -struct Repeated<P, R> { - parser: P, - range: R, -} - -impl<I, P, R> Parser<I> for Repeated<P, R> -where - I: Input, - P: Parser<I>, - R: RangeBounds<usize>, -{ - type Output = Vec<P::Output>; - - fn run<OM: Mode, EM: Mode, Tracer: Trace<I>>( - &self, - mut it: InputIter<I>, - ) -> ParserResult<I, Self::Output, OM, EM> { - 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::<OM, EM, Tracer>(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<P1, P2, R> { - parser: P1, - delimiter: P2, - range: R, -} - -impl<I, P1, P2, R> Parser<I> for SeparatedBy<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)), - }; - - 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: 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<I>() -> impl Parser<I, Output = I> @@ -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<I>() -> impl Parser<I, Output = I> @@ -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(); } diff --git a/tests/sexpr.rs b/tests/sexpr.rs index ecef773..8d02793 100644 --- a/tests/sexpr.rs +++ b/tests/sexpr.rs @@ -1,7 +1,7 @@ #![allow(dead_code)] use mon::{ - Parser, ParserResult, alpha1, alphanumeric, alphanumeric1, input::InputIter, numeric1, tag, + Parser, ParserIter, alpha1, alphanumeric, alphanumeric1, input::InputIter, numeric1, tag, whitespace, }; @@ -35,7 +35,8 @@ fn int<'a>() -> impl Parser<&'a str, Output = Sexpr> { fn sexpr<'a>() -> impl Parser<&'a str, Output = Sexpr> { |it| { sexpr() - .separated_by(whitespace(), 0..) + .separated_by(whitespace()) + .many() .delimited_by(tag("("), tag(")")) .map(|output| Sexpr::List(output)) .or(atom()) |
