use super::*;
pub trait Strategy<'src, I: Input<'src>, O, E: ParserExtra<'src, I> = extra::Default>:
Sealed
{
#[doc(hidden)]
fn recover<M: Mode, P: Parser<'src, I, O, E>>(
&self,
inp: &mut InputRef<'src, '_, I, E>,
parser: &P,
) -> PResult<M, O>;
}
#[derive(Copy, Clone)]
pub struct ViaParser<A>(A);
pub fn via_parser<A>(parser: A) -> ViaParser<A> {
ViaParser(parser)
}
impl<A> Sealed for ViaParser<A> {}
impl<'src, I, O, E, A> Strategy<'src, I, O, E> for ViaParser<A>
where
I: Input<'src>,
A: Parser<'src, I, O, E>,
E: ParserExtra<'src, I>,
{
fn recover<M: Mode, P: Parser<'src, I, O, E>>(
&self,
inp: &mut InputRef<'src, '_, I, E>,
_parser: &P,
) -> PResult<M, O> {
let alt = inp.take_alt().unwrap(); let out = match self.0.go::<M>(inp) {
Ok(out) => out,
Err(()) => {
inp.errors.alt = Some(alt);
return Err(());
}
};
inp.emit(alt.err);
Ok(out)
}
}
#[derive(Copy, Clone)]
pub struct RecoverWith<A, S> {
pub(crate) parser: A,
pub(crate) strategy: S,
}
impl<'src, I, O, E, A, S> Parser<'src, I, O, E> for RecoverWith<A, S>
where
I: Input<'src>,
E: ParserExtra<'src, I>,
A: Parser<'src, I, O, E>,
S: Strategy<'src, I, O, E>,
{
#[doc(hidden)]
#[cfg(feature = "debug")]
fn node_info(&self, scope: &mut debug::NodeScope) -> debug::NodeInfo {
self.parser.node_info(scope)
}
fn go<M: Mode>(&self, inp: &mut InputRef<'src, '_, I, E>) -> PResult<M, O> {
let before = inp.save();
match self.parser.go::<M>(inp) {
Ok(out) => Ok(out),
Err(()) => {
inp.rewind(before.clone());
match self.strategy.recover::<M, _>(inp, &self.parser) {
Ok(out) => Ok(out),
Err(()) => {
inp.rewind(before);
Err(())
}
}
}
}
}
go_extra!(O);
}
#[must_use]
#[derive(Copy, Clone)]
pub struct SkipThenRetryUntil<S, U> {
skip: S,
until: U,
}
impl<S, U> Sealed for SkipThenRetryUntil<S, U> {}
impl<'src, I, O, E, S, U> Strategy<'src, I, O, E> for SkipThenRetryUntil<S, U>
where
I: Input<'src>,
S: Parser<'src, I, (), E>,
U: Parser<'src, I, (), E>,
E: ParserExtra<'src, I>,
{
fn recover<M: Mode, P: Parser<'src, I, O, E>>(
&self,
inp: &mut InputRef<'src, '_, I, E>,
parser: &P,
) -> PResult<M, O> {
let alt = inp.take_alt().unwrap(); loop {
let before = inp.save();
if let Ok(()) = self.until.go::<Check>(inp) {
inp.errors.alt = Some(alt);
inp.rewind(before);
break Err(());
} else {
inp.rewind(before);
}
if let Err(()) = self.skip.go::<Check>(inp) {
inp.errors.alt = Some(alt);
break Err(());
}
let before = inp.save();
if let Some(out) = parser.go::<M>(inp).ok().filter(|_| {
inp.errors
.secondary_errors_since(before.err_count)
.is_empty()
}) {
inp.emit(alt.err);
break Ok(out);
} else {
inp.errors.alt.take();
inp.rewind(before);
}
}
}
}
pub fn skip_then_retry_until<S, U>(skip: S, until: U) -> SkipThenRetryUntil<S, U> {
SkipThenRetryUntil { skip, until }
}
#[must_use]
#[derive(Copy, Clone)]
pub struct SkipUntil<S, U, F> {
skip: S,
until: U,
fallback: F,
}
impl<S, U, F> Sealed for SkipUntil<S, U, F> {}
impl<'src, I, O, E, S, U, F> Strategy<'src, I, O, E> for SkipUntil<S, U, F>
where
I: Input<'src>,
S: Parser<'src, I, (), E>,
U: Parser<'src, I, (), E>,
F: Fn() -> O,
E: ParserExtra<'src, I>,
{
fn recover<M: Mode, P: Parser<'src, I, O, E>>(
&self,
inp: &mut InputRef<'src, '_, I, E>,
_parser: &P,
) -> PResult<M, O> {
let alt = inp.take_alt().unwrap(); loop {
let before = inp.save();
if let Ok(()) = self.until.go::<Check>(inp) {
inp.emit(alt.err);
break Ok(M::bind(|| (self.fallback)()));
}
inp.rewind(before);
if let Err(()) = self.skip.go::<Check>(inp) {
inp.errors.alt = Some(alt);
break Err(());
}
}
}
}
pub fn skip_until<S, U, F>(skip: S, until: U, fallback: F) -> SkipUntil<S, U, F> {
SkipUntil {
skip,
until,
fallback,
}
}
pub fn nested_delimiters<'src, 'parse, I, O, E, F, const N: usize>(
start: I::Token,
end: I::Token,
others: [(I::Token, I::Token); N],
fallback: F,
) -> impl Parser<'src, I, O, E> + Clone + 'parse
where
I: ValueInput<'src>,
I::Token: PartialEq + Clone,
E: extra::ParserExtra<'src, I> + 'parse,
'src: 'parse,
F: Fn(I::Span) -> O + Clone + 'parse,
{
#[allow(clippy::tuple_array_conversions)]
recursive({
let (start, end) = (start.clone(), end.clone());
|block| {
let mut many_block = Parser::boxed(
block
.clone()
.delimited_by(just(start.clone()), just(end.clone())),
);
for (s, e) in &others {
many_block = Parser::boxed(
many_block.or(block.clone().delimited_by(just(s.clone()), just(e.clone()))),
);
}
let skip = [start, end]
.into_iter()
.chain(IntoIterator::into_iter(others).flat_map(|(s, e)| [s, e]))
.collect::<Vec<_>>();
many_block
.or(any().and_is(none_of(skip)).ignored())
.repeated()
}
})
.delimited_by(just(start), just(end))
.map_with(move |_, e| fallback(e.span()))
}