zng_var_proc_macros/
util.rs
1use proc_macro2::{Span, TokenStream, TokenTree};
2use quote::ToTokens;
3
4pub fn token_stream_eq(a: TokenStream, b: TokenStream) -> bool {
6 let mut a = a.into_iter();
7 let mut b = b.into_iter();
8 use TokenTree::*;
9 loop {
10 match (a.next(), b.next()) {
11 (Some(a), Some(b)) => match (a, b) {
12 (Group(a), Group(b)) if a.delimiter() == b.delimiter() && token_stream_eq(a.stream(), b.stream()) => continue,
13 (Ident(a), Ident(b)) if a == b => continue,
14 (Punct(a), Punct(b)) if a.as_char() == b.as_char() && a.spacing() == b.spacing() => continue,
15 (Literal(a), Literal(b)) if a.to_string() == b.to_string() => continue,
16 _ => return false,
17 },
18 (None, None) => return true,
19 _ => return false,
20 }
21 }
22}
23
24pub fn tokens_to_ident_str(tokens: &TokenStream) -> String {
26 let tokens = tokens.to_string();
27 let max = tokens.len().min(40);
28 let mut tokens = tokens[(tokens.len() - max)..]
29 .replace(&['.', ':', ' '][..], "_")
30 .replace('!', "not")
31 .replace("&&", "and")
32 .replace("||", "or")
33 .replace('(', "p")
34 .replace(')', "b")
35 .replace("==", "eq");
36
37 tokens.retain(|c| c == '_' || c.is_alphanumeric());
38
39 tokens
40}
41
42#[derive(Default)]
44pub struct Errors {
45 tokens: TokenStream,
46}
47impl Errors {
48 pub fn push(&mut self, error: impl ToString, span: Span) {
50 let error = error.to_string();
51 self.tokens.extend(quote_spanned! {span=>
52 compile_error!{#error}
53 })
54 }
55
56 pub fn is_empty(&self) -> bool {
57 self.tokens.is_empty()
58 }
59}
60impl ToTokens for Errors {
61 fn to_tokens(&self, tokens: &mut TokenStream) {
62 tokens.extend(self.tokens.clone())
63 }
64 fn to_token_stream(&self) -> TokenStream {
65 self.tokens.clone()
66 }
67 fn into_token_stream(self) -> TokenStream {
68 self.tokens
69 }
70}
71
72macro_rules! abort {
74 ($span:expr, $($tt:tt)*) => {{
75 let error = format!($($tt)*);
76 let error = syn::LitStr::new(&error, proc_macro2::Span::call_site());
77
78 return quote_spanned!($span=> compile_error!{#error}).into();
79 }};
80}
81
82macro_rules! abort_call_site {
84 ($($tt:tt)*) => {
85 abort!(proc_macro2::Span::call_site(), $($tt)*)
86 };
87}
88
89macro_rules! non_user_error {
91 ($e:expr) => {
92 panic!("[{}:{}] invalid non-user input: {}", file!(), line!(), $e)
93 };
94 ($fmt:tt, $($args:tt)+) => {
95 non_user_error! {
96 format_args!($fmt, $($args)+)
97 }
98 }
99}
100
101macro_rules! ident_spanned {
103 ($span:expr=> $($format_name:tt)+) => {
104 proc_macro2::Ident::new(&format!($($format_name)+), $span)
105 };
106}
107
108macro_rules! ident {
110 ($($tt:tt)*) => {
111 ident_spanned!(proc_macro2::Span::call_site()=> $($tt)*)
112 };
113}