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
74
75
|
extern crate proc_macro;
use proc_macro::{TokenStream,TokenTree,Ident,Delimiter};
#[proc_macro_derive(CrimtagMappable)]
pub fn derive_crimtag_mappable(s: TokenStream) -> TokenStream {
let mut i = 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 = g.stream().into_iter();
let mut cur = 0usize;
let mut tok = [gi.next(), gi.next()];
loop {
if let Some(TokenTree::Punct(ch)) = &tok[(cur+1)%2] &&
ch.as_char() == ':' &&
let Some(TokenTree::Ident(id)) = &tok[cur] {
println!("!!!!!!!!!! -> {}", id);
newfunc.push_str(&format!(
r#" "{}" => Some(self.{}.into()),
"#, id, id));
}
println!(" - {:?} {:?}", tok[cur], tok[(cur+1)%2] );
// Update next.
if let Some(ni) = gi.next() {
tok[cur].replace( ni );
cur = (cur+1)%2;
} else {
break;
}
}
}
}
newfunc.push_str(
r#" _ => None,
}
}
}"#);
println!();
println!();
println!("{}", newfunc);
println!();
println!();
newfunc.parse().unwrap()
}
|