pub mod and_p;
pub mod map_p;
pub mod or_p;
pub mod repeat_p;
pub mod string_p;
use crate::{errors::ParsingError, traits::Parser, type_alias::ParserRes};
pub struct ParseMatch<A>(pub A)
where
A: Into<String>;
impl<A> Parser for ParseMatch<A>
where
A: Into<String> + Clone,
{
type Output = String;
fn parse(&self, input: &str) -> ParserRes<Self::Output> {
let match_str: String = self.0.clone().into();
if !input.starts_with(&match_str) {
return Err(ParsingError::PatternNotFound(format!(
"{} did not match pattern: {}",
input, match_str
)));
}
let rest = input.chars().skip(match_str.len()).collect();
Ok((match_str, rest))
}
}
pub struct ParseIf(pub fn(char) -> bool);
impl Parser for ParseIf {
type Output = char;
fn parse(&self, input: &str) -> ParserRes<Self::Output> {
let maybe_first_char = input.chars().next();
if let Some(true) = maybe_first_char.map(self.0) {
return Ok((maybe_first_char.unwrap(), input.chars().skip(1).collect()));
}
Err(ParsingError::PatternNotFound(
"if predicate not met".to_string(),
))
}
}
#[derive(Debug, Clone, Copy)]
pub struct ParseWhileOrNothing<F>(pub F)
where
F: Fn(char) -> bool;
impl<F> Parser for ParseWhileOrNothing<F>
where
F: Fn(char) -> bool,
{
type Output = String;
fn parse(&self, input: &str) -> ParserRes<Self::Output> {
let taken = input.chars().take_while(|&x| self.0(x)).collect::<String>();
let rest = input.chars().skip_while(|&x| self.0(x)).collect::<String>();
Ok((taken, rest))
}
}
#[derive(Debug, Clone, Copy)]
pub struct ParseWhile<F>(pub F)
where
F: Fn(char) -> bool;
impl<F> Parser for ParseWhile<F>
where
F: Fn(char) -> bool,
{
type Output = String;
fn parse(&self, input: &str) -> ParserRes<Self::Output> {
let taken = input.chars().take_while(|&x| self.0(x)).collect::<String>();
if taken.is_empty() {
return Err(ParsingError::PatternNotFound(
"no characters matched predicate".to_string(),
));
}
let rest = input.chars().skip_while(|&x| self.0(x)).collect::<String>();
Ok((taken, rest))
}
}
#[cfg(test)]
mod test_base_parsers {
use super::{ParseIf, ParseMatch, ParseWhile};
use crate::traits::Parser;
#[test]
fn match_parser() {
let parse_if = ParseMatch("if");
let answer = parse_if.parse("if and");
assert_eq!(answer, Ok(("if".to_string(), " and".to_string())));
}
#[test]
fn if_parser() {
let parse_if = ParseIf(|c| c.is_numeric());
let answer = parse_if.parse("12hello");
assert_eq!(answer, Ok(('1', "2hello".to_string())));
}
#[test]
fn parse_while() {
let parse_numbers = ParseWhile(|c| c.is_numeric());
let answer_valid = parse_numbers.parse("123a 1234");
assert_eq!(answer_valid, Ok(("123".to_string(), "a 1234".to_string())));
let answer_bad = parse_numbers.parse("x123a 1234");
assert_eq!(
answer_bad,
Err(crate::errors::ParsingError::PatternNotFound(
"no characters matched predicate".to_string()
))
);
}
}