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