blob: cdd574c57fc52231549e5b9a0e0c72a88762fa38 [file] [log] [blame]
Carl Lerche058ff472019-02-13 16:23:52 -08001//! This crate automatically generates the definition of the `Visit`,
2//! `VisitMut`, and `Fold` traits in `syn` based on the `syn` source. It
3//! discovers structs and enums declared with the `ast_*` macros and generates
4//! the functions for those types.
5//!
6//! It makes a few assumptions about the target crate:
7//! 1. All structs which are discovered must be re-exported in the root of the
8//! crate, even if they were declared in a submodule.
9//! 2. This code cannot discover submodules which are located in subdirectories
10//! - only submodules located in the same directory.
11//! 3. The path to `syn` is hardcoded.
12
13use crate::types;
David Tolnay14d463e2019-02-15 14:23:51 -080014use indexmap::IndexMap;
Carl Lerche058ff472019-02-13 16:23:52 -080015use proc_macro2::TokenStream;
16
17use std::fs::File;
18use std::io::Write;
19
20const FOLD_SRC: &str = "../src/gen/fold.rs";
21const VISIT_SRC: &str = "../src/gen/visit.rs";
22const VISIT_MUT_SRC: &str = "../src/gen/visit_mut.rs";
23
24mod codegen {
25 use crate::types;
26 use inflections::Inflect;
27 use proc_macro2::{Span, TokenStream};
28 use quote::TokenStreamExt;
29 use syn::*;
30
31 #[derive(Default)]
32 pub struct State {
33 pub visit_trait: TokenStream,
34 pub visit_impl: TokenStream,
35 pub visit_mut_trait: TokenStream,
36 pub visit_mut_impl: TokenStream,
37 pub fold_trait: TokenStream,
38 pub fold_impl: TokenStream,
39 }
40
41 fn under_name(name: &str) -> Ident {
42 Ident::new(&name.to_snake_case(), Span::call_site())
43 }
44
45 #[derive(Debug, Eq, PartialEq, Copy, Clone)]
46 enum Kind {
47 Visit,
48 VisitMut,
49 Fold,
50 }
51
52 enum Operand {
53 Borrowed(TokenStream),
54 Owned(TokenStream),
55 }
56
57 use self::Kind::*;
58 use self::Operand::*;
59
60 impl Operand {
61 fn tokens(&self) -> &TokenStream {
62 match *self {
63 Borrowed(ref n) | Owned(ref n) => n,
64 }
65 }
66
67 fn ref_tokens(&self) -> TokenStream {
68 match *self {
69 Borrowed(ref n) => n.clone(),
70 Owned(ref n) => quote!(&#n),
71 }
72 }
73
74 fn ref_mut_tokens(&self) -> TokenStream {
75 match *self {
76 Borrowed(ref n) => n.clone(),
77 Owned(ref n) => quote!(&mut #n),
78 }
79 }
80
81 fn owned_tokens(&self) -> TokenStream {
82 match *self {
83 Borrowed(ref n) => quote!(*#n),
84 Owned(ref n) => n.clone(),
85 }
86 }
87 }
88
89 fn simple_visit(item: &str, kind: Kind, name: &Operand) -> TokenStream {
90 let ident = under_name(item);
91
92 match kind {
93 Visit => {
94 let method = Ident::new(&format!("visit_{}", ident), Span::call_site());
95 let name = name.ref_tokens();
96 quote! {
97 _visitor.#method(#name)
98 }
99 }
100 VisitMut => {
101 let method = Ident::new(&format!("visit_{}_mut", ident), Span::call_site());
102 let name = name.ref_mut_tokens();
103 quote! {
104 _visitor.#method(#name)
105 }
106 }
107 Fold => {
108 let method = Ident::new(&format!("fold_{}", ident), Span::call_site());
109 let name = name.owned_tokens();
110 quote! {
111 _visitor.#method(#name)
112 }
113 }
114 }
115 }
116
117 fn box_visit(
118 elem: &types::Type,
119 features: &types::Features,
David Tolnay157c7eb2019-02-15 13:21:48 -0800120 defs: &types::Definitions,
Carl Lerche058ff472019-02-13 16:23:52 -0800121 kind: Kind,
122 name: &Operand,
123 ) -> Option<TokenStream> {
124 let name = name.owned_tokens();
David Tolnay157c7eb2019-02-15 13:21:48 -0800125 let res = visit(elem, features, defs, kind, &Owned(quote!(*#name)))?;
Carl Lerche058ff472019-02-13 16:23:52 -0800126 Some(match kind {
127 Fold => quote! {
128 Box::new(#res)
129 },
130 Visit | VisitMut => res,
131 })
132 }
133
134 fn vec_visit(
135 elem: &types::Type,
136 features: &types::Features,
David Tolnay157c7eb2019-02-15 13:21:48 -0800137 defs: &types::Definitions,
Carl Lerche058ff472019-02-13 16:23:52 -0800138 kind: Kind,
139 name: &Operand,
140 ) -> Option<TokenStream> {
141 let operand = match kind {
142 Visit | VisitMut => Borrowed(quote!(it)),
143 Fold => Owned(quote!(it)),
144 };
David Tolnay157c7eb2019-02-15 13:21:48 -0800145 let val = visit(elem, features, defs, kind, &operand)?;
Carl Lerche058ff472019-02-13 16:23:52 -0800146 Some(match kind {
147 Visit => {
148 let name = name.ref_tokens();
149 quote! {
150 for it in #name {
151 #val
152 }
153 }
154 }
155 VisitMut => {
156 let name = name.ref_mut_tokens();
157 quote! {
158 for it in #name {
159 #val
160 }
161 }
162 }
163 Fold => {
164 let name = name.owned_tokens();
165 quote! {
166 FoldHelper::lift(#name, |it| { #val })
167 }
168 }
169 })
170 }
171
172 fn punctuated_visit(
173 elem: &types::Type,
174 features: &types::Features,
David Tolnay157c7eb2019-02-15 13:21:48 -0800175 defs: &types::Definitions,
Carl Lerche058ff472019-02-13 16:23:52 -0800176 kind: Kind,
177 name: &Operand,
178 ) -> Option<TokenStream> {
179 let operand = match kind {
180 Visit | VisitMut => Borrowed(quote!(it)),
181 Fold => Owned(quote!(it)),
182 };
David Tolnay157c7eb2019-02-15 13:21:48 -0800183 let val = visit(elem, features, defs, kind, &operand)?;
Carl Lerche058ff472019-02-13 16:23:52 -0800184 Some(match kind {
185 Visit => {
186 let name = name.ref_tokens();
187 quote! {
188 for el in Punctuated::pairs(#name) {
189 let it = el.value();
190 #val
191 }
192 }
193 }
194 VisitMut => {
195 let name = name.ref_mut_tokens();
196 quote! {
197 for mut el in Punctuated::pairs_mut(#name) {
198 let it = el.value_mut();
199 #val
200 }
201 }
202 }
203 Fold => {
204 let name = name.owned_tokens();
205 quote! {
206 FoldHelper::lift(#name, |it| { #val })
207 }
208 }
209 })
210 }
211
212 fn option_visit(
213 elem: &types::Type,
214 features: &types::Features,
David Tolnay157c7eb2019-02-15 13:21:48 -0800215 defs: &types::Definitions,
Carl Lerche058ff472019-02-13 16:23:52 -0800216 kind: Kind,
217 name: &Operand,
218 ) -> Option<TokenStream> {
219 let it = match kind {
220 Visit | VisitMut => Borrowed(quote!(it)),
221 Fold => Owned(quote!(it)),
222 };
David Tolnay157c7eb2019-02-15 13:21:48 -0800223 let val = visit(elem, features, defs, kind, &it)?;
Carl Lerche058ff472019-02-13 16:23:52 -0800224 let name = name.owned_tokens();
225 Some(match kind {
226 Visit => quote! {
227 if let Some(ref it) = #name {
228 #val
229 }
230 },
231 VisitMut => quote! {
232 if let Some(ref mut it) = #name {
233 #val
234 }
235 },
236 Fold => quote! {
237 (#name).map(|it| { #val })
238 },
239 })
240 }
241
242 fn tuple_visit(
243 elems: &[types::Type],
244 features: &types::Features,
David Tolnay157c7eb2019-02-15 13:21:48 -0800245 defs: &types::Definitions,
Carl Lerche058ff472019-02-13 16:23:52 -0800246 kind: Kind,
247 name: &Operand,
248 ) -> Option<TokenStream> {
249 if elems.is_empty() {
250 return None;
251 }
252
253 let mut code = TokenStream::new();
254 for (i, elem) in elems.iter().enumerate() {
255 let name = name.tokens();
256 let i = Index::from(i);
257 let it = Owned(quote!((#name).#i));
258 let val =
David Tolnay157c7eb2019-02-15 13:21:48 -0800259 visit(elem, features, defs, kind, &it).unwrap_or_else(|| noop_visit(kind, &it));
Carl Lerche058ff472019-02-13 16:23:52 -0800260 code.append_all(val);
261 match kind {
262 Fold => code.append_all(quote!(,)),
263 Visit | VisitMut => code.append_all(quote!(;)),
264 }
265 }
266 Some(match kind {
267 Fold => quote! {
268 (#code)
269 },
270 Visit | VisitMut => code,
271 })
272 }
273
David Tolnay157c7eb2019-02-15 13:21:48 -0800274 fn token_punct_visit(repr: &str, kind: Kind, name: &Operand) -> TokenStream {
275 let ty: TokenStream = syn::parse_str(&format!("Token![{}]", repr)).unwrap();
Carl Lerche058ff472019-02-13 16:23:52 -0800276 let name = name.tokens();
277 match kind {
278 Fold => quote! {
279 #ty(tokens_helper(_visitor, &#name.spans))
280 },
281 Visit => quote! {
282 tokens_helper(_visitor, &#name.spans)
283 },
284 VisitMut => quote! {
285 tokens_helper(_visitor, &mut #name.spans)
286 },
287 }
288 }
289
David Tolnay157c7eb2019-02-15 13:21:48 -0800290 fn token_keyword_visit(repr: &str, kind: Kind, name: &Operand) -> TokenStream {
291 let ty: TokenStream = syn::parse_str(&format!("Token![{}]", repr)).unwrap();
Carl Lerche058ff472019-02-13 16:23:52 -0800292 let name = name.tokens();
293 match kind {
294 Fold => quote! {
295 #ty(tokens_helper(_visitor, &#name.span))
296 },
297 Visit => quote! {
298 tokens_helper(_visitor, &#name.span)
299 },
300 VisitMut => quote! {
301 tokens_helper(_visitor, &mut #name.span)
302 },
303 }
304 }
305
306 fn token_group_visit(ty: &str, kind: Kind, name: &Operand) -> TokenStream {
307 let ty = Ident::new(ty, Span::call_site());
308 let name = name.tokens();
309 match kind {
310 Fold => quote! {
311 #ty(tokens_helper(_visitor, &#name.span))
312 },
313 Visit => quote! {
314 tokens_helper(_visitor, &#name.span)
315 },
316 VisitMut => quote! {
317 tokens_helper(_visitor, &mut #name.span)
318 },
319 }
320 }
321
322 fn noop_visit(kind: Kind, name: &Operand) -> TokenStream {
323 match kind {
324 Fold => name.owned_tokens(),
325 Visit | VisitMut => {
326 let name = name.tokens();
327 quote! {
328 skip!(#name)
329 }
330 }
331 }
332 }
333
334 fn visit(
335 ty: &types::Type,
336 features: &types::Features,
David Tolnay157c7eb2019-02-15 13:21:48 -0800337 defs: &types::Definitions,
Carl Lerche058ff472019-02-13 16:23:52 -0800338 kind: Kind,
339 name: &Operand,
340 ) -> Option<TokenStream> {
341 match ty {
David Tolnay157c7eb2019-02-15 13:21:48 -0800342 types::Type::Box(t) => box_visit(&*t, features, defs, kind, name),
343 types::Type::Vec(t) => vec_visit(&*t, features, defs, kind, name),
David Tolnay295141b2019-02-15 12:45:33 -0800344 types::Type::Punctuated(p) => {
David Tolnay157c7eb2019-02-15 13:21:48 -0800345 punctuated_visit(p.element(), features, defs, kind, name)
David Tolnay295141b2019-02-15 12:45:33 -0800346 }
David Tolnay157c7eb2019-02-15 13:21:48 -0800347 types::Type::Option(t) => option_visit(&*t, features, defs, kind, name),
348 types::Type::Tuple(t) => tuple_visit(t, features, defs, kind, name),
Carl Lerche058ff472019-02-13 16:23:52 -0800349 types::Type::Token(t) => {
David Tolnay157c7eb2019-02-15 13:21:48 -0800350 let repr = &defs.tokens[t];
351 let is_keyword = repr.chars().next().unwrap().is_alphabetic();
352 if is_keyword {
353 Some(token_keyword_visit(repr, kind, name))
Carl Lerche058ff472019-02-13 16:23:52 -0800354 } else {
David Tolnay157c7eb2019-02-15 13:21:48 -0800355 Some(token_punct_visit(repr, kind, name))
Carl Lerche058ff472019-02-13 16:23:52 -0800356 }
357 }
David Tolnay295141b2019-02-15 12:45:33 -0800358 types::Type::Group(t) => Some(token_group_visit(&t[..], kind, name)),
David Tolnayd3076572019-02-15 13:32:44 -0800359 types::Type::Syn(t) => {
Carl Lerche058ff472019-02-13 16:23:52 -0800360 fn requires_full(features: &types::Features) -> bool {
361 features.contains("full") && features.len() == 1
362 }
363
364 let mut res = simple_visit(t, kind, name);
365
David Tolnay157c7eb2019-02-15 13:21:48 -0800366 let target = defs.types.iter().find(|ty| ty.ident() == t).unwrap();
Carl Lerche058ff472019-02-13 16:23:52 -0800367
368 Some(
369 if requires_full(target.features()) && !requires_full(features) {
370 quote! {
371 full!(#res)
372 }
373 } else {
374 res
375 },
376 )
377 }
Carl Lerchecbf7cc12019-02-15 14:09:31 -0800378 types::Type::Ext(t) if super::TERMINAL_TYPES.contains(&&t[..]) => {
379 Some(simple_visit(t, kind, name))
380 }
Carl Lerche058ff472019-02-13 16:23:52 -0800381 types::Type::Ext(_) | types::Type::Std(_) => None,
382 }
383 }
384
385 fn visit_features(features: &types::Features) -> TokenStream {
386 match features.len() {
387 0 => quote!(),
388 1 => {
389 let feature = &features[0];
390 quote!(#[cfg(feature = #feature)])
391 }
392 _ => {
393 let features = features.iter().map(|feature| quote!(feature = #feature));
394
395 quote!(#[cfg(any( #(#features),* ))])
396 }
397 }
398 }
399
David Tolnay157c7eb2019-02-15 13:21:48 -0800400 pub fn generate(state: &mut State, s: &types::Node, defs: &types::Definitions) {
Carl Lerche058ff472019-02-13 16:23:52 -0800401 let features = visit_features(s.features());
402 let under_name = under_name(s.ident());
403 let ty = Ident::new(s.ident(), Span::call_site());
404 let visit_fn = Ident::new(&format!("visit_{}", under_name), Span::call_site());
405 let visit_mut_fn = Ident::new(&format!("visit_{}_mut", under_name), Span::call_site());
406 let fold_fn = Ident::new(&format!("fold_{}", under_name), Span::call_site());
407
408 let mut visit_impl = TokenStream::new();
409 let mut visit_mut_impl = TokenStream::new();
410 let mut fold_impl = TokenStream::new();
411
412 match s {
David Tolnayf9bb8ff2019-02-15 13:10:14 -0800413 types::Node::Enum(ref e) => {
Carl Lerche058ff472019-02-13 16:23:52 -0800414 let mut visit_variants = TokenStream::new();
415 let mut visit_mut_variants = TokenStream::new();
416 let mut fold_variants = TokenStream::new();
417
418 for variant in e.variants() {
419 let variant_ident = Ident::new(variant.ident(), Span::call_site());
420
421 if variant.fields().is_empty() {
422 visit_variants.append_all(quote! {
423 #ty::#variant_ident => {}
424 });
425 visit_mut_variants.append_all(quote! {
426 #ty::#variant_ident => {}
427 });
428 fold_variants.append_all(quote! {
429 #ty::#variant_ident => {
430 #ty::#variant_ident
431 }
432 });
433 } else {
434 let mut bind_visit_fields = TokenStream::new();
435 let mut bind_visit_mut_fields = TokenStream::new();
436 let mut bind_fold_fields = TokenStream::new();
437
438 let mut visit_fields = TokenStream::new();
439 let mut visit_mut_fields = TokenStream::new();
440 let mut fold_fields = TokenStream::new();
441
442 for (idx, ty) in variant.fields().iter().enumerate() {
443 let name = format!("_binding_{}", idx);
444 let binding = Ident::new(&name, Span::call_site());
445
446 bind_visit_fields.append_all(quote! {
447 ref #binding,
448 });
449 bind_visit_mut_fields.append_all(quote! {
450 ref mut #binding,
451 });
452 bind_fold_fields.append_all(quote! {
453 #binding,
454 });
455
456 let borrowed_binding = Borrowed(quote!(#binding));
457 let owned_binding = Owned(quote!(#binding));
458
459 visit_fields.append_all(
David Tolnay157c7eb2019-02-15 13:21:48 -0800460 visit(ty, s.features(), defs, Visit, &borrowed_binding)
Carl Lerche058ff472019-02-13 16:23:52 -0800461 .unwrap_or_else(|| noop_visit(Visit, &borrowed_binding)),
462 );
463 visit_mut_fields.append_all(
David Tolnay157c7eb2019-02-15 13:21:48 -0800464 visit(ty, s.features(), defs, VisitMut, &borrowed_binding)
Carl Lerche058ff472019-02-13 16:23:52 -0800465 .unwrap_or_else(|| noop_visit(VisitMut, &borrowed_binding)),
466 );
467 fold_fields.append_all(
David Tolnay157c7eb2019-02-15 13:21:48 -0800468 visit(ty, s.features(), defs, Fold, &owned_binding)
Carl Lerche058ff472019-02-13 16:23:52 -0800469 .unwrap_or_else(|| noop_visit(Fold, &owned_binding)),
470 );
471
472 visit_fields.append_all(quote!(;));
473 visit_mut_fields.append_all(quote!(;));
474 fold_fields.append_all(quote!(,));
475 }
476
477 visit_variants.append_all(quote! {
478 #ty::#variant_ident(#bind_visit_fields) => {
479 #visit_fields
480 }
481 });
482
483 visit_mut_variants.append_all(quote! {
484 #ty::#variant_ident(#bind_visit_mut_fields) => {
485 #visit_mut_fields
486 }
487 });
488
489 fold_variants.append_all(quote! {
490 #ty::#variant_ident(#bind_fold_fields) => {
491 #ty::#variant_ident(
492 #fold_fields
493 )
494 }
495 });
496 }
497 }
498
499 visit_impl.append_all(quote! {
500 match *_i {
501 #visit_variants
502 }
503 });
504
505 visit_mut_impl.append_all(quote! {
506 match *_i {
507 #visit_mut_variants
508 }
509 });
510
511 fold_impl.append_all(quote! {
512 match _i {
513 #fold_variants
514 }
515 });
516 }
David Tolnayf9bb8ff2019-02-15 13:10:14 -0800517 types::Node::Struct(ref v) => {
Carl Lerche058ff472019-02-13 16:23:52 -0800518 let mut fold_fields = TokenStream::new();
519
David Tolnay14d463e2019-02-15 14:23:51 -0800520 for (field, ty) in v.fields() {
521 let id = Ident::new(field, Span::call_site());
Carl Lerche058ff472019-02-13 16:23:52 -0800522 let ref_toks = Owned(quote!(_i.#id));
David Tolnay14d463e2019-02-15 14:23:51 -0800523 let visit_field = visit(ty, v.features(), defs, Visit, &ref_toks)
Carl Lerche058ff472019-02-13 16:23:52 -0800524 .unwrap_or_else(|| noop_visit(Visit, &ref_toks));
525 visit_impl.append_all(quote! {
526 #visit_field;
527 });
528 let visit_mut_field =
David Tolnay14d463e2019-02-15 14:23:51 -0800529 visit(ty, v.features(), defs, VisitMut, &ref_toks)
Carl Lerche058ff472019-02-13 16:23:52 -0800530 .unwrap_or_else(|| noop_visit(VisitMut, &ref_toks));
531 visit_mut_impl.append_all(quote! {
532 #visit_mut_field;
533 });
David Tolnay14d463e2019-02-15 14:23:51 -0800534 let fold = visit(ty, v.features(), defs, Fold, &ref_toks)
Carl Lerche058ff472019-02-13 16:23:52 -0800535 .unwrap_or_else(|| noop_visit(Fold, &ref_toks));
536
537 fold_fields.append_all(quote! {
538 #id: #fold,
539 });
540 }
541
542 if !v.fields().is_empty() {
543 fold_impl.append_all(quote! {
544 #ty {
545 #fold_fields
546 }
547 })
548 } else {
549 if ty == "Ident" {
550 fold_impl.append_all(quote! {
551 let mut _i = _i;
552 let span = _visitor.fold_span(_i.span());
553 _i.set_span(span);
554 });
555 }
556 fold_impl.append_all(quote! {
557 _i
558 });
559 }
560 }
561 }
562
563 let mut include_fold_impl = true;
David Tolnayf9bb8ff2019-02-15 13:10:14 -0800564 if let types::Node::Struct(ref data) = s {
David Tolnay8964fff2019-02-15 14:34:51 -0800565 if data.fields().is_empty() && !super::TERMINAL_TYPES.contains(&&s.ident()) {
Carl Lerche058ff472019-02-13 16:23:52 -0800566 include_fold_impl = false;
567 }
568 }
569
570 state.visit_trait.append_all(quote! {
571 #features
572 fn #visit_fn(&mut self, i: &'ast #ty) {
573 #visit_fn(self, i)
574 }
575 });
576
577 state.visit_impl.append_all(quote! {
578 #features
579 pub fn #visit_fn<'ast, V: Visit<'ast> + ?Sized>(
580 _visitor: &mut V, _i: &'ast #ty
581 ) {
582 #visit_impl
583 }
584 });
585
586 state.visit_mut_trait.append_all(quote! {
587 #features
588 fn #visit_mut_fn(&mut self, i: &mut #ty) {
589 #visit_mut_fn(self, i)
590 }
591 });
592
593 state.visit_mut_impl.append_all(quote! {
594 #features
595 pub fn #visit_mut_fn<V: VisitMut + ?Sized>(
596 _visitor: &mut V, _i: &mut #ty
597 ) {
598 #visit_mut_impl
599 }
600 });
601
602 state.fold_trait.append_all(quote! {
603 #features
604 fn #fold_fn(&mut self, i: #ty) -> #ty {
605 #fold_fn(self, i)
606 }
607 });
608
609 if include_fold_impl {
610 state.fold_impl.append_all(quote! {
611 #features
612 pub fn #fold_fn<V: Fold + ?Sized>(
613 _visitor: &mut V, _i: #ty
614 ) -> #ty {
615 #fold_impl
616 }
617 });
618 }
619 }
620}
621
622fn write_file(path: &str, content: TokenStream) {
623 let mut file = File::create(path).unwrap();
624 write!(
625 file,
626 "// THIS FILE IS AUTOMATICALLY GENERATED; DO NOT EDIT\n\n"
627 )
628 .unwrap();
629 let mut config = rustfmt::Config::default();
630 config.set().emit_mode(rustfmt::EmitMode::Stdout);
631 config.set().verbose(rustfmt::Verbosity::Quiet);
632 config.set().format_macro_matchers(true);
633 config.set().normalize_doc_attributes(true);
634 let mut session = rustfmt::Session::new(config, Some(&mut file));
635 session
636 .format(rustfmt::Input::Text(content.to_string()))
637 .unwrap();
638}
639
Carl Lerchecbf7cc12019-02-15 14:09:31 -0800640const TERMINAL_TYPES: &[&str] = &["Span", "Ident"];
641
David Tolnayf9bb8ff2019-02-15 13:10:14 -0800642pub fn generate(defs: &types::Definitions) {
Carl Lerchecbf7cc12019-02-15 14:09:31 -0800643 let mut defs = defs.clone();
644
645 for &tt in TERMINAL_TYPES {
646 defs.insert(types::Node::Struct(types::Struct::new(
647 tt.to_string(),
648 types::Features::default(),
David Tolnay8964fff2019-02-15 14:34:51 -0800649 IndexMap::new())
Carl Lerchecbf7cc12019-02-15 14:09:31 -0800650 ));
651 }
652
Carl Lerche058ff472019-02-13 16:23:52 -0800653 let mut state = codegen::State::default();
David Tolnayf9bb8ff2019-02-15 13:10:14 -0800654 for s in &defs.types {
Carl Lerchecbf7cc12019-02-15 14:09:31 -0800655 codegen::generate(&mut state, s, &defs);
Carl Lerche058ff472019-02-13 16:23:52 -0800656 }
657
658 let full_macro = quote! {
659 #[cfg(feature = "full")]
660 macro_rules! full {
661 ($e:expr) => {
662 $e
663 };
664 }
665
666 #[cfg(all(feature = "derive", not(feature = "full")))]
667 macro_rules! full {
668 ($e:expr) => {
669 unreachable!()
670 };
671 }
672 };
673
674 let skip_macro = quote! {
675 #[cfg(any(feature = "full", feature = "derive"))]
676 macro_rules! skip {
677 ($($tt:tt)*) => {};
678 }
679 };
680
681 let fold_trait = state.fold_trait;
682 let fold_impl = state.fold_impl;
683 write_file(
684 FOLD_SRC,
685 quote! {
686 // Unreachable code is generated sometimes without the full feature.
687 #![allow(unreachable_code)]
688
689 use *;
690 #[cfg(any(feature = "full", feature = "derive"))]
691 use token::{Brace, Bracket, Paren, Group};
692 use proc_macro2::Span;
693 #[cfg(any(feature = "full", feature = "derive"))]
694 use gen::helper::fold::*;
695
696 #full_macro
697
698 /// Syntax tree traversal to transform the nodes of an owned syntax tree.
699 ///
700 /// See the [module documentation] for details.
701 ///
702 /// [module documentation]: index.html
703 ///
704 /// *This trait is available if Syn is built with the `"fold"` feature.*
705 pub trait Fold {
706 #fold_trait
707 }
708
709 #[cfg(any(feature = "full", feature = "derive"))]
710 macro_rules! fold_span_only {
711 ($f:ident : $t:ident) => {
712 pub fn $f<V: Fold + ?Sized>(_visitor: &mut V, mut _i: $t) -> $t {
713 let span = _visitor.fold_span(_i.span());
714 _i.set_span(span);
715 _i
716 }
717 }
718 }
719
720 #[cfg(any(feature = "full", feature = "derive"))]
721 fold_span_only!(fold_lit_byte: LitByte);
722 #[cfg(any(feature = "full", feature = "derive"))]
723 fold_span_only!(fold_lit_byte_str: LitByteStr);
724 #[cfg(any(feature = "full", feature = "derive"))]
725 fold_span_only!(fold_lit_char: LitChar);
726 #[cfg(any(feature = "full", feature = "derive"))]
727 fold_span_only!(fold_lit_float: LitFloat);
728 #[cfg(any(feature = "full", feature = "derive"))]
729 fold_span_only!(fold_lit_int: LitInt);
730 #[cfg(any(feature = "full", feature = "derive"))]
731 fold_span_only!(fold_lit_str: LitStr);
732
733 #fold_impl
734 },
735 );
736
737 let visit_trait = state.visit_trait;
738 let visit_impl = state.visit_impl;
739 write_file(
740 VISIT_SRC,
741 quote! {
742 #![cfg_attr(feature = "cargo-clippy", allow(trivially_copy_pass_by_ref))]
743
744 use *;
745 #[cfg(any(feature = "full", feature = "derive"))]
746 use punctuated::Punctuated;
747 use proc_macro2::Span;
748 #[cfg(any(feature = "full", feature = "derive"))]
749 use gen::helper::visit::*;
750
751 #full_macro
752 #skip_macro
753
754 /// Syntax tree traversal to walk a shared borrow of a syntax tree.
755 ///
756 /// See the [module documentation] for details.
757 ///
758 /// [module documentation]: index.html
759 ///
760 /// *This trait is available if Syn is built with the `"visit"` feature.*
761 pub trait Visit<'ast> {
762 #visit_trait
763 }
764
765 #visit_impl
766 },
767 );
768
769 let visit_mut_trait = state.visit_mut_trait;
770 let visit_mut_impl = state.visit_mut_impl;
771 write_file(
772 VISIT_MUT_SRC,
773 quote! {
774 use *;
775 #[cfg(any(feature = "full", feature = "derive"))]
776 use punctuated::Punctuated;
777 use proc_macro2::Span;
778 #[cfg(any(feature = "full", feature = "derive"))]
779 use gen::helper::visit_mut::*;
780
781 #full_macro
782 #skip_macro
783
784 /// Syntax tree traversal to mutate an exclusive borrow of a syntax tree in
785 /// place.
786 ///
787 /// See the [module documentation] for details.
788 ///
789 /// [module documentation]: index.html
790 ///
791 /// *This trait is available if Syn is built with the `"visit-mut"` feature.*
792 pub trait VisitMut {
793 #visit_mut_trait
794 }
795
796 #visit_mut_impl
797 },
798 );
799}