kons-macros 0.1.0

variadic tuples
Documentation
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
}