1use super::*;
28
29pub trait Strategy<'src, I: Input<'src>, O, E: ParserExtra<'src, I> = extra::Default>:
35 Sealed
36{
37 #[doc(hidden)]
40 fn recover<M: Mode, P: Parser<'src, I, O, E>>(
41 &self,
42 inp: &mut InputRef<'src, '_, I, E>,
43 parser: &P,
44 ) -> PResult<M, O>;
45}
46
47#[derive(Copy, Clone)]
49pub struct ViaParser<A>(A);
50
51pub fn via_parser<A>(parser: A) -> ViaParser<A> {
53 ViaParser(parser)
54}
55
56impl<A> Sealed for ViaParser<A> {}
57impl<'src, I, O, E, A> Strategy<'src, I, O, E> for ViaParser<A>
58where
59 I: Input<'src>,
60 A: Parser<'src, I, O, E>,
61 E: ParserExtra<'src, I>,
62{
63 fn recover<M: Mode, P: Parser<'src, I, O, E>>(
64 &self,
65 inp: &mut InputRef<'src, '_, I, E>,
66 _parser: &P,
67 ) -> PResult<M, O> {
68 let alt = inp.take_alt().unwrap(); let out = match self.0.go::<M>(inp) {
70 Ok(out) => out,
71 Err(()) => {
72 inp.errors.alt = Some(alt);
73 return Err(());
74 }
75 };
76 inp.emit(alt.err);
77 Ok(out)
78 }
79}
80
81#[derive(Copy, Clone)]
83pub struct RecoverWith<A, S> {
84 pub(crate) parser: A,
85 pub(crate) strategy: S,
86}
87
88impl<'src, I, O, E, A, S> Parser<'src, I, O, E> for RecoverWith<A, S>
89where
90 I: Input<'src>,
91 E: ParserExtra<'src, I>,
92 A: Parser<'src, I, O, E>,
93 S: Strategy<'src, I, O, E>,
94{
95 #[doc(hidden)]
96 #[cfg(feature = "debug")]
97 fn node_info(&self, scope: &mut debug::NodeScope) -> debug::NodeInfo {
98 self.parser.node_info(scope)
99 }
100
101 fn go<M: Mode>(&self, inp: &mut InputRef<'src, '_, I, E>) -> PResult<M, O> {
102 let before = inp.save();
103 match self.parser.go::<M>(inp) {
104 Ok(out) => Ok(out),
105 Err(()) => {
106 inp.rewind(before.clone());
107 match self.strategy.recover::<M, _>(inp, &self.parser) {
108 Ok(out) => Ok(out),
109 Err(()) => {
110 inp.rewind(before);
112 Err(())
113 }
114 }
115 }
116 }
117 }
118
119 go_extra!(O);
120}
121
122#[must_use]
124#[derive(Copy, Clone)]
125pub struct SkipThenRetryUntil<S, U> {
126 skip: S,
127 until: U,
128}
129
130impl<S, U> Sealed for SkipThenRetryUntil<S, U> {}
131impl<'src, I, O, E, S, U> Strategy<'src, I, O, E> for SkipThenRetryUntil<S, U>
132where
133 I: Input<'src>,
134 S: Parser<'src, I, (), E>,
135 U: Parser<'src, I, (), E>,
136 E: ParserExtra<'src, I>,
137{
138 fn recover<M: Mode, P: Parser<'src, I, O, E>>(
139 &self,
140 inp: &mut InputRef<'src, '_, I, E>,
141 parser: &P,
142 ) -> PResult<M, O> {
143 let alt = inp.take_alt().unwrap(); loop {
145 let before = inp.save();
146 if let Ok(()) = self.until.go::<Check>(inp) {
147 inp.errors.alt = Some(alt);
148 inp.rewind(before);
149 break Err(());
150 } else {
151 inp.rewind(before);
152 }
153
154 if let Err(()) = self.skip.go::<Check>(inp) {
155 inp.errors.alt = Some(alt);
156 break Err(());
157 }
158
159 let before = inp.save();
160 if let Some(out) = parser.go::<M>(inp).ok().filter(|_| {
161 inp.errors
162 .secondary_errors_since(before.err_count)
163 .is_empty()
164 }) {
165 inp.emit(alt.err);
166 break Ok(out);
167 } else {
168 inp.errors.alt.take();
169 inp.rewind(before);
170 }
171 }
172 }
173}
174
175pub fn skip_then_retry_until<S, U>(skip: S, until: U) -> SkipThenRetryUntil<S, U> {
177 SkipThenRetryUntil { skip, until }
178}
179
180#[must_use]
182#[derive(Copy, Clone)]
183pub struct SkipUntil<S, U, F> {
184 skip: S,
185 until: U,
186 fallback: F,
187}
188
189impl<S, U, F> Sealed for SkipUntil<S, U, F> {}
190impl<'src, I, O, E, S, U, F> Strategy<'src, I, O, E> for SkipUntil<S, U, F>
191where
192 I: Input<'src>,
193 S: Parser<'src, I, (), E>,
194 U: Parser<'src, I, (), E>,
195 F: Fn() -> O,
196 E: ParserExtra<'src, I>,
197{
198 fn recover<M: Mode, P: Parser<'src, I, O, E>>(
199 &self,
200 inp: &mut InputRef<'src, '_, I, E>,
201 _parser: &P,
202 ) -> PResult<M, O> {
203 let alt = inp.take_alt().unwrap(); loop {
205 let before = inp.save();
206 if let Ok(()) = self.until.go::<Check>(inp) {
207 inp.emit(alt.err);
208 break Ok(M::bind(|| (self.fallback)()));
209 }
210 inp.rewind(before);
211
212 if let Err(()) = self.skip.go::<Check>(inp) {
213 inp.errors.alt = Some(alt);
214 break Err(());
215 }
216 }
217 }
218}
219
220pub fn skip_until<S, U, F>(skip: S, until: U, fallback: F) -> SkipUntil<S, U, F> {
225 SkipUntil {
226 skip,
227 until,
228 fallback,
229 }
230}
231
232pub fn nested_delimiters<'src, 'parse, I, O, E, F, const N: usize>(
241 start: I::Token,
242 end: I::Token,
243 others: [(I::Token, I::Token); N],
244 fallback: F,
245) -> impl Parser<'src, I, O, E> + Clone + 'parse
246where
247 I: ValueInput<'src>,
248 I::Token: PartialEq + Clone,
249 E: extra::ParserExtra<'src, I> + 'parse,
250 'src: 'parse,
251 F: Fn(I::Span) -> O + Clone + 'parse,
252{
253 #[allow(clippy::tuple_array_conversions)]
255 recursive({
257 let (start, end) = (start.clone(), end.clone());
258 |block| {
259 let mut many_block = Parser::boxed(
260 block
261 .clone()
262 .delimited_by(just(start.clone()), just(end.clone())),
263 );
264 for (s, e) in &others {
265 many_block = Parser::boxed(
266 many_block.or(block.clone().delimited_by(just(s.clone()), just(e.clone()))),
267 );
268 }
269
270 let skip = [start, end]
271 .into_iter()
272 .chain(IntoIterator::into_iter(others).flat_map(|(s, e)| [s, e]))
273 .collect::<Vec<_>>();
274
275 many_block
276 .or(any().and_is(none_of(skip)).ignored())
277 .repeated()
278 }
279 })
280 .delimited_by(just(start), just(end))
281 .map_with(move |_, e| fallback(e.span()))
282}