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::{ use crate::parser::modified_parsers::{
BindParser, ConvertParser, LitervalCountParser, LitervalParser, LookAheadParser, MapParser, BindParser, ConvertParser, LitervalCountParser, LitervalParser, LookAheadParser, MapParser,
NextParser, ReverseParser, NextParser, ReverseParser, TryParser,
}; };
use crate::parser::primitive_parsers::{ use crate::parser::primitive_parsers::{
AnyParser, FailParser, FailWithMessageParser, SatisfyParser, SkipParser, SucceedParser, AnyParser, FailParser, FailWithMessageParser, SatifiedMapParser, SatisfyParser, SkipParser,
TakeParser, SucceedParser, TakeParser,
}; };
use std::cell::RefCell; use std::cell::RefCell;
use std::error::Error; 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> fn reverse<TResult>(self, result: TResult) -> ReverseParser<Self, T, TResult>
where where
Self: Sized, Self: Sized,
@ -259,6 +270,16 @@ where
SatisfyParser { predicate } 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> pub fn any<'a, TToken, TContext>() -> impl Parser<'a, TToken, TToken, TContext>
where where
TToken: Debug + Clone + 'a, 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 struct ReverseParser<P, T, TResult> {
pub(crate) parser: P, pub(crate) parser: P,
pub(crate) result: TResult, 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] #[test]
fn reverse_test() { fn reverse_test() {
parser_test_helper(ParserContext::new_with_str("abc", ()), &(), |c, i| { 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 {} pub struct AnyParser {}
impl<'a, TToken, TContext> Parser<'a, TToken, TToken, TContext> for AnyParser impl<'a, TToken, TContext> Parser<'a, TToken, TToken, TContext> for AnyParser
@ -166,8 +192,8 @@ where
mod test { mod test {
use super::*; use super::*;
use crate::parser::{ use crate::parser::{
any, fail, fail_with_message, failed_parser_test_helper, parser_test_helper, satisfy, skip, any, fail, fail_with_message, failed_parser_test_helper, parser_test_helper, satified_map,
succeed, take, satisfy, skip, succeed, take,
}; };
#[test] #[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] #[test]
fn any_test() { fn any_test() {
parser_test_helper(ParserContext::new_with_str("abc", ()), &'a', |c, i| { parser_test_helper(ParserContext::new_with_str("abc", ()), &'a', |c, i| {