logos_codegen/
error.rs

1use std::fmt;
2
3use beef::lean::Cow;
4use proc_macro2::{Span, TokenStream};
5use quote::quote;
6use quote::{quote_spanned, ToTokens, TokenStreamExt};
7
8pub type Result<T> = std::result::Result<T, Error>;
9
10#[derive(Default)]
11pub struct Errors {
12    collected: Vec<SpannedError>,
13}
14
15impl Errors {
16    pub fn err<M>(&mut self, message: M, span: Span) -> &mut Self
17    where
18        M: Into<Cow<'static, str>>,
19    {
20        self.collected.push(SpannedError {
21            message: message.into(),
22            span,
23        });
24
25        self
26    }
27
28    pub fn render(self) -> Option<TokenStream> {
29        let errors = self.collected;
30
31        match errors.len() {
32            0 => None,
33            _ => Some(quote! {
34                fn _logos_derive_compile_errors() {
35                    #(#errors)*
36                }
37            }),
38        }
39    }
40}
41
42pub struct Error(Cow<'static, str>);
43
44#[derive(Debug)]
45pub struct SpannedError {
46    message: Cow<'static, str>,
47    span: Span,
48}
49
50impl Error {
51    pub fn new<M>(message: M) -> Self
52    where
53        M: Into<Cow<'static, str>>,
54    {
55        Error(message.into())
56    }
57
58    pub fn span(self, span: Span) -> SpannedError {
59        SpannedError {
60            message: self.0,
61            span,
62        }
63    }
64}
65
66impl fmt::Display for Error {
67    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
68        self.0.fmt(f)
69    }
70}
71
72impl fmt::Debug for Error {
73    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
74        fmt::Display::fmt(self, f)
75    }
76}
77
78impl From<regex_syntax::Error> for Error {
79    fn from(err: regex_syntax::Error) -> Error {
80        Error(err.to_string().into())
81    }
82}
83
84impl From<&'static str> for Error {
85    fn from(err: &'static str) -> Error {
86        Error(err.into())
87    }
88}
89
90impl From<String> for Error {
91    fn from(err: String) -> Error {
92        Error(err.into())
93    }
94}
95
96impl From<Error> for Cow<'static, str> {
97    fn from(err: Error) -> Self {
98        err.0
99    }
100}
101
102impl ToTokens for SpannedError {
103    fn to_tokens(&self, tokens: &mut TokenStream) {
104        let message = &*self.message;
105
106        tokens.append_all(quote_spanned!(self.span => {
107            compile_error!(#message)
108        }))
109    }
110}