diff options
Diffstat (limited to 'src/combinator/parser.rs')
-rw-r--r-- | src/combinator/parser.rs | 252 |
1 files changed, 243 insertions, 9 deletions
diff --git a/src/combinator/parser.rs b/src/combinator/parser.rs index fb11adc..9ffdb3c 100644 --- a/src/combinator/parser.rs +++ b/src/combinator/parser.rs @@ -1,13 +1,17 @@ +use crate::combinator::trace; +use crate::combinator::trace_result; +#[cfg(feature = "unstable-recover")] +use crate::error::FromRecoverableError; use crate::error::{AddContext, ErrMode, ErrorKind, FromExternalError, ParserError}; use crate::lib::std::borrow::Borrow; use crate::lib::std::ops::Range; +#[cfg(feature = "unstable-recover")] +use crate::stream::Recover; use crate::stream::StreamIsPartial; use crate::stream::{Location, Stream}; -use crate::trace::trace; -use crate::trace::trace_result; use crate::*; -/// Implementation of [`Parser::by_ref`][Parser::by_ref] +/// Implementation of [`Parser::by_ref`] #[cfg_attr(nightly, warn(rustdoc::missing_doc_code_examples))] pub struct ByRef<'p, P> { p: &'p mut P, @@ -35,7 +39,7 @@ where pub struct Map<F, G, I, O, O2, E> where F: Parser<I, O, E>, - G: Fn(O) -> O2, + G: FnMut(O) -> O2, { parser: F, map: G, @@ -48,7 +52,7 @@ where impl<F, G, I, O, O2, E> Map<F, G, I, O, O2, E> where F: Parser<I, O, E>, - G: Fn(O) -> O2, + G: FnMut(O) -> O2, { #[inline(always)] pub(crate) fn new(parser: F, map: G) -> Self { @@ -66,7 +70,7 @@ where impl<F, G, I, O, O2, E> Parser<I, O2, E> for Map<F, G, I, O, O2, E> where F: Parser<I, O, E>, - G: Fn(O) -> O2, + G: FnMut(O) -> O2, { #[inline] fn parse_next(&mut self, i: &mut I) -> PResult<O2, E> { @@ -393,7 +397,7 @@ where pub struct Verify<F, G, I, O, O2, E> where F: Parser<I, O, E>, - G: Fn(&O2) -> bool, + G: FnMut(&O2) -> bool, I: Stream, O: Borrow<O2>, O2: ?Sized, @@ -410,7 +414,7 @@ where impl<F, G, I, O, O2, E> Verify<F, G, I, O, O2, E> where F: Parser<I, O, E>, - G: Fn(&O2) -> bool, + G: FnMut(&O2) -> bool, I: Stream, O: Borrow<O2>, O2: ?Sized, @@ -432,7 +436,7 @@ where impl<F, G, I, O, O2, E> Parser<I, O, E> for Verify<F, G, I, O, O2, E> where F: Parser<I, O, E>, - G: Fn(&O2) -> bool, + G: FnMut(&O2) -> bool, I: Stream, O: Borrow<O2>, O2: ?Sized, @@ -493,6 +497,48 @@ where } } +/// Implementation of [`Parser::default_value`] +#[cfg_attr(nightly, warn(rustdoc::missing_doc_code_examples))] +pub struct DefaultValue<F, I, O, O2, E> +where + F: Parser<I, O, E>, + O2: core::default::Default, +{ + parser: F, + o2: core::marker::PhantomData<O2>, + i: core::marker::PhantomData<I>, + o: core::marker::PhantomData<O>, + e: core::marker::PhantomData<E>, +} + +impl<F, I, O, O2, E> DefaultValue<F, I, O, O2, E> +where + F: Parser<I, O, E>, + O2: core::default::Default, +{ + #[inline(always)] + pub(crate) fn new(parser: F) -> Self { + Self { + parser, + o2: Default::default(), + i: Default::default(), + o: Default::default(), + e: Default::default(), + } + } +} + +impl<F, I, O, O2, E> Parser<I, O2, E> for DefaultValue<F, I, O, O2, E> +where + F: Parser<I, O, E>, + O2: core::default::Default, +{ + #[inline] + fn parse_next(&mut self, input: &mut I) -> PResult<O2, E> { + (self.parser).parse_next(input).map(|_| O2::default()) + } +} + /// Implementation of [`Parser::void`] #[cfg_attr(nightly, warn(rustdoc::missing_doc_code_examples))] pub struct Void<F, I, O, E> @@ -861,3 +907,191 @@ where .parse_next(i) } } + +/// Implementation of [`Parser::retry_after`] +#[cfg_attr(nightly, warn(rustdoc::missing_doc_code_examples))] +#[cfg(feature = "unstable-recover")] +pub struct RetryAfter<P, R, I, O, E> +where + P: Parser<I, O, E>, + R: Parser<I, (), E>, + I: Stream, + I: Recover<E>, + E: FromRecoverableError<I, E>, +{ + parser: P, + recover: R, + i: core::marker::PhantomData<I>, + o: core::marker::PhantomData<O>, + e: core::marker::PhantomData<E>, +} + +#[cfg(feature = "unstable-recover")] +impl<P, R, I, O, E> RetryAfter<P, R, I, O, E> +where + P: Parser<I, O, E>, + R: Parser<I, (), E>, + I: Stream, + I: Recover<E>, + E: FromRecoverableError<I, E>, +{ + #[inline(always)] + pub(crate) fn new(parser: P, recover: R) -> Self { + Self { + parser, + recover, + i: Default::default(), + o: Default::default(), + e: Default::default(), + } + } +} + +#[cfg(feature = "unstable-recover")] +impl<P, R, I, O, E> Parser<I, O, E> for RetryAfter<P, R, I, O, E> +where + P: Parser<I, O, E>, + R: Parser<I, (), E>, + I: Stream, + I: Recover<E>, + E: FromRecoverableError<I, E>, +{ + #[inline(always)] + fn parse_next(&mut self, i: &mut I) -> PResult<O, E> { + if I::is_recovery_supported() { + retry_after_inner(&mut self.parser, &mut self.recover, i) + } else { + self.parser.parse_next(i) + } + } +} + +#[cfg(feature = "unstable-recover")] +fn retry_after_inner<P, R, I, O, E>(parser: &mut P, recover: &mut R, i: &mut I) -> PResult<O, E> +where + P: Parser<I, O, E>, + R: Parser<I, (), E>, + I: Stream, + I: Recover<E>, + E: FromRecoverableError<I, E>, +{ + loop { + let token_start = i.checkpoint(); + let mut err = match parser.parse_next(i) { + Ok(o) => { + return Ok(o); + } + Err(ErrMode::Incomplete(e)) => return Err(ErrMode::Incomplete(e)), + Err(err) => err, + }; + let err_start = i.checkpoint(); + let err_start_eof_offset = i.eof_offset(); + if recover.parse_next(i).is_ok() { + let i_eof_offset = i.eof_offset(); + if err_start_eof_offset == i_eof_offset { + // Didn't advance so bubble the error up + } else if let Err(err_) = i.record_err(&token_start, &err_start, err) { + err = err_; + } else { + continue; + } + } + + i.reset(err_start.clone()); + err = err.map(|err| E::from_recoverable_error(&token_start, &err_start, i, err)); + return Err(err); + } +} + +/// Implementation of [`Parser::resume_after`] +#[cfg(feature = "unstable-recover")] +#[cfg_attr(nightly, warn(rustdoc::missing_doc_code_examples))] +pub struct ResumeAfter<P, R, I, O, E> +where + P: Parser<I, O, E>, + R: Parser<I, (), E>, + I: Stream, + I: Recover<E>, + E: FromRecoverableError<I, E>, +{ + parser: P, + recover: R, + i: core::marker::PhantomData<I>, + o: core::marker::PhantomData<O>, + e: core::marker::PhantomData<E>, +} + +#[cfg(feature = "unstable-recover")] +impl<P, R, I, O, E> ResumeAfter<P, R, I, O, E> +where + P: Parser<I, O, E>, + R: Parser<I, (), E>, + I: Stream, + I: Recover<E>, + E: FromRecoverableError<I, E>, +{ + #[inline(always)] + pub(crate) fn new(parser: P, recover: R) -> Self { + Self { + parser, + recover, + i: Default::default(), + o: Default::default(), + e: Default::default(), + } + } +} + +#[cfg(feature = "unstable-recover")] +impl<P, R, I, O, E> Parser<I, Option<O>, E> for ResumeAfter<P, R, I, O, E> +where + P: Parser<I, O, E>, + R: Parser<I, (), E>, + I: Stream, + I: Recover<E>, + E: FromRecoverableError<I, E>, +{ + #[inline(always)] + fn parse_next(&mut self, i: &mut I) -> PResult<Option<O>, E> { + if I::is_recovery_supported() { + resume_after_inner(&mut self.parser, &mut self.recover, i) + } else { + self.parser.parse_next(i).map(Some) + } + } +} + +#[cfg(feature = "unstable-recover")] +fn resume_after_inner<P, R, I, O, E>( + parser: &mut P, + recover: &mut R, + i: &mut I, +) -> PResult<Option<O>, E> +where + P: Parser<I, O, E>, + R: Parser<I, (), E>, + I: Stream, + I: Recover<E>, + E: FromRecoverableError<I, E>, +{ + let token_start = i.checkpoint(); + let mut err = match parser.parse_next(i) { + Ok(o) => { + return Ok(Some(o)); + } + Err(ErrMode::Incomplete(e)) => return Err(ErrMode::Incomplete(e)), + Err(err) => err, + }; + let err_start = i.checkpoint(); + if recover.parse_next(i).is_ok() { + if let Err(err_) = i.record_err(&token_start, &err_start, err) { + err = err_; + } else { + return Ok(None); + } + } + + i.reset(err_start.clone()); + err = err.map(|err| E::from_recoverable_error(&token_start, &err_start, i, err)); + Err(err) +} |