chisel_json/
results.rs

1//! Error and [Result] types
2//!
3//! This module contains definitions for the main [Result] types used throughout the parser.
4
5use crate::coords::Coords;
6use crate::lexer::lexer_core::Token;
7use std::fmt::{Display, Formatter};
8use std::io::BufRead;
9
10/// Global result type used throughout the parser stages
11pub type ParserResult<T> = Result<T, ParserError>;
12
13/// Enumeration of the various different parser stages that can produce an error
14#[derive(Debug, Copy, Clone)]
15pub enum ParserErrorSource {
16    /// The character input stage of the parser
17    LexerInput,
18    /// The lexing stage of the parser
19    Lexer,
20    /// The parsing stage of the DOM parser
21    DomParser,
22    /// The parsing stage of the SAX parser
23    SaxParser,
24}
25
26impl Display for ParserErrorSource {
27    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
28        match self {
29            ParserErrorSource::LexerInput => write!(f, "lexer input"),
30            ParserErrorSource::Lexer => write!(f, "lexing"),
31            ParserErrorSource::DomParser => write!(f, "DOM parsing"),
32            ParserErrorSource::SaxParser => write!(f, "SAX parsing"),
33        }
34    }
35}
36
37/// A global enumeration of error codes
38#[derive(Debug, Clone, PartialEq)]
39pub enum ParserErrorDetails {
40    /// An invalid file has been specified.  It might not exist, or might not be accessible
41    InvalidFile,
42    /// We can't parse nothing.
43    ZeroLengthInput,
44    /// End of input has been reached. This is used as a stopping condition at various points.
45    EndOfInput,
46    /// If pulling bytes from an underlying stream (or [BufRead]) of some description, and an
47    /// error occurs, this will be returned.
48    StreamFailure,
49    /// Dodgy UTF8 has been found in the input.
50    NonUtf8InputDetected,
51    /// Edge case error condition. This means that something has gone horribly wrong with the
52    /// parse.
53    UnexpectedToken(Token),
54    /// KV pair is expected but not detected.
55    PairExpected,
56    /// Supplied JSON doesn't have an object or array as a root object.
57    InvalidRootObject,
58    /// The parse of an object has failed.
59    InvalidObject,
60    /// The parse of an array has failed.
61    InvalidArray,
62    /// An invalid character has been detected within the input.
63    InvalidCharacter(char),
64    /// Whilst looking for a literal string token (null, true, false) a match couldn't be found
65    MatchFailed(String, String),
66    /// A number has been found with an incorrect string representation.
67    InvalidNumericRepresentation(String),
68    /// An invalid escape sequence has been found within the input.
69    InvalidEscapeSequence(String),
70    /// An invalid unicode escape sequence (\uXXX) has been found within the input.
71    InvalidUnicodeEscapeSequence(String),
72}
73
74impl Display for ParserErrorDetails {
75    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
76        match self {
77            ParserErrorDetails::InvalidFile => write!(f, "invalid file specified"),
78            ParserErrorDetails::ZeroLengthInput => write!(f, "zero length input"),
79            ParserErrorDetails::EndOfInput => write!(f, "end of input reached"),
80            ParserErrorDetails::StreamFailure => write!(f, "failure in the underlying stream"),
81            ParserErrorDetails::NonUtf8InputDetected => write!(f, "non-UTF8 input"),
82            ParserErrorDetails::UnexpectedToken(token) => {
83                write!(f, "unexpected token found: {}", token)
84            }
85            ParserErrorDetails::PairExpected => {
86                write!(f, "pair expected, something else was found")
87            }
88            ParserErrorDetails::InvalidRootObject => write!(f, "invalid JSON"),
89            ParserErrorDetails::InvalidObject => write!(f, "invalid object"),
90            ParserErrorDetails::InvalidArray => write!(f, "invalid array"),
91            ParserErrorDetails::InvalidCharacter(ch) => write!(f, "invalid character: \'{}\'", ch),
92            ParserErrorDetails::MatchFailed(first, second) => write!(
93                f,
94                "a match failed. Looking for \"{}\", found \"{}\"",
95                first, second
96            ),
97            ParserErrorDetails::InvalidNumericRepresentation(repr) => {
98                write!(f, "invalid number representation: \"{}\"", repr)
99            }
100            ParserErrorDetails::InvalidEscapeSequence(seq) => {
101                write!(f, "invalid escape sequence: \"{}\"", seq)
102            }
103            ParserErrorDetails::InvalidUnicodeEscapeSequence(seq) => {
104                write!(f, "invalid unicode escape sequence: \"{}\"", seq)
105            }
106        }
107    }
108}
109
110/// The general error structure
111#[derive(Debug, Clone)]
112pub struct ParserError {
113    /// The originating source for the error
114    pub source: ParserErrorSource,
115    /// The global error code for the error
116    pub details: ParserErrorDetails,
117    /// Parser [Coords]
118    pub coords: Option<Coords>,
119}
120
121impl Display for ParserError {
122    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
123        if self.coords.is_some() {
124            write!(
125                f,
126                "Source: {}, Details: {}, Coords: {}",
127                self.source,
128                self.details,
129                self.coords.unwrap()
130            )
131        } else {
132            write!(f, "Source: {}, Details: {}", self.source, self.details)
133        }
134    }
135}
136#[macro_export]
137macro_rules! lexer_input_error {
138    ($details: expr, $coords : expr) => {
139        Err(ParserError {
140            source: ParserErrorSource::LexerInput,
141            details: $details,
142            coords: Some($coords),
143        })
144    };
145    ($details: expr) => {
146        Err(ParserError {
147            source: ParserErrorSource::LexerInput,
148            details: $details,
149            coords: None,
150        })
151    };
152}
153/// Helper macro for cooking up a [ParserError] specific to the lexer
154#[macro_export]
155macro_rules! lexer_error {
156    ($details: expr, $coords : expr) => {
157        Err(ParserError {
158            source: ParserErrorSource::Lexer,
159            details: $details,
160            coords: Some($coords),
161        })
162    };
163    ($details: expr) => {
164        Err(ParserError {
165            source: ParserErrorSource::Lexer,
166            details: $details,
167            coords: None,
168        })
169    };
170}
171
172/// Helper macro for cooking up a [ParserError] specific to the DOM parser
173#[macro_export]
174macro_rules! dom_parser_error {
175    ($details: expr, $coords: expr) => {
176        Err(ParserError {
177            source: ParserErrorSource::DomParser,
178            details: $details,
179            coords: Some($coords),
180        })
181    };
182    ($details: expr) => {
183        Err(ParserError {
184            source: ParserErrorSource::DomParser,
185            details: $details,
186            coords: None,
187        })
188    };
189}
190
191/// Helper macro for cooking up a [ParserError] specific to the SAX parser
192#[macro_export]
193macro_rules! sax_parser_error {
194    ($details: expr, $coords: expr) => {
195        Err(ParserError {
196            source: ParserErrorSource::SaxParser,
197            details: $details,
198            coords: Some($coords),
199        })
200    };
201    ($details: expr) => {
202        Err(ParserError {
203            source: ParserErrorSource::SaxParser,
204            details: $details,
205            coords: None,
206        })
207    };
208}