mod modified_parsers; mod primitive_parsers; use crate::parser::modified_parsers::{ BindParser, ConvertParser, LitervalCountParser, LitervalParser, LookAheadParser, MapParser, NextParser, ReverseParser, }; use crate::parser::primitive_parsers::{ AnyParser, FailParser, FailWithMessageParser, SatisfyParser, SkipParser, SucceedParser, TakeParser, }; use std::cell::RefCell; use std::fmt::{Debug, Display, Formatter}; use std::marker::PhantomData; use std::rc::Rc; #[derive(Debug)] pub struct FailedParserResult { message: String, } impl FailedParserResult { pub fn new(message: String) -> Self { Self { message } } pub fn message(&self) -> &str { self.message.as_str() } } impl Display for FailedParserResult { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "Parse failed: {}.", self.message) } } pub type ParserResult<'a, TToken, T> = Result<(&'a [TToken], T), (&'a [TToken], FailedParserResult)>; pub struct ParserContext where TToken: Debug + Clone, { pub context: TContext, input_array: Vec, } impl ParserContext where TToken: Debug + Clone, { pub fn new(input: &[TToken], context: TContext) -> Rc> { Rc::new(RefCell::new(Self { input_array: input.iter().map(|x| x.clone()).collect(), context, })) } pub fn input_slice(&self) -> &[TToken] { self.input_array.as_slice() } } impl ParserContext { pub fn new_with_str(input: &str, context: TContext) -> Rc> { Rc::new(RefCell::new(Self { input_array: input.chars().collect(), 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 reverse(self, result: TResult) -> ReverseParser where Self: Sized, TResult: Debug + Clone, { ReverseParser { parser: self, result, 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 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( context: Rc>>, excepted_node: &T, test_parser: P, ) where T: PartialEq + Debug, P: for<'a> Fn(Rc>>, &'a [char]) -> ParserResult<'a, char, T>, { let borrowed_context = context.borrow(); let input = borrowed_context.input_slice(); let (_, actual_result) = test_parser.parse(context.clone(), input).unwrap(); assert_eq!(excepted_node, &actual_result); } #[cfg(test)] pub fn failed_parser_test_helper( context: Rc>>, test_parser: P, ) where T: Debug, P: for<'a> Fn(Rc>>, &'a [char]) -> ParserResult<'a, char, T>, { let borrowed_context = context.borrow(); let input = borrowed_context.input_slice(); let result = test_parser.parse(context.clone(), input); assert!(result.is_err()); }