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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
//! General error types for the parser

use std::borrow::Cow;
use std::fmt::{Display, Formatter};

use crate::coords::Coords;
use crate::lexer::Token;
use crate::parser::Parser;

/// Global result type used throughout the parser stages
pub type ParserResult<T> = Result<T, Error>;

/// Enumeration of the various different parser stages that can produce an error
#[derive(Debug, Copy, Clone)]
pub enum Stage {
    /// The lexer stage of the parser
    Lexer,
    /// The parsing/AST construction stage of the parser
    Parser,
}

impl Display for Stage {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        match self {
            Stage::Lexer => write!(f, "lexing"),
            Stage::Parser => write!(f, "parsing"),
        }
    }
}

/// A global enumeration of error codes
#[derive(Debug, Clone)]
pub enum Details {
    EndOfInput,
    StreamFailure,
    NonUtf8InputDetected,
    UnexpectedToken(Token),
    PairExpected,
    InvalidObject,
    InvalidArray,
    InvalidCharacter(char),
    MatchFailed(String, String),
    InvalidNumericRepresentation(String),
    InvalidEscapeSequence(String),
    InvalidUnicodeEscapeSequence(String),
}

impl Display for Details {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        match self {
            Details::EndOfInput => write!(f, "end of input reached"),
            Details::StreamFailure => write!(f, "failure in the underlying stream"),
            Details::NonUtf8InputDetected => write!(f, "non-UTF8 input"),
            Details::UnexpectedToken(token) => write!(f, "unexpected token found: {}", token),
            Details::PairExpected => write!(f, "pair expected, something else was found"),
            Details::InvalidObject => write!(f, "invalid object"),
            Details::InvalidArray => write!(f, "invalid array"),
            Details::InvalidCharacter(ch) => write!(f, "invalid character: \'{}\'", ch),
            Details::MatchFailed(first, second) => write!(
                f,
                "a match failed. Looking for \"{}\", found \"{}\"",
                first, second
            ),
            Details::InvalidNumericRepresentation(repr) => {
                write!(f, "invalid number representation: \"{}\"", repr)
            }
            Details::InvalidEscapeSequence(seq) => {
                write!(f, "invalid escape sequence: \"{}\"", seq)
            }
            Details::InvalidUnicodeEscapeSequence(seq) => {
                write!(f, "invalid unicode escape sequence: \"{}\"", seq)
            }
        }
    }
}

/// The general error structure
#[derive(Debug, Clone)]
pub struct Error {
    /// The originating stage for the error
    pub stage: Stage,
    /// The global error code for the error
    pub details: Details,
    /// Parser [Coords]
    pub coords: Coords,
}

impl Display for Error {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "Stage: {}, Details: {}, Coords: {}",
            self.stage, self.details, self.coords
        )
    }
}

#[macro_export]
macro_rules! lexer_error {
    ($details: expr, $coords : expr) => {
        Err(Error {
            stage: Stage::Lexer,
            details: $details,
            coords: $coords,
        })
    };
}

#[macro_export]
macro_rules! parser_error {
    ($details: expr, $coords: expr) => {
        Err(Error {
            stage: Stage::Parser,
            details: $details,
            coords: $coords,
        })
    };
}