efmt_derive/
lib.rs

1use proc_macro2::TokenStream;
2use quote::{quote, quote_spanned};
3use syn::spanned::Spanned;
4use syn::{parse_macro_input, parse_quote, Data, DeriveInput, Fields, GenericParam, Generics};
5
6#[proc_macro_derive(Parse)]
7pub fn derive_parse_trait(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
8    let input = parse_macro_input!(input as DeriveInput);
9    let name = input.ident;
10    let generics = add_parse_trait_bounds(input.generics);
11    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
12    let parse = generate_parse_fun_body(&input.data);
13    let expanded = quote! {
14        impl #impl_generics crate::parse::Parse for #name #ty_generics #where_clause {
15            fn parse(ts: &mut crate::parse::TokenStream) -> crate::parse::Result<Self> {
16                #parse
17            }
18        }
19    };
20    proc_macro::TokenStream::from(expanded)
21}
22
23fn add_parse_trait_bounds(mut generics: Generics) -> Generics {
24    for param in &mut generics.params {
25        if let GenericParam::Type(ref mut type_param) = *param {
26            type_param.bounds.push(parse_quote!(crate::parse::Parse));
27        }
28    }
29    generics
30}
31
32fn generate_parse_fun_body(data: &Data) -> TokenStream {
33    match *data {
34        Data::Struct(ref data) => match data.fields {
35            Fields::Named(ref fields) => {
36                let parse = fields.named.iter().map(|f| {
37                    let name = &f.ident;
38                    quote_spanned! { f.span() => #name: ts.parse()? }
39                });
40                quote! {
41                    Ok(Self{
42                        #(#parse ,)*
43                    })
44                }
45            }
46            Fields::Unnamed(ref fields) => {
47                assert_eq!(fields.unnamed.len(), 1);
48                quote! { ts.parse().map(Self) }
49            }
50            Fields::Unit => unimplemented!(),
51        },
52        Data::Enum(ref data) => {
53            let arms = data.variants.iter().map(|variant| {
54                let name = &variant.ident;
55                if let Fields::Unnamed(fields) = &variant.fields {
56                    assert_eq!(fields.unnamed.len(), 1);
57                } else {
58                    unimplemented!();
59                }
60                quote_spanned! { variant.span() => if let Ok(x) = ts.parse() {
61                    return Ok(Self::#name(x));
62                }}
63            });
64            quote! {
65                #( #arms )*
66                Err(ts.take_last_error().expect("unreachable"))
67            }
68        }
69        Data::Union(_) => unimplemented!(),
70    }
71}
72
73#[proc_macro_derive(Span)]
74pub fn derive_span_trait(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
75    let input = parse_macro_input!(input as DeriveInput);
76    let name = input.ident;
77    let generics = add_span_trait_bounds(input.generics);
78    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
79    let start_position = generate_span_start_position_method_body(&input.data);
80    let end_position = generate_span_end_position_method_body(&input.data);
81    let expanded = quote! {
82        impl #impl_generics crate::span::Span for #name #ty_generics #where_clause {
83            fn start_position(&self) -> crate::span::Position {
84                #start_position
85            }
86            fn end_position(&self) -> crate::span::Position {
87                #end_position
88            }
89        }
90    };
91    proc_macro::TokenStream::from(expanded)
92}
93
94fn add_span_trait_bounds(mut generics: Generics) -> Generics {
95    for param in &mut generics.params {
96        if let GenericParam::Type(ref mut type_param) = *param {
97            type_param.bounds.push(parse_quote!(crate::span::Span));
98        }
99    }
100    generics
101}
102
103fn generate_span_start_position_method_body(data: &Data) -> TokenStream {
104    match *data {
105        Data::Struct(ref data) => match data.fields {
106            Fields::Named(ref fields) => {
107                if let Some(field) = fields.named.first() {
108                    let name = &field.ident;
109                    quote! { self.#name.start_position() }
110                } else {
111                    unimplemented!()
112                }
113            }
114            Fields::Unnamed(ref fields) => {
115                assert_eq!(fields.unnamed.len(), 1);
116                quote! { self.0.start_position() }
117            }
118            Fields::Unit => unimplemented!(),
119        },
120        Data::Enum(ref data) => {
121            let arms = data.variants.iter().map(|variant| {
122                let name = &variant.ident;
123                if let Fields::Unnamed(fields) = &variant.fields {
124                    assert_eq!(fields.unnamed.len(), 1);
125                } else {
126                    unimplemented!();
127                }
128                quote_spanned! { variant.span() => Self::#name(x) => x.start_position(), }
129            });
130            quote! {
131                match self {
132                    #(#arms)*
133                }
134            }
135        }
136        Data::Union(_) => unimplemented!(),
137    }
138}
139
140fn generate_span_end_position_method_body(data: &Data) -> TokenStream {
141    match *data {
142        Data::Struct(ref data) => match data.fields {
143            Fields::Named(ref fields) => {
144                if let Some(field) = fields.named.last() {
145                    let name = &field.ident;
146                    quote! { self.#name.end_position() }
147                } else {
148                    unimplemented!()
149                }
150            }
151            Fields::Unnamed(ref fields) => {
152                assert_eq!(fields.unnamed.len(), 1);
153                quote! { self.0.end_position() }
154            }
155            Fields::Unit => unimplemented!(),
156        },
157        Data::Enum(ref data) => {
158            let arms = data.variants.iter().map(|variant| {
159                let name = &variant.ident;
160                if let Fields::Unnamed(fields) = &variant.fields {
161                    assert_eq!(fields.unnamed.len(), 1);
162                } else {
163                    unimplemented!();
164                }
165                quote_spanned! { variant.span() => Self::#name(x) => x.end_position(), }
166            });
167            quote! {
168                match self {
169                    #(#arms)*
170                }
171            }
172        }
173        Data::Union(_) => unimplemented!(),
174    }
175}
176
177#[proc_macro_derive(Format)]
178pub fn derive_format_trait(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
179    let input = parse_macro_input!(input as DeriveInput);
180    let name = input.ident;
181    let generics = add_format_trait_bounds(input.generics);
182    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
183    let format = generate_format_method_body(&input.data);
184    let expanded = quote! {
185        impl #impl_generics crate::format::Format for #name #ty_generics #where_clause {
186            fn format(&self, fmt: &mut crate::format::Formatter)  {
187                #format
188            }
189        }
190    };
191    proc_macro::TokenStream::from(expanded)
192}
193
194fn add_format_trait_bounds(mut generics: Generics) -> Generics {
195    for param in &mut generics.params {
196        if let GenericParam::Type(ref mut type_param) = *param {
197            type_param.bounds.push(parse_quote!(crate::format::Format));
198        }
199    }
200    generics
201}
202
203fn generate_format_method_body(data: &Data) -> TokenStream {
204    match *data {
205        Data::Struct(ref data) => match data.fields {
206            Fields::Named(ref fields) => {
207                let format = fields.named.iter().map(|f| {
208                    let name = &f.ident;
209                    quote_spanned! { f.span() => self.#name.format(fmt) }
210                });
211                quote! {
212                    #(#format ;)*
213                }
214            }
215            Fields::Unnamed(ref fields) => {
216                assert_eq!(fields.unnamed.len(), 1);
217                quote! { self.0.format(fmt) }
218            }
219            Fields::Unit => unimplemented!(),
220        },
221        Data::Enum(ref data) => {
222            let arms = data.variants.iter().map(|variant| {
223                let name = &variant.ident;
224                if let Fields::Unnamed(fields) = &variant.fields {
225                    assert_eq!(fields.unnamed.len(), 1);
226                } else {
227                    unimplemented!();
228                }
229                quote_spanned! { variant.span() => Self::#name(x) => x.format(fmt), }
230            });
231            quote! {
232                match self {
233                    #(#arms)*
234                }
235            }
236        }
237        Data::Union(_) => unimplemented!(),
238    }
239}
240
241#[proc_macro_derive(Element)]
242pub fn derive_element_trait(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
243    let input = parse_macro_input!(input as DeriveInput);
244    let name = input.ident;
245    let generics = add_element_trait_bounds(input.generics);
246    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
247    let is_packable = generate_is_packable_method_body(&input.data);
248    let expanded = quote! {
249        impl #impl_generics crate::items::components::Element for #name #ty_generics #where_clause {
250            fn is_packable(&self) -> bool {
251                #is_packable
252            }
253        }
254    };
255    proc_macro::TokenStream::from(expanded)
256}
257
258fn add_element_trait_bounds(mut generics: Generics) -> Generics {
259    for param in &mut generics.params {
260        if let GenericParam::Type(ref mut type_param) = *param {
261            type_param
262                .bounds
263                .push(parse_quote!(crate::items::components::Element));
264        }
265    }
266    generics
267}
268
269fn generate_is_packable_method_body(data: &Data) -> TokenStream {
270    match *data {
271        Data::Struct(ref data) => match data.fields {
272            Fields::Named(_) => {
273                quote! { false }
274            }
275            Fields::Unnamed(ref fields) => {
276                assert_eq!(fields.unnamed.len(), 1);
277                quote! { self.0.is_packable() }
278            }
279            Fields::Unit => unimplemented!(),
280        },
281        Data::Enum(ref data) => {
282            let arms = data.variants.iter().map(|variant| {
283                let name = &variant.ident;
284                if let Fields::Unnamed(fields) = &variant.fields {
285                    assert_eq!(fields.unnamed.len(), 1);
286                } else {
287                    unimplemented!();
288                }
289                quote_spanned! { variant.span() => Self::#name(x) => x.is_packable(), }
290            });
291            quote! {
292                match self {
293                    #(#arms)*
294                }
295            }
296        }
297        Data::Union(_) => unimplemented!(),
298    }
299}