/// An error signaling that a different kind of token was expected. Returned by /// the various `TryFrom` impls. #[derive(Debug, Clone, Copy)] pubstruct InvalidToken { pub(crate) expected: TokenKind, pub(crate) actual: TokenKind, pub(crate) span: Span,
}
impl InvalidToken { /// Returns a token stream representing `compile_error!("msg");` where /// `"msg"` is the output of `self.to_string()`. **Panics if called outside /// of a proc-macro context!** pubfn to_compile_error(&self) -> proc_macro::TokenStream { use proc_macro::{Delimiter, Ident, Group, Punct, Spacing, TokenTree};
tokens.into_iter().map(|mut t| { t.set_span(span); t }).collect()
}
/// Like [`to_compile_error`][Self::to_compile_error], but returns a token /// stream from `proc_macro2` and does not panic outside of a proc-macro /// context. #[cfg(feature = "proc-macro2")] pubfn to_compile_error2(&self) -> proc_macro2::TokenStream { use proc_macro2::{Delimiter, Ident, Group, Punct, Spacing, TokenTree};
let span = matchself.span {
Span::One(s) => proc_macro2::Span::from(s),
Span::Two(s) => s,
}; let msg = self.to_string(); let tokens = vec![
TokenTree::from(Ident::new("compile_error", span)),
TokenTree::from(Punct::new('!', Spacing::Alone)),
TokenTree::from(Group::new(
Delimiter::Parenthesis,
TokenTree::from(proc_macro2::Literal::string(&msg)).into(),
)),
];
tokens.into_iter().map(|mut t| { t.set_span(span); t }).collect()
}
}
impl std::error::Error for InvalidToken {}
impl fmt::Display for InvalidToken { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn kind_desc(kind: TokenKind) -> &'static str { match kind {
TokenKind::Punct => "a punctuation character",
TokenKind::Ident => "an identifier",
TokenKind::Group => "a group",
TokenKind::Literal => "a literal",
TokenKind::BoolLit => "a bool literal (`true` or `false`)",
TokenKind::ByteLit => "a byte literal (e.g. `b'r')",
TokenKind::ByteStringLit => r#"a byte string literal (e.g. `b"fox"`)"#,
TokenKind::CharLit => "a character literal (e.g. `'P'`)",
TokenKind::FloatLit => "a float literal (e.g. `3.14`)",
TokenKind::IntegerLit => "an integer literal (e.g. `27`)",
TokenKind::StringLit => r#"a string literal (e.g. "Ferris")"#,
}
}
write!(f, "expected {}, but found {}", kind_desc(self.expected), kind_desc(self.actual))
}
}
/// Unfortunately, we have to deal with both cases. #[derive(Debug, Clone, Copy)] pub(crate) enum Span {
One(proc_macro::Span), #[cfg(feature = "proc-macro2")]
Two(proc_macro2::Span),
}
/// Errors during parsing. /// /// This type should be seen primarily for error reporting and not for catching /// specific cases. The span and error kind are not guaranteed to be stable /// over different versions of this library, meaning that a returned error can /// change from one version to the next. There are simply too many fringe cases /// that are not easy to classify as a specific error kind. It depends entirely /// on the specific parser code how an invalid input is categorized. /// /// Consider these examples: /// - `'\` can be seen as /// - invalid escape in character literal, or /// - unterminated character literal. /// - `'''` can be seen as /// - empty character literal, or /// - unescaped quote character in character literal. /// - `0b64` can be seen as /// - binary integer literal with invalid digit 6, or /// - binary integer literal with invalid digit 4, or /// - decimal integer literal with invalid digit b, or /// - decimal integer literal 0 with unknown type suffix `b64`. /// /// If you want to see more if these examples, feel free to check out the unit /// tests of this library. /// /// While this library does its best to emit sensible and precise errors, and to /// keep the returned errors as stable as possible, full stability cannot be /// guaranteed. #[derive(Debug, Clone)] pubstruct ParseError { pub(crate) span: Option<Range<usize>>, pub(crate) kind: ParseErrorKind,
}
impl ParseError { /// Returns a span of this error, if available. **Note**: the returned span /// might change in future versions of this library. See [the documentation /// of this type][ParseError] for more information. pubfn span(&self) -> Option<Range<usize>> { self.span.clone()
}
}
/// This is a free standing function instead of an associated one to reduce /// noise around parsing code. There are lots of places that create errors, we /// I wanna keep them as short as possible. pub(crate) fn perr(span: impl SpanLike, kind: ParseErrorKind) -> ParseError {
ParseError {
span: span.into_span(),
kind,
}
}
/// A `'` character was not escaped in a character or byte literal, or a `"` /// character was not escaped in a string or byte string literal.
UnescapedSingleQuote,
/// A \n, \t or \r raw character in a char or byte literal.
UnescapedSpecialWhitespace,
/// When parsing a character, byte, string or byte string literal directly /// and the input does not start with the corresponding quote character /// (plus optional raw string prefix).
DoesNotStartWithQuote,
/// Unterminated raw string literal.
UnterminatedRawString,
/// String literal without a `"` at the end.
UnterminatedString,
/// Invalid start for a string literal.
InvalidStringLiteralStart,
/// Invalid start for a byte literal.
InvalidByteLiteralStart,
InvalidByteStringLiteralStart,
/// An literal `\r` character not followed by a `\n` character in a /// (raw) string or byte string literal.
IsolatedCr,
/// Literal suffix is not a valid identifier.
InvalidSuffix,
/// Returned by `Float::parse` if an integer literal (no fractional nor /// exponent part) is passed.
UnexpectedIntegerLit,
/// Integer suffixes cannot start with `e` or `E` as this conflicts with the /// grammar for float literals.
IntegerSuffixStartingWithE,
}
impl std::error::Error for ParseError {}
impl fmt::Display for ParseError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { use ParseErrorKind::*;
let description = matchself.kind {
Empty => "input is empty",
UnexpectedChar => "unexpected character",
InvalidLiteral => "invalid literal",
DoesNotStartWithDigit => "number literal does not start with decimal digit",
InvalidDigit => "integer literal contains a digit invalid for its base",
NoDigits => "integer literal does not contain any digits",
NoExponentDigits => "exponent of floating point literal does not contain any digits",
UnknownEscape => "unknown escape",
UnterminatedEscape => "unterminated escape: input ended too soon",
InvalidXEscape => r"invalid `\x` escape: not followed by two hex digits",
NonAsciiXEscape => r"`\x` escape in char/string literal exceed ASCII range",
UnicodeEscapeInByteLiteral => r"`\u{...}` escape in byte (string) literal not allowed",
InvalidStartOfUnicodeEscape => r"invalid start of `\u{...}` escape",
UnicodeEscapeWithoutBrace => r"`Unicode \u{...}` escape without opening brace",
NonHexDigitInUnicodeEscape => r"non-hex digit found in `\u{...}` escape",
TooManyDigitInUnicodeEscape => r"more than six digits in `\u{...}` escape",
InvalidUnicodeEscapeChar => r"value specified in `\u{...}` escape is not a valid char",
UnterminatedUnicodeEscape => r"unterminated `\u{...}` escape",
UnterminatedCharLiteral => "character literal is not terminated",
OverlongCharLiteral => "character literal contains more than one character",
EmptyCharLiteral => "empty character literal",
UnterminatedByteLiteral => "byte literal is not terminated",
OverlongByteLiteral => "byte literal contains more than one byte",
EmptyByteLiteral => "empty byte literal",
NonAsciiInByteLiteral => "non ASCII character in byte (string) literal",
UnescapedSingleQuote => "character literal contains unescaped ' character",
UnescapedSpecialWhitespace => r"unescaped newline (\n), tab (\t) or cr (\r) character",
DoesNotStartWithQuote => "invalid start for char/byte/string literal",
UnterminatedRawString => "unterminated raw (byte) string literal",
UnterminatedString => "unterminated (byte) string literal",
InvalidStringLiteralStart => "invalid start for string literal",
InvalidByteLiteralStart => "invalid start for byte literal",
InvalidByteStringLiteralStart => "invalid start for byte string literal",
IsolatedCr => r"`\r` not immediately followed by `\n` in string",
InvalidSuffix => "literal suffix is not a valid identifier",
UnexpectedIntegerLit => "expected float literal, but found integer",
IntegerSuffixStartingWithE => "integer literal suffix must not start with 'e' or 'E'",
};
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.