const_format_proc_macros/
error.rs
1use crate::spanned::Spans;
2
3use proc_macro2::{
4 Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream as TokenStream2,
5 TokenTree as TokenTree2,
6};
7
8use std::fmt::Display;
9
10#[derive(Debug, Clone)]
11pub struct Error {
12 messages: Vec<CompileError>,
13}
14
15#[derive(Debug, Clone)]
16enum CompileError {
17 Basic {
18 start_span: Span,
19 end_span: Span,
20 msg: String,
21 },
22 #[cfg(feature = "derive")]
23 Syn(TokenStream2),
24}
25
26impl Error {
27 pub fn new<T: Display>(span: Span, msg: T) -> Self {
28 Error {
29 messages: vec![CompileError::Basic {
30 start_span: span,
31 end_span: span,
32 msg: msg.to_string(),
33 }],
34 }
35 }
36
37 pub fn spanned<T: Display>(spans: Spans, msg: T) -> Self {
38 Error {
39 messages: vec![CompileError::Basic {
40 start_span: spans.start,
41 end_span: spans.end,
42 msg: msg.to_string(),
43 }],
44 }
45 }
46
47 pub fn to_compile_error(&self) -> TokenStream2 {
48 macro_rules! tokenstream{
49 ($($tt:expr),* $(,)*) => ({
50 let list: Vec<TokenTree2> = vec![
51 $($tt.into(),)*
52 ];
53 list.into_iter().collect::<TokenStream2>()
54 })
55 }
56
57 self.messages
58 .iter()
59 .map(|em| match em {
60 CompileError::Basic {
61 start_span,
62 end_span,
63 msg,
64 } => {
65 let ts = tokenstream![
66 Ident::new("compile_error", *start_span),
67 {
68 let mut this = Punct::new('!', Spacing::Alone);
69 this.set_span(*start_span);
70 this
71 },
72 {
73 let mut group = Group::new(
74 Delimiter::Parenthesis,
75 tokenstream![{
76 let mut lit = Literal::string(msg);
77 lit.set_span(*end_span);
78 TokenTree2::Literal(lit)
79 }],
80 );
81 group.set_span(*end_span);
82 group
83 },
84 ];
85
86 let mut this = Group::new(Delimiter::Parenthesis, ts);
89 this.set_span(*end_span);
90 tokenstream![this]
91 }
92 #[cfg(feature = "derive")]
93 CompileError::Syn(x) => x.clone(),
94 })
95 .collect()
96 }
97
98 pub fn combine(&mut self, another: Error) {
99 self.messages.extend(another.messages)
100 }
101}
102
103#[cfg(feature = "derive")]
104impl From<syn::Error> for Error {
105 fn from(err: syn::Error) -> Self {
106 Self {
107 messages: vec![CompileError::Syn(err.to_compile_error())],
108 }
109 }
110}