use proc_macro::*;
fn cat(stream: TokenStream, rest: impl IntoIterator<Item = TokenTree>) -> TokenStream {
let mut stream = stream;
stream.extend(rest);
stream
}
fn ident(ident: &str) -> TokenTree {
TokenTree::Ident(Ident::new(ident, Span::call_site()))
}
fn punct(c: char) -> TokenTree {
TokenTree::Punct(Punct::new(c, Spacing::Alone))
}
#[proc_macro]
pub fn kons_impl(stream: TokenStream) -> TokenStream {
let mut stream = stream.into_iter();
let Some(TokenTree::Group(krate)) = stream.next() else { panic!() };
let krate = &krate.stream();
let Some(TokenTree::Group(nil)) = stream.next() else { panic!() };
let mut out = nil.stream();
let mut stream = Vec::from_iter(stream).into_iter();
while let Some(item) = stream.next_back() {
let TokenTree::Group(item) = item else { panic!() };
let mut item = item.stream();
let mut here = TokenStream::new();
loop {
let mut iter = item.into_iter();
let first = iter.next();
let second = iter.next();
match (first, second) {
(Some(TokenTree::Group(first)), None) if first.delimiter() == Delimiter::None => item = first.stream(),
(first, second) => {
here.extend([first, second].into_iter().flatten().chain(iter));
break;
},
}
}
out = cat(
krate.clone(),
[
ident("List"),
Group::new(
Delimiter::Brace,
TokenStream::from_iter(
TokenStream::new()
.into_iter()
.chain([ident("here"), punct(':')])
.chain(here)
.chain([punct(','), ident("there"), punct(':')])
.chain(out)
.chain([punct(',')]),
),
)
.into(),
],
);
}
out
}