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}