1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
|
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<MappedValue<'a>> {{
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()
}
|