extern crate proc_macro; use proc_macro::TokenStream; use syn::{parse_macro_input, DeriveInput, LitStr}; use quote::{quote, ToTokens}; mod nfa; #[proc_macro_attribute] pub fn bird_machine(args: TokenStream, input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); let input_regex = parse_macro_input!(args as LitStr); let input_type_name = &input.ident; let input_lifetimes: Vec<_> = input.generics.lifetimes().collect(); let lifetime = match input_lifetimes.as_slice() { [] => quote!{ 'unrestricted }, [lt] => quote!{ #lt }, _ => panic!("multiple lifetime generics, what is this, pls to halp"), }; let machine = build_machine(&input_regex); dbg!(&machine); let (_, ty_generics, where_clause) = input.generics.split_for_impl(); let impl_decl = quote! { impl<#lifetime> ::bird_machine::Machine<#lifetime> for #input_type_name #ty_generics #where_clause }; let original_regex = quote! { const ORIGINAL_REGEX: &'static str = #input_regex; }; let captures = quote! { fn captures(text: &#lifetime str) -> Option { todo!() } }; let captures_iter = quote! { type CaptureIterator = ::std::iter::Empty; fn captures_iter(text: &#lifetime str) -> Self::CaptureIterator { todo!() } }; let find = quote! { fn find(text: &#lifetime str) -> Option<::bird_machine::Match<#lifetime>> { todo!() } }; let find_at = quote! { fn find_at(text: &#lifetime str, start: usize) -> Option<::bird_machine::Match<#lifetime>> { todo!() } }; let find_iter = quote! { type FindIterator = ::std::iter::Empty<::bird_machine::Match<#lifetime>>; fn find_iter(text: &#lifetime str) -> Self::FindIterator { todo!() } }; let is_match = quote! { fn is_match(text: &#lifetime str) -> bool { todo!() } }; let is_match_at = quote! { fn is_match_at(text: &#lifetime str, start: usize) -> bool { todo!() } }; let replace = quote! { fn replace( text: &#lifetime str, rep: impl ::bird_machine::Replacer<#lifetime, Self>, ) -> ::std::borrow::Cow<#lifetime, str> { todo!() } }; let replace_all = quote! { fn replace_all( text: &#lifetime str, rep: impl ::bird_machine::Replacer<#lifetime, Self>, ) -> ::std::borrow::Cow<#lifetime, str> { todo!() } }; let replacen = quote! { fn replacen( text: &#lifetime str, limit: usize, rep: impl ::bird_machine::Replacer<#lifetime, Self>, ) -> ::std::borrow::Cow<#lifetime, str> { todo!() } }; let split = quote! { type SplitIterator = ::std::iter::Empty<&#lifetime str>; fn split(text: &#lifetime str) -> Self::SplitIterator { todo!() } }; let splitn = quote! { type SplitNIterator = ::std::iter::Empty<&#lifetime str>; fn splitn(text: &#lifetime str, limit: usize) -> Self::SplitNIterator { todo!() } }; let tokens = quote! { #input #machine #impl_decl { #original_regex #captures #captures_iter #find #find_at #find_iter #is_match #is_match_at #replace #replace_all #replacen #split #splitn } }; eprintln!( "{impl_decl} {{\n\n\ {original_regex}\n\n\ {captures}\n\n\ {captures_iter}\n\n\ {find}\n\n\ {find_at}\n\n\ {find_iter}\n\n\ {is_match}\n\n\ {is_match_at}\n\n\ {replace}\n\n\ {replace_all}\n\n\ {replacen}\n\n\ {split}\n\n\ {splitn}\n\n\ }}", impl_decl = impl_decl, original_regex = original_regex, captures = captures, captures_iter = captures_iter, find = find, find_at = find_at, find_iter = find_iter, is_match = is_match, is_match_at = is_match_at, replace = replace, replace_all = replace_all, replacen = replacen, split = split, splitn = splitn, ); tokens.into() } fn build_machine(regex: &LitStr) -> proc_macro2::TokenStream { let regex_text = regex.value(); let regex_ir = regex_syntax::Parser::new() .parse(®ex_text); let regex_ir = match regex_ir { Ok(x) => x, Err(err ) => panic!("error compiling regex {}: {}", regex.to_token_stream(), err), }; dbg!(®ex_ir); // shout out to all the professors who've taught me how to do this let mut built_nfa = nfa::NFA::default(); todo!() }