chisel_parsers/
lib.rs

1use chisel_common::char::coords::Coords;
2use chisel_lexers::json::lexer::LexerError;
3use std::fmt::{Display, Formatter};
4
5/// JSON parser implementations
6pub mod json;
7
8/// Global result type used throughout the parser stages
9pub type ParserResult<T> = Result<T, ParserError>;
10
11/// A global enumeration of error codes
12#[derive(Debug, Clone, PartialEq)]
13pub enum ParserErrorDetails {
14    /// An invalid file has been specified.  It might not exist, or might not be accessible
15    InvalidFile,
16    /// We can't parse nothing.
17    ZeroLengthInput,
18    /// End of input has been reached. This is used as a stopping condition at various points.
19    EndOfInput,
20    /// If pulling bytes from an underlying stream (or [BufRead]) of some description, and an
21    /// error occurs, this will be returned.
22    StreamFailure,
23    /// Dodgy UTF8 has been found in the input.
24    NonUtf8InputDetected,
25    /// Edge case error condition. This means that something has gone horribly wrong with the
26    /// parse.
27    UnexpectedToken(String),
28    /// An array value is expected but not detected
29    ValueExpected,
30    /// KV pair is expected but not detected.
31    PairExpected,
32    /// Supplied JSON doesn't have an object or array as a root object.
33    InvalidRootObject,
34    /// The parse of an object has failed.
35    InvalidObject,
36    /// The parse of an array has failed.
37    InvalidArray,
38    /// An invalid character has been detected within the input.
39    InvalidCharacter(char),
40    /// Whilst looking for a literal string token (null, true, false) a match couldn't be found
41    MatchFailed(String, String),
42    /// A number has been found with an incorrect string representation.
43    InvalidNumericRepresentation(String),
44    /// An invalid escape sequence has been found within the input.
45    InvalidEscapeSequence(String),
46    /// An invalid unicode escape sequence (\uXXX) has been found within the input.
47    InvalidUnicodeEscapeSequence(String),
48    /// A bubbled error from the lexical analysis backend
49    LexerError(String),
50}
51
52impl Display for ParserErrorDetails {
53    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
54        match self {
55            ParserErrorDetails::InvalidFile => write!(f, "invalid file specified"),
56            ParserErrorDetails::ZeroLengthInput => write!(f, "zero length input"),
57            ParserErrorDetails::EndOfInput => write!(f, "end of input reached"),
58            ParserErrorDetails::StreamFailure => write!(f, "failure in the underlying stream"),
59            ParserErrorDetails::NonUtf8InputDetected => write!(f, "non-UTF8 input"),
60            ParserErrorDetails::UnexpectedToken(token) => {
61                write!(f, "unexpected token found: {}", token)
62            }
63            ParserErrorDetails::ValueExpected => {
64                write!(f, "value expected, but a comma was found")
65            }
66            ParserErrorDetails::PairExpected => {
67                write!(f, "pair expected, something else was found")
68            }
69            ParserErrorDetails::InvalidRootObject => write!(f, "invalid JSON"),
70            ParserErrorDetails::InvalidObject => write!(f, "invalid object"),
71            ParserErrorDetails::InvalidArray => write!(f, "invalid array"),
72            ParserErrorDetails::InvalidCharacter(ch) => write!(f, "invalid character: \'{}\'", ch),
73            ParserErrorDetails::MatchFailed(first, second) => write!(
74                f,
75                "a match failed. Looking for \"{}\", found \"{}\"",
76                first, second
77            ),
78            ParserErrorDetails::InvalidNumericRepresentation(repr) => {
79                write!(f, "invalid number representation: \"{}\"", repr)
80            }
81            ParserErrorDetails::InvalidEscapeSequence(seq) => {
82                write!(f, "invalid escape sequence: \"{}\"", seq)
83            }
84            ParserErrorDetails::InvalidUnicodeEscapeSequence(seq) => {
85                write!(f, "invalid unicode escape sequence: \"{}\"", seq)
86            }
87            ParserErrorDetails::LexerError(repr) => {
88                write!(f, "lexer error reported: \"{}\"", repr)
89            }
90        }
91    }
92}
93
94/// The general error structure
95#[derive(Debug, Clone)]
96pub struct ParserError {
97    /// The global error code for the error
98    pub details: ParserErrorDetails,
99    /// Parser [Coords]
100    pub coords: Option<Coords>,
101}
102
103impl Display for ParserError {
104    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
105        if self.coords.is_some() {
106            write!(
107                f,
108                "details: {}, coords: {}",
109                self.details,
110                self.coords.unwrap()
111            )
112        } else {
113            write!(f, "details: {}", self.details)
114        }
115    }
116}
117
118/// Allows conversion from errors arising within the lexical analysis/scanning stage of parsing
119impl From<LexerError> for ParserError {
120    fn from(value: LexerError) -> Self {
121        ParserError {
122            details: ParserErrorDetails::LexerError(value.details.to_string()),
123            coords: value.coords,
124        }
125    }
126}
127
128/// Helper macro for cooking up a [ParserError] specific to the DOM parser
129#[macro_export]
130macro_rules! parser_error {
131    ($details: expr, $coords: expr) => {
132        Err(ParserError {
133            details: $details,
134            coords: Some($coords),
135        })
136    };
137    ($details: expr) => {
138        Err(ParserError {
139            details: $details,
140            coords: None,
141        })
142    };
143}