mod modified_parsers; mod primitive_parsers; use crate::parser::modified_parsers::{ AndThenParser, BindParser, ConvertParser, LitervalCountParser, LitervalParser, LookAheadParser, MapParser, NextParser, OptionalParser, ReverseParser, RunParser, TryParser, }; use crate::parser::primitive_parsers::{ AnyParser, FailParser, FailWithMessageParser, SatifiedMapParser, SatisfyParser, SkipParser, SucceedParser, TakeParser, }; use std::cell::RefCell; use std::error::Error; use std::fmt::{Debug, Display, Formatter}; use std::marker::PhantomData; use std::rc::Rc; #[derive(Debug)] pub struct FailedParserResult<'a, TToken: Debug> { input: &'a [TToken], message: String, } impl<'a, TToken: Debug> FailedParserResult<'a, TToken> { pub fn new(input: &'a [TToken], message: String) -> Self { Self { input, message } } pub fn new_with_str(input: &'a [TToken], message: &'static str) -> Self { Self { input, message: message.to_owned(), } } pub fn new_with_error(input: &'a [TToken], err: anyhow::Error) -> Self { Self { input, message: format!("{}", err), } } pub fn message(&self) -> &str { self.message.as_str() } pub fn input(&self) -> &'a [TToken] { self.input } } impl<'a, TToken: Debug> Error for FailedParserResult<'a, TToken> {} impl<'a, TToken: Debug> Display for FailedParserResult<'a, TToken> { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!( f, "Parse failed: {}, the input is '{:?}'.", self.message, self.input ) } } pub type ParserResult<'a, TToken, T> = Result<(&'a [TToken], T), FailedParserResult<'a, TToken>>; pub struct ParserContext { pub context: TContext, } impl ParserContext { pub fn new(context: TContext) -> Rc> { Rc::new(RefCell::new(Self { context })) } } pub trait Parser<'a, TToken, T, TContext> where TToken: Debug + Clone, T: 'a, { fn parse( &self, context: Rc>>, input: &'a [TToken], ) -> ParserResult<'a, TToken, T>; fn map(self, f: F) -> MapParser where Self: Sized, F: Fn(T) -> TResult, { MapParser { parser: self, mapper: f, phantom: PhantomData, } } fn bind(self, f: F) -> BindParser where Self: Sized, F: Fn(T) -> P, P: Parser<'a, TToken, TResult, TContext>, { BindParser { parser: self, binder: f, phantom_data: PhantomData, } } fn convert(self) -> ConvertParser where Self: Sized, { ConvertParser { parser: self, phantom_data1: PhantomData, phantom_data2: PhantomData, } } fn next(self, handler: H) -> NextParser where Self: Sized, H: for<'f> Fn(ParserResult<'f, TToken, T>) -> ParserResult<'f, TToken, TResult>, { NextParser { parser: self, handler, phantom_data: PhantomData, } } fn literal_count(self) -> LitervalCountParser where Self: Sized, { LitervalCountParser { parser: self, phantom_data: PhantomData, } } fn literal(self) -> LitervalParser where Self: Sized, { LitervalParser { parser: self, phantom_data: PhantomData, } } fn look_ahead(self) -> LookAheadParser where Self: Sized, { LookAheadParser { parser: self, phantom_data: PhantomData, } } fn try_parse(self, result: T) -> TryParser where Self: Sized, T: Clone, { TryParser { parser: self, result, } } fn reverse(self, result: TResult) -> ReverseParser where Self: Sized, TResult: Debug + Clone, { ReverseParser { parser: self, result, phantom_data: PhantomData, } } fn optional(self) -> OptionalParser where Self: Sized, { OptionalParser { parser: self } } fn run(self, action: F) -> RunParser where Self: Sized, F: Fn(&T) -> (), { RunParser { parser: self, action, } } fn and_then(self, mapper: F) -> AndThenParser where Self: Sized, F: Fn(T) -> anyhow::Result, { AndThenParser { parser: self, mapper, phantom_data: PhantomData, } } } impl<'a, TToken, T: 'a, TContext, F> Parser<'a, TToken, T, TContext> for F where TToken: Debug + Clone + 'a, F: Fn(Rc>>, &'a [TToken]) -> ParserResult<'a, TToken, T>, { fn parse( &self, context: Rc>>, input: &'a [TToken], ) -> ParserResult<'a, TToken, T> { (*self)(context, input) } } impl<'a, TToken, T: 'a, TContext> Parser<'a, TToken, T, TContext> for Box> where TToken: Debug + Clone, { fn parse( &self, context: Rc>>, input: &'a [TToken], ) -> ParserResult<'a, TToken, T> { (**self).parse(context, input) } } pub fn succeed<'a, TToken, T, TContext>(value: T) -> impl Parser<'a, TToken, T, TContext> where TToken: Debug + Clone, T: Debug + Clone + 'a, { SucceedParser { value } } pub fn fail<'a, TToken, T: 'a, TContext>() -> impl Parser<'a, TToken, T, TContext> where TToken: Debug + Clone, { FailParser { phantom_data: PhantomData, } } pub fn fail_with_message<'a, TToken, T: 'a, TContext>( message: &str, ) -> impl Parser<'a, TToken, T, TContext> where TToken: Debug + Clone, { FailWithMessageParser { message: message.to_owned(), phantom_data: PhantomData, } } pub fn satisfy<'a, TToken, TContext, TP>(predicate: TP) -> impl Parser<'a, TToken, TToken, TContext> where TToken: Debug + Clone + 'a, TP: Fn(&TToken) -> bool, { SatisfyParser { predicate } } pub fn satified_map<'a, TToken, TContext, T: 'a, F>( mapper: F, ) -> impl Parser<'a, TToken, T, TContext> where TToken: Debug + Clone, F: Fn(&TToken) -> Option, { SatifiedMapParser { mapper } } pub fn any<'a, TToken, TContext>() -> impl Parser<'a, TToken, TToken, TContext> where TToken: Debug + Clone + 'a, { AnyParser {} } pub fn take<'a, TToken, TContext>(count: usize) -> impl Parser<'a, TToken, Vec, TContext> where TToken: Debug + Clone + 'a, { TakeParser { count } } pub fn skip<'a, TToken, TContext>(count: usize) -> impl Parser<'a, TToken, (), TContext> where TToken: Debug + Clone, { SkipParser { count } } #[cfg(test)] pub fn parser_test_helper(input: &str, excepted_node: &T, test_parser: P) where T: PartialEq + Debug, P: for<'a> Fn(Rc>>, &'a [char]) -> ParserResult<'a, char, T>, { let word: Vec = input.chars().collect(); let (_, actual_result) = test_parser .parse(ParserContext::new(()), word.as_slice()) .unwrap(); assert_eq!(excepted_node, &actual_result); } #[cfg(test)] pub fn failed_parser_test_helper(input: &str, test_parser: P) where T: Debug, P: for<'a> Fn(Rc>>, &'a [char]) -> ParserResult<'a, char, T>, { let word: Vec = input.chars().collect(); let result = test_parser.parse(ParserContext::new(()), word.as_slice()); assert!(result.is_err()); }