zng_var_proc_macros/
util.rsuse proc_macro2::{Span, TokenStream, TokenTree};
use quote::ToTokens;
pub fn token_stream_eq(a: TokenStream, b: TokenStream) -> bool {
let mut a = a.into_iter();
let mut b = b.into_iter();
use TokenTree::*;
loop {
match (a.next(), b.next()) {
(Some(a), Some(b)) => match (a, b) {
(Group(a), Group(b)) if a.delimiter() == b.delimiter() && token_stream_eq(a.stream(), b.stream()) => continue,
(Ident(a), Ident(b)) if a == b => continue,
(Punct(a), Punct(b)) if a.as_char() == b.as_char() && a.spacing() == b.spacing() => continue,
(Literal(a), Literal(b)) if a.to_string() == b.to_string() => continue,
_ => return false,
},
(None, None) => return true,
_ => return false,
}
}
}
pub fn tokens_to_ident_str(tokens: &TokenStream) -> String {
let tokens = tokens.to_string();
let max = tokens.len().min(40);
let mut tokens = tokens[(tokens.len() - max)..]
.replace(&['.', ':', ' '][..], "_")
.replace('!', "not")
.replace("&&", "and")
.replace("||", "or")
.replace('(', "p")
.replace(')', "b")
.replace("==", "eq");
tokens.retain(|c| c == '_' || c.is_alphanumeric());
tokens
}
#[derive(Default)]
pub struct Errors {
tokens: TokenStream,
}
impl Errors {
pub fn push(&mut self, error: impl ToString, span: Span) {
let error = error.to_string();
self.tokens.extend(quote_spanned! {span=>
compile_error!{#error}
})
}
pub fn is_empty(&self) -> bool {
self.tokens.is_empty()
}
}
impl ToTokens for Errors {
fn to_tokens(&self, tokens: &mut TokenStream) {
tokens.extend(self.tokens.clone())
}
fn to_token_stream(&self) -> TokenStream {
self.tokens.clone()
}
fn into_token_stream(self) -> TokenStream {
self.tokens
}
}
macro_rules! abort {
($span:expr, $($tt:tt)*) => {{
let error = format!($($tt)*);
let error = syn::LitStr::new(&error, proc_macro2::Span::call_site());
return quote_spanned!($span=> compile_error!{#error}).into();
}};
}
macro_rules! abort_call_site {
($($tt:tt)*) => {
abort!(proc_macro2::Span::call_site(), $($tt)*)
};
}
macro_rules! non_user_error {
($e:expr) => {
panic!("[{}:{}] invalid non-user input: {}", file!(), line!(), $e)
};
($fmt:tt, $($args:tt)+) => {
non_user_error! {
format_args!($fmt, $($args)+)
}
}
}
macro_rules! ident_spanned {
($span:expr=> $($format_name:tt)+) => {
proc_macro2::Ident::new(&format!($($format_name)+), $span)
};
}
macro_rules! ident {
($($tt:tt)*) => {
ident_spanned!(proc_macro2::Span::call_site()=> $($tt)*)
};
}