scan_rules/
error.rs

1/*
2Copyright ⓒ 2016 Daniel Keep.
3
4Licensed under the MIT license (see LICENSE or <http://opensource.org
5/licenses/MIT>) or the Apache License, Version 2.0 (see LICENSE of
6<http://www.apache.org/licenses/LICENSE-2.0>), at your option. All
7files in the project carrying such notice may not be copied, modified,
8or distributed except according to those terms.
9*/
10/*!
11Defines error types used by the crate.
12*/
13use std::error::Error;
14use std::fmt;
15use std::io;
16use std::num::{ParseFloatError, ParseIntError};
17
18/**
19Represents an error that occurred during scanning.
20
21Depending on what happened, it could represent an actual scanning failure, a problem with the pattern, an underlying IO failure, or something else entirely.
22*/
23#[derive(Debug)]
24pub struct ScanError {
25    /**
26    The rough cursor position at which this error occurred.  This will typically be the position the input cursor was at when it began trying to scan a particular literal or value.
27    */
28    pub at: ScanErrorAt,
29
30    /**
31    The kind of error that occurred.
32    */
33    pub kind: ScanErrorKind,
34
35    /**
36    Dummy private field to prevent exhaustive deconstruction.
37    */
38    _priv: (),
39}
40
41impl ScanError {
42    /**
43    Construct a new `ScanError`.
44    */
45    pub fn new(at: usize, kind: ScanErrorKind) -> Self {
46        ScanError {
47            at: ScanErrorAt { bytes: at },
48            kind: kind,
49            _priv: (),
50        }
51    }
52
53    /**
54    Shorthand for constructing an `ExpectedEnd` error.
55    */
56    pub fn expected_end() -> Self {
57        Self::new(0, ScanErrorKind::ExpectedEnd)
58    }
59
60    /**
61    Shorthand for constructing an `Float` error.
62    */
63    pub fn float(err: ParseFloatError) -> Self {
64        Self::new(0, ScanErrorKind::Float(err))
65    }
66
67    /**
68    Shorthand for constructing an `Int` error.
69    */
70    pub fn int(err: ParseIntError) -> Self {
71        Self::new(0, ScanErrorKind::Int(err))
72    }
73
74    /**
75    Shorthand for constructing an `Io` error.
76    */
77    pub fn io(err: io::Error) -> Self {
78        Self::new(0, ScanErrorKind::Io(err))
79    }
80
81    /**
82    Shorthand for constructing a `LiteralMismatch` error.
83    */
84    pub fn literal_mismatch() -> Self {
85        Self::new(0, ScanErrorKind::LiteralMismatch)
86    }
87
88    /**
89    Shorthand for constructing a `Syntax` error.
90    */
91    pub fn syntax(desc: &'static str) -> Self {
92        Self::new(0, ScanErrorKind::Syntax(desc))
93    }
94
95    /**
96    Shorthand for constructing a `SyntaxNoMessage` error.
97    */
98    pub fn syntax_no_message() -> Self {
99        Self::new(0, ScanErrorKind::SyntaxNoMessage)
100    }
101
102    /**
103    Shorthand for constructing an `Other` error.
104    */
105    pub fn other<E: Into<Box<Error>>>(err: E) -> Self {
106        Self::new(0, ScanErrorKind::from_other(err))
107    }
108
109    /**
110    Compare two `ScanError`s, and return the one which occurred the furthest into the input cursor.
111    */
112    pub fn furthest_along(self, other: Self) -> Self {
113        if self.at.offset() >= other.at.offset() {
114            self
115        } else {
116            other
117        }
118    }
119
120    /**
121    Adds the given number of `bytes` to the error's position.
122
123    This is used where an error has been generated by trying to scan a subslice of the original input, and the position needs to be corrected.
124    */
125    pub fn add_offset(self, bytes: usize) -> Self {
126        ScanError::new(self.at.offset() + bytes, self.kind)
127    }
128}
129
130impl<'a> fmt::Display for ScanError {
131    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
132        try!("scan error: ".fmt(fmt));
133        try!(self.kind.fmt(fmt));
134        try!(", at offset: ".fmt(fmt));
135        try!(self.at.offset().fmt(fmt));
136        Ok(())
137    }
138}
139
140impl Error for ScanError {
141    fn cause(&self) -> Option<&Error> {
142        self.kind.cause()
143    }
144
145    fn description(&self) -> &str {
146        self.kind.description()
147    }
148}
149
150/**
151Represents the position at which an error occurred.
152*/
153/*
154This exists because I'm still considering including the input which generated the error, for the sake of nice error messages.
155
156I'm not using `StrCursor`, because I don't want errors tied to a specific input wrapper.
157*/
158#[derive(Debug)]
159pub struct ScanErrorAt {
160    /// Offset in bytes.
161    bytes: usize,
162}
163
164impl ScanErrorAt {
165    /**
166    Return the offset from the start of input that an error occurred at, in bytes.
167    */
168    pub fn offset(&self) -> usize {
169        self.bytes
170    }
171}
172
173/**
174Indicates the kind of error that occurred during scanning.
175*/
176#[derive(Debug)]
177pub enum ScanErrorKind {
178    /// Failed to match a literal pattern term.
179    LiteralMismatch,
180
181    /// General syntax error.
182    Syntax(&'static str),
183
184    /**
185    General syntax error.
186
187    Due to [Rust issue #26448](https://github.com/rust-lang/rust/issues/26448), some scanners which want to return a `Syntax` error *cannot*.
188    */
189    SyntaxNoMessage,
190
191    /// Expected end-of-input.
192    ExpectedEnd,
193
194    /// Floating point parsing failed.
195    Float(ParseFloatError),
196
197    /// Integer parsing failed.
198    Int(ParseIntError),
199
200    /// An IO error occurred.
201    Io(io::Error),
202
203    /// Some other error occurred.
204    Other(Box<Error>),
205
206    /// Hidden variant to prevent exhaustive matching.
207    #[doc(hidden)]
208    __DoNotMatch,
209}
210
211impl ScanErrorKind {
212    /**
213    Construct an `Other` error from some generic error value.
214    */
215    pub fn from_other<E: Into<Box<Error>>>(err: E) -> Self {
216        ScanErrorKind::Other(err.into())
217    }
218}
219
220impl fmt::Display for ScanErrorKind {
221    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
222        use self::ScanErrorKind::*;
223        match *self {
224            LiteralMismatch => "did not match literal".fmt(fmt),
225            Syntax(desc) => {
226                try!("syntax error: ".fmt(fmt));
227                try!(desc.fmt(fmt));
228                Ok(())
229            },
230            SyntaxNoMessage => "unknown syntax error".fmt(fmt),
231            ExpectedEnd => "expected end of input".fmt(fmt),
232            Float(ref err) => err.fmt(fmt),
233            Int(ref err) => err.fmt(fmt),
234            Io(ref err) => err.fmt(fmt),
235            Other(ref err) => err.fmt(fmt),
236            __DoNotMatch => panic!("do not use ScanErrorKind::__DoNotMatch!"),
237        }
238    }
239}
240
241impl Error for ScanErrorKind {
242    fn cause(&self) -> Option<&Error> {
243        use self::ScanErrorKind::*;
244        match *self {
245            LiteralMismatch 
246            | Syntax(_)
247            | SyntaxNoMessage
248            | ExpectedEnd
249            => None,
250            Float(ref err) => err.cause(),
251            Int(ref err) => err.cause(),
252            Io(ref err) => err.cause(),
253            Other(ref err) => err.cause(),
254            __DoNotMatch => panic!("do not use ScanErrorKind::__DoNotMatch!"),
255        }
256    }
257
258    fn description(&self) -> &str {
259        use self::ScanErrorKind::*;
260        match *self {
261            LiteralMismatch => "did not match literal",
262            Syntax(_) => "syntax error",
263            SyntaxNoMessage => "unknown syntax error",
264            ExpectedEnd => "expected end of input",
265            Float(ref err) => err.description(),
266            Int(ref err) => err.description(),
267            Io(ref err) => err.description(),
268            Other(ref err) => err.description(),
269            __DoNotMatch => panic!("do not use ScanErrorKind::__DoNotMatch!"),
270        }
271    }
272}