use crate::Mismatch;
use crate::combinators::*;
use crate::error::{Error, MismatchElement};
use crate::input::{CharToken, Input, InputToken, StringInput};
pub trait Parser<IT, O>: Fn(&mut Input<IT>) -> Result<O, Error>
where
IT: InputToken,
{
fn with_expectation<E>(self, expectation: E) -> impl Parser<IT, O>
where
E: MismatchElement + Clone + 'static,
Self: Sized,
{
move |input| match self(input) {
Ok(result) => Ok(result),
Err(Error::EndOfInput(Some(_))) => {
Err(Error::EndOfInput(Some(Box::new(expectation.clone()))))
}
Err(Error::EndOfInput(None)) => {
Err(Error::EndOfInput(Some(Box::new(expectation.clone()))))
}
Err(Error::UnexpectedToken(s, p, Some(mut mismatch))) => {
mismatch.replace_expectation(expectation.clone());
Err(Error::UnexpectedToken(s, p, Some(mismatch)))
}
Err(Error::UnexpectedToken(s, p, None)) => {
let mismatch = Mismatch::without_found(expectation.clone());
Err(Error::UnexpectedToken(s, p, Some(mismatch)))
}
Err(error) => Err(error),
}
}
fn map<F, MO>(self, f: F) -> impl Parser<IT, MO>
where
F: Fn(O) -> MO,
Self: Sized,
{
move |input| match self(input) {
Ok(value) => Ok(f(value)),
Err(e) => Err(e),
}
}
fn and_then<F, P, NO>(self, f: F) -> impl Parser<IT, NO>
where
F: Fn(O) -> P,
P: Parser<IT, NO>,
Self: Sized,
{
move |input| match self(input) {
Ok(value) => f(value)(input),
Err(e) => Err(e),
}
}
fn and<P, NO>(self, other: P) -> impl Parser<IT, NO>
where
P: Parser<IT, NO>,
Self: Sized,
{
move |input| match self(input) {
Ok(_) => other(input),
Err(e) => Err(e),
}
}
fn exhaustive(self) -> impl Parser<IT, O>
where
Self: Sized,
{
move |input| {
let output = self(input)?;
end_of_input()(input)?;
Ok(output)
}
}
fn attempt(self) -> impl Parser<IT, O>
where
Self: Sized,
{
move |input| attempt(&self)(input)
}
fn maybe(self) -> impl Parser<IT, Option<O>>
where
Self: Sized,
{
move |input| maybe(&self)(input)
}
fn many0(self) -> impl Parser<IT, Vec<O>>
where
Self: Sized,
{
move |input| many0(&self)(input)
}
fn many1(self) -> impl Parser<IT, Vec<O>>
where
Self: Sized,
{
move |input| many1(&self)(input)
}
fn between<PO, PC, OO, OC>(self, open: &PO, close: &PC) -> impl Parser<IT, O>
where
PO: Parser<IT, OO>,
PC: Parser<IT, OC>,
Self: Sized,
{
move |input| between(open, &self, close)(input)
}
fn count(self, c: usize) -> impl Parser<IT, Vec<O>>
where
Self: Sized,
{
move |input| count(&self, c)(input)
}
fn many0_up_to(self, max_count: usize) -> impl Parser<IT, Vec<O>>
where
Self: Sized,
{
move |input| many0_up_to(&self, max_count)(input)
}
fn many1_up_to(self, max_count: usize) -> impl Parser<IT, Vec<O>>
where
Self: Sized,
{
move |input| many1_up_to(&self, max_count)(input)
}
}
impl<IT, O, X> Parser<IT, O> for X
where
X: Fn(&mut Input<IT>) -> Result<O, Error>,
IT: InputToken,
{
}
pub trait StringParser<O>: Parser<CharToken, O> {}
impl<O, X> StringParser<O> for X where X: Fn(&mut StringInput) -> Result<O, Error> {}
#[cfg(test)]
mod tests {
mod map {
use crate::input::Position;
use crate::*;
#[test]
fn empty() {
let parser = is('2').map(|c: char| c.to_digit(10));
let mut input = Input::new_from_chars("".chars(), None);
assert_eq!(
parser(&mut input),
Err(Error::EndOfInput(Some(Box::new('2'))))
);
}
#[test]
fn success_simple() {
let parser = is('2').map(|c: char| c.to_digit(10));
let mut input = Input::new_from_chars("2".chars(), None);
assert_eq!(parser(&mut input), Ok(Some(2)));
assert!(end_of_input()(&mut input).is_ok()); }
#[test]
fn success_chained() {
let parser = is('2')
.map(|c: char| c.to_digit(10))
.map(|o| o.unwrap())
.map(|x| x * 3);
let mut input = Input::new_from_chars("2".chars(), None);
assert_eq!(parser(&mut input), Ok(6));
assert!(end_of_input()(&mut input).is_ok()); }
#[test]
fn fail_simple() {
let parser = is('2').map(|c: char| c.to_digit(10));
let mut input = Input::new_from_chars("3".chars(), None);
let mismatch = Mismatch::new('2', '3');
assert_eq!(
parser(&mut input),
Err(Error::UnexpectedToken(
None,
Position::new(1, 1),
Some(mismatch)
))
);
assert!(end_of_input()(&mut input).is_err()); }
#[test]
fn fail_chained() {
let parser = is('5')
.map(|c: char| c.to_digit(10))
.map(|o| o.unwrap())
.map(|x| x * 7);
let mut input = Input::new_from_chars("3".chars(), None);
let mismatch = Mismatch::new('5', '3');
assert_eq!(
parser(&mut input),
Err(Error::UnexpectedToken(
None,
Position::new(1, 1),
Some(mismatch)
))
);
assert!(end_of_input()(&mut input).is_err()); }
}
mod and_then {
use crate::input::Position;
use crate::*;
#[test]
fn empty() {
let double_parser = is('2').and_then(is);
let mut input = Input::new_from_chars("".chars(), None);
assert_eq!(
double_parser(&mut input),
Err(Error::EndOfInput(Some(Box::new('2'))))
);
}
#[test]
fn success_simple() {
let double_parser = is('2').and_then(is);
let mut input = Input::new_from_chars("22".chars(), None);
assert_eq!(double_parser(&mut input), Ok('2'));
assert!(end_of_input()(&mut input).is_ok()); }
#[test]
fn success_chained() {
let triple_parser = is('2').and_then(is).and_then(is);
let mut input = Input::new_from_chars("222".chars(), None);
assert_eq!(triple_parser(&mut input), Ok('2'));
assert!(end_of_input()(&mut input).is_ok()); }
#[test]
fn fail_simple() {
let double_parser = is('2').and_then(is);
let mut input = Input::new_from_chars("23".chars(), None);
let mismatch = Mismatch::new('2', '3');
assert_eq!(
double_parser(&mut input),
Err(Error::UnexpectedToken(
None,
Position::new(1, 2),
Some(mismatch)
))
);
assert!(end_of_input()(&mut input).is_err()); }
#[test]
fn fail_chained() {
let triple_parser = is('2').and_then(is).and_then(is);
let mut input = Input::new_from_chars("223".chars(), None);
let mismatch = Mismatch::new('2', '3');
assert_eq!(
triple_parser(&mut input),
Err(Error::UnexpectedToken(
None,
Position::new(1, 3),
Some(mismatch)
))
);
assert!(end_of_input()(&mut input).is_err()); }
}
mod and {
use crate::input::Position;
use crate::*;
#[test]
fn empty() {
let double_parser = is('2').and(is('3'));
let mut input = Input::new_from_chars("".chars(), None);
assert_eq!(
double_parser(&mut input),
Err(Error::EndOfInput(Some(Box::new('2'))))
);
}
#[test]
fn success_simple() {
let double_parser = is('2').and(is('3'));
let mut input = Input::new_from_chars("23".chars(), None);
assert_eq!(double_parser(&mut input), Ok('3'));
assert!(end_of_input()(&mut input).is_ok()); }
#[test]
fn success_chained() {
let triple_parser = is('2').and(is('3')).and(is('4'));
let mut input = Input::new_from_chars("234".chars(), None);
assert_eq!(triple_parser(&mut input), Ok('4'));
assert!(end_of_input()(&mut input).is_ok()); }
#[test]
fn fail_simple() {
let double_parser = is('2').and(is('3'));
let mut input = Input::new_from_chars("22".chars(), None);
let mismatch = Mismatch::new('3', '2');
assert_eq!(
double_parser(&mut input),
Err(Error::UnexpectedToken(
None,
Position::new(1, 2),
Some(mismatch)
))
);
assert!(end_of_input()(&mut input).is_err()); }
#[test]
fn fail_chained() {
let triple_parser = is('2').and(is('3')).and(is('4'));
let mut input = Input::new_from_chars("233".chars(), None);
let mismatch = Mismatch::new('4', '3');
assert_eq!(
triple_parser(&mut input),
Err(Error::UnexpectedToken(
None,
Position::new(1, 3),
Some(mismatch)
))
);
assert!(end_of_input()(&mut input).is_err()); }
}
mod exhaustive {
use crate::input::Position;
use crate::*;
#[test]
fn empty() {
let parser = is('a').exhaustive();
let mut input = Input::new_from_chars("".chars(), None);
let expected = Box::new("a");
assert_eq!(parser(&mut input), Err(Error::EndOfInput(Some(expected))));
}
#[test]
fn leftover() {
let parser = is('a').exhaustive();
let mut input = Input::new_from_chars("aa".chars(), None);
let position = Position::new(1, 2);
let mismatch = Mismatch::new("end of input", "a");
assert_eq!(
parser(&mut input),
Err(Error::UnexpectedToken(None, position, Some(mismatch)))
);
}
#[test]
fn success_simple() {
let parser = is('a').exhaustive();
let mut input = Input::new_from_chars("a".chars(), None);
assert_eq!(parser(&mut input), Ok('a'));
}
#[test]
fn success_separated_by_1() {
let is_digit = |c: &char| c.to_digit(10);
let parse_number = satisfy(is_digit);
let parse_comma = is(',');
let parser = separated_by1(&parse_number, &parse_comma);
let parser = parser.exhaustive();
let mut input = Input::new_from_chars("1,1,1,1,1".chars(), None);
assert_eq!(parser(&mut input), Ok(vec![1, 1, 1, 1, 1]));
}
#[test]
fn fail_separated_by_1() {
let is_digit = |c: &char| c.to_digit(10);
let parse_number = satisfy(is_digit);
let parse_comma = is(',');
let parser = separated_by1(&parse_number, &parse_comma);
let parser = parser.exhaustive();
let mut input = Input::new_from_chars("1,1,1,1,1#".chars(), None);
let position = Position::new(1, 10);
let mismatch = Mismatch::new("end of input", '#');
assert_eq!(
parser(&mut input),
Err(Error::UnexpectedToken(None, position, Some(mismatch)))
);
}
}
}