extern crate proc_macro; use proc_macro::{TokenStream,TokenTree,/*Ident,*/Delimiter}; use lookahead::LookAhead; #[proc_macro_derive(CrimtagMappable)] pub fn derive_crimtag_mappable(s: TokenStream) -> TokenStream { let mut i = LookAhead::<2,_,_>::new(s.into_iter()); while let Some(t) = i.next() { if let TokenTree::Ident(ident) = t && ident.to_string() == "struct" { break; } } let name = if let Some(TokenTree::Ident(ident)) = i.next() { ident.to_string() } else { panic!("No name found in struct."); }; // TODO: Expand this to include the generic parameters and the where? at // least the parameters. //println!("struct name: {:?}", name); let mut newfunc = format!( r#"impl<'a> crimtag::MappedStructure<'a> for {} {{ fn get_value(&'a self, id: &str) -> Option> {{ match id {{ "#, name); // We're going to cheat. Every field name is followed directly by a colon, // so all we really need to do is hunt for colons and then take the // previous item. while let Some(n) = i.next() { if let TokenTree::Group(g) = &n && g.delimiter() == Delimiter::Brace { // Operate on the struct members. let mut gi = LookAhead::<2,_,_>::new(g.stream().into_iter()); loop { if let Some(TokenTree::Punct(ch)) = gi.peek(1) && ch.as_char() == ':' && let Some(TokenTree::Ident(id)) = gi.peek(0) { //println!("!!!!!!!!!! -> {}", id); newfunc.push_str(&format!( r#" "{}" => Some((&self.{}).into()), "#, id, id)); } //println!(" -> {:?} ", gi.peek(0)); //println!(" {:?}", gi.peek(1) ); // Update next. if gi.next().is_none() { break; } } } } newfunc.push_str( r#" _ => None, } } }"#); /* println!(); println!(); println!("{}", newfunc); println!(); println!(); */ newfunc.parse().unwrap() }