moniker_derive/
lib.rs

1#![recursion_limit = "128"]
2
3extern crate quote;
4extern crate syn;
5#[macro_use]
6extern crate synstructure;
7extern crate proc_macro2;
8
9use synstructure::{BindStyle, Structure};
10
11decl_derive!([BoundTerm] => bound_term_derive);
12
13fn bound_term_derive(mut s: Structure) -> proc_macro2::TokenStream {
14    s.bind_with(|_| BindStyle::Ref);
15    let term_eq_body = {
16        let body = s.variants().iter().fold(quote!(), |acc, v| {
17            // Create two sets of bindings, one for the lhs, and another for the rhs
18            let mut lhs = v.clone();
19            let mut rhs = v.clone();
20            lhs.binding_name(|_, i| {
21                syn::Ident::new(
22                    &format!("__binding_lhs_{}", i),
23                    proc_macro2::Span::call_site(),
24                )
25            });
26            rhs.binding_name(|_, i| {
27                syn::Ident::new(
28                    &format!("__binding_rhs_{}", i),
29                    proc_macro2::Span::call_site(),
30                )
31            });
32
33            let lhs_pat = lhs.pat();
34            let rhs_pat = rhs.pat();
35
36            // build up the alpha-equality expression for this variant
37            let arm_body = <_>::zip(lhs.bindings().iter(), rhs.bindings()).fold(
38                quote!(true),
39                |acc, (lhs, rhs)| {
40                    quote! { #acc && moniker::BoundTerm::<String>::term_eq(#lhs, #rhs) }
41                },
42            );
43
44            quote! { #acc (&#lhs_pat, &#rhs_pat) => #arm_body, }
45        });
46
47        // Avoid the 'unreachable match' warning for types with zero or one variants
48        match s.variants().len() {
49            0 | 1 => body,
50            _ => quote! { #body (_, _) => false },
51        }
52    };
53
54    s.bind_with(|_| BindStyle::RefMut);
55    let close_term_body = s.each(|bi| {
56        quote!{ moniker::BoundTerm::<String>::close_term(#bi, __state, __on_free); }
57    });
58    let open_term_body = s.each(|bi| {
59        quote!{ moniker::BoundTerm::<String>::open_term(#bi, __state, __on_bound); }
60    });
61
62    s.bind_with(|_| BindStyle::Ref);
63    let visit_vars_body = s.each(|bi| {
64        quote!{ moniker::BoundTerm::<String>::visit_vars(#bi, __on_var); }
65    });
66    s.bind_with(|_| BindStyle::RefMut);
67    let visit_mut_vars_body = s.each(|bi| {
68        quote!{ moniker::BoundTerm::<String>::visit_mut_vars(#bi, __on_var); }
69    });
70
71    s.gen_impl(quote! {
72        extern crate moniker;
73
74        gen impl moniker::BoundTerm<String> for @Self {
75            fn term_eq(&self, other: &Self) -> bool {
76                match (self, other) { #term_eq_body }
77            }
78
79            fn close_term(
80                &mut self,
81                __state: moniker::ScopeState,
82                __on_free: &impl moniker::OnFreeFn<String>,
83            ) {
84                match *self { #close_term_body }
85            }
86
87            fn open_term(
88                &mut self,
89                __state: moniker::ScopeState,
90                __on_bound: &impl moniker::OnBoundFn<String>,
91            ) {
92                match *self { #open_term_body }
93            }
94
95            fn visit_vars(&self, __on_var: &mut impl FnMut(&moniker::Var<String>)) {
96                match *self { #visit_vars_body }
97            }
98
99            fn visit_mut_vars(&mut self, __on_var: &mut impl FnMut(&mut moniker::Var<String>)) {
100                match *self { #visit_mut_vars_body }
101            }
102        }
103    })
104}
105
106decl_derive!([BoundPattern] => bound_pattern_derive);
107
108fn bound_pattern_derive(mut s: Structure) -> proc_macro2::TokenStream {
109    s.bind_with(|_| BindStyle::Ref);
110    let pattern_eq_body = {
111        let body = s.variants().iter().fold(quote!(), |acc, v| {
112            // Create two sets of bindings, one for the lhs, and another for the rhs
113            let mut lhs = v.clone();
114            let mut rhs = v.clone();
115            lhs.binding_name(|_, i| {
116                syn::Ident::new(
117                    &format!("__binding_lhs_{}", i),
118                    proc_macro2::Span::call_site(),
119                )
120            });
121            rhs.binding_name(|_, i| {
122                syn::Ident::new(
123                    &format!("__binding_rhs_{}", i),
124                    proc_macro2::Span::call_site(),
125                )
126            });
127
128            let lhs_pat = lhs.pat();
129            let rhs_pat = rhs.pat();
130
131            // build up the alpha-equality expression for this variant
132            let arm_body = <_>::zip(lhs.bindings().iter(), rhs.bindings()).fold(
133                quote!(true),
134                |acc, (lhs, rhs)| {
135                    quote! { #acc && moniker::BoundPattern::<String>::pattern_eq(#lhs, #rhs) }
136                },
137            );
138
139            quote! { #acc (&#lhs_pat, &#rhs_pat) => #arm_body, }
140        });
141
142        // Avoid the 'unreachable match' warning for types with zero or one variants
143        match s.variants().len() {
144            0 | 1 => body,
145            _ => quote! { #body (_, _) => false },
146        }
147    };
148
149    s.bind_with(|_| BindStyle::RefMut);
150    let close_pattern_body = s.each(|bi| {
151        quote!{ moniker::BoundPattern::<String>::close_pattern(#bi, __state, __on_free); }
152    });
153    let open_pattern_body = s.each(|bi| {
154        quote!{ moniker::BoundPattern::<String>::open_pattern(#bi, __state, __on_bound); }
155    });
156
157    s.bind_with(|_| BindStyle::Ref);
158    let visit_vars_body = s.each(|bi| {
159        quote!{ moniker::BoundPattern::<String>::visit_vars(#bi, __on_var); }
160    });
161    s.bind_with(|_| BindStyle::RefMut);
162    let visit_mut_vars_body = s.each(|bi| {
163        quote!{ moniker::BoundPattern::<String>::visit_mut_vars(#bi, __on_var); }
164    });
165
166    s.bind_with(|_| BindStyle::Ref);
167    let visit_binders_body = s.each(|bi| {
168        quote!{ moniker::BoundPattern::<String>::visit_binders(#bi, __on_binder); }
169    });
170    s.bind_with(|_| BindStyle::RefMut);
171    let visit_mut_binders_body = s.each(|bi| {
172        quote!{ moniker::BoundPattern::<String>::visit_mut_binders(#bi, __on_binder); }
173    });
174
175    s.gen_impl(quote! {
176        extern crate moniker;
177
178        gen impl moniker::BoundPattern<String> for @Self {
179            fn pattern_eq(&self, other: &Self) -> bool {
180                match (self, other) { #pattern_eq_body }
181            }
182
183            fn close_pattern(
184                &mut self,
185                __state: moniker::ScopeState,
186                __on_free: &impl moniker::OnFreeFn<String>,
187            ) {
188                match *self { #close_pattern_body }
189            }
190
191            fn open_pattern(
192                &mut self,
193                __state: moniker::ScopeState,
194                __on_bound: &impl moniker::OnBoundFn<String>,
195            ) {
196                match *self { #open_pattern_body }
197            }
198
199            fn visit_vars(&self, __on_var: &mut impl FnMut(&moniker::Var<String>)) {
200                match *self { #visit_vars_body }
201            }
202
203            fn visit_mut_vars(
204                &mut self,
205                __on_var: &mut impl FnMut(&mut moniker::Var<String>),
206            ) {
207                match *self { #visit_mut_vars_body }
208            }
209
210            fn visit_binders(&self, __on_binder: &mut impl FnMut(&moniker::Binder<String>)) {
211                match *self { #visit_binders_body }
212            }
213
214            fn visit_mut_binders(
215                &mut self,
216                __on_binder: &mut impl FnMut(&mut moniker::Binder<String>),
217            ) {
218                match *self { #visit_mut_binders_body }
219            }
220        }
221    })
222}