blob: a51a80030a67dde4952c533e33f6c51ce951dde1 [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;
14use proc_macro2::TokenStream;
15
16use std::fs::File;
17use std::io::Write;
18
19const FOLD_SRC: &str = "../src/gen/fold.rs";
20const VISIT_SRC: &str = "../src/gen/visit.rs";
21const VISIT_MUT_SRC: &str = "../src/gen/visit_mut.rs";
22
23mod codegen {
24 use crate::types;
25 use inflections::Inflect;
26 use proc_macro2::{Span, TokenStream};
27 use quote::TokenStreamExt;
28 use syn::*;
29
30 #[derive(Default)]
31 pub struct State {
32 pub visit_trait: TokenStream,
33 pub visit_impl: TokenStream,
34 pub visit_mut_trait: TokenStream,
35 pub visit_mut_impl: TokenStream,
36 pub fold_trait: TokenStream,
37 pub fold_impl: TokenStream,
38 }
39
40 fn under_name(name: &str) -> Ident {
41 Ident::new(&name.to_snake_case(), Span::call_site())
42 }
43
44 #[derive(Debug, Eq, PartialEq, Copy, Clone)]
45 enum Kind {
46 Visit,
47 VisitMut,
48 Fold,
49 }
50
51 enum Operand {
52 Borrowed(TokenStream),
53 Owned(TokenStream),
54 }
55
56 use self::Kind::*;
57 use self::Operand::*;
58
59 impl Operand {
60 fn tokens(&self) -> &TokenStream {
61 match *self {
62 Borrowed(ref n) | Owned(ref n) => n,
63 }
64 }
65
66 fn ref_tokens(&self) -> TokenStream {
67 match *self {
68 Borrowed(ref n) => n.clone(),
69 Owned(ref n) => quote!(&#n),
70 }
71 }
72
73 fn ref_mut_tokens(&self) -> TokenStream {
74 match *self {
75 Borrowed(ref n) => n.clone(),
76 Owned(ref n) => quote!(&mut #n),
77 }
78 }
79
80 fn owned_tokens(&self) -> TokenStream {
81 match *self {
82 Borrowed(ref n) => quote!(*#n),
83 Owned(ref n) => n.clone(),
84 }
85 }
86 }
87
88 fn simple_visit(item: &str, kind: Kind, name: &Operand) -> TokenStream {
89 let ident = under_name(item);
90
91 match kind {
92 Visit => {
93 let method = Ident::new(&format!("visit_{}", ident), Span::call_site());
94 let name = name.ref_tokens();
95 quote! {
96 _visitor.#method(#name)
97 }
98 }
99 VisitMut => {
100 let method = Ident::new(&format!("visit_{}_mut", ident), Span::call_site());
101 let name = name.ref_mut_tokens();
102 quote! {
103 _visitor.#method(#name)
104 }
105 }
106 Fold => {
107 let method = Ident::new(&format!("fold_{}", ident), Span::call_site());
108 let name = name.owned_tokens();
109 quote! {
110 _visitor.#method(#name)
111 }
112 }
113 }
114 }
115
116 fn box_visit(
117 elem: &types::Type,
118 features: &types::Features,
David Tolnay157c7eb2019-02-15 13:21:48 -0800119 defs: &types::Definitions,
Carl Lerche058ff472019-02-13 16:23:52 -0800120 kind: Kind,
121 name: &Operand,
122 ) -> Option<TokenStream> {
123 let name = name.owned_tokens();
David Tolnay157c7eb2019-02-15 13:21:48 -0800124 let res = visit(elem, features, defs, kind, &Owned(quote!(*#name)))?;
Carl Lerche058ff472019-02-13 16:23:52 -0800125 Some(match kind {
126 Fold => quote! {
127 Box::new(#res)
128 },
129 Visit | VisitMut => res,
130 })
131 }
132
133 fn vec_visit(
134 elem: &types::Type,
135 features: &types::Features,
David Tolnay157c7eb2019-02-15 13:21:48 -0800136 defs: &types::Definitions,
Carl Lerche058ff472019-02-13 16:23:52 -0800137 kind: Kind,
138 name: &Operand,
139 ) -> Option<TokenStream> {
140 let operand = match kind {
141 Visit | VisitMut => Borrowed(quote!(it)),
142 Fold => Owned(quote!(it)),
143 };
David Tolnay157c7eb2019-02-15 13:21:48 -0800144 let val = visit(elem, features, defs, kind, &operand)?;
Carl Lerche058ff472019-02-13 16:23:52 -0800145 Some(match kind {
146 Visit => {
147 let name = name.ref_tokens();
148 quote! {
149 for it in #name {
150 #val
151 }
152 }
153 }
154 VisitMut => {
155 let name = name.ref_mut_tokens();
156 quote! {
157 for it in #name {
158 #val
159 }
160 }
161 }
162 Fold => {
163 let name = name.owned_tokens();
164 quote! {
165 FoldHelper::lift(#name, |it| { #val })
166 }
167 }
168 })
169 }
170
171 fn punctuated_visit(
172 elem: &types::Type,
173 features: &types::Features,
David Tolnay157c7eb2019-02-15 13:21:48 -0800174 defs: &types::Definitions,
Carl Lerche058ff472019-02-13 16:23:52 -0800175 kind: Kind,
176 name: &Operand,
177 ) -> Option<TokenStream> {
178 let operand = match kind {
179 Visit | VisitMut => Borrowed(quote!(it)),
180 Fold => Owned(quote!(it)),
181 };
David Tolnay157c7eb2019-02-15 13:21:48 -0800182 let val = visit(elem, features, defs, kind, &operand)?;
Carl Lerche058ff472019-02-13 16:23:52 -0800183 Some(match kind {
184 Visit => {
185 let name = name.ref_tokens();
186 quote! {
187 for el in Punctuated::pairs(#name) {
188 let it = el.value();
189 #val
190 }
191 }
192 }
193 VisitMut => {
194 let name = name.ref_mut_tokens();
195 quote! {
196 for mut el in Punctuated::pairs_mut(#name) {
197 let it = el.value_mut();
198 #val
199 }
200 }
201 }
202 Fold => {
203 let name = name.owned_tokens();
204 quote! {
205 FoldHelper::lift(#name, |it| { #val })
206 }
207 }
208 })
209 }
210
211 fn option_visit(
212 elem: &types::Type,
213 features: &types::Features,
David Tolnay157c7eb2019-02-15 13:21:48 -0800214 defs: &types::Definitions,
Carl Lerche058ff472019-02-13 16:23:52 -0800215 kind: Kind,
216 name: &Operand,
217 ) -> Option<TokenStream> {
218 let it = match kind {
219 Visit | VisitMut => Borrowed(quote!(it)),
220 Fold => Owned(quote!(it)),
221 };
David Tolnay157c7eb2019-02-15 13:21:48 -0800222 let val = visit(elem, features, defs, kind, &it)?;
Carl Lerche058ff472019-02-13 16:23:52 -0800223 let name = name.owned_tokens();
224 Some(match kind {
225 Visit => quote! {
226 if let Some(ref it) = #name {
227 #val
228 }
229 },
230 VisitMut => quote! {
231 if let Some(ref mut it) = #name {
232 #val
233 }
234 },
235 Fold => quote! {
236 (#name).map(|it| { #val })
237 },
238 })
239 }
240
241 fn tuple_visit(
242 elems: &[types::Type],
243 features: &types::Features,
David Tolnay157c7eb2019-02-15 13:21:48 -0800244 defs: &types::Definitions,
Carl Lerche058ff472019-02-13 16:23:52 -0800245 kind: Kind,
246 name: &Operand,
247 ) -> Option<TokenStream> {
248 if elems.is_empty() {
249 return None;
250 }
251
252 let mut code = TokenStream::new();
253 for (i, elem) in elems.iter().enumerate() {
254 let name = name.tokens();
255 let i = Index::from(i);
256 let it = Owned(quote!((#name).#i));
257 let val =
David Tolnay157c7eb2019-02-15 13:21:48 -0800258 visit(elem, features, defs, kind, &it).unwrap_or_else(|| noop_visit(kind, &it));
Carl Lerche058ff472019-02-13 16:23:52 -0800259 code.append_all(val);
260 match kind {
261 Fold => code.append_all(quote!(,)),
262 Visit | VisitMut => code.append_all(quote!(;)),
263 }
264 }
265 Some(match kind {
266 Fold => quote! {
267 (#code)
268 },
269 Visit | VisitMut => code,
270 })
271 }
272
David Tolnay157c7eb2019-02-15 13:21:48 -0800273 fn token_punct_visit(repr: &str, kind: Kind, name: &Operand) -> TokenStream {
274 let ty: TokenStream = syn::parse_str(&format!("Token![{}]", repr)).unwrap();
Carl Lerche058ff472019-02-13 16:23:52 -0800275 let name = name.tokens();
276 match kind {
277 Fold => quote! {
278 #ty(tokens_helper(_visitor, &#name.spans))
279 },
280 Visit => quote! {
281 tokens_helper(_visitor, &#name.spans)
282 },
283 VisitMut => quote! {
284 tokens_helper(_visitor, &mut #name.spans)
285 },
286 }
287 }
288
David Tolnay157c7eb2019-02-15 13:21:48 -0800289 fn token_keyword_visit(repr: &str, kind: Kind, name: &Operand) -> TokenStream {
290 let ty: TokenStream = syn::parse_str(&format!("Token![{}]", repr)).unwrap();
Carl Lerche058ff472019-02-13 16:23:52 -0800291 let name = name.tokens();
292 match kind {
293 Fold => quote! {
294 #ty(tokens_helper(_visitor, &#name.span))
295 },
296 Visit => quote! {
297 tokens_helper(_visitor, &#name.span)
298 },
299 VisitMut => quote! {
300 tokens_helper(_visitor, &mut #name.span)
301 },
302 }
303 }
304
305 fn token_group_visit(ty: &str, kind: Kind, name: &Operand) -> TokenStream {
306 let ty = Ident::new(ty, Span::call_site());
307 let name = name.tokens();
308 match kind {
309 Fold => quote! {
310 #ty(tokens_helper(_visitor, &#name.span))
311 },
312 Visit => quote! {
313 tokens_helper(_visitor, &#name.span)
314 },
315 VisitMut => quote! {
316 tokens_helper(_visitor, &mut #name.span)
317 },
318 }
319 }
320
321 fn noop_visit(kind: Kind, name: &Operand) -> TokenStream {
322 match kind {
323 Fold => name.owned_tokens(),
324 Visit | VisitMut => {
325 let name = name.tokens();
326 quote! {
327 skip!(#name)
328 }
329 }
330 }
331 }
332
333 fn visit(
334 ty: &types::Type,
335 features: &types::Features,
David Tolnay157c7eb2019-02-15 13:21:48 -0800336 defs: &types::Definitions,
Carl Lerche058ff472019-02-13 16:23:52 -0800337 kind: Kind,
338 name: &Operand,
339 ) -> Option<TokenStream> {
340 match ty {
David Tolnay157c7eb2019-02-15 13:21:48 -0800341 types::Type::Box(t) => box_visit(&*t, features, defs, kind, name),
342 types::Type::Vec(t) => vec_visit(&*t, features, defs, kind, name),
David Tolnay485973a2019-02-15 14:42:48 -0800343 types::Type::Punctuated(p) => punctuated_visit(&p.element, features, defs, kind, name),
David Tolnay157c7eb2019-02-15 13:21:48 -0800344 types::Type::Option(t) => option_visit(&*t, features, defs, kind, name),
345 types::Type::Tuple(t) => tuple_visit(t, features, defs, kind, name),
Carl Lerche058ff472019-02-13 16:23:52 -0800346 types::Type::Token(t) => {
David Tolnay157c7eb2019-02-15 13:21:48 -0800347 let repr = &defs.tokens[t];
348 let is_keyword = repr.chars().next().unwrap().is_alphabetic();
349 if is_keyword {
350 Some(token_keyword_visit(repr, kind, name))
Carl Lerche058ff472019-02-13 16:23:52 -0800351 } else {
David Tolnay157c7eb2019-02-15 13:21:48 -0800352 Some(token_punct_visit(repr, kind, name))
Carl Lerche058ff472019-02-13 16:23:52 -0800353 }
354 }
David Tolnay295141b2019-02-15 12:45:33 -0800355 types::Type::Group(t) => Some(token_group_visit(&t[..], kind, name)),
David Tolnayd3076572019-02-15 13:32:44 -0800356 types::Type::Syn(t) => {
Carl Lerche058ff472019-02-13 16:23:52 -0800357 fn requires_full(features: &types::Features) -> bool {
David Tolnay440fe582019-02-15 20:23:14 -0800358 features.any.contains("full") && features.any.len() == 1
Carl Lerche058ff472019-02-13 16:23:52 -0800359 }
360
361 let mut res = simple_visit(t, kind, name);
362
David Tolnayc2be7b22019-02-15 18:48:31 -0800363 let target = defs.types.iter().find(|ty| ty.ident == *t).unwrap();
Carl Lerche058ff472019-02-13 16:23:52 -0800364
365 Some(
David Tolnayc2be7b22019-02-15 18:48:31 -0800366 if requires_full(&target.features) && !requires_full(features) {
Carl Lerche058ff472019-02-13 16:23:52 -0800367 quote! {
368 full!(#res)
369 }
370 } else {
371 res
372 },
373 )
374 }
Carl Lerchecbf7cc12019-02-15 14:09:31 -0800375 types::Type::Ext(t) if super::TERMINAL_TYPES.contains(&&t[..]) => {
376 Some(simple_visit(t, kind, name))
377 }
Carl Lerche058ff472019-02-13 16:23:52 -0800378 types::Type::Ext(_) | types::Type::Std(_) => None,
379 }
380 }
381
382 fn visit_features(features: &types::Features) -> TokenStream {
David Tolnay440fe582019-02-15 20:23:14 -0800383 let features = &features.any;
Carl Lerche058ff472019-02-13 16:23:52 -0800384 match features.len() {
385 0 => quote!(),
David Tolnay440fe582019-02-15 20:23:14 -0800386 1 => quote!(#[cfg(feature = #(#features)*)]),
387 _ => quote!(#[cfg(any(#(feature = #features),*))]),
Carl Lerche058ff472019-02-13 16:23:52 -0800388 }
389 }
390
David Tolnay157c7eb2019-02-15 13:21:48 -0800391 pub fn generate(state: &mut State, s: &types::Node, defs: &types::Definitions) {
David Tolnayc2be7b22019-02-15 18:48:31 -0800392 let features = visit_features(&s.features);
393 let under_name = under_name(&s.ident);
394 let ty = Ident::new(&s.ident, Span::call_site());
Carl Lerche058ff472019-02-13 16:23:52 -0800395 let visit_fn = Ident::new(&format!("visit_{}", under_name), Span::call_site());
396 let visit_mut_fn = Ident::new(&format!("visit_{}_mut", under_name), Span::call_site());
397 let fold_fn = Ident::new(&format!("fold_{}", under_name), Span::call_site());
398
399 let mut visit_impl = TokenStream::new();
400 let mut visit_mut_impl = TokenStream::new();
401 let mut fold_impl = TokenStream::new();
402
David Tolnayc2be7b22019-02-15 18:48:31 -0800403 match &s.data {
404 types::Data::Enum(variants) => {
Carl Lerche058ff472019-02-13 16:23:52 -0800405 let mut visit_variants = TokenStream::new();
406 let mut visit_mut_variants = TokenStream::new();
407 let mut fold_variants = TokenStream::new();
408
David Tolnayc2be7b22019-02-15 18:48:31 -0800409 for variant in variants {
David Tolnay485973a2019-02-15 14:42:48 -0800410 let variant_ident = Ident::new(&variant.ident, Span::call_site());
Carl Lerche058ff472019-02-13 16:23:52 -0800411
David Tolnay485973a2019-02-15 14:42:48 -0800412 if variant.fields.is_empty() {
Carl Lerche058ff472019-02-13 16:23:52 -0800413 visit_variants.append_all(quote! {
414 #ty::#variant_ident => {}
415 });
416 visit_mut_variants.append_all(quote! {
417 #ty::#variant_ident => {}
418 });
419 fold_variants.append_all(quote! {
420 #ty::#variant_ident => {
421 #ty::#variant_ident
422 }
423 });
424 } else {
425 let mut bind_visit_fields = TokenStream::new();
426 let mut bind_visit_mut_fields = TokenStream::new();
427 let mut bind_fold_fields = TokenStream::new();
428
429 let mut visit_fields = TokenStream::new();
430 let mut visit_mut_fields = TokenStream::new();
431 let mut fold_fields = TokenStream::new();
432
David Tolnay485973a2019-02-15 14:42:48 -0800433 for (idx, ty) in variant.fields.iter().enumerate() {
Carl Lerche058ff472019-02-13 16:23:52 -0800434 let name = format!("_binding_{}", idx);
435 let binding = Ident::new(&name, Span::call_site());
436
437 bind_visit_fields.append_all(quote! {
438 ref #binding,
439 });
440 bind_visit_mut_fields.append_all(quote! {
441 ref mut #binding,
442 });
443 bind_fold_fields.append_all(quote! {
444 #binding,
445 });
446
447 let borrowed_binding = Borrowed(quote!(#binding));
448 let owned_binding = Owned(quote!(#binding));
449
450 visit_fields.append_all(
David Tolnayc2be7b22019-02-15 18:48:31 -0800451 visit(ty, &s.features, defs, Visit, &borrowed_binding)
Carl Lerche058ff472019-02-13 16:23:52 -0800452 .unwrap_or_else(|| noop_visit(Visit, &borrowed_binding)),
453 );
454 visit_mut_fields.append_all(
David Tolnayc2be7b22019-02-15 18:48:31 -0800455 visit(ty, &s.features, defs, VisitMut, &borrowed_binding)
Carl Lerche058ff472019-02-13 16:23:52 -0800456 .unwrap_or_else(|| noop_visit(VisitMut, &borrowed_binding)),
457 );
458 fold_fields.append_all(
David Tolnayc2be7b22019-02-15 18:48:31 -0800459 visit(ty, &s.features, defs, Fold, &owned_binding)
Carl Lerche058ff472019-02-13 16:23:52 -0800460 .unwrap_or_else(|| noop_visit(Fold, &owned_binding)),
461 );
462
463 visit_fields.append_all(quote!(;));
464 visit_mut_fields.append_all(quote!(;));
465 fold_fields.append_all(quote!(,));
466 }
467
468 visit_variants.append_all(quote! {
469 #ty::#variant_ident(#bind_visit_fields) => {
470 #visit_fields
471 }
472 });
473
474 visit_mut_variants.append_all(quote! {
475 #ty::#variant_ident(#bind_visit_mut_fields) => {
476 #visit_mut_fields
477 }
478 });
479
480 fold_variants.append_all(quote! {
481 #ty::#variant_ident(#bind_fold_fields) => {
482 #ty::#variant_ident(
483 #fold_fields
484 )
485 }
486 });
487 }
488 }
489
490 visit_impl.append_all(quote! {
491 match *_i {
492 #visit_variants
493 }
494 });
495
496 visit_mut_impl.append_all(quote! {
497 match *_i {
498 #visit_mut_variants
499 }
500 });
501
502 fold_impl.append_all(quote! {
503 match _i {
504 #fold_variants
505 }
506 });
507 }
David Tolnayc2be7b22019-02-15 18:48:31 -0800508 types::Data::Struct(fields) => {
Carl Lerche058ff472019-02-13 16:23:52 -0800509 let mut fold_fields = TokenStream::new();
510
David Tolnayc2be7b22019-02-15 18:48:31 -0800511 for (field, ty) in fields {
David Tolnay485973a2019-02-15 14:42:48 -0800512 let id = Ident::new(&field, Span::call_site());
Carl Lerche058ff472019-02-13 16:23:52 -0800513 let ref_toks = Owned(quote!(_i.#id));
David Tolnayc2be7b22019-02-15 18:48:31 -0800514 let visit_field = visit(&ty, &s.features, defs, Visit, &ref_toks)
Carl Lerche058ff472019-02-13 16:23:52 -0800515 .unwrap_or_else(|| noop_visit(Visit, &ref_toks));
516 visit_impl.append_all(quote! {
517 #visit_field;
518 });
David Tolnayc2be7b22019-02-15 18:48:31 -0800519 let visit_mut_field = visit(&ty, &s.features, defs, VisitMut, &ref_toks)
David Tolnay47fe7402019-02-15 14:35:25 -0800520 .unwrap_or_else(|| noop_visit(VisitMut, &ref_toks));
Carl Lerche058ff472019-02-13 16:23:52 -0800521 visit_mut_impl.append_all(quote! {
522 #visit_mut_field;
523 });
David Tolnayc2be7b22019-02-15 18:48:31 -0800524 let fold = visit(&ty, &s.features, defs, Fold, &ref_toks)
Carl Lerche058ff472019-02-13 16:23:52 -0800525 .unwrap_or_else(|| noop_visit(Fold, &ref_toks));
526
527 fold_fields.append_all(quote! {
528 #id: #fold,
529 });
530 }
531
David Tolnayc2be7b22019-02-15 18:48:31 -0800532 if !fields.is_empty() {
Carl Lerche058ff472019-02-13 16:23:52 -0800533 fold_impl.append_all(quote! {
534 #ty {
535 #fold_fields
536 }
537 })
538 } else {
539 if ty == "Ident" {
540 fold_impl.append_all(quote! {
541 let mut _i = _i;
542 let span = _visitor.fold_span(_i.span());
543 _i.set_span(span);
544 });
545 }
546 fold_impl.append_all(quote! {
547 _i
548 });
549 }
550 }
David Tolnayc2be7b22019-02-15 18:48:31 -0800551 types::Data::Private => {
552 if ty == "Ident" {
553 fold_impl.append_all(quote! {
554 let mut _i = _i;
555 let span = _visitor.fold_span(_i.span());
556 _i.set_span(span);
557 });
558 }
559 fold_impl.append_all(quote! {
560 _i
561 });
Carl Lerche058ff472019-02-13 16:23:52 -0800562 }
563 }
564
David Tolnayc2be7b22019-02-15 18:48:31 -0800565 let include_fold_impl = match &s.data {
566 types::Data::Private => super::TERMINAL_TYPES.contains(&s.ident.as_str()),
567 types::Data::Struct(_) | types::Data::Enum(_) => true,
568 };
569
Carl Lerche058ff472019-02-13 16:23:52 -0800570 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 {
David Tolnayc2be7b22019-02-15 18:48:31 -0800646 defs.types.push(types::Node {
647 ident: tt.to_string(),
648 features: types::Features::default(),
649 data: types::Data::Private,
650 });
Carl Lerchecbf7cc12019-02-15 14:09:31 -0800651 }
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}