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}