macros_utils/
error.rs

1use std::{error::Error, fmt::Display};
2
3use proc_macro2::Span;
4use proc_macro_error::{Diagnostic, Level};
5use thiserror::Error;
6
7use crate::{Delimiter, Token};
8
9/// The error type for this crate. Can be either a `Parse(ParseError)` from this crate or a `User(Box<dyn Error + Send + Sync>)` user error.
10#[derive(Debug, Error)]
11pub enum MacrosError {
12    #[error(transparent)]
13    Parse(ParseError),
14    #[error(transparent)]
15    User(Box<dyn Error + Send + Sync>),
16}
17
18impl From<Box<dyn Error + Send + Sync>> for MacrosError {
19    fn from(error: Box<dyn Error + Send + Sync>) -> Self {
20        Self::User(error)
21    }
22}
23
24impl From<ParseError> for MacrosError {
25    fn from(error: ParseError) -> Self {
26        Self::Parse(error)
27    }
28}
29
30impl MacrosError {
31    /// Convert the error into a `proc_macro_error::Diagnostic`.
32    pub fn into_diagnostic(self) -> Diagnostic {
33        match self {
34            Self::Parse(error) => error.into_diagnostic(),
35            Self::User(error) => Diagnostic::new(Level::Error, error.to_string()),
36        }
37    }
38
39    /// Add a message to the error if it is a `Self::Parse` and the error is an `UnexpectedEndOfInput`.
40    pub fn unexpected_end_of_input(mut self, msg: &str) -> Self {
41        if let Self::Parse(error) = &mut self {
42            error.unexpected_end_of_input(msg);
43        };
44        self
45    }
46}
47
48/// A parse error encountered while parsing a `MacroStream`.
49#[derive(Debug, Error)]
50pub struct ParseError {
51    #[source]
52    pub error: ParseErrorKind,
53    pub span: Span,
54    pub level: Level,
55}
56
57impl ParseError {
58    /// Create a new parse error with the given span and kind.
59    pub fn new(span: Span, error: ParseErrorKind) -> Self {
60        Self {
61            error,
62            span,
63            level: Level::Error,
64        }
65    }
66
67    /// Create a new parse error with the given kind and the `Span::call_site()` span.
68    pub fn call_site(error: ParseErrorKind) -> Self {
69        Self {
70            error,
71            span: Span::call_site(),
72            level: Level::Error,
73        }
74    }
75
76    /// Convert the error into a `proc_macro_error::Diagnostic`.
77    pub fn into_diagnostic(self) -> Diagnostic {
78        Diagnostic::spanned(self.span, self.level, self.error.to_string())
79    }
80
81    /// Add a message to the error if it is an `UnexpectedEndOfInput` error.
82    pub fn unexpected_end_of_input(&mut self, msg: &str) {
83        if let ParseErrorKind::UnexpectedEndOfInput(s) = &mut self.error {
84            s.push_str(msg);
85        }
86    }
87}
88
89impl Display for ParseError {
90    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
91        self.error.fmt(f)
92    }
93}
94
95impl From<ParseError> for Diagnostic {
96    fn from(error: ParseError) -> Diagnostic {
97        error.into_diagnostic()
98    }
99}
100
101/// The specific kind of parse error encountered.
102#[non_exhaustive]
103#[derive(Debug, Error)]
104pub enum ParseErrorKind {
105    #[error("Unknown literal: {0}")]
106    UnknownLiteral(String),
107    #[error("Invalid byte with value {0}")]
108    InvalidByte(u8),
109    #[error("Invalid escape character with byte value {0}")]
110    InvalidEscapeCharacter(u8),
111    #[error("The suffix of a numerical literal cannot start with the letter e")]
112    SuffixNoE,
113    #[error("Invalid digit {0} for base {1}")]
114    InvalidDigit(u8, u8),
115    #[error("A float literal cannot contain multiple decimal points")]
116    MultipleDecimalPointsInFloat,
117    #[error("A float literal cannot contain multiple exponent parts")]
118    MultipleExponentsInFloat,
119    #[error("A float literal cannot contain a sign in outside the exponent")]
120    UnexpectedSignInFloat,
121    #[error("A float literal cannot contain multiple signs in the exponent")]
122    MultipleSignsInFloat,
123    #[error("The exponent of a float literal must have at least one digit")]
124    MissingExponentDigits,
125    #[error("A unicode escape sequence must start with a {{")]
126    MissingUnicodeOpeningBrace,
127    #[error("A unicode escape sequence must end with a }}")]
128    TooManyUnicodeDigits,
129    #[error("A unicode escape sequence must have at least one digit")]
130    MissingUnicodeDigits,
131    #[error("Unexpected end of input, message: {0}")]
132    UnexpectedEndOfInput(String),
133    #[error("Expected {0:?}, but found {1:?}")]
134    Expected(Token, Token),
135    #[error("No matching choice found")]
136    NoMatchingChoice,
137    #[error("Expected a group delimited by {0}")]
138    ExpectedGroup(Delimiter),
139    #[error("Input is too long")]
140    InputTooLong,
141    #[error("Expected one or more repetitions, but found none")]
142    ExpectedRepetition,
143    #[error("Validator must have a non-validator pattern preceding it")]
144    InvalidValidatorPosition,
145    #[error("Validator failed with message: {0}")]
146    ValidatorFailed(String),
147}