v9_attr/attr.rs
1//! Attribute macro wrappers for `v9`'s `decl_` series of macros.
2
3extern crate proc_macro;
4use crate::proc_macro::*;
5use std::str::FromStr;
6
7fn make(name: &str, input: TokenStream) -> TokenStream {
8 // Not sure why this doesn't work.
9 /*
10 let mut out = TokenStream::new();
11 out.extend(vec![
12 TokenTree::Ident(Ident::new("v9", span)),
13 TokenTree::Punct(Punct::new(':', Spacing::Joint)),
14 TokenTree::Punct(Punct::new(':', Spacing::Alone)),
15 TokenTree::Ident(Ident::new(name, span)),
16 TokenTree::Punct(Punct::new('!', Spacing::Alone)),
17 TokenTree::Group(Group::new(Delimiter::Brace, input.clone())),
18 ]);
19 */
20 let ret = FromStr::from_str(&format!("v9::{}! {{ {} }}", name, input)).unwrap();
21 //println!("{:#?}", ret);
22 ret
23}
24
25// FIXME: Use Span::def_site().
26
27/// Wrapper around [`v9::decl_table!`](../v9/macro.decl_table.html).
28#[proc_macro_attribute]
29pub fn table(_attr: TokenStream, input: TokenStream) -> TokenStream {
30 make("decl_table", input)
31}
32
33/// Wrapper around [`v9::decl_context!`](../v9/macro.decl_context.html).
34#[proc_macro_attribute]
35pub fn context(_attr: TokenStream, input: TokenStream) -> TokenStream {
36 make("decl_context", input)
37}
38
39/// A *sorta* wrapper around [`v9::decl_property!`](../v9/macro.decl_property.html).
40/// There are two complications:
41/// 1. This is pretty much inherently only going to work on local types, so the `~i32` thing doesn't work.
42///
43/// 2. The struct must `impl Default`. (Well, I guess there could be a `struct Foo {} = init;` thing,
44/// but that'd look weird!)
45#[proc_macro_attribute]
46pub fn property(_attr: TokenStream, input: TokenStream) -> TokenStream {
47 // #[property(cheese_db)]
48 // pub struct Cheeses;
49 let mut vis = TokenStream::new();
50 let mut hit_struct = false;
51 let mut struct_name = None;
52 for t in input.clone().into_iter() {
53 // '#'? Skip. '[]'? Skip.
54 // 'struct'? The name follows.
55 // Anything else? Prolly the visibility
56 match t {
57 TokenTree::Punct(ref p) if p.as_char() == '#' => (),
58 TokenTree::Group(ref g) if g.delimiter() == Delimiter::Bracket => (),
59 TokenTree::Ident(ref i) if &i.to_string() == "struct" => hit_struct = true,
60 TokenTree::Ident(ref i) if hit_struct => {
61 struct_name = Some(i.clone());
62 break;
63 },
64 t => vis.extend(Some(t)),
65 }
66 }
67 let struct_name = struct_name.expect("expected 'struct name' or something");
68 let out = format!(r#"
69{input}
70mod _v9_property_call_{name} {{
71 type TheType = super::{name};
72 v9::decl_property! {{ {vis} {name}: TheType }}
73}}
74"#, input=input, vis=vis, name=struct_name);
75 let ret = FromStr::from_str(&out).unwrap();
76 ret
77}