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}