1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
use core::fmt;
use std::error::Error;
use crate::debug::DebugSymbol;


// Lexer Errors

#[derive(Debug)]
pub enum ErrorKind {
    IOError,
    UnexpectedEOF,
    NoMatchingRule,
    CouldNotReadToken,
    MaxTokenLengthExceeded,
    SourceTooLong,
}

impl fmt::Display for ErrorKind {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        let msg = match self {
            Self::IOError => "error reading source text",
            Self::NoMatchingRule => "unrecognized token",
            Self::UnexpectedEOF => "unexpected end of file",
            Self::CouldNotReadToken => "invalid token",
            Self::MaxTokenLengthExceeded => "max token length exceeded",
            Self::SourceTooLong => "max source length exceeded",
        };
        fmt.write_str(msg)
    }
}


#[derive(Debug)]
pub struct LexerError {
    kind: ErrorKind,
    symbol: DebugSymbol,
    cause: Option<Box<dyn Error>>,
}

impl LexerError {
    pub fn new(kind: ErrorKind, symbol: DebugSymbol) -> Self {
        LexerError {
            kind, symbol,
            cause: None,
        }
    }
    
    pub fn caused_by(mut self, cause: Box<dyn Error>) -> Self {
        self.cause = Some(cause); self
    }
    
    pub fn kind(&self) -> &ErrorKind { &self.kind }
    pub fn debug_symbol(&self) -> &DebugSymbol { &self.symbol }
    
}

impl Error for LexerError {
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        self.cause.as_ref().map(|o| o.as_ref())
    }
}

impl fmt::Display for LexerError {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(fmt, "{}", self.kind)?;
        if let Some(err) = self.source() {
            write!(fmt, ": {}", err)?;
        }
        Ok(())
    }
}