diff --git a/src/parser.rs b/src/parser.rs index 922ffd1..5883fb8 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -3,7 +3,7 @@ mod primitive_parsers; use crate::parser::modified_parsers::{ BindParser, ConvertParser, LitervalCountParser, LitervalParser, LookAheadParser, MapParser, - NextParser, ReverseParser, TryParser, + NextParser, OptionalParser, ReverseParser, TryParser, }; use crate::parser::primitive_parsers::{ AnyParser, FailParser, FailWithMessageParser, SatifiedMapParser, SatisfyParser, SkipParser, @@ -200,6 +200,13 @@ where phantom_data: PhantomData, } } + + fn optional(self) -> OptionalParser + where + Self: Sized, + { + OptionalParser { parser: self } + } } impl<'a, TToken, T: 'a, TContext, F> Parser<'a, TToken, T, TContext> for F diff --git a/src/parser/modified_parsers.rs b/src/parser/modified_parsers.rs index d4893d6..545d862 100644 --- a/src/parser/modified_parsers.rs +++ b/src/parser/modified_parsers.rs @@ -240,6 +240,27 @@ where } } +pub struct OptionalParser

{ + pub(crate) parser: P, +} + +impl<'a, TToken, T: 'a, TContext, P> Parser<'a, TToken, Option, TContext> for OptionalParser

+where + TToken: Debug + Clone, + P: Parser<'a, TToken, T, TContext>, +{ + fn parse( + &self, + context: Rc>>, + input: &'a [TToken], + ) -> ParserResult<'a, TToken, Option> { + match self.parser.parse(context, input) { + Ok(r) => Ok((r.0, Some(r.1))), + Err(r) => Ok((r.input, None)), + } + } +} + #[cfg(test)] mod test { use super::*; @@ -414,4 +435,16 @@ mod test { char_parser('a').reverse(()).parse(c, i) }); } + + #[test] + fn optional_test() { + parser_test_helper( + ParserContext::new_with_str("abc", ()), + &Some('a'), + |c, i| char_parser('a').optional().parse(c, i), + ); + parser_test_helper(ParserContext::new_with_str("bc", ()), &None, |c, i| { + char_parser('a').optional().parse(c, i) + }); + } }