add: modified parsers.
This commit is contained in:
		@@ -1,4 +1,2 @@
 | 
			
		||||
extern crate core;
 | 
			
		||||
 | 
			
		||||
mod parser;
 | 
			
		||||
mod text;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,10 @@
 | 
			
		||||
mod modified_parsers;
 | 
			
		||||
mod primitive_parsers;
 | 
			
		||||
 | 
			
		||||
use crate::parser::modified_parsers::{BindParser, ConvertParser, MapParser, NextParser};
 | 
			
		||||
use crate::parser::modified_parsers::{
 | 
			
		||||
    BindParser, ConvertParser, LitervalParser, LookAheadParser, MapParser, NextParser,
 | 
			
		||||
    ReverseParser,
 | 
			
		||||
};
 | 
			
		||||
use crate::parser::primitive_parsers::{
 | 
			
		||||
    AnyParser, FailParser, FailWithMessageParser, SatisfyParser, SkipParser, SucceedParser,
 | 
			
		||||
    TakeParser,
 | 
			
		||||
@@ -121,6 +124,38 @@ where
 | 
			
		||||
            phantom_data: PhantomData,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn literal(self) -> LitervalParser<Self, T>
 | 
			
		||||
    where
 | 
			
		||||
        Self: Sized,
 | 
			
		||||
    {
 | 
			
		||||
        LitervalParser {
 | 
			
		||||
            parser: self,
 | 
			
		||||
            phantom_data: PhantomData,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn look_ahead(self) -> LookAheadParser<Self, T>
 | 
			
		||||
    where
 | 
			
		||||
        Self: Sized,
 | 
			
		||||
    {
 | 
			
		||||
        LookAheadParser {
 | 
			
		||||
            parser: self,
 | 
			
		||||
            phantom_data: PhantomData,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn reverse<TResult>(self, result: TResult) -> ReverseParser<Self, T, TResult>
 | 
			
		||||
    where
 | 
			
		||||
        Self: Sized,
 | 
			
		||||
        TResult: Debug + Clone,
 | 
			
		||||
    {
 | 
			
		||||
        ReverseParser {
 | 
			
		||||
            parser: self,
 | 
			
		||||
            result,
 | 
			
		||||
            phantom_data: PhantomData,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<TToken, T, TContext, F> Parser<TToken, T, TContext> for F
 | 
			
		||||
@@ -226,4 +261,3 @@ pub fn failed_parser_test_helper<T, P>(
 | 
			
		||||
 | 
			
		||||
    assert!(result.is_err());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
use crate::parser::{Parser, ParserContext, ParserResult};
 | 
			
		||||
use crate::parser::{FailedParserResult, Parser, ParserContext, ParserResult};
 | 
			
		||||
use std::cell::RefCell;
 | 
			
		||||
use std::fmt::Debug;
 | 
			
		||||
use std::marker::PhantomData;
 | 
			
		||||
@@ -97,10 +97,102 @@ where
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct LitervalParser<P, T> {
 | 
			
		||||
    pub(crate) parser: P,
 | 
			
		||||
    pub(crate) phantom_data: PhantomData<T>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<TToken, T, TContext, P> Parser<TToken, Vec<TToken>, TContext> for LitervalParser<P, T>
 | 
			
		||||
where
 | 
			
		||||
    TToken: Debug + Clone,
 | 
			
		||||
    P: Parser<TToken, T, TContext>,
 | 
			
		||||
{
 | 
			
		||||
    fn parse<'a>(
 | 
			
		||||
        &self,
 | 
			
		||||
        context: Rc<RefCell<ParserContext<TToken, TContext>>>,
 | 
			
		||||
        input: &'a [TToken],
 | 
			
		||||
    ) -> ParserResult<'a, TToken, Vec<TToken>> {
 | 
			
		||||
        let origin_input = input;
 | 
			
		||||
        let (input, _) = self.parser.parse(context, input)?;
 | 
			
		||||
 | 
			
		||||
        if origin_input.is_empty() {
 | 
			
		||||
            return Err((
 | 
			
		||||
                input,
 | 
			
		||||
                FailedParserResult::new(
 | 
			
		||||
                    "Empty input, the 'literal' parser cann't get length of elememtn.".to_owned(),
 | 
			
		||||
                ),
 | 
			
		||||
            ));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let length = (&origin_input[1..]).as_ptr() as usize - origin_input.as_ptr() as usize;
 | 
			
		||||
        let index = (input.as_ptr() as usize - origin_input.as_ptr() as usize) / length;
 | 
			
		||||
 | 
			
		||||
        Ok((
 | 
			
		||||
            input,
 | 
			
		||||
            (&origin_input[..index])
 | 
			
		||||
                .into_iter()
 | 
			
		||||
                .map(|x| x.clone())
 | 
			
		||||
                .collect(),
 | 
			
		||||
        ))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct LookAheadParser<P, T> {
 | 
			
		||||
    pub(crate) parser: P,
 | 
			
		||||
    pub(crate) phantom_data: PhantomData<T>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<TToken, T, TContext, P> Parser<TToken, T, TContext> for LookAheadParser<P, T>
 | 
			
		||||
where
 | 
			
		||||
    TToken: Debug + Clone,
 | 
			
		||||
    P: Parser<TToken, T, TContext>,
 | 
			
		||||
{
 | 
			
		||||
    fn parse<'a>(
 | 
			
		||||
        &self,
 | 
			
		||||
        context: Rc<RefCell<ParserContext<TToken, TContext>>>,
 | 
			
		||||
        input: &'a [TToken],
 | 
			
		||||
    ) -> ParserResult<'a, TToken, T> {
 | 
			
		||||
        let original_input = input;
 | 
			
		||||
        let (_, r) = self.parser.parse(context, input)?;
 | 
			
		||||
 | 
			
		||||
        Ok((original_input, r))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct ReverseParser<P, T, TResult> {
 | 
			
		||||
    pub(crate) parser: P,
 | 
			
		||||
    pub(crate) result: TResult,
 | 
			
		||||
    pub(crate) phantom_data: PhantomData<T>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<TToken, T, TResult, TContext, P> Parser<TToken, TResult, TContext>
 | 
			
		||||
    for ReverseParser<P, T, TResult>
 | 
			
		||||
where
 | 
			
		||||
    TToken: Debug + Clone,
 | 
			
		||||
    TResult: Debug + Clone,
 | 
			
		||||
    P: Parser<TToken, T, TContext>,
 | 
			
		||||
{
 | 
			
		||||
    fn parse<'a>(
 | 
			
		||||
        &self,
 | 
			
		||||
        context: Rc<RefCell<ParserContext<TToken, TContext>>>,
 | 
			
		||||
        input: &'a [TToken],
 | 
			
		||||
    ) -> ParserResult<'a, TToken, TResult> {
 | 
			
		||||
        match self.parser.parse(context, input) {
 | 
			
		||||
            Ok((input, _)) => Err((
 | 
			
		||||
                input,
 | 
			
		||||
                FailedParserResult::new("Reverse failed succeeded.".to_owned()),
 | 
			
		||||
            )),
 | 
			
		||||
            Err((input, _)) => Ok((input, self.result.clone())),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod test {
 | 
			
		||||
    use super::*;
 | 
			
		||||
    use crate::parser::{parser_test_helper, take};
 | 
			
		||||
    use crate::parser::{
 | 
			
		||||
        failed_parser_test_helper, parser_test_helper, satisfy, take, FailedParserResult,
 | 
			
		||||
    };
 | 
			
		||||
    use crate::text::char_parser;
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
@@ -128,4 +220,121 @@ mod test {
 | 
			
		||||
                .bind(|_| char_parser('c')),
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    struct Number(i32);
 | 
			
		||||
 | 
			
		||||
    impl From<Number> for String {
 | 
			
		||||
        fn from(value: Number) -> Self {
 | 
			
		||||
            format!("{}", value.0)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn convert_test() {
 | 
			
		||||
        fn single_numer_parser(
 | 
			
		||||
            context: Rc<RefCell<ParserContext<char, ()>>>,
 | 
			
		||||
            input: &[char],
 | 
			
		||||
        ) -> ParserResult<char, Number> {
 | 
			
		||||
            let (input, result) = satisfy(|c: &char| c.is_numeric()).parse(context, input)?;
 | 
			
		||||
 | 
			
		||||
            match result.to_digit(10) {
 | 
			
		||||
                None => Err((input, FailedParserResult::new("What?".to_string()))),
 | 
			
		||||
                Some(r) => Ok((input, Number(r as i32))),
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        parser_test_helper(
 | 
			
		||||
            ParserContext::new_with_str("9", ()),
 | 
			
		||||
            &"9".to_owned(),
 | 
			
		||||
            single_numer_parser.convert(),
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        parser_test_helper(
 | 
			
		||||
            ParserContext::new_with_str("1", ()),
 | 
			
		||||
            &"1".to_owned(),
 | 
			
		||||
            single_numer_parser.convert(),
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        failed_parser_test_helper(
 | 
			
		||||
            ParserContext::new_with_str("abc", ()),
 | 
			
		||||
            single_numer_parser.convert::<String>(),
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn next_test() {
 | 
			
		||||
        let parser = || {
 | 
			
		||||
            satisfy(|c: &char| c.is_numeric()).next(|r| match r {
 | 
			
		||||
                Ok((input, result)) => match result.to_digit(10) {
 | 
			
		||||
                    None => Err((input, FailedParserResult::new("What?".to_string()))),
 | 
			
		||||
                    Some(r) => Ok((input, Number(r as i32))),
 | 
			
		||||
                },
 | 
			
		||||
                Err(r) => Err(r),
 | 
			
		||||
            })
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        parser_test_helper(
 | 
			
		||||
            ParserContext::new_with_str("9", ()),
 | 
			
		||||
            &"9".to_owned(),
 | 
			
		||||
            parser().convert(),
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        parser_test_helper(
 | 
			
		||||
            ParserContext::new_with_str("1", ()),
 | 
			
		||||
            &"1".to_owned(),
 | 
			
		||||
            parser().convert(),
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        failed_parser_test_helper(
 | 
			
		||||
            ParserContext::new_with_str("abc", ()),
 | 
			
		||||
            parser().convert::<String>(),
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn literal_test() {
 | 
			
		||||
        parser_test_helper(
 | 
			
		||||
            ParserContext::new_with_str("abc", ()),
 | 
			
		||||
            &vec!['a'],
 | 
			
		||||
            char_parser('a').literal(),
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        parser_test_helper(
 | 
			
		||||
            ParserContext::new_with_str("abc", ()),
 | 
			
		||||
            &vec!['a', 'b'],
 | 
			
		||||
            char_parser('a').bind(|_| char_parser('b')).literal(),
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        parser_test_helper(
 | 
			
		||||
            ParserContext::new_with_str("abc", ()),
 | 
			
		||||
            &vec!['a', 'b', 'c'],
 | 
			
		||||
            char_parser('a')
 | 
			
		||||
                .bind(|_| char_parser('b'))
 | 
			
		||||
                .bind(|_| char_parser('c'))
 | 
			
		||||
                .literal(),
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn look_ahead_test() {
 | 
			
		||||
        parser_test_helper(
 | 
			
		||||
            ParserContext::new_with_str("abc", ()),
 | 
			
		||||
            &'a',
 | 
			
		||||
            char_parser('a').look_ahead().bind(|_| char_parser('a')),
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn reverse_test() {
 | 
			
		||||
        parser_test_helper(
 | 
			
		||||
            ParserContext::new_with_str("abc", ()),
 | 
			
		||||
            &(),
 | 
			
		||||
            char_parser('b').reverse(()),
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        failed_parser_test_helper(
 | 
			
		||||
            ParserContext::new_with_str("abc", ()),
 | 
			
		||||
            char_parser('a').reverse(()),
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										15
									
								
								src/text.rs
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								src/text.rs
									
									
									
									
									
								
							@@ -24,10 +24,23 @@ pub fn string_parser<TContext>(str: String) -> impl Parser<char, String, TContex
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod test {
 | 
			
		||||
    use super::*;
 | 
			
		||||
    use crate::parser::{parser_test_helper, ParserContext, ParserResult};
 | 
			
		||||
    use crate::parser::{
 | 
			
		||||
        failed_parser_test_helper, parser_test_helper, ParserContext, ParserResult,
 | 
			
		||||
    };
 | 
			
		||||
    use std::cell::RefCell;
 | 
			
		||||
    use std::rc::Rc;
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn char_parser_test() {
 | 
			
		||||
        parser_test_helper(
 | 
			
		||||
            ParserContext::new_with_str("abc", ()),
 | 
			
		||||
            &'a',
 | 
			
		||||
            char_parser('a'),
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        failed_parser_test_helper(ParserContext::new_with_str("bc", ()), char_parser('a'));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn string_parser_test() {
 | 
			
		||||
        parser_test_helper(
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user