add: TryParser and SatifiedMapParser.

This commit is contained in:
jackfiled 2024-11-21 23:15:49 +08:00
parent dd00a37369
commit 814ab29cb6
3 changed files with 101 additions and 5 deletions

View File

@ -3,11 +3,11 @@ mod primitive_parsers;
use crate::parser::modified_parsers::{
BindParser, ConvertParser, LitervalCountParser, LitervalParser, LookAheadParser, MapParser,
NextParser, ReverseParser,
NextParser, ReverseParser, TryParser,
};
use crate::parser::primitive_parsers::{
AnyParser, FailParser, FailWithMessageParser, SatisfyParser, SkipParser, SucceedParser,
TakeParser,
AnyParser, FailParser, FailWithMessageParser, SatifiedMapParser, SatisfyParser, SkipParser,
SucceedParser, TakeParser,
};
use std::cell::RefCell;
use std::error::Error;
@ -178,6 +178,17 @@ where
}
}
fn try_parse(self, result: T) -> TryParser<Self, T>
where
Self: Sized,
T: Clone,
{
TryParser {
parser: self,
result,
}
}
fn reverse<TResult>(self, result: TResult) -> ReverseParser<Self, T, TResult>
where
Self: Sized,
@ -259,6 +270,16 @@ where
SatisfyParser { predicate }
}
pub fn satified_map<'a, TToken, TContext, T: 'a, F>(
mapper: F,
) -> impl Parser<'a, TToken, T, TContext>
where
TToken: Debug + Clone,
F: Fn(&TToken) -> Option<T>,
{
SatifiedMapParser { mapper }
}
pub fn any<'a, TToken, TContext>() -> impl Parser<'a, TToken, TToken, TContext>
where
TToken: Debug + Clone + 'a,

View File

@ -189,6 +189,29 @@ where
}
}
pub struct TryParser<P, T> {
pub(crate) parser: P,
pub(crate) result: T,
}
impl<'a, TToken, T, TContext, P> Parser<'a, TToken, T, TContext> for TryParser<P, T>
where
TToken: Debug + Clone,
T: Clone + 'a,
P: Parser<'a, TToken, T, TContext>,
{
fn parse(
&self,
context: Rc<RefCell<ParserContext<TToken, TContext>>>,
input: &'a [TToken],
) -> ParserResult<'a, TToken, T> {
match self.parser.parse(context, input) {
Err(r) => Ok((r.input, self.result.clone())),
r => r,
}
}
}
pub struct ReverseParser<P, T, TResult> {
pub(crate) parser: P,
pub(crate) result: TResult,
@ -370,6 +393,17 @@ mod test {
});
}
#[test]
fn try_parse_test() {
parser_test_helper(ParserContext::new_with_str("abc", ()), &'a', |c, i| {
char_parser('a').try_parse('a').parse(c, i)
});
parser_test_helper(ParserContext::new_with_str("bc", ()), &'a', |c, i| {
char_parser('a').try_parse('a').parse(c, i)
});
}
#[test]
fn reverse_test() {
parser_test_helper(ParserContext::new_with_str("abc", ()), &(), |c, i| {

View File

@ -86,6 +86,32 @@ where
}
}
pub struct SatifiedMapParser<F> {
pub(crate) mapper: F,
}
impl<'a, TToken, TContext, T: 'a, F> Parser<'a, TToken, T, TContext> for SatifiedMapParser<F>
where
TToken: Debug + Clone,
F: Fn(&TToken) -> Option<T>,
{
fn parse(
&self,
_: Rc<RefCell<ParserContext<TToken, TContext>>>,
input: &'a [TToken],
) -> ParserResult<'a, TToken, T> {
if input.is_empty() {
return Err(FailedParserResult::new_with_str(input, "Input is empty"));
}
if let Some(result) = (self.mapper)(&input[0]) {
Ok((&input[1..], result))
} else {
Err(FailedParserResult::new_with_str(input, "Predicate failed."))
}
}
}
pub struct AnyParser {}
impl<'a, TToken, TContext> Parser<'a, TToken, TToken, TContext> for AnyParser
@ -166,8 +192,8 @@ where
mod test {
use super::*;
use crate::parser::{
any, fail, fail_with_message, failed_parser_test_helper, parser_test_helper, satisfy, skip,
succeed, take,
any, fail, fail_with_message, failed_parser_test_helper, parser_test_helper, satified_map,
satisfy, skip, succeed, take,
};
#[test]
@ -202,6 +228,21 @@ mod test {
});
}
#[test]
fn satified_map_test() {
parser_test_helper(ParserContext::new_with_str("123", ()), &1, |c, i| {
satified_map(|x: &char| x.to_digit(10)).parse(c, i)
});
parser_test_helper(ParserContext::new_with_str("23", ()), &2, |c, i| {
satified_map(|x: &char| x.to_digit(10)).parse(c, i)
});
parser_test_helper(ParserContext::new_with_str("3", ()), &3, |c, i| {
satified_map(|x: &char| x.to_digit(10)).parse(c, i)
});
}
#[test]
fn any_test() {
parser_test_helper(ParserContext::new_with_str("abc", ()), &'a', |c, i| {