python_syntax/
error.rs

1use std::{
2    error,
3    fmt::{self, Display},
4};
5
6use crate::{source::Location, token::Token};
7
8#[derive(Debug, Clone, PartialEq)]
9pub struct Error {
10    pub location: Location,
11    pub kind: ErrorKind,
12}
13
14impl Error {
15    pub fn new(kind: ErrorKind, location: Location) -> Error {
16        Error { kind, location }
17    }
18}
19
20#[derive(Debug, Clone, PartialEq)]
21pub enum ErrorKind {
22    UnexpectedCharacter(char),
23    UnmatchedDedent,
24    MixedTabsAndSpaces,
25    NonAsciiBytes { offset: usize },
26    UnicodeDecode { offset: usize },
27    UnterminatedString,
28    UnexpectedToken { token: Token, expected: Vec<String> },
29    UnexpectedEof,
30}
31
32impl error::Error for Error {
33    fn description(&self) -> &str {
34        match self.kind {
35            ErrorKind::UnexpectedCharacter(_) => "unexpected character",
36            ErrorKind::UnmatchedDedent => "unmatched indentation",
37            ErrorKind::MixedTabsAndSpaces => "inconsistent use of tabs and spaces",
38            ErrorKind::NonAsciiBytes { .. } => "bytes can only contains ASCII characters",
39            ErrorKind::UnicodeDecode { .. } => "malformed unicode escape",
40            ErrorKind::UnterminatedString => "unterminated string",
41            ErrorKind::UnexpectedToken { .. } => "unexpected token, expected one of: ",
42            ErrorKind::UnexpectedEof => "unexpected EOF",
43        }
44    }
45}
46
47impl Display for Error {
48    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49        write!(f, "{}", self.kind)
50    }
51}
52
53impl Display for ErrorKind {
54    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55        match self {
56            ErrorKind::UnexpectedCharacter(c) => write!(f, "unexpected character \"{}\"", c),
57            ErrorKind::UnmatchedDedent => write!(f, "unmatched indentation"),
58            ErrorKind::MixedTabsAndSpaces => write!(f, "inconsistent use of tabs and spaces"),
59            ErrorKind::NonAsciiBytes { .. } => {
60                write!(f, "bytes can only contains ASCII characters")
61            }
62            ErrorKind::UnicodeDecode { .. } => write!(f, "malformed unicode escape"),
63            ErrorKind::UnterminatedString => write!(f, "unterminated string"),
64            ErrorKind::UnexpectedToken { token, expected } => {
65                write!(f, "unexpected {}, expected one of: ", token,)?;
66                let mut it = expected.iter();
67                write!(f, "{}", it.next().unwrap())?;
68                for e in it {
69                    write!(f, ", {}", e)?;
70                }
71                Ok(())
72            }
73            ErrorKind::UnexpectedEof => write!(f, "unexpected EOF"),
74        }
75    }
76}
77
78impl From<lalrpop_util::ParseError<Location, Token, Error>> for Error {
79    fn from(e: lalrpop_util::ParseError<Location, Token, Error>) -> Error {
80        use lalrpop_util::ParseError::*;
81        match e {
82            e @ InvalidToken { .. } => {
83                // https://github.com/lalrpop/lalrpop/blob/57f72944e39b680c343125289af455dfcd60d04a/lalrpop/src/lexer/intern_token/mod.rs#L207
84                // This variant is used only by internal LALRPOP lexer,
85                // since we have a custom one this is unimplemented.
86                unreachable!("{:?}", e)
87            }
88            e @ UnrecognizedEOF { .. } => {
89                // This is unreachable because our custom lexer outputs
90                // EOF token. This will be handled in UnrecognizedToken variant.
91                unreachable!("{:?}", e)
92            }
93            UnrecognizedToken {
94                token: (start, Token::Eof, _),
95                ..
96            } => Error::new(ErrorKind::UnexpectedEof, start),
97            UnrecognizedToken {
98                token: (start, token, _),
99                expected,
100            } => Error::new(ErrorKind::UnexpectedToken { token, expected }, start),
101            e @ ExtraToken { .. } => {
102                // This is unreachable because parse rules consume all tokens
103                // until EOF.
104                unreachable!("{:?}", e)
105            }
106            User { error } => error,
107        }
108    }
109}