Pass input out

This commit is contained in:
Greg Shuflin 2024-01-26 22:01:21 -08:00
parent e697b8ed21
commit 9efd9d78d1
4 changed files with 23 additions and 18 deletions

View File

@ -1,21 +1,19 @@
use crate::Parser; use crate::Parser;
pub fn choice<'a, I, O, E>(parsers: &'a [&'a dyn Parser<I, O, E>]) -> impl Parser<I, O, E> + 'a pub fn choice<'a, I, O, E>(parsers: &'a [&'a dyn Parser<I, O, E>]) -> impl Parser<I, O, E> + 'a {
where move |mut input: I| {
I: Clone,
{
move |input: I| {
//TODO need a more principled way to return an error when no choices work //TODO need a more principled way to return an error when no choices work
let mut err = None; let mut err = None;
for parser in parsers.iter() { for parser in parsers.iter() {
match parser.parse(input.clone()) { match parser.parse(input) {
Ok(res) => return Ok(res), Ok(res) => return Ok(res),
Err(e) => { Err((e, rest)) => {
err = Some(e); err = Some(e);
input = rest;
} }
} }
} }
Err(err.unwrap()) Err((err.unwrap(), input))
} }
} }

View File

@ -3,16 +3,23 @@ use crate::Parser;
pub fn repeated<P, I, O, E>(parser: P) -> impl Parser<I, Vec<O>, E> pub fn repeated<P, I, O, E>(parser: P) -> impl Parser<I, Vec<O>, E>
where where
P: Parser<I, O, E>, P: Parser<I, O, E>,
I: Copy,
{ {
move |input: I| { move |input: I| {
let mut acc = input; let mut acc = input;
let mut results = vec![]; let mut results = vec![];
while let Ok((item, rest)) = parser.parse(acc) { loop {
match parser.parse(acc) {
Ok((item, rest)) => {
results.push(item); results.push(item);
acc = rest; acc = rest;
} }
Err((_err, rest)) => {
acc = rest;
break;
}
}
}
Ok((results, acc)) Ok((results, acc))
} }
} }

View File

@ -11,7 +11,7 @@ pub use map::*;
pub use primitives::*; pub use primitives::*;
pub use sequence::*; pub use sequence::*;
type ParseResult<I, O, E> = Result<(O, I), E>; type ParseResult<I, O, E> = Result<(O, I), (E, I)>;
pub trait Parser<I, O, E> { pub trait Parser<I, O, E> {
fn parse(&self, input: I) -> ParseResult<I, O, E>; fn parse(&self, input: I) -> ParseResult<I, O, E>;
@ -51,7 +51,7 @@ mod tests {
let a = literal("bongo"); let a = literal("bongo");
let b = literal("sucy"); let b = literal("sucy");
let c = literal("ara"); let c = literal("ara");
let inputs = [&a as &dyn Parser<&str, &str, &str>, &b, &c]; let inputs = [&a as &dyn Parser<&str, &str, ()>, &b, &c];
let parser = choice(&inputs); let parser = choice(&inputs);
let output = parser.parse("ara hajimete").unwrap(); let output = parser.parse("ara hajimete").unwrap();

View File

@ -1,16 +1,16 @@
use crate::{ParseResult, Parser}; use crate::{ParseResult, Parser};
pub fn literal(expected: &'static str) -> impl Fn(&str) -> ParseResult<&str, &str, &str> { pub fn literal(expected: &'static str) -> impl Fn(&str) -> ParseResult<&str, &str, ()> {
move |input| match input.get(0..expected.len()) { move |input| match input.get(0..expected.len()) {
Some(next) if next == expected => Ok((next, &input[expected.len()..])), Some(next) if next == expected => Ok((next, &input[expected.len()..])),
_ => Err(input), _ => Err(((), input)),
} }
} }
pub fn literal_char<'a>(expected: char) -> impl Parser<&'a str, char, &'a str> { pub fn literal_char<'a>(expected: char) -> impl Parser<&'a str, char, ()> {
move |input: &'a str| match input.chars().next() { move |input: &'a str| match input.chars().next() {
Some(ch) if ch == expected => Ok((expected, &input[ch.len_utf8()..])), Some(ch) if ch == expected => Ok((expected, &input[ch.len_utf8()..])),
_ => Err(input), _ => Err(((), input)),
} }
} }