1use std::{fmt, ops::Range};
2
3
4#[derive(Debug, Clone, Copy)]
7pub struct InvalidToken {
8 pub(crate) expected: TokenKind,
9 pub(crate) actual: TokenKind,
10 pub(crate) span: Span,
11}
12
13impl InvalidToken {
14 pub fn to_compile_error(&self) -> proc_macro::TokenStream {
18 use proc_macro::{Delimiter, Ident, Group, Punct, Spacing, TokenTree};
19
20 let span = match self.span {
21 Span::One(s) => s,
22 #[cfg(feature = "proc-macro2")]
23 Span::Two(s) => s.unwrap(),
24 };
25 let msg = self.to_string();
26 let tokens = vec![
27 TokenTree::from(Ident::new("compile_error", span)),
28 TokenTree::from(Punct::new('!', Spacing::Alone)),
29 TokenTree::from(Group::new(
30 Delimiter::Parenthesis,
31 TokenTree::from(proc_macro::Literal::string(&msg)).into(),
32 )),
33 ];
34
35
36 tokens.into_iter().map(|mut t| { t.set_span(span); t }).collect()
37 }
38
39 #[cfg(feature = "proc-macro2")]
43 pub fn to_compile_error2(&self) -> proc_macro2::TokenStream {
44 use proc_macro2::{Delimiter, Ident, Group, Punct, Spacing, TokenTree};
45
46 let span = match self.span {
47 Span::One(s) => proc_macro2::Span::from(s),
48 Span::Two(s) => s,
49 };
50 let msg = self.to_string();
51 let tokens = vec![
52 TokenTree::from(Ident::new("compile_error", span)),
53 TokenTree::from(Punct::new('!', Spacing::Alone)),
54 TokenTree::from(Group::new(
55 Delimiter::Parenthesis,
56 TokenTree::from(proc_macro2::Literal::string(&msg)).into(),
57 )),
58 ];
59
60
61 tokens.into_iter().map(|mut t| { t.set_span(span); t }).collect()
62 }
63}
64
65impl std::error::Error for InvalidToken {}
66
67impl fmt::Display for InvalidToken {
68 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
69 fn kind_desc(kind: TokenKind) -> &'static str {
70 match kind {
71 TokenKind::Punct => "a punctuation character",
72 TokenKind::Ident => "an identifier",
73 TokenKind::Group => "a group",
74 TokenKind::Literal => "a literal",
75 TokenKind::BoolLit => "a bool literal (`true` or `false`)",
76 TokenKind::ByteLit => "a byte literal (e.g. `b'r')",
77 TokenKind::ByteStringLit => r#"a byte string literal (e.g. `b"fox"`)"#,
78 TokenKind::CharLit => "a character literal (e.g. `'P'`)",
79 TokenKind::FloatLit => "a float literal (e.g. `3.14`)",
80 TokenKind::IntegerLit => "an integer literal (e.g. `27`)",
81 TokenKind::StringLit => r#"a string literal (e.g. "Ferris")"#,
82 }
83 }
84
85 write!(f, "expected {}, but found {}", kind_desc(self.expected), kind_desc(self.actual))
86 }
87}
88
89#[derive(Debug, Clone, Copy, PartialEq, Eq)]
90pub(crate) enum TokenKind {
91 Punct,
92 Ident,
93 Group,
94 Literal,
95 BoolLit,
96 ByteLit,
97 ByteStringLit,
98 CharLit,
99 FloatLit,
100 IntegerLit,
101 StringLit,
102}
103
104#[derive(Debug, Clone, Copy)]
106pub(crate) enum Span {
107 One(proc_macro::Span),
108 #[cfg(feature = "proc-macro2")]
109 Two(proc_macro2::Span),
110}
111
112impl From<proc_macro::Span> for Span {
113 fn from(src: proc_macro::Span) -> Self {
114 Self::One(src)
115 }
116}
117
118#[cfg(feature = "proc-macro2")]
119impl From<proc_macro2::Span> for Span {
120 fn from(src: proc_macro2::Span) -> Self {
121 Self::Two(src)
122 }
123}
124
125#[derive(Debug, Clone)]
154pub struct ParseError {
155 pub(crate) span: Option<Range<usize>>,
156 pub(crate) kind: ParseErrorKind,
157}
158
159impl ParseError {
160 pub fn span(&self) -> Option<Range<usize>> {
164 self.span.clone()
165 }
166}
167
168pub(crate) fn perr(span: impl SpanLike, kind: ParseErrorKind) -> ParseError {
172 ParseError {
173 span: span.into_span(),
174 kind,
175 }
176}
177
178pub(crate) trait SpanLike {
179 fn into_span(self) -> Option<Range<usize>>;
180}
181
182impl SpanLike for Option<Range<usize>> {
183 #[inline(always)]
184 fn into_span(self) -> Option<Range<usize>> {
185 self
186 }
187}
188impl SpanLike for Range<usize> {
189 #[inline(always)]
190 fn into_span(self) -> Option<Range<usize>> {
191 Some(self)
192 }
193}
194impl SpanLike for usize {
195 #[inline(always)]
196 fn into_span(self) -> Option<Range<usize>> {
197 Some(self..self + 1)
198 }
199}
200
201
202#[derive(Debug, Clone, Copy, PartialEq, Eq)]
204#[non_exhaustive]
205pub(crate) enum ParseErrorKind {
206 Empty,
208
209 UnexpectedChar,
211
212 InvalidLiteral,
214
215 DoesNotStartWithDigit,
217
218 InvalidDigit,
220
221 NoDigits,
223
224 NoExponentDigits,
226
227 UnknownEscape,
229
230 UnterminatedEscape,
233
234 InvalidXEscape,
236
237 NonAsciiXEscape,
239
240 UnicodeEscapeInByteLiteral,
242
243 InvalidStartOfUnicodeEscape,
245
246 UnicodeEscapeWithoutBrace,
248
249 NonHexDigitInUnicodeEscape,
252
253 TooManyDigitInUnicodeEscape,
255
256 InvalidUnicodeEscapeChar,
258
259 UnterminatedUnicodeEscape,
261
262 UnterminatedCharLiteral,
264
265 OverlongCharLiteral,
267
268 EmptyCharLiteral,
270
271 UnterminatedByteLiteral,
272 OverlongByteLiteral,
273 EmptyByteLiteral,
274 NonAsciiInByteLiteral,
275
276 UnescapedSingleQuote,
279
280 UnescapedSpecialWhitespace,
282
283 DoesNotStartWithQuote,
287
288 UnterminatedRawString,
290
291 UnterminatedString,
293
294 InvalidStringLiteralStart,
296
297 InvalidByteLiteralStart,
299
300 InvalidByteStringLiteralStart,
301
302 CarriageReturn,
304
305 InvalidSuffix,
307
308 UnexpectedIntegerLit,
311
312 IntegerSuffixStartingWithE,
315}
316
317impl std::error::Error for ParseError {}
318
319impl fmt::Display for ParseError {
320 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
321 use ParseErrorKind::*;
322
323 let description = match self.kind {
324 Empty => "input is empty",
325 UnexpectedChar => "unexpected character",
326 InvalidLiteral => "invalid literal",
327 DoesNotStartWithDigit => "number literal does not start with decimal digit",
328 InvalidDigit => "integer literal contains a digit invalid for its base",
329 NoDigits => "integer literal does not contain any digits",
330 NoExponentDigits => "exponent of floating point literal does not contain any digits",
331 UnknownEscape => "unknown escape",
332 UnterminatedEscape => "unterminated escape: input ended too soon",
333 InvalidXEscape => r"invalid `\x` escape: not followed by two hex digits",
334 NonAsciiXEscape => r"`\x` escape in char/string literal exceed ASCII range",
335 UnicodeEscapeInByteLiteral => r"`\u{...}` escape in byte (string) literal not allowed",
336 InvalidStartOfUnicodeEscape => r"invalid start of `\u{...}` escape",
337 UnicodeEscapeWithoutBrace => r"`Unicode \u{...}` escape without opening brace",
338 NonHexDigitInUnicodeEscape => r"non-hex digit found in `\u{...}` escape",
339 TooManyDigitInUnicodeEscape => r"more than six digits in `\u{...}` escape",
340 InvalidUnicodeEscapeChar => r"value specified in `\u{...}` escape is not a valid char",
341 UnterminatedUnicodeEscape => r"unterminated `\u{...}` escape",
342 UnterminatedCharLiteral => "character literal is not terminated",
343 OverlongCharLiteral => "character literal contains more than one character",
344 EmptyCharLiteral => "empty character literal",
345 UnterminatedByteLiteral => "byte literal is not terminated",
346 OverlongByteLiteral => "byte literal contains more than one byte",
347 EmptyByteLiteral => "empty byte literal",
348 NonAsciiInByteLiteral => "non ASCII character in byte (string) literal",
349 UnescapedSingleQuote => "character literal contains unescaped ' character",
350 UnescapedSpecialWhitespace => r"unescaped newline (\n), tab (\t) or cr (\r) character",
351 DoesNotStartWithQuote => "invalid start for char/byte/string literal",
352 UnterminatedRawString => "unterminated raw (byte) string literal",
353 UnterminatedString => "unterminated (byte) string literal",
354 InvalidStringLiteralStart => "invalid start for string literal",
355 InvalidByteLiteralStart => "invalid start for byte literal",
356 InvalidByteStringLiteralStart => "invalid start for byte string literal",
357 CarriageReturn => r"`\r` not allowed in string literals",
358 InvalidSuffix => "literal suffix is not a valid identifier",
359 UnexpectedIntegerLit => "expected float literal, but found integer",
360 IntegerSuffixStartingWithE => "integer literal suffix must not start with 'e' or 'E'",
361 };
362
363 description.fmt(f)?;
364 if let Some(span) = &self.span {
365 write!(f, " (at {}..{})", span.start, span.end)?;
366 }
367
368 Ok(())
369 }
370}