feat: and run and and_then parser.

This commit is contained in:
jackfiled 2024-12-01 17:44:26 +08:00
parent 88d1eb937f
commit 0e87775943
2 changed files with 107 additions and 3 deletions

View File

@ -2,8 +2,8 @@ mod modified_parsers;
mod primitive_parsers;
use crate::parser::modified_parsers::{
BindParser, ConvertParser, LitervalCountParser, LitervalParser, LookAheadParser, MapParser,
NextParser, OptionalParser, ReverseParser, TryParser,
AndThenParser, BindParser, ConvertParser, LitervalCountParser, LitervalParser, LookAheadParser,
MapParser, NextParser, OptionalParser, ReverseParser, RunParser, TryParser,
};
use crate::parser::primitive_parsers::{
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 {
self.message.as_str()
}
@ -207,6 +214,29 @@ where
{
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

View File

@ -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)]
mod test {
use super::*;
use crate::parser::{
failed_parser_test_helper, parser_test_helper, satisfy, take, FailedParserResult,
};
use crate::text::char_parser;
use crate::text::{char_parser, char_satisfy};
#[test]
fn map_test() {
@ -447,4 +502,23 @@ mod test {
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)
});
}
}