From 40a355a42d4a9444dc753c04c6608dade2f06a23 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 03:13:27 +0200 Subject: Adding upstream version 125.0.1. Signed-off-by: Daniel Baumann --- third_party/rust/litrs/src/err.rs | 371 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 371 insertions(+) create mode 100644 third_party/rust/litrs/src/err.rs (limited to 'third_party/rust/litrs/src/err.rs') diff --git a/third_party/rust/litrs/src/err.rs b/third_party/rust/litrs/src/err.rs new file mode 100644 index 0000000000..86d51dc4a8 --- /dev/null +++ b/third_party/rust/litrs/src/err.rs @@ -0,0 +1,371 @@ +use std::{fmt, ops::Range}; + + +/// An error signaling that a different kind of token was expected. Returned by +/// the various `TryFrom` impls. +#[derive(Debug, Clone, Copy)] +pub struct 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!** + pub fn to_compile_error(&self) -> proc_macro::TokenStream { + use proc_macro::{Delimiter, Ident, Group, Punct, Spacing, TokenTree}; + + let span = match self.span { + Span::One(s) => s, + #[cfg(feature = "proc-macro2")] + Span::Two(s) => s.unwrap(), + }; + 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_macro::Literal::string(&msg)).into(), + )), + ]; + + + 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")] + pub fn to_compile_error2(&self) -> proc_macro2::TokenStream { + use proc_macro2::{Delimiter, Ident, Group, Punct, Spacing, TokenTree}; + + let span = match self.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)) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub(crate) enum TokenKind { + Punct, + Ident, + Group, + Literal, + BoolLit, + ByteLit, + ByteStringLit, + CharLit, + FloatLit, + IntegerLit, + StringLit, +} + +/// 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), +} + +impl From for Span { + fn from(src: proc_macro::Span) -> Self { + Self::One(src) + } +} + +#[cfg(feature = "proc-macro2")] +impl From for Span { + fn from(src: proc_macro2::Span) -> Self { + Self::Two(src) + } +} + +/// 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)] +pub struct ParseError { + pub(crate) span: Option>, + 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. + pub fn span(&self) -> Option> { + 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, + } +} + +pub(crate) trait SpanLike { + fn into_span(self) -> Option>; +} + +impl SpanLike for Option> { + #[inline(always)] + fn into_span(self) -> Option> { + self + } +} +impl SpanLike for Range { + #[inline(always)] + fn into_span(self) -> Option> { + Some(self) + } +} +impl SpanLike for usize { + #[inline(always)] + fn into_span(self) -> Option> { + Some(self..self + 1) + } +} + + +/// Kinds of errors. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[non_exhaustive] +pub(crate) enum ParseErrorKind { + /// The input was an empty string + Empty, + + /// An unexpected char was encountered. + UnexpectedChar, + + /// Literal was not recognized. + InvalidLiteral, + + /// Input does not start with decimal digit when trying to parse an integer. + DoesNotStartWithDigit, + + /// A digit invalid for the specified integer base was found. + InvalidDigit, + + /// Integer literal does not contain any valid digits. + NoDigits, + + /// Exponent of a float literal does not contain any digits. + NoExponentDigits, + + /// An unknown escape code, e.g. `\b`. + UnknownEscape, + + /// A started escape sequence where the input ended before the escape was + /// finished. + UnterminatedEscape, + + /// An `\x` escape where the two digits are not valid hex digits. + InvalidXEscape, + + /// A string or character literal using the `\xNN` escape where `NN > 0x7F`. + NonAsciiXEscape, + + /// A `\u{...}` escape in a byte or byte string literal. + UnicodeEscapeInByteLiteral, + + /// A Unicode escape that does not start with a hex digit. + InvalidStartOfUnicodeEscape, + + /// A `\u{...}` escape that lacks the opening brace. + UnicodeEscapeWithoutBrace, + + /// In a `\u{...}` escape, a non-hex digit and non-underscore character was + /// found. + NonHexDigitInUnicodeEscape, + + /// More than 6 digits found in unicode escape. + TooManyDigitInUnicodeEscape, + + /// The value from a unicode escape does not represent a valid character. + InvalidUnicodeEscapeChar, + + /// A `\u{..` escape that is not terminated (lacks the closing brace). + UnterminatedUnicodeEscape, + + /// A character literal that's not terminated. + UnterminatedCharLiteral, + + /// A character literal that contains more than one character. + OverlongCharLiteral, + + /// An empty character literal, i.e. `''`. + EmptyCharLiteral, + + UnterminatedByteLiteral, + OverlongByteLiteral, + EmptyByteLiteral, + NonAsciiInByteLiteral, + + /// 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 = match self.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'", + }; + + description.fmt(f)?; + if let Some(span) = &self.span { + write!(f, " (at {}..{})", span.start, span.end)?; + } + + Ok(()) + } +} -- cgit v1.2.3