Skip to main content

utils/parser/
error.rs

1use crate::ascii::AsciiSet;
2use crate::parser::then::Then2;
3use crate::parser::{ParseState, Parser, ParserResult};
4use std::error::Error;
5use std::fmt::{Debug, Display, Formatter};
6
7/// Error type returned by parsers.
8///
9/// Returned by both [`Parser::parse_ctx`] and [`Leaf::parse`](super::Leaf::parse).
10#[non_exhaustive]
11#[derive(Debug, Copy, Clone)]
12pub enum ParseError {
13    /// Expected $type.
14    Expected(&'static str),
15    /// Expected $literal.
16    ExpectedLiteral(&'static str),
17    /// Expected $byte.
18    ExpectedByte(u8),
19    /// Expected $min - $max.
20    ExpectedByteRange(u8, u8),
21    /// Expected one of $set.
22    ExpectedOneOf(AsciiSet),
23    /// Expected one of $bytes.
24    ExpectedOneOfBytes(&'static [u8]),
25    /// Expected one of $literals.
26    ExpectedOneOfLiterals(&'static [&'static str]),
27    /// Expected at least $n characters matching $set.
28    ExpectedAtLeastMatches(usize, fn(&u8) -> bool),
29    /// Expected at most $n characters matching $set.
30    ExpectedAtMostMatches(usize, fn(&u8) -> bool),
31    /// Expected exactly $n characters matching $set.
32    ExpectedExactlyMatches(usize, fn(&u8) -> bool),
33    /// Expected $n items or less.
34    ExpectedLessItems(usize),
35    /// Expected end of input.
36    ExpectedEof(),
37    /// Expected number <= $num.
38    NumberTooLarge(i128),
39    /// Expected number >= $num.
40    NumberTooSmall(i128),
41    /// Number out of range.
42    ///
43    /// Used as a fallback if min/max bound doesn't fit in an [`i128`] (for example, [`u128::MAX`]).
44    NumberOutOfRange(),
45    /// Custom error returned by [`Parser::map_res`] & [`Parser::error_msg`].
46    Custom(&'static str),
47}
48
49impl ParseError {
50    #[inline]
51    pub(super) fn too_large(max: impl TryInto<i128>) -> Self {
52        if let Ok(max) = max.try_into() {
53            Self::NumberTooLarge(max)
54        } else {
55            Self::NumberOutOfRange()
56        }
57    }
58
59    #[inline]
60    pub(super) fn too_small(min: impl TryInto<i128>) -> Self {
61        if let Ok(min) = min.try_into() {
62            Self::NumberTooSmall(min)
63        } else {
64            Self::NumberOutOfRange()
65        }
66    }
67}
68
69impl Display for ParseError {
70    #[cold]
71    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
72        match *self {
73            ParseError::Expected(x) => write!(f, "expected {x}"),
74            ParseError::ExpectedLiteral(x) => write!(f, "expected {x:?}"),
75            ParseError::ExpectedByte(x) => write!(f, "expected {:?}", x as char),
76            ParseError::ExpectedByteRange(min, max) => {
77                write!(f, "expected {:?}-{:?}", min as char, max as char)
78            }
79            ParseError::ExpectedAtLeastMatches(n, set_fn) => {
80                let set = AsciiSet::from(|b| set_fn(&b));
81                if n == 1 {
82                    write!(f, "expected at least 1 character matching {set}")
83                } else {
84                    write!(f, "expected at least {n} characters matching {set}")
85                }
86            }
87            ParseError::ExpectedAtMostMatches(n, set_fn) => {
88                let set = AsciiSet::from(|b| set_fn(&b));
89                write!(f, "expected at most {n} characters matching {set}")
90            }
91            ParseError::ExpectedExactlyMatches(n, set_fn) => {
92                let set = AsciiSet::from(|b| set_fn(&b));
93                write!(f, "expected exactly {n} characters matching {set}")
94            }
95            ParseError::ExpectedOneOf(set) => write!(f, "expected one of {set}"),
96            ParseError::ExpectedOneOfBytes(bytes) => {
97                write_one_of(f, bytes.iter().map(|&b| b as char))
98            }
99            ParseError::ExpectedOneOfLiterals(literals) => write_one_of(f, literals.iter()),
100            ParseError::ExpectedEof() => write!(f, "expected end of input"),
101            ParseError::ExpectedLessItems(x) => write!(f, "expected {x} items or less"),
102            ParseError::NumberTooLarge(x) => write!(f, "expected number <= {x}"),
103            ParseError::NumberTooSmall(x) => write!(f, "expected number >= {x}"),
104            ParseError::NumberOutOfRange() => write!(f, "number out of range"),
105            ParseError::Custom(x) => f.write_str(x),
106        }
107    }
108}
109
110impl Error for ParseError {}
111
112/// Write "expected $item" or "expected one of $item, $item, ...".
113fn write_one_of<T: Debug>(
114    f: &mut Formatter<'_>,
115    mut items: impl ExactSizeIterator<Item = T>,
116) -> std::fmt::Result {
117    if items.len() == 1 {
118        return write!(f, "expected {:?}", items.next().unwrap());
119    }
120    write!(f, "expected one of ")?;
121    for (i, item) in items.enumerate() {
122        let separator = if i == 0 { "" } else { ", " };
123        write!(f, "{separator}{item:?}")?;
124    }
125    Ok(())
126}
127
128impl PartialEq for ParseError {
129    fn eq(&self, other: &Self) -> bool {
130        match (*self, *other) {
131            // Equality based on the produced sets. This avoids the following warning:
132            //     warning: function pointer comparisons do not produce meaningful results since
133            //     their addresses are not guaranteed to be unique
134            // Alternatively, the AsciiSet itself could be stored in the ParseError, but that would
135            // make constructing the error more expensive, slowing down backtracking.
136            (Self::ExpectedAtLeastMatches(a1, a2), Self::ExpectedAtLeastMatches(b1, b2))
137            | (Self::ExpectedAtMostMatches(a1, a2), Self::ExpectedAtMostMatches(b1, b2))
138            | (Self::ExpectedExactlyMatches(a1, a2), Self::ExpectedExactlyMatches(b1, b2)) => {
139                a1 == b1 && AsciiSet::from(|b| a2(&b)) == AsciiSet::from(|b| b2(&b))
140            }
141
142            // Simple equality
143            (Self::Expected(a), Self::Expected(b))
144            | (Self::ExpectedLiteral(a), Self::ExpectedLiteral(b))
145            | (Self::Custom(a), Self::Custom(b)) => a == b,
146            (Self::ExpectedByte(a), Self::ExpectedByte(b)) => a == b,
147            (Self::ExpectedByteRange(a1, a2), Self::ExpectedByteRange(b1, b2)) => {
148                a1 == b1 && a2 == b2
149            }
150            (Self::ExpectedOneOf(a), Self::ExpectedOneOf(b)) => a == b,
151            (Self::ExpectedOneOfBytes(a), Self::ExpectedOneOfBytes(b)) => a == b,
152            (Self::ExpectedOneOfLiterals(a), Self::ExpectedOneOfLiterals(b)) => a == b,
153            (Self::ExpectedLessItems(a), Self::ExpectedLessItems(b)) => a == b,
154            (Self::ExpectedEof(), Self::ExpectedEof())
155            | (Self::NumberOutOfRange(), Self::NumberOutOfRange()) => true,
156            (Self::NumberTooLarge(a), Self::NumberTooLarge(b))
157            | (Self::NumberTooSmall(a), Self::NumberTooSmall(b)) => a == b,
158
159            // Ensure new variants are explicitly handled
160            (
161                Self::Expected(_)
162                | Self::ExpectedLiteral(_)
163                | Self::ExpectedByte(_)
164                | Self::ExpectedByteRange(_, _)
165                | Self::ExpectedOneOf(_)
166                | Self::ExpectedOneOfBytes(_)
167                | Self::ExpectedOneOfLiterals(_)
168                | Self::ExpectedAtLeastMatches(_, _)
169                | Self::ExpectedAtMostMatches(_, _)
170                | Self::ExpectedExactlyMatches(_, _)
171                | Self::ExpectedLessItems(_)
172                | Self::ExpectedEof()
173                | Self::NumberTooLarge(_)
174                | Self::NumberTooSmall(_)
175                | Self::NumberOutOfRange()
176                | Self::Custom(_),
177                _,
178            ) => false,
179        }
180    }
181}
182
183impl Eq for ParseError {}
184
185impl PartialEq<ParseError> for Box<dyn Error> {
186    fn eq(&self, other: &ParseError) -> bool {
187        if let Some(pe) = self.downcast_ref::<ParseError>() {
188            pe == other
189        } else {
190            false
191        }
192    }
193}
194impl PartialEq<Box<dyn Error>> for ParseError {
195    fn eq(&self, other: &Box<dyn Error>) -> bool {
196        other == self
197    }
198}
199
200#[derive(Copy, Clone)]
201pub struct WithErrorMsg<P> {
202    pub(super) parser: P,
203    pub(super) message: &'static str,
204}
205impl<'i, P: Parser<'i>> Parser<'i> for WithErrorMsg<P> {
206    type Output = P::Output;
207    type Then<T: Parser<'i>> = Then2<Self, T>;
208
209    #[inline]
210    fn parse_ctx(
211        &self,
212        input: &'i [u8],
213        state: &mut ParseState<'i>,
214        commit: &mut bool,
215        tail: bool,
216    ) -> ParserResult<'i, Self::Output> {
217        let prev_remaining = state.error.map(|e| e.1);
218        self.parser
219            .parse_ctx(input, state, commit, tail)
220            .inspect_err(|_| {
221                let remaining = state.error.unwrap().1;
222                if prev_remaining != Some(remaining) {
223                    // If the error location has changed, update the stored message
224                    state.error = Some((ParseError::Custom(self.message), remaining));
225                }
226            })
227    }
228}