1use std::error;
2use std::fmt::{Debug, Display, Formatter};
3
4use backtrace::Backtrace;
5
6use crate::parser::Token;
7
8#[derive(PartialOrd, PartialEq, Eq)]
9pub enum ErrorKind {
10 ExpectedText(Token),
11 ExpectedTextGot(String, Token),
12 ExpectedSeparator(Token),
13 ExpectedSeparatorGot(char, Token),
14 UnexpectedToken(Token),
15 MissingModuleName,
16 UnexpectedEndOfStream,
17 InvalidRangeValue(Token),
18 InvalidNumberForEnumVariant(Token),
19 InvalidValueForConstant(Token),
20 InvalidTag(Token),
21 InvalidPositionForExtensionMarker(Token),
22 InvalidIntText(Token),
23 UnsupportedLiteral(Token),
24 InvalidLiteral(Token),
25}
26
27pub struct Error {
28 kind: ErrorKind,
29 backtrace: Backtrace,
30}
31
32impl From<ErrorKind> for Error {
33 fn from(kind: ErrorKind) -> Self {
34 Error {
35 kind,
36 backtrace: Backtrace::new(),
37 }
38 }
39}
40
41impl PartialEq for Error {
42 fn eq(&self, other: &Self) -> bool {
43 self.kind.eq(&other.kind)
44 }
45}
46
47impl Error {
48 pub fn invalid_int_value(token: Token) -> Self {
49 ErrorKind::InvalidIntText(token).into()
50 }
51
52 pub fn invalid_position_for_extension_marker(token: Token) -> Self {
53 ErrorKind::InvalidPositionForExtensionMarker(token).into()
54 }
55
56 pub fn invalid_tag(token: Token) -> Self {
57 ErrorKind::InvalidTag(token).into()
58 }
59
60 pub fn invalid_value_for_constant(token: Token) -> Self {
61 ErrorKind::InvalidValueForConstant(token).into()
62 }
63
64 pub fn invalid_number_for_enum_variant(token: Token) -> Self {
65 ErrorKind::InvalidNumberForEnumVariant(token).into()
66 }
67
68 pub fn invalid_range_value(token: Token) -> Self {
69 ErrorKind::InvalidRangeValue(token).into()
70 }
71
72 pub fn no_text(token: Token) -> Self {
73 ErrorKind::ExpectedText(token).into()
74 }
75
76 pub fn expected_text(text: String, token: Token) -> Self {
77 ErrorKind::ExpectedTextGot(text, token).into()
78 }
79
80 pub fn no_separator(token: Token) -> Self {
81 ErrorKind::ExpectedSeparator(token).into()
82 }
83
84 pub fn expected_separator(separator: char, token: Token) -> Self {
85 ErrorKind::ExpectedSeparatorGot(separator, token).into()
86 }
87
88 pub fn missing_module_name() -> Self {
89 ErrorKind::MissingModuleName.into()
90 }
91
92 pub fn unexpected_token(token: Token) -> Self {
93 ErrorKind::UnexpectedToken(token).into()
94 }
95
96 pub fn unexpected_end_of_stream() -> Self {
97 ErrorKind::UnexpectedEndOfStream.into()
98 }
99
100 pub fn unsupported_value_reference_literal(token: Token) -> Self {
101 ErrorKind::UnsupportedLiteral(token).into()
102 }
103
104 fn backtrace(&self) -> &Backtrace {
105 &self.backtrace
106 }
107
108 pub fn token(&self) -> Option<&Token> {
109 match &self.kind {
110 ErrorKind::ExpectedText(t) => Some(t),
111 ErrorKind::ExpectedTextGot(_, t) => Some(t),
112 ErrorKind::ExpectedSeparator(t) => Some(t),
113 ErrorKind::ExpectedSeparatorGot(_, t) => Some(t),
114 ErrorKind::UnexpectedToken(t) => Some(t),
115 ErrorKind::MissingModuleName => None,
116 ErrorKind::UnexpectedEndOfStream => None,
117 ErrorKind::InvalidRangeValue(t) => Some(t),
118 ErrorKind::InvalidNumberForEnumVariant(t) => Some(t),
119 ErrorKind::InvalidValueForConstant(t) => Some(t),
120 ErrorKind::InvalidTag(t) => Some(t),
121 ErrorKind::InvalidPositionForExtensionMarker(t) => Some(t),
122 ErrorKind::InvalidIntText(t) => Some(t),
123 ErrorKind::UnsupportedLiteral(t) => Some(t),
124 ErrorKind::InvalidLiteral(t) => Some(t),
125 }
126 }
127}
128
129impl error::Error for Error {}
130
131impl Debug for Error {
132 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
133 writeln!(f, "{}", self)?;
134 writeln!(f, "{:?}", self.backtrace())?;
135 Ok(())
136 }
137}
138
139impl Display for Error {
140 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
141 match &self.kind {
142 ErrorKind::ExpectedText(token) => write!(
143 f,
144 "At line {}, column {} expected text, but instead got: {}",
145 token.location().line(),
146 token.location().column(),
147 token,
148 ),
149 ErrorKind::ExpectedTextGot(text, token) => write!(
150 f,
151 "At line {}, column {} expected a text like \"{}\", but instead got: {}",
152 token.location().line(),
153 token.location().column(),
154 text,
155 token,
156 ),
157 ErrorKind::ExpectedSeparator(token) => write!(
158 f,
159 "At line {}, column {} expected separator, but instead got: {}",
160 token.location().line(),
161 token.location().column(),
162 token,
163 ),
164 ErrorKind::ExpectedSeparatorGot(separator, token) => write!(
165 f,
166 "At line {}, column {} expected a separator like '{}', but instead got: {}",
167 token.location().line(),
168 token.location().column(),
169 separator,
170 token,
171 ),
172 ErrorKind::UnexpectedToken(token) => write!(
173 f,
174 "At line {}, column {} an unexpected token was encountered: {}",
175 token.location().line(),
176 token.location().column(),
177 token,
178 ),
179 ErrorKind::MissingModuleName => {
180 writeln!(f, "The ASN definition is missing the module name")
181 }
182 ErrorKind::UnexpectedEndOfStream => write!(f, "Unexpected end of stream or file"),
183 ErrorKind::InvalidRangeValue(token) => write!(
184 f,
185 "At line {}, column {} an unexpected range value was encountered: {}",
186 token.location().line(),
187 token.location().column(),
188 token,
189 ),
190 ErrorKind::InvalidNumberForEnumVariant(token) => write!(
191 f,
192 "At line {}, column {} an invalid value for an enum variant was encountered: {}",
193 token.location().line(),
194 token.location().column(),
195 token,
196 ),
197 ErrorKind::InvalidValueForConstant(token) => write!(
198 f,
199 "At line {}, column {} an invalid value for an constant value was encountered: {}",
200 token.location().line(),
201 token.location().column(),
202 token,
203 ),
204 ErrorKind::InvalidTag(token) => write!(
205 f,
206 "At line {}, column {} an invalid value for a tag was encountered: {}",
207 token.location().line(),
208 token.location().column(),
209 token,
210 ),
211 ErrorKind::InvalidPositionForExtensionMarker(token) => write!(
212 f,
213 "At line {}, column {} an extension marker is present, which this is not allowed at that position",
214 token.location().line(),
215 token.location().column(),
216 ),
217 ErrorKind::InvalidIntText(token) => write!(
218 f,
219 "At line {}, column {} a number was expected but instead got: {}",
220 token.location().line(),
221 token.location().column(),
222 token
223 ),
224 ErrorKind::UnsupportedLiteral(token) => write!(
225 f,
226 "At line {}, column {} an (yet) unsupported value reference literal was discovered: {}",
227 token.location().line(),
228 token.location().column(),
229 token
230 ),
231 ErrorKind::InvalidLiteral(token) => write!(
232 f,
233 "At line {}, column {} an invalid literal was discovered: {}",
234 token.location().line(),
235 token.location().column(),
236 token
237 ),
238 }
239 }
240}