summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Turner <jturner.usa@gmail.com>2025-10-31 22:00:42 +0000
committerJohn Turner <jturner.usa@gmail.com>2025-11-01 17:13:21 +0000
commit2c96e1c6de13821558b5aa40212a0eb7b1b6856f (patch)
tree66f2b6bdc5dec5b6c00f3e9a32d4ee93fdb3a4de
parent821f132bd5c8678327c2ab8764bd7d172a7b7ee4 (diff)
downloadmon-2c96e1c6de13821558b5aa40212a0eb7b1b6856f.tar.gz
create ParserIter trait
-rw-r--r--.dir-locals.el2
-rw-r--r--src/lib.rs354
-rw-r--r--tests/sexpr.rs5
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))
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<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())