feat: and run and and_then parser.
This commit is contained in:
parent
88d1eb937f
commit
0e87775943
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user