prism_parser/core/
recovery.rs1use crate::core::context::ParserContext;
2use crate::core::parser::Parser;
3use crate::core::pos::Pos;
4use crate::core::presult::PResult;
5use crate::core::presult::PResult::{PErr, POk};
6use crate::core::state::ParserState;
7use crate::error::error_printer::ErrorLabel;
8use crate::error::ParseError;
9use crate::grammar::action_result::ActionResult;
10
11const MAX_RECOVERIES: usize = 2;
12
13pub fn parse_with_recovery<'a, 'arn: 'a, 'grm: 'arn, O, E: ParseError<L = ErrorLabel<'grm>>>(
14 sub: &'a impl Parser<'arn, 'grm, O, E>,
15 pos: Pos,
16 state: &mut ParserState<'arn, 'grm, E>,
17 context: ParserContext,
18) -> Result<O, Vec<E>> {
19 let mut result_errors: Vec<E> = Vec::new();
20 let mut err_state: Option<(Pos, Pos)> = None;
21
22 loop {
23 match sub.parse(pos, state, context) {
24 POk(o, _, _, _) => {
25 return if result_errors.is_empty() {
26 Ok(o)
27 } else {
28 if let Some(last) = result_errors.last_mut() {
30 last.set_end(err_state.unwrap().1);
31 }
32 Err(result_errors)
33 };
34 }
35 PErr(e, p) => {
36 if err_state.is_none() || err_state.unwrap().1 < p {
38 if let Some(last) = result_errors.last_mut() {
40 last.set_end(err_state.unwrap().1);
41 }
42
43 if result_errors.len() >= MAX_RECOVERIES {
45 return Err(result_errors);
46 }
47
48 result_errors.push(e);
50 err_state = Some((p, p));
51 } else if let Some((_err_state_start, err_state_end)) = &mut err_state {
52 if *err_state_end == Pos::end(state.input) {
54 result_errors
55 .last_mut()
56 .unwrap()
57 .set_end(Pos::end(state.input));
58 return Err(result_errors);
59 }
60
61 *err_state_end = err_state_end.next(state.input).0;
63 assert!(*err_state_end <= Pos::end(state.input));
64 } else {
65 unreachable!()
66 }
67 state
68 .recovery_points
69 .insert(err_state.unwrap().0, err_state.unwrap().1);
70 state
71 .recovery_points
72 .insert(err_state.unwrap().1, err_state.unwrap().1);
73 state.clear();
74 }
75 }
76 }
77}
78
79pub fn recovery_point<'a, 'arn: 'a, 'grm: 'arn, E: ParseError<L = ErrorLabel<'grm>> + 'arn>(
80 item: impl Parser<'arn, 'grm, &'arn ActionResult<'arn, 'grm>, E> + 'a,
81) -> impl Parser<'arn, 'grm, &'arn ActionResult<'arn, 'grm>, E> + 'a {
82 move |pos: Pos,
83 state: &mut ParserState<'arn, 'grm, E>,
84 context: ParserContext|
85 -> PResult<_, E> {
86 match item.parse(
88 pos,
89 state,
90 ParserContext {
91 recovery_disabled: true,
92 ..context
93 },
94 ) {
95 r @ POk(_, _, _, _) => r,
96 PErr(e, s) => {
97 if let Some(to) = state.recovery_points.get(&s) {
98 POk(ActionResult::VOID, pos, *to, Some((e, s)))
99 } else {
100 PErr(e, s)
101 }
102 }
103 }
104 }
105}