syn_error_experiment/
error.rs

1use std;
2use std::fmt::{self, Display};
3use std::iter::FromIterator;
4
5use proc_macro2::{
6    Delimiter, Group, Ident, LexError, Literal, Punct, Spacing, Span, TokenStream, TokenTree,
7};
8
9use syn::buffer::Cursor;
10
11/// The result of a Syn parser.
12pub type Result<T> = std::result::Result<T, Error>;
13
14/// Error returned when a Syn parser cannot parse the input tokens.
15#[derive(Debug)]
16pub struct Error {
17    span: Span,
18    message: String,
19}
20
21impl Error {
22    pub fn new<T: Display>(span: Span, message: T) -> Self {
23        Error {
24            span: span,
25            message: message.to_string(),
26        }
27    }
28
29    /// Render the error as an invocation of [`compile_error!`].
30    ///
31    /// The [`parse_macro_input!`] macro provides a convenient way to invoke
32    /// this method correctly in a procedural macro.
33    ///
34    /// [`compile_error!`]: https://doc.rust-lang.org/std/macro.compile_error.html
35    /// [`parse_macro_input!`]: ../macro.parse_macro_input.html
36    pub fn into_compile_error(self) -> TokenStream {
37        // compile_error!($message)
38        TokenStream::from_iter(vec![
39            TokenTree::Ident(Ident::new("compile_error", self.span)),
40            TokenTree::Punct({
41                let mut punct = Punct::new('!', Spacing::Alone);
42                punct.set_span(self.span);
43                punct
44            }),
45            TokenTree::Group({
46                let mut group = Group::new(Delimiter::Brace, {
47                    TokenStream::from_iter(vec![TokenTree::Literal({
48                        let mut string = Literal::string(&self.message);
49                        string.set_span(self.span);
50                        string
51                    })])
52                });
53                group.set_span(self.span);
54                group
55            }),
56        ])
57    }
58}
59
60// Not public API.
61#[doc(hidden)]
62pub fn new_at<T: Display>(scope: Span, cursor: Cursor, message: T) -> Error {
63    if cursor.eof() {
64        Error::new(scope, format!("unexpected end of input, {}", message))
65    } else {
66        Error::new(cursor.span(), message)
67    }
68}
69
70impl Display for Error {
71    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
72        formatter.write_str(&self.message)
73    }
74}
75
76impl std::error::Error for Error {
77    fn description(&self) -> &str {
78        "parse error"
79    }
80}
81
82impl From<LexError> for Error {
83    fn from(err: LexError) -> Self {
84        Error::new(Span::call_site(), format!("{:?}", err))
85    }
86}