peg_runtime/
error.rs

1//! Parse error reporting
2
3use crate::{Parse, RuleResult};
4use std::fmt::{self, Debug, Display};
5
6#[cfg(feature = "std")]
7use std::collections::BTreeSet;
8
9#[cfg(not(feature = "std"))]
10use {alloc::collections::BTreeSet, alloc::vec::Vec};
11
12/// A set of literals or names that failed to match
13#[derive(PartialEq, Eq, Debug, Clone)]
14pub struct ExpectedSet {
15    expected: BTreeSet<&'static str>,
16}
17
18impl ExpectedSet {
19    /// Iterator of expected literals
20    pub fn tokens<'a>(&'a self) -> impl Iterator<Item = &'static str> + 'a {
21        self.expected.iter().map(|x| *x)
22    }
23}
24
25impl Display for ExpectedSet {
26    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
27        if self.expected.is_empty() {
28            write!(fmt, "<unreported>")?;
29        } else if self.expected.len() == 1 {
30            write!(fmt, "{}", self.expected.iter().next().unwrap())?;
31        } else {
32            let mut errors = self.tokens().collect::<Vec<_>>();
33            errors.sort();
34            let mut iter = errors.into_iter();
35
36            write!(fmt, "one of {}", iter.next().unwrap())?;
37            for elem in iter {
38                write!(fmt, ", {}", elem)?;
39            }
40        }
41
42        Ok(())
43    }
44}
45
46/// A parse failure.
47#[derive(PartialEq, Eq, Debug, Clone)]
48pub struct ParseError<L> {
49    /// The furthest position the parser reached in the input before failing.
50    pub location: L,
51
52    /// The set of literals that failed to match at that position.
53    pub expected: ExpectedSet,
54}
55
56impl<L: Display> Display for ParseError<L> {
57    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::result::Result<(), ::std::fmt::Error> {
58        write!(
59            fmt,
60            "error at {}: expected {}",
61            self.location, self.expected
62        )
63    }
64}
65
66#[cfg(any(feature = "std", feature = "unstable"))]
67impl<L: Display + Debug> ::std::error::Error for ParseError<L> {
68    fn description(&self) -> &str {
69        "parse error"
70    }
71}
72
73#[doc(hidden)]
74pub struct ErrorState {
75    /// Furthest failure we've hit so far.
76    pub max_err_pos: usize,
77
78    /// Are we inside a lookahead/quiet block? If so, failure is disabled.
79    /// Non-zero => yes, to support nested blocks.
80    pub suppress_fail: usize,
81
82    /// Are we reparsing after a failure? If so, compute and store expected set of all alternative expectations
83    /// when we are at offset `max_err_pos`.
84    pub reparsing_on_error: bool,
85
86    /// The set of tokens we expected to find when we hit the failure. Updated when `reparsing_on_error`.
87    pub expected: ExpectedSet,
88}
89
90impl ErrorState {
91    pub fn new(initial_pos: usize) -> Self {
92        ErrorState {
93            max_err_pos: initial_pos,
94            suppress_fail: 0,
95            reparsing_on_error: false,
96            expected: ExpectedSet {
97                expected: BTreeSet::new(),
98            },
99        }
100    }
101
102    /// Set up for reparsing to record the details of the furthest failure.
103    pub fn reparse_for_error(&mut self) {
104        self.suppress_fail = 0;
105        self.reparsing_on_error = true;
106    }
107
108    #[inline(never)]
109    pub fn mark_failure_slow_path(&mut self, pos: usize, expected: &'static str) {
110        if pos == self.max_err_pos {
111            self.expected.expected.insert(expected);
112        }
113    }
114
115    /// Flag a failure.
116    #[inline(always)]
117    pub fn mark_failure(&mut self, pos: usize, expected: &'static str) -> RuleResult<()> {
118        if self.suppress_fail == 0 {
119            if self.reparsing_on_error {
120                self.mark_failure_slow_path(pos, expected);
121            } else if pos > self.max_err_pos {
122                self.max_err_pos = pos;
123            }
124        }
125        RuleResult::Failed
126    }
127
128    pub fn into_parse_error<I: Parse + ?Sized>(self, input: &I) -> ParseError<I::PositionRepr> {
129        ParseError {
130            location: Parse::position_repr(input, self.max_err_pos.into()),
131            expected: self.expected,
132        }
133    }
134}