1use crate::token::Token;
2
3#[derive(Debug, Clone, PartialEq, Eq)]
4pub enum ParseErrorKind {
5 ExpectedRule,
6 ExpectedStatement,
7 ExpectedIdentifier,
8 UnsupportedStatement,
9 UnsupportedSubTarget,
10 ExpectedLeftParen,
11 ExpectedLeftBrace,
12 ExpectedRightSquareBracket,
13 ExpectedComma,
14 ExpectedColon,
15 ExpectedSemicolon,
16 ExpectedWhile,
17 ExpectedRightBrace,
18 ExpectedRightParen,
19 MissingPrintfFormatString,
20 InvalidNumericLiteral,
21}
22
23#[derive(Debug, Clone, PartialEq)]
24pub struct ParseError<'a> {
25 pub kind: ParseErrorKind,
26 pub token: Token<'a>,
27}
28
29impl std::fmt::Display for ParseError<'_> {
30 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
31 match &self.kind {
32 ParseErrorKind::ExpectedRule => write!(
33 f,
34 "unexpected token {:?} ({:?}) at byte {}: expected rule",
35 self.token.kind, self.token.literal, self.token.span.start
36 ),
37 ParseErrorKind::ExpectedStatement => write!(
38 f,
39 "unexpected token {:?} ({:?}) at byte {}: expected statement",
40 self.token.kind, self.token.literal, self.token.span.start
41 ),
42 ParseErrorKind::ExpectedIdentifier => write!(
43 f,
44 "unexpected token {:?} ({:?}) at byte {}: expected identifier",
45 self.token.kind, self.token.literal, self.token.span.start
46 ),
47 ParseErrorKind::UnsupportedStatement => write!(
48 f,
49 "unexpected token {:?} ({:?}) at byte {}: unsupported statement syntax",
50 self.token.kind, self.token.literal, self.token.span.start
51 ),
52 ParseErrorKind::UnsupportedSubTarget => write!(
53 f,
54 "unexpected token {:?} ({:?}) at byte {}: sub target argument is not supported",
55 self.token.kind, self.token.literal, self.token.span.start
56 ),
57 ParseErrorKind::ExpectedLeftParen => write!(
58 f,
59 "unexpected token {:?} ({:?}) at byte {}: expected left paren",
60 self.token.kind, self.token.literal, self.token.span.start
61 ),
62 ParseErrorKind::ExpectedLeftBrace => write!(
63 f,
64 "unexpected token {:?} ({:?}) at byte {}: expected left brace",
65 self.token.kind, self.token.literal, self.token.span.start
66 ),
67 ParseErrorKind::ExpectedRightSquareBracket => write!(
68 f,
69 "unexpected token {:?} ({:?}) at byte {}: expected right square bracket",
70 self.token.kind, self.token.literal, self.token.span.start
71 ),
72 ParseErrorKind::ExpectedComma => write!(
73 f,
74 "unexpected token {:?} ({:?}) at byte {}: expected comma",
75 self.token.kind, self.token.literal, self.token.span.start
76 ),
77 ParseErrorKind::ExpectedColon => write!(
78 f,
79 "unexpected token {:?} ({:?}) at byte {}: expected colon",
80 self.token.kind, self.token.literal, self.token.span.start
81 ),
82 ParseErrorKind::ExpectedSemicolon => write!(
83 f,
84 "unexpected token {:?} ({:?}) at byte {}: expected semicolon",
85 self.token.kind, self.token.literal, self.token.span.start
86 ),
87 ParseErrorKind::ExpectedWhile => write!(
88 f,
89 "unexpected token {:?} ({:?}) at byte {}: expected while",
90 self.token.kind, self.token.literal, self.token.span.start
91 ),
92 ParseErrorKind::ExpectedRightBrace => write!(
93 f,
94 "unexpected token {:?} ({:?}) at byte {}: expected right brace",
95 self.token.kind, self.token.literal, self.token.span.start
96 ),
97 ParseErrorKind::ExpectedRightParen => write!(
98 f,
99 "unexpected token {:?} ({:?}) at byte {}: expected right paren",
100 self.token.kind, self.token.literal, self.token.span.start
101 ),
102 ParseErrorKind::MissingPrintfFormatString => write!(
103 f,
104 "printf requires a format string at byte {}",
105 self.token.span.start
106 ),
107 ParseErrorKind::InvalidNumericLiteral => write!(
108 f,
109 "invalid numeric literal {:?} at byte {}",
110 self.token.literal, self.token.span.start
111 ),
112 }
113 }
114}
115
116impl std::error::Error for ParseError<'_> {}
117
118#[cfg(test)]
119mod tests {
120 use super::*;
121 use crate::token::{Token, TokenKind};
122
123 fn parse_error(kind: ParseErrorKind, token: Token<'static>) -> ParseError<'static> {
124 ParseError { kind, token }
125 }
126
127 #[test]
128 fn display_expected_rule_error() {
129 let err = parse_error(
130 ParseErrorKind::ExpectedRule,
131 Token::new(TokenKind::Else, "else", 12),
132 );
133
134 assert_eq!(
135 format!("{err}"),
136 "unexpected token Else (\"else\") at byte 12: expected rule"
137 );
138 }
139
140 #[test]
141 fn display_expected_statement_error() {
142 let err = parse_error(
143 ParseErrorKind::ExpectedStatement,
144 Token::new(TokenKind::Else, "else", 4),
145 );
146
147 assert_eq!(
148 format!("{err}"),
149 "unexpected token Else (\"else\") at byte 4: expected statement"
150 );
151 }
152
153 #[test]
154 fn display_expected_identifier_error() {
155 let err = parse_error(
156 ParseErrorKind::ExpectedIdentifier,
157 Token::new(TokenKind::Number, "1", 8),
158 );
159
160 assert_eq!(
161 format!("{err}"),
162 "unexpected token Number (\"1\") at byte 8: expected identifier"
163 );
164 }
165
166 #[test]
167 fn display_unsupported_statement_error() {
168 let err = parse_error(
169 ParseErrorKind::UnsupportedStatement,
170 Token::new(TokenKind::Plus, "+", 6),
171 );
172
173 assert_eq!(
174 format!("{err}"),
175 "unexpected token Plus (\"+\") at byte 6: unsupported statement syntax"
176 );
177 }
178
179 #[test]
180 fn display_unsupported_sub_target_error() {
181 let err = parse_error(
182 ParseErrorKind::UnsupportedSubTarget,
183 Token::new(TokenKind::Comma, ",", 12),
184 );
185
186 assert_eq!(
187 format!("{err}"),
188 "unexpected token Comma (\",\") at byte 12: sub target argument is not supported"
189 );
190 }
191
192 #[test]
193 fn display_expected_left_paren_error() {
194 let err = parse_error(
195 ParseErrorKind::ExpectedLeftParen,
196 Token::new(TokenKind::Identifier, "x", 5),
197 );
198
199 assert_eq!(
200 format!("{err}"),
201 "unexpected token Identifier (\"x\") at byte 5: expected left paren"
202 );
203 }
204
205 #[test]
206 fn display_expected_left_brace_error() {
207 let err = parse_error(
208 ParseErrorKind::ExpectedLeftBrace,
209 Token::new(TokenKind::Print, "print", 6),
210 );
211
212 assert_eq!(
213 format!("{err}"),
214 "unexpected token Print (\"print\") at byte 6: expected left brace"
215 );
216 }
217
218 #[test]
219 fn display_expected_right_square_bracket_error() {
220 let err = parse_error(
221 ParseErrorKind::ExpectedRightSquareBracket,
222 Token::new(TokenKind::Assign, "=", 9),
223 );
224
225 assert_eq!(
226 format!("{err}"),
227 "unexpected token Assign (\"=\") at byte 9: expected right square bracket"
228 );
229 }
230
231 #[test]
232 fn display_expected_comma_error() {
233 let err = parse_error(
234 ParseErrorKind::ExpectedComma,
235 Token::new(TokenKind::Identifier, "arr", 11),
236 );
237
238 assert_eq!(
239 format!("{err}"),
240 "unexpected token Identifier (\"arr\") at byte 11: expected comma"
241 );
242 }
243
244 #[test]
245 fn display_expected_colon_error() {
246 let err = parse_error(
247 ParseErrorKind::ExpectedColon,
248 Token::new(TokenKind::RightCurlyBrace, "}", 13),
249 );
250
251 assert_eq!(
252 format!("{err}"),
253 "unexpected token RightCurlyBrace (\"}\") at byte 13: expected colon"
254 );
255 }
256
257 #[test]
258 fn display_expected_semicolon_error() {
259 let err = parse_error(
260 ParseErrorKind::ExpectedSemicolon,
261 Token::new(TokenKind::Identifier, "i", 15),
262 );
263
264 assert_eq!(
265 format!("{err}"),
266 "unexpected token Identifier (\"i\") at byte 15: expected semicolon"
267 );
268 }
269
270 #[test]
271 fn display_expected_while_error() {
272 let err = parse_error(
273 ParseErrorKind::ExpectedWhile,
274 Token::new(TokenKind::RightCurlyBrace, "}", 7),
275 );
276
277 assert_eq!(
278 format!("{err}"),
279 "unexpected token RightCurlyBrace (\"}\") at byte 7: expected while"
280 );
281 }
282
283 #[test]
284 fn display_expected_right_paren_error() {
285 let err = parse_error(
286 ParseErrorKind::ExpectedRightParen,
287 Token::new(TokenKind::Print, "print", 10),
288 );
289
290 assert_eq!(
291 format!("{err}"),
292 "unexpected token Print (\"print\") at byte 10: expected right paren"
293 );
294 }
295
296 #[test]
297 fn display_expected_right_brace_error() {
298 let err = parse_error(
299 ParseErrorKind::ExpectedRightBrace,
300 Token::new(TokenKind::Eof, "", 16),
301 );
302
303 assert_eq!(
304 format!("{err}"),
305 "unexpected token Eof (\"\") at byte 16: expected right brace"
306 );
307 }
308
309 #[test]
310 fn display_missing_printf_format_string_error() {
311 let err = parse_error(
312 ParseErrorKind::MissingPrintfFormatString,
313 Token::new(TokenKind::RightCurlyBrace, "}", 14),
314 );
315
316 assert_eq!(
317 format!("{err}"),
318 "printf requires a format string at byte 14"
319 );
320 }
321
322 #[test]
323 fn display_invalid_numeric_literal_error() {
324 let err = parse_error(
325 ParseErrorKind::InvalidNumericLiteral,
326 Token::new(TokenKind::Number, "0xZZ", 3),
327 );
328
329 assert_eq!(
330 format!("{err}"),
331 "invalid numeric literal \"0xZZ\" at byte 3"
332 );
333 }
334}