use std::collections::HashMap;
use proc_macro::{TokenTree as TT, *};
use uuid::Uuid;
fn replace_syms(tokens: TokenStream, named_syms: &mut HashMap<String, Ident>) -> TokenStream {
let mut tokens = tokens.into_iter().peekable();
let mut out = TokenStream::new();
loop {
out.extend(Some(match tokens.next() {
Some(ref p1 @ TT::Punct(ref punct)) if punct.as_char() == '/' => match tokens.peek() {
Some(TT::Punct(ref punct)) if punct.as_char() == '?' => {
let p2 = tokens.next().unwrap();
match tokens.peek() {
Some(TT::Punct(punct)) if punct.as_char() == '@' => {
tokens.next();
match tokens.next() {
Some(TT::Ident(name)) => {
let name =
named_syms.entry(name.to_string()).or_insert_with(gen_sym);
match tokens.next() {
Some(TT::Punct(ref punct)) if punct.as_char() == '/' => {
TT::Ident(name.clone())
}
Some(tok) => tok,
None => break,
}
}
Some(tok) => tok,
None => break,
}
}
Some(TT::Punct(punct)) if punct.as_char() == '/' => {
tokens.next();
TT::Ident(gen_sym())
}
_ => p2,
}
}
_ => p1.clone(),
},
Some(TT::Group(group)) => {
Group::new(group.delimiter(), replace_syms(group.stream(), named_syms)).into()
}
Some(tok) => tok,
None => break,
}))
}
out
}
#[proc_macro]
pub fn randsym(input: TokenStream) -> TokenStream {
let mut named_syms = HashMap::new();
replace_syms(input, &mut named_syms)
}
fn gen_sym() -> Ident {
Ident::new(
&format!("_randsym_{}", Uuid::new_v4().simple()),
Span::call_site(),
)
}