1use proc_macro::TokenStream;
2use proc_macro2;
3use proc_macro2::Span;
4use quote::{format_ident, quote, quote_spanned};
5use syn::{parse_macro_input, DeriveInput, Ident, LitInt};
6
7#[proc_macro_derive(GetLoc, attributes(loc))]
42pub fn derive_get_loc(item: TokenStream) -> TokenStream {
43 let input = parse_macro_input!(item as DeriveInput);
44 let name = input.ident;
45 let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
46
47 match input.data {
48 syn::Data::Struct(v) => match v.fields {
49 syn::Fields::Named(v) => {
50 let mut has_loc = false;
51 let mut loc_id: Option<&Ident> = None;
52 for f in v.named.iter() {
53 #[allow(unused_assignments)]
54 if f.ident.as_ref().map(|id| id == "loc").unwrap_or(false) {
55 has_loc = true;
56 loc_id = f.ident.as_ref();
57 break;
58 }
59 for attr in f.attrs.iter() {
60 let path = &attr.path;
61 if path.get_ident().map(|id| id == "loc").unwrap_or(false) {
62 if !has_loc && loc_id.is_some() {
63 return syn::Error::new(
64 Span::call_site(),
65 "Cannot have multiple loc",
66 )
67 .to_compile_error()
68 .into();
69 }
70 loc_id = f.ident.as_ref();
71 if loc_id.is_none() {
72 return syn::Error::new(Span::call_site(), "Field has no name")
73 .to_compile_error()
74 .into();
75 }
76 }
77 }
78 }
79 if loc_id.is_none() {
80 return syn::Error::new(Span::call_site(), "Not found field loc")
81 .to_compile_error()
82 .into();
83 }
84 let loc_id = loc_id.unwrap();
85 let imp = quote! {
86 impl #impl_generics ::srcpos_get::GetLoc for #name #ty_generics #where_clause {
87 fn loc(&self) -> ::srcpos_get::Loc {
88 use ::srcpos_get::GetLoc;
89 self.#loc_id.loc()
90 }
91 }
92 };
93 return imp.into();
94 }
95 syn::Fields::Unnamed(v) => {
96 let mut loc_id: Option<usize> = None;
97 for (i, f) in v.unnamed.iter().enumerate() {
98 for attr in f.attrs.iter() {
99 let path = &attr.path;
100 if path.get_ident().map(|id| id == "loc").unwrap_or(false) {
101 if loc_id.is_some() {
102 return syn::Error::new(
103 Span::call_site(),
104 "Cannot have multiple loc",
105 )
106 .to_compile_error()
107 .into();
108 }
109 loc_id = Some(i);
110 }
111 }
112 }
113 if v.unnamed.len() == 0 {
114 return syn::Error::new(Span::call_site(), "There is nothing to get")
115 .to_compile_error()
116 .into();
117 }
118 if v.unnamed.len() == 1 && loc_id.is_none() {
119 loc_id = Some(0);
120 }
121 if loc_id.is_none() {
122 return syn::Error::new(Span::call_site(), "Not found field loc")
123 .to_compile_error()
124 .into();
125 }
126 let loc_id = loc_id.unwrap().to_string();
127 let loc_id = LitInt::new(loc_id.as_str(), Span::call_site());
128 let imp = quote! {
129 impl #impl_generics ::srcpos_get::GetLoc for #name #ty_generics #where_clause {
130 fn loc(&self) -> ::srcpos_get::Loc {
131 use ::srcpos_get::GetLoc;
132 self.#loc_id.loc()
133 }
134 }
135 };
136 return imp.into();
137 }
138 syn::Fields::Unit => {
139 return syn::Error::new(Span::call_site(), "There is nothing to get")
140 .to_compile_error()
141 .into();
142 }
143 },
144 syn::Data::Enum(v) => {
145 let mut vimps = vec![];
146 if v.variants.len() == 0 {
147 return syn::Error::new(Span::call_site(), "There is nothing to get")
148 .to_compile_error()
149 .into();
150 }
151 for variant in v.variants.iter() {
152 match &variant.fields {
153 syn::Fields::Named(v) => {
154 let mut has_loc = false;
155 let mut loc_id: Option<&Ident> = None;
156 for f in v.named.iter() {
157 #[allow(unused_assignments)]
158 if f.ident.as_ref().map(|id| id == "loc").unwrap_or(false) {
159 has_loc = true;
160 loc_id = f.ident.as_ref();
161 break;
162 }
163 for attr in f.attrs.iter() {
164 let path = &attr.path;
165 if path.get_ident().map(|id| id == "loc").unwrap_or(false) {
166 if !has_loc && loc_id.is_some() {
167 return syn::Error::new(
168 variant.ident.span(),
169 "[GetLoc] Cannot have multiple loc",
170 )
171 .to_compile_error()
172 .into();
173 }
174 loc_id = f.ident.as_ref();
175 if loc_id.is_none() {
176 return syn::Error::new(
177 variant.ident.span(),
178 "[GetLoc] Field has no name",
179 )
180 .to_compile_error()
181 .into();
182 }
183 }
184 }
185 }
186 if loc_id.is_none() {
187 return syn::Error::new(
188 variant.ident.span(),
189 "[GetLoc] Not found field loc",
190 )
191 .to_compile_error()
192 .into();
193 }
194 let loc_id = loc_id.unwrap();
195 let vname = &variant.ident;
196 let imp = quote_spanned! { variant.ident.span() => Self::#vname { #loc_id, .. } => #loc_id.loc() };
197 vimps.push(imp);
198 }
199 syn::Fields::Unnamed(v) => {
200 let mut loc_id: Option<usize> = None;
201 for (i, f) in v.unnamed.iter().enumerate() {
202 for attr in f.attrs.iter() {
203 let path = &attr.path;
204 if path.get_ident().map(|id| id == "loc").unwrap_or(false) {
205 if loc_id.is_some() {
206 return syn::Error::new(
207 variant.ident.span(),
208 "[GetLoc] Cannot have multiple loc",
209 )
210 .to_compile_error()
211 .into();
212 }
213 loc_id = Some(i);
214 }
215 }
216 }
217 if v.unnamed.len() == 0 {
218 return syn::Error::new(
219 variant.ident.span(),
220 "[GetLoc] There is nothing to get",
221 )
222 .to_compile_error()
223 .into();
224 }
225 if v.unnamed.len() == 1 && loc_id.is_none() {
226 loc_id = Some(0);
227 }
228 if loc_id.is_none() {
229 return syn::Error::new(
230 variant.ident.span(),
231 "[GetLoc] Not found field loc",
232 )
233 .to_compile_error()
234 .into();
235 }
236 let loc_id = loc_id.unwrap();
237 let ids = (0..(variant.fields.len())).into_iter().map(|i| {
238 if i != loc_id {
239 format_ident!("_")
240 } else {
241 format_ident!("v{}", i)
242 }
243 });
244 let loc_id = format_ident!("v{}", loc_id);
245 let vname = &variant.ident;
246 let imp = quote_spanned! { variant.ident.span() => Self::#vname(#(#ids),*) => #loc_id.loc() };
247 vimps.push(imp);
248 }
249 syn::Fields::Unit => {
250 return syn::Error::new(
251 variant.ident.span(),
252 "[GetLoc] There is nothing to get",
253 )
254 .to_compile_error()
255 .into();
256 }
257 }
258 }
259 let imp = quote! {
260 impl #impl_generics ::srcpos_get::GetLoc for #name #ty_generics #where_clause {
261 fn loc(&self) -> ::srcpos_get::Loc {
262 use ::srcpos_get::GetLoc;
263 match self {
264 #(#vimps),*
265 }
266 }
267 }
268 };
269 return imp.into();
270 }
271 syn::Data::Union(_) => {
272 return syn::Error::new(Span::call_site(), "Does not support union")
273 .to_compile_error()
274 .into();
275 }
276 }
277}
278
279#[proc_macro_derive(GetPos, attributes(pos))]
314pub fn derive_get_pos(item: TokenStream) -> TokenStream {
315 let input = parse_macro_input!(item as DeriveInput);
316 let name = input.ident;
317 let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
318
319 match input.data {
320 syn::Data::Struct(v) => match v.fields {
321 syn::Fields::Named(v) => {
322 let mut has_loc = false;
323 let mut loc_id: Option<&Ident> = None;
324 for f in v.named.iter() {
325 #[allow(unused_assignments)]
326 if f.ident.as_ref().map(|id| id == "pos").unwrap_or(false) {
327 has_loc = true;
328 loc_id = f.ident.as_ref();
329 break;
330 }
331 for attr in f.attrs.iter() {
332 let path = &attr.path;
333 if path.get_ident().map(|id| id == "pos").unwrap_or(false) {
334 if !has_loc && loc_id.is_some() {
335 return syn::Error::new(
336 Span::call_site(),
337 "Cannot have multiple pos",
338 )
339 .to_compile_error()
340 .into();
341 }
342 loc_id = f.ident.as_ref();
343 if loc_id.is_none() {
344 return syn::Error::new(Span::call_site(), "Field has no name")
345 .to_compile_error()
346 .into();
347 }
348 }
349 }
350 }
351 if loc_id.is_none() {
352 return syn::Error::new(Span::call_site(), "Not found field pos")
353 .to_compile_error()
354 .into();
355 }
356 let loc_id = loc_id.unwrap();
357 let imp = quote! {
358 impl #impl_generics ::srcpos_get::GetPos for #name #ty_generics #where_clause {
359 fn pos(&self) -> ::srcpos_get::Pos {
360 use ::srcpos_get::GetPos;
361 self.#loc_id.pos()
362 }
363 }
364 };
365 return imp.into();
366 }
367 syn::Fields::Unnamed(v) => {
368 let mut loc_id: Option<usize> = None;
369 for (i, f) in v.unnamed.iter().enumerate() {
370 for attr in f.attrs.iter() {
371 let path = &attr.path;
372 if path.get_ident().map(|id| id == "pos").unwrap_or(false) {
373 if loc_id.is_some() {
374 return syn::Error::new(
375 Span::call_site(),
376 "Cannot have multiple pos",
377 )
378 .to_compile_error()
379 .into();
380 }
381 loc_id = Some(i);
382 }
383 }
384 }
385 if v.unnamed.len() == 0 {
386 return syn::Error::new(Span::call_site(), "There is nothing to get")
387 .to_compile_error()
388 .into();
389 }
390 if v.unnamed.len() == 1 && loc_id.is_none() {
391 loc_id = Some(0);
392 }
393 if loc_id.is_none() {
394 return syn::Error::new(Span::call_site(), "Not found field pos")
395 .to_compile_error()
396 .into();
397 }
398 let loc_id = loc_id.unwrap().to_string();
399 let loc_id = LitInt::new(loc_id.as_str(), Span::call_site());
400 let imp = quote! {
401 impl #impl_generics ::srcpos_get::GetPos for #name #ty_generics #where_clause {
402 fn pos(&self) -> ::srcpos_get::Pos {
403 use ::srcpos_get::GetPos;
404 self.#loc_id.pos()
405 }
406 }
407 };
408 return imp.into();
409 }
410 syn::Fields::Unit => {
411 return syn::Error::new(Span::call_site(), "There is nothing to get")
412 .to_compile_error()
413 .into();
414 }
415 },
416 syn::Data::Enum(v) => {
417 let mut vimps = vec![];
418 if v.variants.len() == 0 {
419 return syn::Error::new(Span::call_site(), "There is nothing to get")
420 .to_compile_error()
421 .into();
422 }
423 for variant in v.variants.iter() {
424 match &variant.fields {
425 syn::Fields::Named(v) => {
426 let mut has_loc = false;
427 let mut loc_id: Option<&Ident> = None;
428 for f in v.named.iter() {
429 #[allow(unused_assignments)]
430 if f.ident.as_ref().map(|id| id == "pos").unwrap_or(false) {
431 has_loc = true;
432 loc_id = f.ident.as_ref();
433 break;
434 }
435 for attr in f.attrs.iter() {
436 let path = &attr.path;
437 if path.get_ident().map(|id| id == "pos").unwrap_or(false) {
438 if !has_loc && loc_id.is_some() {
439 return syn::Error::new(
440 variant.ident.span(),
441 "[GetPos] Cannot have multiple pos",
442 )
443 .to_compile_error()
444 .into();
445 }
446 loc_id = f.ident.as_ref();
447 if loc_id.is_none() {
448 return syn::Error::new(
449 variant.ident.span(),
450 "[GetPos] Field has no name",
451 )
452 .to_compile_error()
453 .into();
454 }
455 }
456 }
457 }
458 if loc_id.is_none() {
459 return syn::Error::new(
460 variant.ident.span(),
461 "[GetPos] Not found field pos",
462 )
463 .to_compile_error()
464 .into();
465 }
466 let loc_id = loc_id.unwrap();
467 let vname = &variant.ident;
468 let imp = quote_spanned! { variant.ident.span() => Self::#vname { #loc_id, .. } => #loc_id.pos() };
469 vimps.push(imp);
470 }
471 syn::Fields::Unnamed(v) => {
472 let mut loc_id: Option<usize> = None;
473 for (i, f) in v.unnamed.iter().enumerate() {
474 for attr in f.attrs.iter() {
475 let path = &attr.path;
476 if path.get_ident().map(|id| id == "pos").unwrap_or(false) {
477 if loc_id.is_some() {
478 return syn::Error::new(
479 variant.ident.span(),
480 "[GetPos] Cannot have multiple pos",
481 )
482 .to_compile_error()
483 .into();
484 }
485 loc_id = Some(i);
486 }
487 }
488 }
489 if v.unnamed.len() == 0 {
490 return syn::Error::new(
491 variant.ident.span(),
492 "[GetPos] There is nothing to get",
493 )
494 .to_compile_error()
495 .into();
496 }
497 if v.unnamed.len() == 1 && loc_id.is_none() {
498 loc_id = Some(0);
499 }
500 if loc_id.is_none() {
501 return syn::Error::new(
502 variant.ident.span(),
503 "[GetPos] Not found field pos",
504 )
505 .to_compile_error()
506 .into();
507 }
508 let loc_id = loc_id.unwrap();
509 let ids = (0..(variant.fields.len())).into_iter().map(|i| {
510 if i != loc_id {
511 format_ident!("_")
512 } else {
513 format_ident!("v{}", i)
514 }
515 });
516 let loc_id = format_ident!("v{}", loc_id);
517 let vname = &variant.ident;
518 let imp = quote_spanned! { variant.ident.span() => Self::#vname(#(#ids),*) => #loc_id.pos() };
519 vimps.push(imp);
520 }
521 syn::Fields::Unit => {
522 return syn::Error::new(
523 variant.ident.span(),
524 "[GetPos] There is nothing to get",
525 )
526 .to_compile_error()
527 .into();
528 }
529 }
530 }
531 let imp = quote! {
532 impl #impl_generics ::srcpos_get::GetPos for #name #ty_generics #where_clause {
533 fn pos(&self) -> ::srcpos_get::Pos {
534 use ::srcpos_get::GetPos;
535 match self {
536 #(#vimps),*
537 }
538 }
539 }
540 };
541 return imp.into();
542 }
543 syn::Data::Union(_) => {
544 return syn::Error::new(Span::call_site(), "Does not support union")
545 .to_compile_error()
546 .into();
547 }
548 }
549}