expr_parser/
error.rs

1use std::{error::Error, fmt};
2
3use crate::{parser::Parser, token::Tokenizer, Span};
4
5#[derive(Clone, Debug)]
6pub struct ParseErrors<P, T, Idx> {
7    pub errors: Vec<ParseError<P, T, Idx>>,
8}
9
10impl<P, T, Idx> Error for ParseErrors<P, T, Idx> where Self: fmt::Debug + fmt::Display {}
11
12pub type ParseErrorsFor<P, T> = ParseErrors<
13    <P as Parser<<T as Tokenizer>::Token>>::Error,
14    <T as Tokenizer>::Error,
15    <T as Tokenizer>::Position,
16>;
17
18impl<P: fmt::Display, T: fmt::Display, Idx: fmt::Display> fmt::Display for ParseErrors<P, T, Idx> {
19    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
20        if self.errors.len() == 1 {
21            f.write_str("Encountered 1 error:\n")?;
22        } else {
23            writeln!(f, "Encountered {} errors:", self.errors.len())?;
24        }
25        for error in &self.errors {
26            writeln!(f, "{error}")?;
27        }
28        Ok(())
29    }
30}
31
32impl<P, T, Idx> From<Vec<ParseError<P, T, Idx>>> for ParseErrors<P, T, Idx> {
33    fn from(errors: Vec<ParseError<P, T, Idx>>) -> Self {
34        ParseErrors { errors }
35    }
36}
37
38#[derive(Clone, Copy, Debug)]
39pub struct ParseError<P, T, Idx> {
40    pub span: Span<Idx>,
41    pub kind: ParseErrorKind<P, T, Idx>,
42}
43
44impl<P, T, Idx> Error for ParseError<P, T, Idx> where Self: fmt::Debug + fmt::Display {}
45
46impl<P, T, Idx> fmt::Display for ParseError<P, T, Idx>
47where
48    Span<Idx>: fmt::Display,
49    ParseErrorKind<P, T, Idx>: fmt::Display,
50{
51    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
52        write!(f, "Parse error at {}: {}", self.span, self.kind)
53    }
54}
55
56#[derive(Clone, Copy, Debug, Eq, PartialEq)]
57pub enum ParseErrorKind<P, T, Idx> {
58    EndOfInput { expected: &'static str },
59    UnexpectedToken { expected: &'static str },
60    MismatchedDelimiter { opening: Span<Idx> },
61    UnmatchedRightDelimiter,
62    UnmatchedLeftDelimiter,
63    Parser(P),
64    Tokenizer(T),
65}
66
67impl<P, T, Idx> fmt::Display for ParseErrorKind<P, T, Idx>
68where
69    P: fmt::Display,
70    T: fmt::Display,
71    Idx: fmt::Display,
72{
73    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
74        match self {
75            Self::EndOfInput { expected } => {
76                write!(f, "Unexpected end of input (expected {expected})")
77            }
78            Self::UnexpectedToken { expected } => {
79                write!(f, "Unexpected token (expected {expected})")
80            }
81            Self::MismatchedDelimiter { opening } => {
82                write!(f, "Mismatched closing delimiter (opening {opening})")
83            }
84            Self::UnmatchedRightDelimiter => f.write_str("Unmatched closing delimiter"),
85            Self::UnmatchedLeftDelimiter => f.write_str("Unmatched opening delimiter"),
86            Self::Parser(err) => fmt::Display::fmt(err, f),
87            Self::Tokenizer(err) => fmt::Display::fmt(err, f),
88        }
89    }
90}
91
92impl<P, T, Idx> ParseErrorKind<P, T, Idx> {
93    #[cfg(test)]
94    pub(crate) fn map_tokenizer_error<U>(
95        self,
96        f: impl FnOnce(T) -> U,
97    ) -> ParseErrorKind<P, U, Idx> {
98        match self {
99            Self::EndOfInput { expected } => ParseErrorKind::EndOfInput { expected },
100            Self::UnexpectedToken { expected } => ParseErrorKind::UnexpectedToken { expected },
101            Self::MismatchedDelimiter { opening } => {
102                ParseErrorKind::MismatchedDelimiter { opening }
103            }
104            Self::UnmatchedRightDelimiter => ParseErrorKind::UnmatchedRightDelimiter,
105            Self::UnmatchedLeftDelimiter => ParseErrorKind::UnmatchedLeftDelimiter,
106            Self::Parser(e) => ParseErrorKind::Parser(e),
107            Self::Tokenizer(e) => ParseErrorKind::Tokenizer(f(e)),
108        }
109    }
110}