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;
|
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
|
||||||
|
|
|
@ -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)
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user