zero or more

This commit is contained in:
Greg Shuflin 2022-10-16 00:30:06 -07:00
parent 4eda356fd7
commit 870c9beb54
1 changed files with 29 additions and 8 deletions

View File

@ -1,5 +1,6 @@
#![feature(assert_matches)]
#![allow(dead_code)] //TODO eventually turn this off
use std::rc::Rc;
type ParseResult<I, O, E> = Result<(O, I), E>;
@ -16,6 +17,15 @@ where
}
}
impl<I, O, E, T> Parser<I, O, E> for Rc<T>
where
T: Parser<I, O, E>,
{
fn parse(&self, input: I) -> ParseResult<I, O, E> {
self.as_ref().parse(input)
}
}
fn literal(expected: &'static str) -> impl Fn(&str) -> ParseResult<&str, &str, &str> {
move |input| match input.get(0..expected.len()) {
Some(next) if next == expected => Ok((expected, &input[expected.len()..])),
@ -49,7 +59,7 @@ where
}
}
fn one_or_more<P, I, O>(parser: P) -> impl Parser<I, Vec<O>, I>
fn zero_or_more<P, I, O>(parser: P) -> impl Parser<I, Vec<O>, I>
where
P: Parser<I, O, I>,
I: Copy,
@ -57,13 +67,6 @@ where
move |mut input| {
let mut results = Vec::new();
if let Ok((result, rest)) = parser.parse(input) {
results.push(result);
input = rest;
} else {
return Err(input);
}
while let Ok((item, rest)) = parser.parse(input) {
results.push(item);
input = rest;
@ -73,6 +76,22 @@ where
}
}
fn one_or_more<P, I, O>(parser: P) -> impl Parser<I, Vec<O>, I>
where
P: Parser<I, O, I>,
I: Copy,
{
let parser = std::rc::Rc::new(parser);
map(
seq(parser.clone(), zero_or_more(parser)),
|(first, rest)| {
let mut output = vec![first];
output.extend(rest.into_iter());
output
},
)
}
/// Parses a standard identifier in a programming language
fn identifier(input: &str) -> ParseResult<&str, String, &str> {
let mut chars = input.chars();
@ -130,5 +149,7 @@ mod tests {
let p = one_or_more(literal("bongo "));
let input = "bongo bongo bongo bongo bongo ";
assert_matches!(p.parse(input), Ok((v, "")) if v.len() == 5);
let input = "bongo ecks";
assert_matches!(p.parse(input), Ok((v, "ecks")) if v.len() == 1);
}
}