summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Turner <jturner.usa@gmail.com>2025-10-21 20:48:00 -0400
committerJohn Turner <jturner.usa@gmail.com>2025-10-21 20:48:21 -0400
commit0e23b9fa82d95ca365523afac554a4fb6d461a23 (patch)
tree296fc7fc3e8208198b7e87adf4a016a9ea93aedf
parent876855e826bf3c7bd47b822fb41fd91ab46ad7e5 (diff)
downloadmon-0e23b9fa82d95ca365523afac554a4fb6d461a23.tar.gz
impl some basic parsers and combinators
-rw-r--r--src/input.rs127
-rw-r--r--src/lib.rs821
-rw-r--r--src/mode.rs66
-rw-r--r--tests/sexpr.rs66
4 files changed, 1080 insertions, 0 deletions
diff --git a/src/input.rs b/src/input.rs
new file mode 100644
index 0000000..0857c8c
--- /dev/null
+++ b/src/input.rs
@@ -0,0 +1,127 @@
+use core::{fmt, iter, slice, str::CharIndices};
+
+use crate::Span;
+
+pub trait Input: Clone {
+ type Item;
+ type Items: Clone + Iterator<Item = (usize, Self::Item)>;
+
+ fn items(&self) -> Self::Items;
+
+ fn slice(&self, span: Span) -> Self;
+
+ fn len(&self) -> usize;
+}
+
+impl<'a> Input for &'a str {
+ type Item = char;
+ type Items = CharIndices<'a>;
+
+ fn items(&self) -> Self::Items {
+ self.char_indices()
+ }
+
+ fn slice(&self, span: Span) -> Self {
+ &self[span]
+ }
+
+ fn len(&self) -> usize {
+ (*self).len()
+ }
+}
+
+impl<'a> Input for &'a [u8] {
+ type Item = u8;
+ type Items = iter::Enumerate<iter::Copied<slice::Iter<'a, u8>>>;
+
+ fn items(&self) -> Self::Items {
+ self.iter().copied().enumerate()
+ }
+
+ fn slice(&self, span: Span) -> Self {
+ &self[span]
+ }
+
+ fn len(&self) -> usize {
+ (*self).len()
+ }
+}
+
+pub trait Character {
+ fn is_alphabetic(&self) -> bool;
+
+ fn is_numeric(&self) -> bool;
+
+ fn is_whitespace(&self) -> bool;
+
+ fn is_alphanumeric(&self) -> bool {
+ self.is_alphabetic() || self.is_numeric()
+ }
+}
+
+impl Character for char {
+ fn is_alphabetic(&self) -> bool {
+ (*self).is_ascii_alphabetic()
+ }
+
+ fn is_numeric(&self) -> bool {
+ (*self).is_numeric()
+ }
+
+ fn is_whitespace(&self) -> bool {
+ (*self).is_whitespace()
+ }
+}
+
+#[derive(Clone)]
+pub struct InputIter<I: Input> {
+ pub it: I::Items,
+ pub input: I,
+}
+
+impl<I> InputIter<I>
+where
+ I: Input,
+{
+ pub fn new(input: I) -> Self {
+ Self {
+ it: input.items(),
+ input,
+ }
+ }
+
+ pub fn position(&self) -> usize {
+ match self.it.clone().next() {
+ Some((i, _)) => i,
+ None => self.input.len(),
+ }
+ }
+
+ pub fn is_finished(&self) -> bool {
+ self.clone().next().is_none()
+ }
+
+ pub fn rest(&self) -> I {
+ self.input.slice(self.position()..self.input.len())
+ }
+}
+
+impl<I> Iterator for InputIter<I>
+where
+ I: Input,
+{
+ type Item = (usize, I::Item);
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.it.next()
+ }
+}
+
+impl<I> fmt::Debug for InputIter<I>
+where
+ I: Input + fmt::Debug,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{:?}", self.rest())
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..fc91cb1
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,821 @@
+use core::{cmp::PartialEq, fmt, iter::Iterator, marker::Sized, ops::Range};
+
+use crate::{
+ input::{Character, Input, InputIter},
+ mode::{Check, Emit, Mode},
+};
+
+pub mod input;
+pub mod mode;
+
+pub type Span = Range<usize>;
+
+pub type ParserOk<I, O> = (InputIter<I>, O);
+
+pub type ParserResult<I, O, OM = Emit, EM = Emit> =
+ Result<ParserOk<I, <OM as Mode>::Output<O>>, <EM as Mode>::Output<InputIter<I>>>;
+
+pub trait Trace<I: Input> {
+ fn trace(parser: &str, input: InputIter<I>);
+}
+
+pub struct DebugTracer;
+
+impl<I> Trace<I> for DebugTracer
+where
+ I: Input + fmt::Debug,
+{
+ fn trace(parser: &str, input: InputIter<I>) {
+ eprintln!("{}:{:?}", parser, input)
+ }
+}
+
+impl<I> Trace<I> for ()
+where
+ I: Input,
+{
+ fn trace(_: &str, _: InputIter<I>) {}
+}
+
+#[derive(Debug)]
+pub enum ParserFinishedError<I: Input> {
+ Err(InputIter<I>),
+ Unfinished(InputIter<I>),
+}
+
+pub trait Parser<I: Input>: Sized {
+ type Output;
+
+ fn run<OM: Mode, EM: Mode, T: Trace<I>>(
+ &mut self,
+ it: InputIter<I>,
+ ) -> ParserResult<I, Self::Output, OM, EM>;
+
+ fn parse(&mut self, it: InputIter<I>) -> ParserResult<I, Self::Output> {
+ self.run::<Emit, Emit, ()>(it)
+ }
+
+ fn check(&mut self, it: InputIter<I>) -> ParserResult<I, Self::Output, Check, Emit> {
+ self.run::<Check, Emit, ()>(it)
+ }
+
+ fn trace<T: Trace<I>>(&mut self, it: InputIter<I>) -> ParserResult<I, Self::Output> {
+ self.run::<Emit, Emit, T>(it)
+ }
+
+ fn parse_finished(&mut self, it: InputIter<I>) -> Result<Self::Output, ParserFinishedError<I>> {
+ match self.parse(it) {
+ Ok((rest, output)) if rest.is_finished() => Ok(output),
+ Ok((rest, _)) => Err(ParserFinishedError::Unfinished(rest)),
+ Err(rest) => Err(ParserFinishedError::Err(rest)),
+ }
+ }
+
+ fn check_finished(&mut self, it: InputIter<I>) -> Result<(), ParserFinishedError<I>> {
+ match self.parse(it) {
+ Ok((rest, _)) if rest.is_finished() => Ok(()),
+ Ok((rest, _)) => Err(ParserFinishedError::Unfinished(rest)),
+ Err(rest) => Err(ParserFinishedError::Err(rest)),
+ }
+ }
+
+ fn map<F, O>(self, f: F) -> impl Parser<I, Output = O>
+ where
+ F: Fn(Self::Output) -> O,
+ {
+ Map { parser: self, f }
+ }
+
+ fn and<P>(self, right: P) -> impl Parser<I, Output = (Self::Output, P::Output)>
+ where
+ P: Parser<I>,
+ {
+ And { left: self, right }
+ }
+
+ fn or<P, O>(self, right: P) -> impl Parser<I, Output = O>
+ where
+ Self: Parser<I, Output = O>,
+ P: Parser<I, Output = O>,
+ {
+ Or { left: self, right }
+ }
+
+ fn and_not<P>(self, not: P) -> impl Parser<I, Output = Self::Output>
+ where
+ P: Parser<I>,
+ {
+ AndNot { parser: self, not }
+ }
+
+ fn preceded_by<P>(self, preceded: P) -> impl Parser<I, Output = Self::Output>
+ where
+ P: Parser<I>,
+ {
+ PrecededBy {
+ parser: self,
+ preceded,
+ }
+ }
+
+ fn followed_by<P>(self, followed: P) -> impl Parser<I, Output = Self::Output>
+ where
+ P: Parser<I>,
+ {
+ FollowedBy {
+ parser: self,
+ followed,
+ }
+ }
+
+ fn delimited_by<P1, P2>(self, left: P1, right: P2) -> impl Parser<I, Output = Self::Output>
+ where
+ P1: Parser<I>,
+ P2: Parser<I>,
+ {
+ DelimitedBy {
+ parser: self,
+ left,
+ right,
+ }
+ }
+
+ fn recognize(self) -> impl Parser<I, Output = I> {
+ Recognize { parser: self }
+ }
+
+ fn separated_list<P>(self, delimiter: P) -> impl Parser<I, Output = Vec<Self::Output>>
+ where
+ P: Parser<I>,
+ {
+ SeparatedList {
+ parser: self,
+ delimiter,
+ }
+ }
+
+ fn separated_list1<P>(self, delimiter: P) -> impl Parser<I, Output = Vec<Self::Output>>
+ where
+ P: Parser<I>,
+ {
+ SeparatedList1 {
+ parser: self,
+ delimiter,
+ }
+ }
+}
+
+impl<I, O, F> Parser<I> for F
+where
+ I: Input,
+ F: Fn(InputIter<I>) -> Result<ParserOk<I, O>, InputIter<I>>,
+{
+ type Output = O;
+
+ fn run<OM: Mode, EM: Mode, Tracer: Trace<I>>(
+ &mut self,
+ it: InputIter<I>,
+ ) -> ParserResult<I, Self::Output, OM, EM> {
+ Tracer::trace("fn", it.clone());
+
+ match self(it) {
+ Ok((rest, output)) => Ok((rest, OM::bind(|| output))),
+ Err(rest) => Err(EM::bind(|| rest)),
+ }
+ }
+}
+
+struct Map<P, F> {
+ parser: P,
+ f: F,
+}
+
+impl<I, P, F, O> Parser<I> for Map<P, F>
+where
+ I: Input,
+ P: Parser<I>,
+ F: Fn(P::Output) -> O,
+{
+ type Output = O;
+
+ fn run<OM: Mode, EM: Mode, Tracer: Trace<I>>(
+ &mut self,
+ it: InputIter<I>,
+ ) -> ParserResult<I, Self::Output, OM, EM> {
+ match self.parser.run::<OM, EM, Tracer>(it) {
+ Ok((rest, output)) => Ok((rest, OM::map(output, |o| (self.f)(o)))),
+ Err(rest) => Err(rest),
+ }
+ }
+}
+
+struct And<P1, P2> {
+ left: P1,
+ right: P2,
+}
+
+impl<I, P1, P2> Parser<I> for And<P1, P2>
+where
+ I: Input,
+ P1: Parser<I>,
+ P2: Parser<I>,
+{
+ type Output = (P1::Output, P2::Output);
+
+ fn run<OM: Mode, EM: Mode, Tracer: Trace<I>>(
+ &mut self,
+ it: InputIter<I>,
+ ) -> ParserResult<I, Self::Output, OM, EM> {
+ Tracer::trace("and", it.clone());
+
+ let (rest, o1) = match self.left.run::<OM, EM, Tracer>(it) {
+ Ok((rest, output)) => (rest, output),
+ Err(rest) => return Err(rest),
+ };
+
+ let (rest, o2) = match self.right.run::<OM, EM, Tracer>(rest) {
+ Ok((rest, output)) => (rest, output),
+ Err(rest) => return Err(rest),
+ };
+
+ Ok((rest, OM::combine(o1, o2, |o1, o2| (o1, o2))))
+ }
+}
+
+struct AndNot<P1, P2> {
+ parser: P1,
+ not: P2,
+}
+
+impl<I, P1, P2> Parser<I> for AndNot<P1, P2>
+where
+ I: Input,
+ P1: Parser<I>,
+ P2: Parser<I>,
+{
+ type Output = P1::Output;
+
+ fn run<OM: Mode, EM: Mode, Tracer: Trace<I>>(
+ &mut self,
+ it: InputIter<I>,
+ ) -> ParserResult<I, Self::Output, OM, EM> {
+ Tracer::trace("andnot", it.clone());
+
+ match self.not.run::<Check, Check, Tracer>(it.clone()) {
+ Ok(_) => return Err(EM::bind(|| it.clone())),
+ _ => (),
+ };
+
+ self.parser.run::<OM, EM, Tracer>(it)
+ }
+}
+
+struct Or<P1, P2> {
+ left: P1,
+ right: P2,
+}
+
+impl<I, P1, P2, O> Parser<I> for Or<P1, P2>
+where
+ I: Input,
+ P1: Parser<I, Output = O>,
+ P2: Parser<I, Output = O>,
+{
+ type Output = O;
+
+ fn run<OM: Mode, EM: Mode, Tracer: Trace<I>>(
+ &mut self,
+ it: InputIter<I>,
+ ) -> ParserResult<I, Self::Output, OM, EM> {
+ Tracer::trace("or", it.clone());
+
+ match (
+ self.left.run::<OM, EM, Tracer>(it.clone()),
+ self.right.run::<OM, EM, Tracer>(it.clone()),
+ ) {
+ (Ok((rest, output)), _) => Ok((rest, output)),
+ (_, Ok((rest, output))) => Ok((rest, output)),
+ (_, Err(rest)) => Err(rest),
+ }
+ }
+}
+
+pub struct Take {
+ amt: usize,
+}
+
+impl<I> Parser<I> for Take
+where
+ I: Input,
+{
+ type Output = I;
+
+ fn run<OM: Mode, EM: Mode, Tracer: Trace<I>>(
+ &mut self,
+ mut it: InputIter<I>,
+ ) -> ParserResult<I, Self::Output, OM, EM> {
+ Tracer::trace("take", it.clone());
+
+ let start = it.clone();
+
+ for _ in 0..self.amt {
+ match it.next() {
+ Some(_) => continue,
+ None => return Err(EM::bind(|| it)),
+ }
+ }
+
+ Ok((
+ it.clone(),
+ OM::bind(|| it.input.slice(start.position()..it.position())),
+ ))
+ }
+}
+
+pub fn take<I>(amt: usize) -> impl Parser<I, Output = I>
+where
+ I: Input,
+{
+ Take { amt }
+}
+
+pub struct TakeWhile<P> {
+ parser: P,
+}
+
+impl<I, P> Parser<I> for TakeWhile<P>
+where
+ I: Input,
+ P: Parser<I>,
+{
+ type Output = I;
+
+ fn run<OM: Mode, EM: Mode, Tracer: Trace<I>>(
+ &mut self,
+ mut it: InputIter<I>,
+ ) -> ParserResult<I, Self::Output, OM, EM> {
+ Tracer::trace("takewhile", it.clone());
+
+ let start = it.clone();
+
+ while let Ok((rest, _)) = self.parser.run::<Check, Check, Tracer>(it.clone()) {
+ it = rest;
+ }
+
+ Ok((
+ it.clone(),
+ OM::bind(|| it.input.slice(start.position()..it.position())),
+ ))
+ }
+}
+
+pub fn take_while<I, P>(parser: P) -> impl Parser<I, Output = I>
+where
+ I: Input,
+ P: Parser<I>,
+{
+ TakeWhile { parser }
+}
+
+pub struct TakeWhile1<P> {
+ parser: P,
+}
+
+impl<I, P> Parser<I> for TakeWhile1<P>
+where
+ I: Input,
+ P: Parser<I>,
+{
+ type Output = I;
+
+ fn run<OM: Mode, EM: Mode, Tracer: Trace<I>>(
+ &mut self,
+ mut it: InputIter<I>,
+ ) -> ParserResult<I, Self::Output, OM, EM> {
+ Tracer::trace("takewhile1", it.clone());
+
+ let start = it.clone();
+
+ while let Ok((rest, _)) = self.parser.run::<Check, Check, Tracer>(it.clone()) {
+ it = rest;
+ }
+
+ if it.position() > start.position() {
+ Ok((
+ it.clone(),
+ OM::bind(|| it.input.slice(start.position()..it.position())),
+ ))
+ } else {
+ Err(EM::bind(|| it))
+ }
+ }
+}
+
+pub fn take_while1<I, P>(parser: P) -> impl Parser<I, Output = I>
+where
+ I: Input,
+ P: Parser<I>,
+{
+ TakeWhile1 { parser }
+}
+
+pub struct OneOf<It> {
+ it: It,
+}
+
+impl<I, It> Parser<I> for OneOf<It>
+where
+ I: Input,
+ I::Item: PartialEq<It::Item>,
+ It: Iterator,
+{
+ type Output = I::Item;
+
+ fn run<OM: Mode, EM: Mode, Tracer: Trace<I>>(
+ &mut self,
+ mut it: InputIter<I>,
+ ) -> ParserResult<I, Self::Output, OM, EM> {
+ Tracer::trace("oneof", it.clone());
+
+ match it.next() {
+ Some((_, item)) if self.it.any(|i| item == i) => Ok((it, OM::bind(|| item))),
+ _ => Err(EM::bind(|| it)),
+ }
+ }
+}
+
+pub fn one_of<I, It>(it: It) -> impl Parser<I, Output = I::Item>
+where
+ I: Input,
+ I::Item: PartialEq<It::Item>,
+ It: Iterator,
+{
+ OneOf { it }
+}
+
+pub struct If<F> {
+ f: F,
+}
+
+impl<I, F> Parser<I> for If<F>
+where
+ I: Input,
+ F: Fn(&I::Item) -> bool,
+{
+ type Output = I::Item;
+
+ fn run<OM: Mode, EM: Mode, Tracer: Trace<I>>(
+ &mut self,
+ mut it: InputIter<I>,
+ ) -> ParserResult<I, Self::Output, OM, EM> {
+ Tracer::trace("if", it.clone());
+
+ match it.next() {
+ Some((_, output)) if (self.f)(&output) => Ok((it, OM::bind(|| output))),
+ _ => Err(EM::bind(|| it)),
+ }
+ }
+}
+
+pub fn r#if<I, F>(f: F) -> impl Parser<I, Output = I::Item>
+where
+ I: Input,
+ F: Fn(&I::Item) -> bool,
+{
+ If { f }
+}
+
+struct PrecededBy<P1, P2> {
+ parser: P1,
+ preceded: P2,
+}
+
+impl<I, P1, P2> Parser<I> for PrecededBy<P1, P2>
+where
+ I: Input,
+ P1: Parser<I>,
+ P2: Parser<I>,
+{
+ type Output = P1::Output;
+
+ fn run<OM: Mode, EM: Mode, Tracer: Trace<I>>(
+ &mut self,
+ it: InputIter<I>,
+ ) -> ParserResult<I, Self::Output, OM, EM> {
+ Tracer::trace("preceded by", it.clone());
+
+ let rest = match self.preceded.check(it.clone()) {
+ Ok((rest, _)) => rest,
+ Err(_) => return Err(EM::bind(|| it)),
+ };
+
+ self.parser.run::<OM, EM, Tracer>(rest)
+ }
+}
+
+pub struct FollowedBy<P1, P2> {
+ parser: P1,
+ followed: P2,
+}
+
+impl<I, P1, P2> Parser<I> for FollowedBy<P1, P2>
+where
+ I: Input,
+ P1: Parser<I>,
+ P2: Parser<I>,
+{
+ type Output = P1::Output;
+
+ fn run<OM: Mode, EM: Mode, Tracer: Trace<I>>(
+ &mut self,
+ it: InputIter<I>,
+ ) -> ParserResult<I, Self::Output, OM, EM> {
+ Tracer::trace("followed by", it.clone());
+
+ let (rest, output) = match self.parser.run::<OM, EM, Tracer>(it) {
+ Ok((rest, output)) => (rest, output),
+ Err(rest) => return Err(rest),
+ };
+
+ let Ok((rest, _)) = self.followed.check(rest.clone()) else {
+ return Err(EM::bind(|| rest.clone()));
+ };
+
+ Ok((rest, output))
+ }
+}
+
+struct DelimitedBy<P1, P2, P3> {
+ parser: P1,
+ left: P2,
+ right: P3,
+}
+
+impl<I, P1, P2, P3> Parser<I> for DelimitedBy<P1, P2, P3>
+where
+ I: Input,
+ P1: Parser<I>,
+ P2: Parser<I>,
+ P3: Parser<I>,
+{
+ type Output = P1::Output;
+
+ fn run<OM: Mode, EM: Mode, Tracer: Trace<I>>(
+ &mut self,
+ it: InputIter<I>,
+ ) -> ParserResult<I, Self::Output, OM, EM> {
+ Tracer::trace("delimited by", it.clone());
+
+ let rest = match self.left.check(it.clone()) {
+ Ok((rest, _)) => rest,
+ Err(_) => return Err(EM::bind(|| it)),
+ };
+
+ let (rest, output) = match self.parser.run::<OM, EM, Tracer>(rest.clone()) {
+ Ok((rest, output)) => (rest, output),
+ Err(rest) => return Err(rest),
+ };
+
+ let Ok((rest, _)) = self.right.check(rest.clone()) else {
+ return Err(EM::bind(|| rest));
+ };
+
+ Ok((rest, output))
+ }
+}
+
+struct Recognize<P> {
+ parser: P,
+}
+
+impl<I, P> Parser<I> for Recognize<P>
+where
+ I: Input,
+ P: Parser<I>,
+{
+ type Output = I;
+
+ fn run<OM: Mode, EM: Mode, Tracer: Trace<I>>(
+ &mut self,
+ it: InputIter<I>,
+ ) -> ParserResult<I, Self::Output, OM, EM> {
+ Tracer::trace("recognize", it.clone());
+
+ let start = it.clone();
+
+ let rest = match self.parser.check(it.clone()) {
+ Ok((rest, _)) => rest,
+ Err(_) => return Err(EM::bind(|| it)),
+ };
+
+ Ok((
+ rest.clone(),
+ OM::bind(|| it.input.slice(start.position()..rest.position())),
+ ))
+ }
+}
+
+struct Tag<T>(T);
+
+impl<I, T> Parser<I> for Tag<T>
+where
+ I: Input + PartialEq<T>,
+ T: Input,
+{
+ type Output = I;
+
+ fn run<OM: Mode, EM: Mode, Tracer: Trace<I>>(
+ &mut self,
+ it: InputIter<I>,
+ ) -> ParserResult<I, Self::Output, OM, EM> {
+ Tracer::trace("tag", it.clone());
+
+ match take(self.0.len()).parse(it.clone()) {
+ Ok((rest, output)) if output == self.0 => Ok((rest, OM::bind(|| output))),
+ Ok(_) => return Err(EM::bind(|| it)),
+ Err(rest) => return Err(EM::bind(|| rest)),
+ }
+ }
+}
+
+pub fn tag<I, T>(tag: T) -> impl Parser<I, Output = I>
+where
+ I: Input + PartialEq<T>,
+ T: Input,
+{
+ Tag(tag)
+}
+
+struct SeparatedList<P1, P2> {
+ parser: P1,
+ delimiter: P2,
+}
+
+impl<I, P1, P2> Parser<I> for SeparatedList<P1, P2>
+where
+ I: Input,
+ P1: Parser<I>,
+ P2: Parser<I>,
+{
+ type Output = Vec<P1::Output>;
+
+ fn run<OM: Mode, EM: Mode, Tracer: Trace<I>>(
+ &mut self,
+ mut it: InputIter<I>,
+ ) -> ParserResult<I, Self::Output, OM, EM> {
+ Tracer::trace("separated list", it.clone());
+
+ let mut outputs = OM::bind(|| Vec::new());
+
+ loop {
+ 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
+ }
+ _ => break,
+ };
+
+ it = match self.delimiter.check(it.clone()) {
+ Ok((rest, _)) => rest,
+ _ => break,
+ };
+ }
+
+ Ok((it, outputs))
+ }
+}
+
+pub struct SeparatedList1<P1, P2> {
+ parser: P1,
+ delimiter: P2,
+}
+
+impl<I, P1, P2> Parser<I> for SeparatedList1<P1, P2>
+where
+ I: Input,
+ P1: Parser<I>,
+ P2: Parser<I>,
+{
+ type Output = Vec<P1::Output>;
+
+ fn run<OM: Mode, EM: Mode, Tracer: Trace<I>>(
+ &mut self,
+ mut it: InputIter<I>,
+ ) -> ParserResult<I, Self::Output, OM, EM> {
+ Tracer::trace("separated list 1", it.clone());
+
+ it = match self.delimiter.check(it.clone()) {
+ Ok((rest, _)) => rest,
+ Err(_) => it,
+ };
+
+ let mut outputs = OM::bind(|| Vec::new());
+ let mut len = 0;
+
+ loop {
+ 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
+ });
+ len += 1;
+ rest
+ }
+ _ => break,
+ };
+
+ it = match self.delimiter.check(it.clone()) {
+ Ok((rest, _)) => rest,
+ _ if len > 0 => break,
+ _ => return Err(EM::bind(|| it)),
+ };
+ }
+
+ Ok((it, outputs))
+ }
+}
+
+pub fn alpha<I>() -> impl Parser<I, Output = I>
+where
+ I: Input,
+ I::Item: Character,
+{
+ take_while(r#if(|c: &I::Item| c.is_alphabetic()))
+}
+
+pub fn alpha1<I>() -> impl Parser<I, Output = I>
+where
+ I: Input,
+ I::Item: Character,
+{
+ take_while1(r#if(|c: &I::Item| c.is_alphabetic()))
+}
+
+pub fn numeric<I>() -> impl Parser<I, Output = I>
+where
+ I: Input,
+ I::Item: Character,
+{
+ take_while(r#if(|c: &I::Item| c.is_numeric()))
+}
+
+pub fn numeric1<I>() -> impl Parser<I, Output = I>
+where
+ I: Input,
+ I::Item: Character,
+{
+ take_while1(r#if(|c: &I::Item| c.is_numeric()))
+}
+
+pub fn alphanumeric<I>() -> impl Parser<I, Output = I>
+where
+ I: Input,
+ I::Item: Character,
+{
+ take_while(r#if(|c: &I::Item| c.is_alphanumeric()))
+}
+
+pub fn alphanumeric1<I>() -> impl Parser<I, Output = I>
+where
+ I: Input,
+ I::Item: Character,
+{
+ take_while1(r#if(|c: &I::Item| c.is_alphanumeric()))
+}
+
+pub fn whitespace<I>() -> impl Parser<I, Output = I>
+where
+ I: Input,
+ I::Item: Character,
+{
+ take_while(r#if(|c: &I::Item| c.is_whitespace()))
+}
+
+pub fn whitespace1<I>() -> impl Parser<I, Output = I>
+where
+ I: Input,
+ I::Item: Character,
+{
+ take_while1(r#if(|c: &I::Item| c.is_whitespace()))
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ #[test]
+ fn test_separated_list() {
+ let input = "a b c";
+ let it = InputIter::new(input);
+
+ alpha1()
+ .separated_list(whitespace())
+ .check_finished(it)
+ .unwrap();
+ }
+}
diff --git a/src/mode.rs b/src/mode.rs
new file mode 100644
index 0000000..3825e31
--- /dev/null
+++ b/src/mode.rs
@@ -0,0 +1,66 @@
+pub trait Mode {
+ type Output<T>;
+
+ fn bind<T, F>(f: F) -> Self::Output<T>
+ where
+ F: FnOnce() -> T;
+
+ fn map<T, U, F>(t: Self::Output<T>, f: F) -> Self::Output<U>
+ where
+ F: FnOnce(T) -> U;
+
+ fn combine<T, U, V, F>(t: Self::Output<T>, u: Self::Output<U>, f: F) -> Self::Output<V>
+ where
+ F: FnOnce(T, U) -> V;
+}
+
+pub struct Emit;
+
+impl Mode for Emit {
+ type Output<T> = T;
+
+ fn bind<T, F>(f: F) -> Self::Output<T>
+ where
+ F: FnOnce() -> T,
+ {
+ f()
+ }
+
+ fn map<T, U, F>(t: Self::Output<T>, f: F) -> Self::Output<U>
+ where
+ F: FnOnce(T) -> U,
+ {
+ f(t)
+ }
+
+ fn combine<T, U, V, F>(t: Self::Output<T>, u: Self::Output<U>, f: F) -> Self::Output<V>
+ where
+ F: FnOnce(T, U) -> V,
+ {
+ f(t, u)
+ }
+}
+
+pub struct Check;
+
+impl Mode for Check {
+ type Output<T> = ();
+
+ fn bind<T, F>(_: F) -> Self::Output<T>
+ where
+ F: FnOnce() -> T,
+ {
+ }
+
+ fn map<T, U, F>(_: Self::Output<T>, _: F) -> Self::Output<U>
+ where
+ F: FnOnce(T) -> U,
+ {
+ }
+
+ fn combine<T, U, V, F>(_: Self::Output<T>, _: Self::Output<U>, _: F) -> Self::Output<V>
+ where
+ F: FnOnce(T, U) -> V,
+ {
+ }
+}
diff --git a/tests/sexpr.rs b/tests/sexpr.rs
new file mode 100644
index 0000000..651d534
--- /dev/null
+++ b/tests/sexpr.rs
@@ -0,0 +1,66 @@
+#![allow(dead_code)]
+
+use mon::{
+ alpha1, alphanumeric, alphanumeric1, input::InputIter, numeric1, tag, whitespace, Parser,
+ ParserResult,
+};
+
+#[derive(Debug)]
+enum Sexpr {
+ List(Vec<Sexpr>),
+ Atom(String),
+ String(String),
+ Int(i64),
+}
+
+fn atom<'a>() -> impl Parser<&'a str, Output = Sexpr> {
+ alpha1()
+ .and(alphanumeric())
+ .recognize()
+ .map(|output: &str| Sexpr::Atom(output.to_string()))
+}
+
+fn string<'a>() -> impl Parser<&'a str, Output = Sexpr> {
+ alphanumeric1()
+ .delimited_by(tag("\""), tag("\""))
+ .map(|output: &str| Sexpr::String(output.to_string()))
+}
+
+fn int<'a>() -> impl Parser<&'a str, Output = Sexpr> {
+ numeric1().map(|output: &str| Sexpr::Int(output.parse().unwrap()))
+}
+
+fn sexpr<'a>(it: InputIter<&'a str>) -> ParserResult<&'a str, Sexpr> {
+ sexpr
+ .separated_list(whitespace())
+ .delimited_by(tag("("), tag(")"))
+ .map(|output| Sexpr::List(output))
+ .or(atom())
+ .or(string())
+ .or(int())
+ .parse(it)
+}
+
+#[test]
+fn test_atom() {
+ let input = "atom";
+ let it = InputIter::new(input);
+
+ atom().check_finished(it).unwrap();
+}
+
+#[test]
+fn test_string() {
+ let input = r#""string""#;
+ let it = InputIter::new(input);
+
+ string().check_finished(it).unwrap()
+}
+
+#[test]
+fn test_sexpr() {
+ let input = r#"(let ((a "hello") (b 2)))"#;
+ let it = InputIter::new(input);
+
+ dbg!(sexpr(it).unwrap());
+}