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 fn into_span(self) -> Option<Range<usize>> {
184 self
185 }
186}
187impl SpanLike for Range<usize> {
188 fn into_span(self) -> Option<Range<usize>> {
189 Some(self)
190 }
191}
192impl SpanLike for usize {
193 fn into_span(self) -> Option<Range<usize>> {
194 Some(self..self + 1)
195 }
196}
197
198
199#[derive(Debug, Clone, Copy, PartialEq, Eq)]
201#[non_exhaustive]
202pub(crate) enum ParseErrorKind {
203 Empty,
205
206 UnexpectedChar,
208
209 InvalidLiteral,
211
212 DoesNotStartWithDigit,
214
215 InvalidDigit,
217
218 NoDigits,
220
221 InvalidIntegerTypeSuffix,
223
224 InvalidFloatTypeSuffix,
227
228 NoExponentDigits,
230
231 UnknownEscape,
233
234 UnterminatedEscape,
237
238 InvalidXEscape,
240
241 NonAsciiXEscape,
243
244 UnicodeEscapeInByteLiteral,
246
247 InvalidStartOfUnicodeEscape,
249
250 UnicodeEscapeWithoutBrace,
252
253 NonHexDigitInUnicodeEscape,
256
257 TooManyDigitInUnicodeEscape,
259
260 InvalidUnicodeEscapeChar,
262
263 UnterminatedUnicodeEscape,
265
266 UnterminatedCharLiteral,
268
269 OverlongCharLiteral,
271
272 EmptyCharLiteral,
274
275 UnterminatedByteLiteral,
276 OverlongByteLiteral,
277 EmptyByteLiteral,
278 NonAsciiInByteLiteral,
279
280 UnescapedSingleQuote,
283
284 UnescapedSpecialWhitespace,
286
287 DoesNotStartWithQuote,
291
292 UnterminatedRawString,
294
295 UnterminatedString,
297
298 InvalidStringLiteralStart,
300
301 InvalidByteLiteralStart,
303
304 InvalidByteStringLiteralStart,
305
306 IsolatedCr,
309}
310
311impl std::error::Error for ParseError {}
312
313impl fmt::Display for ParseError {
314 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
315 use ParseErrorKind::*;
316
317 let description = match self.kind {
318 Empty => "input is empty",
319 UnexpectedChar => "unexpected character",
320 InvalidLiteral => "invalid literal",
321 DoesNotStartWithDigit => "number literal does not start with decimal digit",
322 InvalidDigit => "integer literal contains a digit invalid for its base",
323 NoDigits => "integer literal does not contain any digits",
324 InvalidIntegerTypeSuffix => "invalid integer type suffix",
325 InvalidFloatTypeSuffix => "invalid floating point type suffix",
326 NoExponentDigits => "exponent of floating point literal does not contain any digits",
327 UnknownEscape => "unknown escape",
328 UnterminatedEscape => "unterminated escape: input ended too soon",
329 InvalidXEscape => r"invalid `\x` escape: not followed by two hex digits",
330 NonAsciiXEscape => r"`\x` escape in char/string literal exceed ASCII range",
331 UnicodeEscapeInByteLiteral => r"`\u{...}` escape in byte (string) literal not allowed",
332 InvalidStartOfUnicodeEscape => r"invalid start of `\u{...}` escape",
333 UnicodeEscapeWithoutBrace => r"`Unicode \u{...}` escape without opening brace",
334 NonHexDigitInUnicodeEscape => r"non-hex digit found in `\u{...}` escape",
335 TooManyDigitInUnicodeEscape => r"more than six digits in `\u{...}` escape",
336 InvalidUnicodeEscapeChar => r"value specified in `\u{...}` escape is not a valid char",
337 UnterminatedUnicodeEscape => r"unterminated `\u{...}` escape",
338 UnterminatedCharLiteral => "character literal is not terminated",
339 OverlongCharLiteral => "character literal contains more than one character",
340 EmptyCharLiteral => "empty character literal",
341 UnterminatedByteLiteral => "byte literal is not terminated",
342 OverlongByteLiteral => "byte literal contains more than one byte",
343 EmptyByteLiteral => "empty byte literal",
344 NonAsciiInByteLiteral => "non ASCII character in byte (string) literal",
345 UnescapedSingleQuote => "character literal contains unescaped ' character",
346 UnescapedSpecialWhitespace => r"unescaped newline (\n), tab (\t) or cr (\r) character",
347 DoesNotStartWithQuote => "invalid start for char/byte/string literal",
348 UnterminatedRawString => "unterminated raw (byte) string literal",
349 UnterminatedString => "unterminated (byte) string literal",
350 InvalidStringLiteralStart => "invalid start for string literal",
351 InvalidByteLiteralStart => "invalid start for byte literal",
352 InvalidByteStringLiteralStart => "invalid start for byte string literal",
353 IsolatedCr => r"`\r` not immediately followed by `\n` in string",
354 };
355
356 description.fmt(f)?;
357 if let Some(span) = &self.span {
358 write!(f, " (at {}..{})", span.start, span.end)?;
359 }
360
361 Ok(())
362 }
363}