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; 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

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)] #[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)
});
}
} }