1use super::*;
6
7pub trait Strategy<I: Clone, O, E: Error<I>> {
9 fn recover<D: Debugger, P: Parser<I, O, Error = E>>(
11 &self,
12 recovered_errors: Vec<Located<I, P::Error>>,
13 fatal_error: Located<I, P::Error>,
14 parser: P,
15 debugger: &mut D,
16 stream: &mut StreamOf<I, P::Error>,
17 ) -> PResult<I, O, P::Error>;
18}
19
20#[must_use]
22#[derive(Copy, Clone)]
23pub struct SkipThenRetryUntil<I, const N: usize>(
24 pub(crate) [I; N],
25 pub(crate) bool,
26 pub(crate) bool,
27);
28
29impl<I, const N: usize> SkipThenRetryUntil<I, N> {
30 pub fn skip_start(self) -> Self {
35 Self(self.0, self.1, true)
36 }
37
38 pub fn consume_end(self) -> Self {
43 Self(self.0, true, self.2)
44 }
45}
46
47impl<I: Clone + PartialEq, O, E: Error<I>, const N: usize> Strategy<I, O, E>
48 for SkipThenRetryUntil<I, N>
49{
50 fn recover<D: Debugger, P: Parser<I, O, Error = E>>(
51 &self,
52 a_errors: Vec<Located<I, P::Error>>,
53 a_err: Located<I, P::Error>,
54 parser: P,
55 debugger: &mut D,
56 stream: &mut StreamOf<I, P::Error>,
57 ) -> PResult<I, O, P::Error> {
58 if self.2 {
59 let _ = stream.next();
60 }
61 loop {
62 #[allow(deprecated)]
63 let (mut errors, res) = stream.try_parse(|stream| {
64 #[allow(deprecated)]
65 debugger.invoke(&parser, stream)
66 });
67 if let Ok(out) = res {
68 errors.push(a_err);
69 break (errors, Ok(out));
70 }
71 #[allow(clippy::blocks_in_if_conditions)]
72 if !stream.attempt(
73 |stream| match stream.next().2.map(|tok| self.0.contains(&tok)) {
74 Some(true) => (self.1, false),
75 Some(false) => (true, true),
76 None => (false, false),
77 },
78 ) {
79 break (a_errors, Err(a_err));
80 }
81 }
82 }
83}
84
85pub fn skip_then_retry_until<I, const N: usize>(until: [I; N]) -> SkipThenRetryUntil<I, N> {
93 SkipThenRetryUntil(until, false, true)
94}
95
96#[must_use]
98#[derive(Copy, Clone)]
99pub struct SkipUntil<I, F, const N: usize>(
100 pub(crate) [I; N],
101 pub(crate) F,
102 pub(crate) bool,
103 pub(crate) bool,
104);
105
106impl<I, F, const N: usize> SkipUntil<I, F, N> {
107 pub fn skip_start(self) -> Self {
112 Self(self.0, self.1, self.2, true)
113 }
114
115 pub fn consume_end(self) -> Self {
120 Self(self.0, self.1, true, self.3)
121 }
122}
123
124impl<I: Clone + PartialEq, O, F: Fn(E::Span) -> O, E: Error<I>, const N: usize> Strategy<I, O, E>
125 for SkipUntil<I, F, N>
126{
127 fn recover<D: Debugger, P: Parser<I, O, Error = E>>(
128 &self,
129 mut a_errors: Vec<Located<I, P::Error>>,
130 a_err: Located<I, P::Error>,
131 _parser: P,
132 _debugger: &mut D,
133 stream: &mut StreamOf<I, P::Error>,
134 ) -> PResult<I, O, P::Error> {
135 let pre_state = stream.save();
136 if self.3 {
137 let _ = stream.next();
138 }
139 a_errors.push(a_err);
140 loop {
141 match stream.attempt(|stream| {
142 let (at, span, tok) = stream.next();
143 match tok.map(|tok| self.0.contains(&tok)) {
144 Some(true) => (self.2, Ok(true)),
145 Some(false) => (true, Ok(false)),
146 None => (true, Err((at, span))),
147 }
148 }) {
149 Ok(true) => break (a_errors, Ok(((self.1)(stream.span_since(pre_state)), None))),
150 Ok(false) => {}
151 Err(_) if stream.save() > pre_state => {
152 break (a_errors, Ok(((self.1)(stream.span_since(pre_state)), None)))
153 }
154 Err((at, span)) => {
155 break (
156 a_errors,
157 Err(Located::at(
158 at,
159 E::expected_input_found(span, self.0.iter().cloned().map(Some), None),
160 )),
161 )
162 }
163 }
164 }
165 }
166}
167
168pub fn skip_until<I, F, const N: usize>(until: [I; N], fallback: F) -> SkipUntil<I, F, N> {
175 SkipUntil(until, fallback, false, false)
176}
177
178#[must_use]
180#[derive(Copy, Clone)]
181pub struct NestedDelimiters<I, F, const N: usize>(
182 pub(crate) I,
183 pub(crate) I,
184 pub(crate) [(I, I); N],
185 pub(crate) F,
186);
187
188impl<I: Clone + PartialEq, O, F: Fn(E::Span) -> O, E: Error<I>, const N: usize> Strategy<I, O, E>
189 for NestedDelimiters<I, F, N>
190{
191 #[allow(clippy::blocks_in_if_conditions)]
194 fn recover<D: Debugger, P: Parser<I, O, Error = E>>(
195 &self,
196 mut a_errors: Vec<Located<I, P::Error>>,
197 a_err: Located<I, P::Error>,
198 _parser: P,
199 _debugger: &mut D,
200 stream: &mut StreamOf<I, P::Error>,
201 ) -> PResult<I, O, P::Error> {
202 let mut balance = 0;
203 let mut balance_others = [0; N];
204 let mut starts = Vec::new();
205 let mut error = None;
206 let pre_state = stream.save();
207 let recovered = loop {
208 if match stream.next() {
209 (_, span, Some(t)) if t == self.0 => {
210 balance += 1;
211 starts.push(span);
212 true
213 }
214 (_, _, Some(t)) if t == self.1 => {
215 balance -= 1;
216 starts.pop();
217 true
218 }
219 (at, span, Some(t)) => {
220 for (balance_other, others) in balance_others.iter_mut().zip(self.2.iter()) {
221 if t == others.0 {
222 *balance_other += 1;
223 } else if t == others.1 {
224 *balance_other -= 1;
225
226 if *balance_other < 0 && balance == 1 {
227 error.get_or_insert_with(|| {
229 Located::at(
230 at,
231 P::Error::unclosed_delimiter(
232 starts.pop().unwrap(),
233 self.0.clone(),
234 span.clone(),
235 self.1.clone(),
236 Some(t.clone()),
237 ),
238 )
239 });
240 }
241 }
242 }
243 false
244 }
245 (at, span, None) => {
246 if balance > 0 && balance == 1 {
247 error.get_or_insert_with(|| match starts.pop() {
248 Some(start) => Located::at(
249 at,
250 P::Error::unclosed_delimiter(
251 start,
252 self.0.clone(),
253 span,
254 self.1.clone(),
255 None,
256 ),
257 ),
258 None => Located::at(
259 at,
260 P::Error::expected_input_found(
261 span,
262 Some(Some(self.1.clone())),
263 None,
264 ),
265 ),
266 });
267 }
268 break false;
269 }
270 } {
271 match balance.cmp(&0) {
272 Ordering::Equal => break true,
273 Ordering::Less => break false,
275 Ordering::Greater => (),
276 }
277 } else if balance == 0 {
278 break false;
280 }
281 };
282
283 if let Some(e) = error {
284 a_errors.push(e);
285 }
286
287 if recovered {
288 if a_errors.last().map_or(true, |e| a_err.at < e.at) {
289 a_errors.push(a_err);
290 }
291 (a_errors, Ok(((self.3)(stream.span_since(pre_state)), None)))
292 } else {
293 (a_errors, Err(a_err))
294 }
295 }
296}
297
298pub fn nested_delimiters<I: PartialEq, F, const N: usize>(
306 start: I,
307 end: I,
308 others: [(I, I); N],
309 fallback: F,
310) -> NestedDelimiters<I, F, N> {
311 assert!(
312 start != end,
313 "Start and end delimiters cannot be the same when using `NestedDelimiters`"
314 );
315 NestedDelimiters(start, end, others, fallback)
316}
317
318#[derive(Copy, Clone)]
320pub struct SkipParser<R>(pub(crate) R);
321
322impl<I: Clone + PartialEq, O, R: Parser<I, O, Error = E>, E: Error<I>> Strategy<I, O, E>
323 for SkipParser<R>
324{
325 fn recover<D: Debugger, P: Parser<I, O, Error = E>>(
326 &self,
327 mut a_errors: Vec<Located<I, P::Error>>,
328 a_err: Located<I, P::Error>,
329 _parser: P,
330 debugger: &mut D,
331 stream: &mut StreamOf<I, P::Error>,
332 ) -> PResult<I, O, P::Error> {
333 a_errors.push(a_err);
334
335 let (mut errors, res) = self.0.parse_inner(debugger, stream);
336 a_errors.append(&mut errors);
337 (a_errors, res)
338 }
339}
340
341pub fn skip_parser<R>(recovery_parser: R) -> SkipParser<R> {
375 SkipParser(recovery_parser)
376}
377
378#[must_use]
380#[derive(Copy, Clone)]
381pub struct Recovery<A, S>(pub(crate) A, pub(crate) S);
382
383impl<I: Clone, O, A: Parser<I, O, Error = E>, S: Strategy<I, O, E>, E: Error<I>> Parser<I, O>
384 for Recovery<A, S>
385{
386 type Error = E;
387
388 fn parse_inner<D: Debugger>(
389 &self,
390 debugger: &mut D,
391 stream: &mut StreamOf<I, E>,
392 ) -> PResult<I, O, E> {
393 match stream.try_parse(|stream| {
394 #[allow(deprecated)]
395 debugger.invoke(&self.0, stream)
396 }) {
397 (a_errors, Ok(a_out)) => (a_errors, Ok(a_out)),
398 (a_errors, Err(a_err)) => self.1.recover(a_errors, a_err, &self.0, debugger, stream),
399 }
400 }
401
402 fn parse_inner_verbose(&self, d: &mut Verbose, s: &mut StreamOf<I, E>) -> PResult<I, O, E> {
403 #[allow(deprecated)]
404 self.parse_inner(d, s)
405 }
406 fn parse_inner_silent(&self, d: &mut Silent, s: &mut StreamOf<I, E>) -> PResult<I, O, E> {
407 #[allow(deprecated)]
408 self.parse_inner(d, s)
409 }
410}
411
412#[cfg(test)]
413mod tests {
414 use crate::error::Cheap;
415 use crate::prelude::*;
416
417 #[test]
418 fn recover_with_skip_then_retry_until() {
419 let parser = just::<_, _, Cheap<_>>('a')
420 .recover_with(skip_then_retry_until([',']))
421 .separated_by(just(','));
422 {
423 let (result, errors) = parser.parse_recovery("a,a,2a,a");
424 assert_eq!(result, Some(vec!['a', 'a', 'a', 'a']));
425 assert_eq!(errors.len(), 1)
426 }
427 {
428 let (result, errors) = parser.parse_recovery("a,a,2 a,a");
429 assert_eq!(result, Some(vec!['a', 'a', 'a', 'a']));
430 assert_eq!(errors.len(), 1)
431 }
432 {
433 let (result, errors) = parser.parse_recovery("a,a,2 a,a");
434 assert_eq!(result, Some(vec!['a', 'a', 'a', 'a']));
435 assert_eq!(errors.len(), 1)
436 }
437 }
438
439 #[test]
440 fn until_nothing() {
441 #[derive(Debug, Clone, Copy, PartialEq)]
442 pub enum Token {
443 Foo,
444 Bar,
445 }
446
447 fn lexer() -> impl Parser<char, Token, Error = Simple<char>> {
448 let foo = just("foo").to(Token::Foo);
449 let bar = just("bar").to(Token::Bar);
450
451 choice((foo, bar)).recover_with(skip_then_retry_until([]))
452 }
453
454 let (result, errors) = lexer().parse_recovery("baz");
455 assert_eq!(result, None);
456 assert_eq!(errors.len(), 1);
457 }
458}