feat: and run and and_then parser.
This commit is contained in:
		@@ -2,8 +2,8 @@ mod modified_parsers;
 | 
				
			|||||||
mod primitive_parsers;
 | 
					mod primitive_parsers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::parser::modified_parsers::{
 | 
					use crate::parser::modified_parsers::{
 | 
				
			||||||
    BindParser, ConvertParser, LitervalCountParser, LitervalParser, LookAheadParser, MapParser,
 | 
					    AndThenParser, BindParser, ConvertParser, LitervalCountParser, LitervalParser, LookAheadParser,
 | 
				
			||||||
    NextParser, OptionalParser, ReverseParser, TryParser,
 | 
					    MapParser, NextParser, OptionalParser, ReverseParser, RunParser, TryParser,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use crate::parser::primitive_parsers::{
 | 
					use crate::parser::primitive_parsers::{
 | 
				
			||||||
    AnyParser, FailParser, FailWithMessageParser, SatifiedMapParser, SatisfyParser, SkipParser,
 | 
					    AnyParser, FailParser, FailWithMessageParser, SatifiedMapParser, SatisfyParser, SkipParser,
 | 
				
			||||||
@@ -33,6 +33,13 @@ impl<'a, TToken: Debug> FailedParserResult<'a, TToken> {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn new_with_error(input: &'a [TToken], err: anyhow::Error) -> Self {
 | 
				
			||||||
 | 
					        Self {
 | 
				
			||||||
 | 
					            input,
 | 
				
			||||||
 | 
					            message: format!("{}", err),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn message(&self) -> &str {
 | 
					    pub fn message(&self) -> &str {
 | 
				
			||||||
        self.message.as_str()
 | 
					        self.message.as_str()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -207,6 +214,29 @@ where
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        OptionalParser { parser: self }
 | 
					        OptionalParser { parser: self }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn run<F>(self, action: F) -> RunParser<Self, F>
 | 
				
			||||||
 | 
					    where
 | 
				
			||||||
 | 
					        Self: Sized,
 | 
				
			||||||
 | 
					        F: Fn(&T) -> (),
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        RunParser {
 | 
				
			||||||
 | 
					            parser: self,
 | 
				
			||||||
 | 
					            action,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn and_then<TResult, F>(self, mapper: F) -> AndThenParser<Self, F, T>
 | 
				
			||||||
 | 
					    where
 | 
				
			||||||
 | 
					        Self: Sized,
 | 
				
			||||||
 | 
					        F: Fn(T) -> anyhow::Result<TResult>,
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        AndThenParser {
 | 
				
			||||||
 | 
					            parser: self,
 | 
				
			||||||
 | 
					            mapper,
 | 
				
			||||||
 | 
					            phantom_data: PhantomData,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<'a, TToken, T: 'a, TContext, F> Parser<'a, TToken, T, TContext> for F
 | 
					impl<'a, TToken, T: 'a, TContext, F> Parser<'a, TToken, T, TContext> for F
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -261,13 +261,68 @@ where
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub struct RunParser<P, F> {
 | 
				
			||||||
 | 
					    pub(crate) parser: P,
 | 
				
			||||||
 | 
					    pub(crate) action: F,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<'a, TToken, T: 'a, TContext, P, F> Parser<'a, TToken, T, TContext> for RunParser<P, F>
 | 
				
			||||||
 | 
					where
 | 
				
			||||||
 | 
					    TToken: Debug + Clone,
 | 
				
			||||||
 | 
					    P: Parser<'a, TToken, T, TContext>,
 | 
				
			||||||
 | 
					    F: Fn(&T) -> (),
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    fn parse(
 | 
				
			||||||
 | 
					        &self,
 | 
				
			||||||
 | 
					        context: Rc<RefCell<ParserContext<TToken, TContext>>>,
 | 
				
			||||||
 | 
					        input: &'a [TToken],
 | 
				
			||||||
 | 
					    ) -> ParserResult<'a, TToken, T> {
 | 
				
			||||||
 | 
					        match self.parser.parse(context, input) {
 | 
				
			||||||
 | 
					            Ok(r) => {
 | 
				
			||||||
 | 
					                (self.action)(&r.1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                Ok(r)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            r => r,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub struct AndThenParser<P, F, T> {
 | 
				
			||||||
 | 
					    pub(crate) parser: P,
 | 
				
			||||||
 | 
					    pub(crate) mapper: F,
 | 
				
			||||||
 | 
					    pub(crate) phantom_data: PhantomData<T>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<'a, TToken, T: 'a, TResult: 'a, TContext, P, F> Parser<'a, TToken, TResult, TContext>
 | 
				
			||||||
 | 
					    for AndThenParser<P, F, T>
 | 
				
			||||||
 | 
					where
 | 
				
			||||||
 | 
					    TToken: Debug + Clone,
 | 
				
			||||||
 | 
					    P: Parser<'a, TToken, T, TContext>,
 | 
				
			||||||
 | 
					    F: Fn(T) -> anyhow::Result<TResult>,
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    fn parse(
 | 
				
			||||||
 | 
					        &self,
 | 
				
			||||||
 | 
					        context: Rc<RefCell<ParserContext<TToken, TContext>>>,
 | 
				
			||||||
 | 
					        input: &'a [TToken],
 | 
				
			||||||
 | 
					    ) -> ParserResult<'a, TToken, TResult> {
 | 
				
			||||||
 | 
					        match self.parser.parse(context, input) {
 | 
				
			||||||
 | 
					            Ok((i, r)) => match (self.mapper)(r) {
 | 
				
			||||||
 | 
					                Ok(result) => Ok((i, result)),
 | 
				
			||||||
 | 
					                Err(err) => Err(FailedParserResult::new_with_error(i, err)),
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            Err(r) => Err(r),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[cfg(test)]
 | 
					#[cfg(test)]
 | 
				
			||||||
mod test {
 | 
					mod test {
 | 
				
			||||||
    use super::*;
 | 
					    use super::*;
 | 
				
			||||||
    use crate::parser::{
 | 
					    use crate::parser::{
 | 
				
			||||||
        failed_parser_test_helper, parser_test_helper, satisfy, take, FailedParserResult,
 | 
					        failed_parser_test_helper, parser_test_helper, satisfy, take, FailedParserResult,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    use crate::text::char_parser;
 | 
					    use crate::text::{char_parser, char_satisfy};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
    fn map_test() {
 | 
					    fn map_test() {
 | 
				
			||||||
@@ -447,4 +502,23 @@ mod test {
 | 
				
			|||||||
            char_parser('a').optional().parse(c, i)
 | 
					            char_parser('a').optional().parse(c, i)
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn run_test() {
 | 
				
			||||||
 | 
					        parser_test_helper(ParserContext::new_with_str("abc", ()), &'a', |c, i| {
 | 
				
			||||||
 | 
					            char_parser('a').run(|c| assert_eq!(c, &'a')).parse(c, i)
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn and_then_test() {
 | 
				
			||||||
 | 
					        parser_test_helper(ParserContext::new_with_str("123", ()), &1, |c, i| {
 | 
				
			||||||
 | 
					            char_satisfy(char::is_ascii_digit)
 | 
				
			||||||
 | 
					                .and_then(|c| {
 | 
				
			||||||
 | 
					                    let word = c.to_string();
 | 
				
			||||||
 | 
					                    Ok(i32::from_str_radix(word.as_str(), 10)?)
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					                .parse(c, i)
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user