superfilter_macro/
lib.rs

1//! This is a support library for poe-superfilter, it contains procedural macros needed in it.
2
3#![recursion_limit="128"]
4
5extern crate proc_macro;
6extern crate syn;
7#[macro_use] extern crate quote;
8
9use syn::{DeriveInput, Variant};
10use proc_macro::TokenStream;
11
12fn impl_match_variants<F>(ast: &DeriveInput, gen_code: F) -> quote::Tokens
13    where F: Fn(&Variant) -> quote::Tokens {
14    if let &syn::Body::Enum(ref variants) = &ast.body {
15        let name = &ast.ident;
16        let mut impl_variants = quote::Tokens::new();
17        for v in variants {
18            let v_ident = &v.ident;
19            let code = gen_code(&v);
20            impl_variants.append(quote! {
21                #name::#v_ident #code,
22            });
23        }
24
25        impl_variants
26    } else {
27        panic!("This derive only works for enums")
28    }
29}
30
31/// Macro for custom derive of the Transform Trait
32#[proc_macro_derive(Transform)]
33pub fn inner_transform(input: TokenStream) -> TokenStream {
34    // Construct a string representation of the type definition
35    let s = input.to_string();
36
37    // Parse the string representation
38    let ast = syn::parse_macro_input(&s).unwrap();
39
40    // Build the impl
41    let gen = impl_transform(&ast);
42
43    // Return the generated impl
44    gen.parse().unwrap()
45}
46
47fn impl_transform(ast: &DeriveInput) -> quote::Tokens {
48    let name = &ast.ident;
49    let transform_variants = impl_match_variants(&ast, |_| {
50        quote! { (ref n) => { n.transform(ctx) } }
51    });
52
53    let location_variants = impl_match_variants(&ast, |_| {
54        quote! { (ref n) => { n.location() } }
55    });
56
57    quote! {
58        impl Transform for #name {
59            fn transform(&self, ctx: TransformContext)
60                -> Result<Option<TransformedNode>> {
61                match *self {
62                    #transform_variants
63                }
64            }
65
66            fn location(&self) -> AstLocation {
67                match *self {
68                    #location_variants
69                }
70            }
71        }
72    }
73}
74
75/// Macro for custom derive of the TransformResult Trait
76#[proc_macro_derive(TransformResult)]
77pub fn inner_transform_result(input: TokenStream) -> TokenStream {
78    // Construct a string representation of the type definition
79    let s = input.to_string();
80
81    // Parse the string representation
82    let ast = syn::parse_macro_input(&s).unwrap();
83
84    // Build the impl
85    let gen = impl_transform_result(&ast);
86
87    // Return the generated impl
88    gen.parse().unwrap()
89}
90
91fn impl_transform_result(ast: &DeriveInput) -> quote::Tokens {
92    let name = &ast.ident;
93    let return_variants = impl_match_variants(&ast, |_| {
94        quote! { (ref n) => { n.return_value() } }
95    });
96
97    let render_variants = impl_match_variants(&ast, |_| {
98        quote! { (ref n) => { n.render(ctx, buf) } }
99    });
100
101    quote! {
102        impl TransformResult for #name {
103            fn return_value(&self) -> ScopeValue {
104                match *self {
105                    #return_variants
106                }
107            }
108
109            /// Renders the output for this node into a writable stream.
110            fn render(&self, ctx: RenderContext, buf: &mut Write) -> Result<()> {
111                match *self {
112                    #render_variants
113                }
114            }
115        }
116    }
117}
118
119/// Macro for custom derive of the TransformResult Trait
120#[proc_macro_derive(InnerScopeValue)]
121pub fn inner_scope_value(input: TokenStream) -> TokenStream {
122    // Construct a string representation of the type definition
123    let s = input.to_string();
124
125    // Parse the string representation
126    let ast = syn::parse_macro_input(&s).unwrap();
127
128    // Build the impl
129    let gen = impl_inner_scope_value(&ast);
130
131    // Return the generated impl
132    gen.parse().unwrap()
133}
134
135fn impl_inner_scope_value(ast: &DeriveInput) -> quote::Tokens {
136    let name = &ast.ident;
137    let add_variants = impl_match_variants(&ast, |_| {
138        quote! { (v) => { v.try_add(other.try_into()?) } }
139    });
140    let mul_variants = impl_match_variants(&ast, |_| {
141        quote! { (v) => { v.try_mul(other.try_into()?) } }
142    });
143    let sub_variants = impl_match_variants(&ast, |_| {
144        quote! { (v) => { v.try_sub(other.try_into()?) } }
145    });
146    let div_variants = impl_match_variants(&ast, |_| {
147        quote! { (v) => { v.try_div(other.try_into()?) } }
148    });
149    let cmp_variants = impl_match_variants(&ast, |_| {
150        quote! { (ref v) => { v.try_cmp(other.try_into()?) } }
151    });
152    let eq_variants = impl_match_variants(&ast, |_| {
153        quote! { (ref v) => { v.try_eq(other.try_into()?) } }
154    });
155    let type_name_variants = impl_match_variants(&ast, |_| {
156        quote! { (ref v) => { v.type_name() } }
157    });
158
159    quote! {
160        impl InnerScopeValue for #name {
161            fn try_add(self, other: Self) -> Result<Self> {
162                match self {
163                    #add_variants
164                }
165            }
166
167            fn try_sub(self, other: Self) -> Result<Self> {
168                match self {
169                    #sub_variants
170                }
171            }
172
173            fn try_mul(self, other: Self) -> Result<Self> {
174                match self {
175                    #mul_variants
176                }
177            }
178
179            fn try_div(self, other: Self) -> Result<Self> {
180                match self {
181                    #div_variants
182                }
183            }
184
185            fn try_cmp(&self, other: Self) -> Result<Ordering> {
186                match *self {
187                    #cmp_variants
188                }
189            }
190
191            fn try_eq(&self, other: Self) -> Result<bool> {
192                match *self {
193                    #eq_variants
194                }
195            }
196
197            fn type_name(&self) -> &'static str {
198                match *self {
199                    #type_name_variants
200                }
201            }
202        }
203    }
204}