elise_derive/
lib.rs

1#![recursion_limit = "128"]
2
3#[macro_use]
4extern crate synstructure;
5#[macro_use]
6extern crate quote;
7
8extern crate proc_macro;
9
10mod accessors;
11mod null_trace;
12mod reroot;
13mod trace;
14
15use proc_macro2::*;
16use syn::buffer::TokenBuffer;
17use syn::punctuated::Punctuated;
18use syn::*;
19
20use crate::accessors::accessors;
21use crate::null_trace::null_trace_impl;
22use crate::reroot::reroot_impl;
23use crate::trace::trace_impl;
24
25decl_derive!([GC, attributes(gc)] => gc_derive);
26
27fn gc_derive(s: synstructure::Structure) -> TokenStream {
28    let tagged_fields = tagged_fields(&s);
29    let accessors = accessors(&s, &tagged_fields[..]);
30    let trace_impl = trace_impl(&s);
31    let reroot_impl = reroot_impl(&s);
32    let null_trace_impl = null_trace_impl(&s);
33    let gc_impl = gc_impl(&s);
34    quote! {
35        #accessors
36        #trace_impl
37        #reroot_impl
38        #null_trace_impl
39        #gc_impl
40    }
41}
42
43fn gc_impl(s: &synstructure::Structure) -> TokenStream {
44    s.gen_impl(quote! {
45        extern crate elise;
46
47        gen impl<'__root> elise::GC<'__root> for @Self {
48        }
49    })
50}
51
52fn tagged_fields<'a>(s: &'a synstructure::Structure<'a>) -> Vec<&'a synstructure::BindingInfo<'a>> {
53    s.variants()
54        .iter()
55        .flat_map(|v| v.bindings())
56        .filter(|binding| binding.ast().attrs.iter().any(|attr| is_attr(attr, "gc")))
57        .collect()
58}
59
60fn is_attr(attr: &syn::Attribute, ident: &str) -> bool {
61    attr.path.segments.last().unwrap().value().ident == ident
62}
63
64fn has_attr(s: &synstructure::Structure, ident: &str) -> bool {
65    if let Some(attr) = s.ast().attrs.iter().find(|attr| is_attr(attr, "gc")) {
66        let attr_content = attr.tts.clone().into_iter().next().unwrap();
67        if let TokenTree::Group(attr_content) = attr_content {
68            let buffer = TokenBuffer::new2(attr_content.stream());
69            let idents = Punctuated::<Ident, token::Comma>::parse_terminated(buffer.begin())
70                .unwrap()
71                .0;
72            idents.into_iter().any(|i| i == ident)
73        } else {
74            false
75        }
76    } else {
77        false
78    }
79}