pegtastic_runtime/
error.rs1use std::fmt::{ self, Display, Debug };
4use crate::{ RuleResult, Parse };
5use std::collections::HashSet;
6
7#[derive(PartialEq, Eq, Debug, Clone)]
9pub struct ExpectedSet {
10 expected: HashSet<&'static str>,
11}
12
13impl ExpectedSet {
14 pub fn tokens<'a>(&'a self) -> impl Iterator<Item = &'static str> + 'a {
16 self.expected.iter().map(|x| *x)
17 }
18}
19
20impl Display for ExpectedSet {
21 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
22 if self.expected.is_empty() {
23 write!(fmt, "<unreported>")?;
24 } else if self.expected.len() == 1 {
25 write!(fmt, "{}", self.expected.iter().next().unwrap())?;
26 } else {
27 let mut errors = self.tokens().collect::<Vec<_>>();
28 errors.sort();
29 let mut iter = errors.into_iter();
30
31 write!(fmt, "one of {}", iter.next().unwrap())?;
32 for elem in iter {
33 write!(fmt, ", {}", elem)?;
34 }
35 }
36
37 Ok(())
38 }
39}
40
41#[derive(PartialEq, Eq, Debug, Clone)]
43pub struct ParseError<L> {
44 pub location: L,
46
47 pub expected: ExpectedSet,
49}
50
51impl<L: Display> Display for ParseError<L> {
52 fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::result::Result<(), ::std::fmt::Error> {
53 write!(fmt, "error at {}: expected {}", self.location, self.expected)
54 }
55}
56
57impl<L: Display + Debug> ::std::error::Error for ParseError<L> {
58 fn description(&self) -> &str {
59 "parse error"
60 }
61}
62
63#[doc(hidden)]
64pub struct ErrorState {
65 pub max_err_pos: usize,
66 pub suppress_fail: usize,
67 pub reparsing_on_error: bool,
68 pub expected: ExpectedSet,
69}
70
71impl ErrorState {
72 pub fn new(initial_pos: usize) -> ErrorState {
73 ErrorState {
74 max_err_pos: initial_pos,
75 suppress_fail: 0,
76 reparsing_on_error: false,
77 expected: ExpectedSet { expected: HashSet::new() },
78 }
79 }
80
81 pub fn reparse_for_error(&mut self) {
82 self.suppress_fail = 0;
83 self.reparsing_on_error = true;
84 }
85
86 #[inline(never)]
87 pub fn mark_failure_slow_path(&mut self, pos: usize, expected: &'static str) {
88 if pos == self.max_err_pos {
89 self.expected.expected.insert(expected);
90 }
91 }
92
93 #[inline(always)]
94 pub fn mark_failure(&mut self, pos: usize, expected: &'static str) -> RuleResult<()> {
95 if self.suppress_fail == 0 {
96 if self.reparsing_on_error {
97 self.mark_failure_slow_path(pos, expected);
98 } else if pos > self.max_err_pos {
99 self.max_err_pos = pos;
100 }
101 }
102 RuleResult::Failed
103 }
104
105 pub fn into_parse_error<I: Parse + ?Sized>(self, input: &I) -> ParseError<I::PositionRepr> {
106 ParseError {
107 location: Parse::position_repr(input, self.max_err_pos.into()),
108 expected: self.expected,
109 }
110 }
111}