add: modified parsers.
This commit is contained in:
		@@ -1,4 +1,2 @@
 | 
				
			|||||||
extern crate core;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
mod parser;
 | 
					mod parser;
 | 
				
			||||||
mod text;
 | 
					mod text;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,10 @@
 | 
				
			|||||||
mod modified_parsers;
 | 
					mod modified_parsers;
 | 
				
			||||||
mod primitive_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::{
 | 
					use crate::parser::primitive_parsers::{
 | 
				
			||||||
    AnyParser, FailParser, FailWithMessageParser, SatisfyParser, SkipParser, SucceedParser,
 | 
					    AnyParser, FailParser, FailWithMessageParser, SatisfyParser, SkipParser, SucceedParser,
 | 
				
			||||||
    TakeParser,
 | 
					    TakeParser,
 | 
				
			||||||
@@ -121,6 +124,38 @@ where
 | 
				
			|||||||
            phantom_data: PhantomData,
 | 
					            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
 | 
					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());
 | 
					    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::cell::RefCell;
 | 
				
			||||||
use std::fmt::Debug;
 | 
					use std::fmt::Debug;
 | 
				
			||||||
use std::marker::PhantomData;
 | 
					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)]
 | 
					#[cfg(test)]
 | 
				
			||||||
mod test {
 | 
					mod test {
 | 
				
			||||||
    use super::*;
 | 
					    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;
 | 
					    use crate::text::char_parser;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
@@ -128,4 +220,121 @@ mod test {
 | 
				
			|||||||
                .bind(|_| char_parser('c')),
 | 
					                .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)]
 | 
					#[cfg(test)]
 | 
				
			||||||
mod test {
 | 
					mod test {
 | 
				
			||||||
    use super::*;
 | 
					    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::cell::RefCell;
 | 
				
			||||||
    use std::rc::Rc;
 | 
					    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]
 | 
					    #[test]
 | 
				
			||||||
    fn string_parser_test() {
 | 
					    fn string_parser_test() {
 | 
				
			||||||
        parser_test_helper(
 | 
					        parser_test_helper(
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user