1use core::fmt;
2use std::error::Error;
3use crate::debug::DebugSymbol;
4
5
6#[derive(Debug)]
9pub enum ErrorKind {
10 IOError,
11 UnexpectedEOF,
12 NoMatchingRule,
13 CouldNotReadToken,
14 MaxTokenLengthExceeded,
15 SourceTooLong,
16}
17
18impl fmt::Display for ErrorKind {
19 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
20 let msg = match self {
21 Self::IOError => "error reading source text",
22 Self::NoMatchingRule => "unrecognized token",
23 Self::UnexpectedEOF => "unexpected end of file",
24 Self::CouldNotReadToken => "invalid token",
25 Self::MaxTokenLengthExceeded => "max token length exceeded",
26 Self::SourceTooLong => "max source length exceeded",
27 };
28 fmt.write_str(msg)
29 }
30}
31
32
33#[derive(Debug)]
34pub struct LexerError {
35 kind: ErrorKind,
36 symbol: DebugSymbol,
37 cause: Option<Box<dyn Error>>,
38}
39
40impl LexerError {
41 pub fn new(kind: ErrorKind, symbol: DebugSymbol) -> Self {
42 LexerError {
43 kind, symbol,
44 cause: None,
45 }
46 }
47
48 pub fn caused_by(mut self, cause: Box<dyn Error>) -> Self {
49 self.cause = Some(cause); self
50 }
51
52 pub fn kind(&self) -> &ErrorKind { &self.kind }
53 pub fn debug_symbol(&self) -> &DebugSymbol { &self.symbol }
54
55}
56
57impl Error for LexerError {
58 fn source(&self) -> Option<&(dyn Error + 'static)> {
59 self.cause.as_ref().map(|o| o.as_ref())
60 }
61}
62
63impl fmt::Display for LexerError {
64 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
65 write!(fmt, "{}", self.kind)?;
66 if let Some(err) = self.source() {
67 write!(fmt, ": {}", err)?;
68 }
69 Ok(())
70 }
71}
72