Skip to main content

chumsky/
error.rs

1//! Error types, traits and utilities.
2//!
3//! *“I like the cover," he said. "Don't Panic. It's the first helpful or intelligible thing anybody's said to me all
4//! day.”*
5//!
6//! You can implement the [`Error`] trait to create your own parser errors, or you can use one provided by the crate
7//! like [`Cheap`], [`Simple`] or [`Rich`].
8
9use super::*;
10use alloc::borrow::Cow;
11
12pub use label::LabelError;
13
14/// A trait that describes parser error types.
15///
16/// If you have a custom error type in your compiler, or your needs are not sufficiently met by [`Simple`], you should
17/// implement this trait. If your error type has 'extra' features that allow for more specific error messages, you can
18/// use the [`Parser::map_err`] or [`Parser::try_map`] functions to take advantage of these inline within your parser.
19///
20/// # Examples
21///
22/// ```
23/// use chumsky::{prelude::*, error::{Error, LabelError}, util::MaybeRef, DefaultExpected};
24/// type Span = SimpleSpan<usize>;
25///
26/// // A custom error type
27/// #[derive(Debug, PartialEq)]
28/// enum MyError {
29///     ExpectedFound {
30///         span: Span,
31///         expected: Vec<DefaultExpected<'static, char>>,
32///         found: Option<char>,
33///     },
34///     NotADigit(Span, char),
35/// }
36///
37/// impl<'a> Error<'a, &'a str> for MyError {
38///     fn merge(mut self, mut other: Self) -> Self {
39///         if let (Self::ExpectedFound { expected, .. }, Self::ExpectedFound { expected: expected_other, .. }) = (
40///             &mut self,
41///             &mut other,
42///         ) {
43///             expected.append(expected_other);
44///         }
45///         self
46///     }
47/// }
48///
49/// impl<'a> LabelError<'a, &'a str, DefaultExpected<'a, char>> for MyError {
50///     fn expected_found<Iter: IntoIterator<Item = DefaultExpected<'a, char>>>(
51///         expected: Iter,
52///         found: Option<MaybeRef<'a, char>>,
53///         span: Span,
54///     ) -> Self {
55///         Self::ExpectedFound {
56///             span,
57///             expected: expected
58///                 .into_iter()
59///                 .map(|e| e.into_owned())
60///                 .collect(),
61///             found: found.as_deref().copied(),
62///         }
63///     }
64/// }
65///
66/// let numeral = any::<_, extra::Err<MyError>>().try_map(|c: char, span| match c.to_digit(10) {
67///     Some(x) => Ok(x),
68///     None => Err(MyError::NotADigit(span, c)),
69/// });
70///
71/// assert_eq!(numeral.parse("3").into_result(), Ok(3));
72/// assert_eq!(numeral.parse("7").into_result(), Ok(7));
73/// assert_eq!(numeral.parse("f").into_errors(), vec![MyError::NotADigit((0..1).into(), 'f')]);
74/// ```
75// TODO: Add support for more specialised kinds of error: unclosed delimiters, and more
76pub trait Error<'a, I: Input<'a>>:
77    Sized + LabelError<'a, I, DefaultExpected<'a, I::Token>>
78{
79    /// Merge two errors that point to the same input together, combining their information.
80    #[inline(always)]
81    fn merge(self, other: Self) -> Self {
82        #![allow(unused_variables)]
83        self
84    }
85}
86
87/// A ZST error type that tracks only whether a parse error occurred at all. This type is for when
88/// you want maximum parse speed, at the cost of all error reporting.
89///
90/// # Examples
91///
92/// ```
93/// use chumsky::prelude::*;
94///
95/// let parser = just::<_, _, extra::Err<EmptyErr>>("valid");
96/// let error = parser.parse("invalid").into_errors()[0];
97///
98/// assert_eq!(error, EmptyErr::default());
99/// ```
100#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
101#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Copy, Clone, Default)]
102pub struct EmptyErr(());
103
104impl<'a, I: Input<'a>> Error<'a, I> for EmptyErr {}
105
106impl<'a, I: Input<'a>, L> LabelError<'a, I, L> for EmptyErr {
107    #[inline(always)]
108    fn expected_found<E: IntoIterator<Item = L>>(
109        _: E,
110        _: Option<MaybeRef<'a, I::Token>>,
111        _: I::Span,
112    ) -> Self {
113        EmptyErr(())
114    }
115}
116
117impl fmt::Display for EmptyErr {
118    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
119        write!(f, "error")
120    }
121}
122
123/// A very cheap error type that tracks only the error span ([`SimpleSpan`] by default).
124/// This type is most useful when you want fast parsing but do not particularly care about the quality of error messages.
125///
126/// # Examples
127///
128/// ```
129/// use chumsky::prelude::*;
130///
131/// let parser = just::<_, _, extra::Err<Cheap>>("+");
132/// let error = parser.parse("-").into_errors()[0];
133///
134/// assert_eq!(error.span(), &SimpleSpan::new((), 0..1));
135/// ```
136#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
137#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
138pub struct Cheap<S = SimpleSpan<usize>> {
139    span: S,
140}
141
142impl<S> Cheap<S> {
143    /// Create a new [`Cheap`] error.
144    pub fn new(span: S) -> Self {
145        Self { span }
146    }
147
148    /// Get the span than that error related to.
149    ///
150    /// If the span type is unspecified, it is [`SimpleSpan`].
151    pub fn span(&self) -> &S {
152        &self.span
153    }
154}
155
156impl<'a, I: Input<'a>> Error<'a, I> for Cheap<I::Span> {}
157
158impl<'a, I: Input<'a>, L> LabelError<'a, I, L> for Cheap<I::Span> {
159    #[inline]
160    fn expected_found<E: IntoIterator<Item = L>>(
161        _expected: E,
162        _found: Option<MaybeRef<'a, I::Token>>,
163        span: I::Span,
164    ) -> Self {
165        Self { span }
166    }
167}
168
169impl<S> fmt::Debug for Cheap<S>
170where
171    S: fmt::Debug,
172{
173    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
174        write!(f, "at {:?}", self.span)?;
175        Ok(())
176    }
177}
178
179impl<S> fmt::Display for Cheap<S>
180where
181    S: fmt::Debug,
182{
183    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
184        fmt::Debug::fmt(self, f)
185    }
186}
187
188/// A simple error type that tracks the error span ([`SimpleSpan`] by default) and found token. This type is most useful when you want fast parsing
189/// but do not particularly care about the quality of error messages.
190///
191/// # Examples
192///
193/// ```
194/// use chumsky::prelude::*;
195///
196/// let parser = just::<_, _, extra::Err<Simple<char>>>("+");
197/// let error = parser.parse("-").into_errors()[0];
198///
199/// assert_eq!(error.span(), &SimpleSpan::new((), 0..1));
200/// assert_eq!(error.found(), Some(&'-'));
201/// ```
202#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
203#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
204pub struct Simple<'a, T, S = SimpleSpan<usize>> {
205    span: S,
206    found: Option<MaybeRef<'a, T>>,
207}
208
209impl<T, S> Simple<'_, T, S> {
210    /// Get the span than that error related to.
211    ///
212    /// If the span type is unspecified, it is [`SimpleSpan`].
213    pub fn span(&self) -> &S {
214        &self.span
215    }
216
217    /// Get the token found by this error when parsing. `None` implies that the error expected the end of input.
218    pub fn found(&self) -> Option<&T> {
219        self.found.as_deref()
220    }
221}
222
223impl<'a, T, S> Simple<'a, T, S> {
224    /// Create a new [`Simple`] error.
225    pub fn new(found: Option<MaybeRef<'a, T>>, span: S) -> Self {
226        Self { span, found }
227    }
228
229    /// Transform this error's tokens using the given function.
230    ///
231    /// This is useful when you wish to combine errors from multiple compilation passes (lexing and parsing, say) where
232    /// the token type for each pass is different (`char` vs `MyToken`, say).
233    pub fn map_token<U, F: FnOnce(T) -> U>(self, f: F) -> Simple<'a, U, S>
234    where
235        T: Clone,
236    {
237        Simple {
238            span: self.span,
239            found: self.found.map(|found| f(found.into_inner()).into()),
240        }
241    }
242
243    /// Transform this error's span using the given function.
244    ///
245    /// This is useful when you need to convert spans from one representation to another,
246    /// such as when enriching or interning spans.
247    pub fn map_span<S2, F: FnOnce(S) -> S2>(self, f: F) -> Simple<'a, T, S2> {
248        Simple {
249            span: f(self.span),
250            found: self.found,
251        }
252    }
253}
254
255impl<'a, I: Input<'a>> Error<'a, I> for Simple<'a, I::Token, I::Span> {}
256
257impl<'a, I: Input<'a>, L> LabelError<'a, I, L> for Simple<'a, I::Token, I::Span> {
258    #[inline]
259    fn expected_found<E: IntoIterator<Item = L>>(
260        _expected: E,
261        found: Option<MaybeRef<'a, I::Token>>,
262        span: I::Span,
263    ) -> Self {
264        Self { span, found }
265    }
266}
267
268impl<T, S> fmt::Debug for Simple<'_, T, S>
269where
270    T: fmt::Debug,
271    S: fmt::Debug,
272{
273    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
274        write!(f, "found ")?;
275        write_token(f, T::fmt, self.found.as_deref())?;
276        write!(f, " at {:?}", self.span)?;
277        Ok(())
278    }
279}
280
281impl<T, S> fmt::Display for Simple<'_, T, S>
282where
283    T: fmt::Debug,
284    S: fmt::Debug,
285{
286    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
287        fmt::Debug::fmt(self, f)
288    }
289}
290
291/// An expected pattern for a [`Rich`] error.
292#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
293#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
294#[non_exhaustive]
295pub enum RichPattern<'a, T> {
296    /// A specific token.
297    Token(MaybeRef<'a, T>),
298    /// A labelled pattern.
299    Label(Cow<'a, str>),
300    /// A specific keyword.
301    Identifier(String),
302    /// Anything other than the end of input.
303    Any,
304    /// Something other than the provided input.
305    SomethingElse,
306    /// The end of input.
307    EndOfInput,
308}
309
310impl<'a, T> TryFrom<DefaultExpected<'a, T>> for RichPattern<'a, T> {
311    type Error = ();
312    fn try_from(expected: DefaultExpected<'a, T>) -> Result<Self, ()> {
313        Ok(match expected {
314            DefaultExpected::Token(tok) => RichPattern::Token(tok),
315            DefaultExpected::Any => RichPattern::Any,
316            DefaultExpected::SomethingElse => RichPattern::SomethingElse,
317            DefaultExpected::EndOfInput => RichPattern::EndOfInput,
318            DefaultExpected::NothingElse => return Err(()),
319        })
320    }
321}
322
323impl<'a, Slice: core::fmt::Debug, T> TryFrom<text::TextExpected<Slice>> for RichPattern<'a, T> {
324    type Error = ();
325    fn try_from(expected: text::TextExpected<Slice>) -> Result<Self, ()> {
326        Ok(match expected {
327            text::TextExpected::Whitespace => RichPattern::Label(Cow::Borrowed("whitespace")),
328            text::TextExpected::InlineWhitespace => {
329                RichPattern::Label(Cow::Borrowed("inline whitespace"))
330            }
331            text::TextExpected::Newline => RichPattern::Label(Cow::Borrowed("newline")),
332            text::TextExpected::Digit(start, _end) if start > 0 => {
333                RichPattern::Label(Cow::Borrowed("non-zero digit"))
334            }
335            text::TextExpected::Digit(_, _) => RichPattern::Label(Cow::Borrowed("digit")),
336            text::TextExpected::AnyIdentifier => RichPattern::Label(Cow::Borrowed("identifier")),
337            text::TextExpected::Identifier(i) => RichPattern::Identifier(alloc::format!("{i:?}")),
338            text::TextExpected::Int => RichPattern::Label(Cow::Borrowed("int")),
339        })
340    }
341}
342
343impl<'a, T> TryFrom<MaybeRef<'a, T>> for RichPattern<'a, T> {
344    type Error = ();
345    fn try_from(tok: MaybeRef<'a, T>) -> Result<Self, ()> {
346        Ok(RichPattern::Token(tok))
347    }
348}
349
350impl<T> TryFrom<&'static str> for RichPattern<'_, T> {
351    type Error = ();
352    fn try_from(label: &'static str) -> Result<Self, ()> {
353        Ok(RichPattern::Label(Cow::Borrowed(label)))
354    }
355}
356
357impl<T> TryFrom<String> for RichPattern<'_, T> {
358    type Error = ();
359    fn try_from(label: String) -> Result<Self, ()> {
360        Ok(RichPattern::Label(Cow::Owned(label)))
361    }
362}
363
364impl TryFrom<char> for RichPattern<'_, char> {
365    type Error = ();
366    fn try_from(c: char) -> Result<Self, ()> {
367        Ok(Self::Token(MaybeRef::Val(c)))
368    }
369}
370
371impl<'a, T> RichPattern<'a, T> {
372    /// Transform this pattern's tokens using the given function.
373    ///
374    /// This is useful when you wish to combine errors from multiple compilation passes (lexing and parsing, say) where
375    /// the token type for each pass is different (`char` vs `MyToken`, say).
376    pub fn map_token<U, F: FnMut(T) -> U>(self, mut f: F) -> RichPattern<'a, U>
377    where
378        T: Clone,
379    {
380        match self {
381            Self::Token(t) => RichPattern::Token(f(t.into_inner()).into()),
382            Self::Label(l) => RichPattern::Label(l),
383            Self::Identifier(i) => RichPattern::Identifier(i),
384            Self::Any => RichPattern::Any,
385            Self::SomethingElse => RichPattern::SomethingElse,
386            Self::EndOfInput => RichPattern::EndOfInput,
387        }
388    }
389
390    /// Convert this pattern into an owned version of itself by cloning any borrowed internal tokens, if necessary.
391    pub fn into_owned<'b>(self) -> RichPattern<'b, T>
392    where
393        T: Clone,
394    {
395        match self {
396            Self::Token(tok) => RichPattern::Token(tok.into_owned()),
397            Self::Label(l) => RichPattern::Label(Cow::Owned(l.into_owned())),
398            Self::Identifier(i) => RichPattern::Identifier(i),
399            Self::Any => RichPattern::Any,
400            Self::SomethingElse => RichPattern::SomethingElse,
401            Self::EndOfInput => RichPattern::EndOfInput,
402        }
403    }
404
405    fn write(
406        &self,
407        f: &mut fmt::Formatter,
408        mut fmt_token: impl FnMut(&T, &mut fmt::Formatter<'_>) -> fmt::Result,
409    ) -> fmt::Result {
410        match self {
411            Self::Token(tok) => {
412                write!(f, "'")?;
413                fmt_token(tok, f)?;
414                write!(f, "'")
415            }
416            Self::Label(l) => write!(f, "{l}"),
417            Self::Identifier(i) => write!(f, "'{i}'"),
418            Self::Any => write!(f, "any"),
419            Self::SomethingElse => write!(f, "something else"),
420            Self::EndOfInput => write!(f, "end of input"),
421        }
422    }
423}
424
425impl<T> fmt::Debug for RichPattern<'_, T>
426where
427    T: fmt::Debug,
428{
429    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
430        self.write(f, |t, f| write!(f, "{t:?}"))
431    }
432}
433
434impl<T> fmt::Display for RichPattern<'_, T>
435where
436    T: fmt::Display,
437{
438    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
439        self.write(f, |t, f| write!(f, "{t}"))
440    }
441}
442
443/// The reason for a [`Rich`] error.
444#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
445#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
446pub enum RichReason<'a, T, C = String> {
447    /// An unexpected input was found
448    ExpectedFound {
449        /// The tokens expected
450        expected: Vec<RichPattern<'a, T>>,
451        /// The tokens found
452        found: Option<MaybeRef<'a, T>>,
453    },
454    /// A custom error
455    Custom(C),
456}
457
458impl<'a, T, C> RichReason<'a, T, C> {
459    /// Return the token that was found by this error reason. `None` implies that the end of input was expected.
460    pub fn found(&self) -> Option<&T> {
461        match self {
462            Self::ExpectedFound { found, .. } => found.as_deref(),
463            Self::Custom(_) => None,
464        }
465    }
466
467    /// Convert this reason into an owned version of itself by cloning any borrowed internal tokens, if necessary.
468    pub fn into_owned<'b>(self) -> RichReason<'b, T, C>
469    where
470        T: Clone,
471    {
472        match self {
473            Self::ExpectedFound { found, expected } => RichReason::ExpectedFound {
474                expected: expected.into_iter().map(RichPattern::into_owned).collect(),
475                found: found.map(MaybeRef::into_owned),
476            },
477            Self::Custom(msg) => RichReason::Custom(msg),
478        }
479    }
480
481    fn take_found(&mut self) -> Option<MaybeRef<'a, T>> {
482        match self {
483            RichReason::ExpectedFound { found, .. } => found.take(),
484            RichReason::Custom(_) => None,
485        }
486    }
487
488    /// Transform this `RichReason`'s tokens using the given function.
489    ///
490    /// This is useful when you wish to combine errors from multiple compilation passes (lexing and parsing, say) where
491    /// the token type for each pass is different (`char` vs `MyToken`, say).
492    pub fn map_token<U, F: FnMut(T) -> U>(self, mut f: F) -> RichReason<'a, U, C>
493    where
494        T: Clone,
495    {
496        match self {
497            RichReason::ExpectedFound { expected, found } => RichReason::ExpectedFound {
498                expected: expected
499                    .into_iter()
500                    .map(|pat| pat.map_token(&mut f))
501                    .collect(),
502                found: found.map(|found| f(found.into_inner()).into()),
503            },
504            RichReason::Custom(msg) => RichReason::Custom(msg),
505        }
506    }
507}
508
509impl<'a, T, C> RichReason<'a, T, C>
510where
511    C: fmt::Display,
512{
513    fn inner_fmt<S>(
514        &self,
515        f: &mut fmt::Formatter<'_>,
516        mut fmt_token: impl FnMut(&T, &mut fmt::Formatter<'_>) -> fmt::Result,
517        mut fmt_span: impl FnMut(&S, &mut fmt::Formatter<'_>) -> fmt::Result,
518        span: Option<&S>,
519        context: &[(RichPattern<'a, T>, S)],
520    ) -> fmt::Result {
521        match self {
522            RichReason::ExpectedFound { expected, found } => {
523                write!(f, "found ")?;
524                write_token(f, &mut fmt_token, found.as_deref())?;
525                if let Some(span) = span {
526                    write!(f, " at ")?;
527                    fmt_span(span, f)?;
528                }
529                write!(f, " expected ")?;
530                match &expected[..] {
531                    [] => write!(f, "something else")?,
532                    [expected] => expected.write(f, &mut fmt_token)?,
533                    _ => {
534                        for expected in &expected[..expected.len() - 1] {
535                            expected.write(f, &mut fmt_token)?;
536                            write!(f, ", ")?;
537                        }
538                        write!(f, "or ")?;
539                        expected.last().unwrap().write(f, &mut fmt_token)?;
540                    }
541                }
542            }
543            RichReason::Custom(msg) => {
544                write!(f, "{msg}")?;
545                if let Some(span) = span {
546                    write!(f, " at ")?;
547                    fmt_span(span, f)?;
548                }
549            }
550        }
551        for (l, s) in context {
552            write!(f, " in ")?;
553            l.write(f, &mut fmt_token)?;
554            write!(f, " at ")?;
555            fmt_span(s, f)?;
556        }
557        Ok(())
558    }
559}
560
561impl<T, C> RichReason<'_, T, C>
562where
563    T: PartialEq,
564{
565    #[inline]
566    fn flat_merge(self, other: Self) -> Self {
567        match (self, other) {
568            // Prefer first error, if ambiguous
569            (a @ RichReason::Custom(_), _) => a,
570            (_, b @ RichReason::Custom(_)) => b,
571            (
572                RichReason::ExpectedFound {
573                    expected: mut this_expected,
574                    found,
575                },
576                RichReason::ExpectedFound {
577                    expected: mut other_expected,
578                    ..
579                },
580            ) => {
581                // Try to avoid allocations if we possibly can by using the longer vector
582                if other_expected.len() > this_expected.len() {
583                    core::mem::swap(&mut this_expected, &mut other_expected);
584                }
585                for expected in other_expected {
586                    if !this_expected[..].contains(&expected) {
587                        this_expected.push(expected);
588                    }
589                }
590                RichReason::ExpectedFound {
591                    expected: this_expected,
592                    found,
593                }
594            }
595        }
596    }
597}
598
599impl<T, C> fmt::Display for RichReason<'_, T, C>
600where
601    T: fmt::Display,
602    C: fmt::Display,
603{
604    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
605        self.inner_fmt(f, T::fmt, |_: &(), _| Ok(()), None, &[])
606    }
607}
608
609/// A rich default error type that tracks error spans, expected inputs, and the actual input found at an error site.
610///
611/// Please note that it uses a [`Vec`] to remember expected symbols. If you find this to be too slow, you can
612/// implement [`Error`] for your own error type or use [`Simple`] instead.
613///
614/// This error type stores a span ([`SimpleSpan`] by default), a [`RichReason`], and a list of expected [`RichPattern`] with their spans.
615///
616/// # Examples
617///
618/// ```
619/// use chumsky::prelude::*;
620/// use chumsky::error::{RichReason, RichPattern};
621///
622/// let parser = one_of::<_, _, extra::Err<Rich<char>>>("1234");
623/// let error = parser.parse("5").into_errors()[0].clone();
624///
625/// assert_eq!(error.span(), &SimpleSpan::new((), 0..1));
626/// assert!(matches!(error.reason(), &RichReason::ExpectedFound {..}));
627/// assert_eq!(error.found(), Some(&'5'));
628///
629/// ```
630#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
631pub struct Rich<'a, T, S = SimpleSpan<usize>, C = String> {
632    span: S,
633    reason: Box<RichReason<'a, T, C>>,
634    context: Vec<(RichPattern<'a, T>, S)>,
635}
636
637impl<T, S, C> Rich<'_, T, S, C>
638where
639    C: fmt::Display,
640{
641    fn inner_fmt(
642        &self,
643        f: &mut fmt::Formatter<'_>,
644        fmt_token: impl FnMut(&T, &mut fmt::Formatter<'_>) -> fmt::Result,
645        fmt_span: impl FnMut(&S, &mut fmt::Formatter<'_>) -> fmt::Result,
646        with_spans: bool,
647    ) -> fmt::Result {
648        self.reason.inner_fmt(
649            f,
650            fmt_token,
651            fmt_span,
652            if with_spans { Some(&self.span) } else { None },
653            &self.context,
654        )
655    }
656}
657
658impl<'a, T, S, C> Rich<'a, T, S, C> {
659    /// Create an error with a custom message and span
660    #[inline]
661    pub fn custom<M: Into<C>>(span: S, msg: M) -> Self {
662        Rich {
663            span,
664            reason: Box::new(RichReason::Custom(msg.into())),
665            context: Vec::new(),
666        }
667    }
668
669    /// Get the span associated with this error.
670    ///
671    /// If the span type is unspecified, it is [`SimpleSpan`].
672    pub fn span(&self) -> &S {
673        &self.span
674    }
675
676    /// Get the reason for this error.
677    pub fn reason(&self) -> &RichReason<'a, T, C> {
678        &self.reason
679    }
680
681    /// Take the reason from this error.
682    pub fn into_reason(self) -> RichReason<'a, T, C> {
683        *self.reason
684    }
685
686    /// Get the token found by this error when parsing. `None` implies that the error expected the end of input.
687    pub fn found(&self) -> Option<&T> {
688        self.reason.found()
689    }
690
691    /// Return an iterator over the labelled contexts of this error, from least general to most.
692    ///
693    /// 'Context' here means parser patterns that the parser was in the process of parsing when the error occurred. To
694    /// add labelled contexts, see [`Parser::labelled`].
695    pub fn contexts(&self) -> impl Iterator<Item = (&RichPattern<'a, T>, &S)> {
696        self.context.iter().map(|(l, s)| (l, s))
697    }
698
699    /// Convert this error into an owned version of itself by cloning any borrowed internal tokens, if necessary.
700    pub fn into_owned<'b>(self) -> Rich<'b, T, S, C>
701    where
702        T: Clone,
703    {
704        Rich {
705            reason: Box::new(self.reason.into_owned()),
706            context: self
707                .context
708                .into_iter()
709                .map(|(p, s)| (p.into_owned(), s))
710                .collect(),
711            ..self
712        }
713    }
714
715    /// Get an iterator over the expected items associated with this error
716    pub fn expected(&self) -> impl ExactSizeIterator<Item = &RichPattern<'a, T>> {
717        match &*self.reason {
718            RichReason::ExpectedFound { expected, .. } => expected.iter(),
719            RichReason::Custom(_) => [].iter(),
720        }
721    }
722
723    /// Transform this error's tokens using the given function.
724    ///
725    /// This is useful when you wish to combine errors from multiple compilation passes (lexing and parsing, say) where
726    /// the token type for each pass is different (`char` vs `MyToken`, say).
727    pub fn map_token<U, F: FnMut(T) -> U>(self, mut f: F) -> Rich<'a, U, S, C>
728    where
729        T: Clone,
730    {
731        Rich {
732            span: self.span,
733            reason: Box::new(self.reason.map_token(&mut f)),
734            context: self
735                .context
736                .into_iter()
737                .map(|(p, s)| (p.map_token(&mut f), s))
738                .collect(),
739        }
740    }
741
742    /// Transform this error's spans using the given function.
743    ///
744    /// This is useful when you need to convert spans, such as enriching or
745    /// interning spans.
746    pub fn map_span<S2, F: FnMut(S) -> S2>(self, mut f: F) -> Rich<'a, T, S2, C> {
747        Rich {
748            span: f(self.span),
749            reason: self.reason,
750            context: self.context.into_iter().map(|(p, s)| (p, f(s))).collect(),
751        }
752    }
753}
754
755impl<'a, I: Input<'a>, C> Error<'a, I> for Rich<'a, I::Token, I::Span, C>
756where
757    I::Token: PartialEq,
758{
759    #[inline]
760    fn merge(self, other: Self) -> Self {
761        let new_reason = self.reason.flat_merge(*other.reason);
762        Self {
763            span: self.span,
764            reason: Box::new(new_reason),
765            context: self.context, // TOOD: Merge contexts
766        }
767    }
768}
769
770impl<'a, I: Input<'a>, L, C> LabelError<'a, I, L> for Rich<'a, I::Token, I::Span, C>
771where
772    I::Token: PartialEq,
773    L: TryInto<RichPattern<'a, I::Token>>,
774{
775    #[inline]
776    fn expected_found<E: IntoIterator<Item = L>>(
777        expected: E,
778        found: Option<MaybeRef<'a, I::Token>>,
779        span: I::Span,
780    ) -> Self {
781        Self {
782            span,
783            reason: Box::new(RichReason::ExpectedFound {
784                expected: expected
785                    .into_iter()
786                    .filter_map(|tok| tok.try_into().ok())
787                    .collect(),
788                found,
789            }),
790            context: Vec::new(),
791        }
792    }
793
794    #[inline]
795    fn merge_expected_found<E: IntoIterator<Item = L>>(
796        mut self,
797        new_expected: E,
798        new_found: Option<MaybeRef<'a, I::Token>>,
799        _span: I::Span,
800    ) -> Self {
801        match &mut *self.reason {
802            RichReason::ExpectedFound { expected, found } => {
803                for new_expected in new_expected {
804                    if let Ok(new_expected) = new_expected.try_into() {
805                        if !expected[..].contains(&new_expected) {
806                            expected.push(new_expected);
807                        }
808                    }
809                }
810                *found = found.take().or(new_found); //land
811            }
812            RichReason::Custom(_) => {}
813        }
814        // TOOD: Merge contexts
815        self
816    }
817
818    #[inline]
819    fn replace_expected_found<E: IntoIterator<Item = L>>(
820        mut self,
821        new_expected: E,
822        new_found: Option<MaybeRef<'a, I::Token>>,
823        span: I::Span,
824    ) -> Self {
825        self.span = span;
826        match &mut *self.reason {
827            RichReason::ExpectedFound { expected, found } => {
828                expected.clear();
829                expected.extend(
830                    new_expected
831                        .into_iter()
832                        .filter_map(|tok| tok.try_into().ok()),
833                );
834                *found = new_found;
835            }
836            _ => {
837                *self.reason = RichReason::ExpectedFound {
838                    expected: new_expected
839                        .into_iter()
840                        .filter_map(|tok| tok.try_into().ok())
841                        .collect(),
842                    found: new_found,
843                };
844            }
845        }
846        self.context.clear();
847        self
848    }
849
850    #[inline]
851    fn label_with(&mut self, label: L) {
852        // Opportunistically attempt to reuse allocations if we can
853        match &mut *self.reason {
854            RichReason::ExpectedFound { expected, found: _ } => {
855                expected.clear();
856                expected.extend(label.try_into().ok());
857            }
858            _ => {
859                *self.reason = RichReason::ExpectedFound {
860                    expected: label.try_into().ok().into_iter().collect(),
861                    found: self.reason.take_found(),
862                };
863            }
864        }
865    }
866
867    #[inline]
868    fn in_context(&mut self, label: L, span: I::Span) {
869        if let Ok(label) = label.try_into() {
870            if self.context.iter().all(|(l, _)| l != &label) {
871                self.context.push((label, span));
872            }
873        }
874    }
875}
876
877impl<T, S, C> fmt::Debug for Rich<'_, T, S, C>
878where
879    T: fmt::Debug,
880    S: fmt::Debug,
881    C: fmt::Display,
882{
883    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
884        self.inner_fmt(f, T::fmt, S::fmt, true)
885    }
886}
887
888impl<T, S, C> fmt::Display for Rich<'_, T, S, C>
889where
890    T: fmt::Display,
891    S: fmt::Display,
892    C: fmt::Display,
893{
894    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
895        self.inner_fmt(f, T::fmt, S::fmt, false)
896    }
897}
898
899fn write_token<T>(
900    f: &mut fmt::Formatter,
901    mut fmt_token: impl FnMut(&T, &mut fmt::Formatter<'_>) -> fmt::Result,
902    tok: Option<&T>,
903) -> fmt::Result {
904    match tok {
905        Some(tok) => {
906            write!(f, "'")?;
907            fmt_token(tok, f)?;
908            write!(f, "'")
909        }
910        None => write!(f, "end of input"),
911    }
912}