use proc_macro2::{TokenStream as TokenStream2, TokenTree};
use quote::quote;
use crate::util::debug_trace;
const OPERATOR: char = '$';
const ENTRY_PAT: &str = "entry_pat";
const ASSOC_TS: &str = "assoc_ts";
pub fn substitute(
tokens: &TokenStream2,
entry_pat: &syn::Pat,
assoc_ts: Option<&TokenStream2>,
) -> TokenStream2 {
debug_trace!("substitution pass");
let mut out = Vec::new();
let mut iter = tokens.clone().into_iter().peekable();
while let Some(tt) = iter.next() {
match tt {
TokenTree::Punct(ref punct) if punct.as_char() == OPERATOR => {
if let Some(TokenTree::Ident(ident)) = iter.peek() {
let ident_name = ident.to_string();
debug_trace!("found placeholder: ${}", ident_name);
let replacement = match ident_name.as_str() {
ENTRY_PAT => quote!(#entry_pat),
ASSOC_TS => quote!(#assoc_ts),
_ => {
out.push(TokenTree::Punct(punct.clone()));
continue;
}
};
iter.next();
out.extend(replacement);
continue;
}
out.push(punct.clone().into());
}
TokenTree::Group(group) => {
let inner = substitute(&group.stream(), entry_pat, assoc_ts);
let new_group = proc_macro2::Group::new(group.delimiter(), inner);
out.push(new_group.into());
}
other => out.push(other),
}
}
let result: TokenStream2 = out.into_iter().collect();
debug_trace!("substitution result: {}", result);
result
}