aboutsummaryrefslogtreecommitdiff
path: root/src/combinator/parser.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/combinator/parser.rs')
-rw-r--r--src/combinator/parser.rs252
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)
+}