blob: 3daf75aa408cc6f0e1b5c8eb7fe4de70ab03743b [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;
David Tolnay397bd0b2019-02-15 20:51:10 -080015use quote::quote;
16use rustfmt_nightly as rustfmt;
Carl Lerche058ff472019-02-13 16:23:52 -080017
18use std::fs::File;
19use std::io::Write;
20
21const FOLD_SRC: &str = "../src/gen/fold.rs";
22const VISIT_SRC: &str = "../src/gen/visit.rs";
23const VISIT_MUT_SRC: &str = "../src/gen/visit_mut.rs";
24
25mod codegen {
26 use crate::types;
27 use inflections::Inflect;
28 use proc_macro2::{Span, TokenStream};
David Tolnay397bd0b2019-02-15 20:51:10 -080029 use quote::{quote, TokenStreamExt};
Carl Lerche058ff472019-02-13 16:23:52 -080030 use syn::*;
31
32 #[derive(Default)]
33 pub struct State {
34 pub visit_trait: TokenStream,
35 pub visit_impl: TokenStream,
36 pub visit_mut_trait: TokenStream,
37 pub visit_mut_impl: TokenStream,
38 pub fold_trait: TokenStream,
39 pub fold_impl: TokenStream,
40 }
41
42 fn under_name(name: &str) -> Ident {
43 Ident::new(&name.to_snake_case(), Span::call_site())
44 }
45
46 #[derive(Debug, Eq, PartialEq, Copy, Clone)]
47 enum Kind {
48 Visit,
49 VisitMut,
50 Fold,
51 }
52
53 enum Operand {
54 Borrowed(TokenStream),
55 Owned(TokenStream),
56 }
57
58 use self::Kind::*;
59 use self::Operand::*;
60
61 impl Operand {
62 fn tokens(&self) -> &TokenStream {
63 match *self {
64 Borrowed(ref n) | Owned(ref n) => n,
65 }
66 }
67
68 fn ref_tokens(&self) -> TokenStream {
69 match *self {
70 Borrowed(ref n) => n.clone(),
71 Owned(ref n) => quote!(&#n),
72 }
73 }
74
75 fn ref_mut_tokens(&self) -> TokenStream {
76 match *self {
77 Borrowed(ref n) => n.clone(),
78 Owned(ref n) => quote!(&mut #n),
79 }
80 }
81
82 fn owned_tokens(&self) -> TokenStream {
83 match *self {
84 Borrowed(ref n) => quote!(*#n),
85 Owned(ref n) => n.clone(),
86 }
87 }
88 }
89
90 fn simple_visit(item: &str, kind: Kind, name: &Operand) -> TokenStream {
91 let ident = under_name(item);
92
93 match kind {
94 Visit => {
95 let method = Ident::new(&format!("visit_{}", ident), Span::call_site());
96 let name = name.ref_tokens();
97 quote! {
98 _visitor.#method(#name)
99 }
100 }
101 VisitMut => {
102 let method = Ident::new(&format!("visit_{}_mut", ident), Span::call_site());
103 let name = name.ref_mut_tokens();
104 quote! {
105 _visitor.#method(#name)
106 }
107 }
108 Fold => {
109 let method = Ident::new(&format!("fold_{}", ident), Span::call_site());
110 let name = name.owned_tokens();
111 quote! {
112 _visitor.#method(#name)
113 }
114 }
115 }
116 }
117
118 fn box_visit(
119 elem: &types::Type,
120 features: &types::Features,
David Tolnay157c7eb2019-02-15 13:21:48 -0800121 defs: &types::Definitions,
Carl Lerche058ff472019-02-13 16:23:52 -0800122 kind: Kind,
123 name: &Operand,
124 ) -> Option<TokenStream> {
125 let name = name.owned_tokens();
David Tolnay157c7eb2019-02-15 13:21:48 -0800126 let res = visit(elem, features, defs, kind, &Owned(quote!(*#name)))?;
Carl Lerche058ff472019-02-13 16:23:52 -0800127 Some(match kind {
128 Fold => quote! {
129 Box::new(#res)
130 },
131 Visit | VisitMut => res,
132 })
133 }
134
135 fn vec_visit(
136 elem: &types::Type,
137 features: &types::Features,
David Tolnay157c7eb2019-02-15 13:21:48 -0800138 defs: &types::Definitions,
Carl Lerche058ff472019-02-13 16:23:52 -0800139 kind: Kind,
140 name: &Operand,
141 ) -> Option<TokenStream> {
142 let operand = match kind {
143 Visit | VisitMut => Borrowed(quote!(it)),
144 Fold => Owned(quote!(it)),
145 };
David Tolnay157c7eb2019-02-15 13:21:48 -0800146 let val = visit(elem, features, defs, kind, &operand)?;
Carl Lerche058ff472019-02-13 16:23:52 -0800147 Some(match kind {
148 Visit => {
149 let name = name.ref_tokens();
150 quote! {
151 for it in #name {
152 #val
153 }
154 }
155 }
156 VisitMut => {
157 let name = name.ref_mut_tokens();
158 quote! {
159 for it in #name {
160 #val
161 }
162 }
163 }
164 Fold => {
165 let name = name.owned_tokens();
166 quote! {
167 FoldHelper::lift(#name, |it| { #val })
168 }
169 }
170 })
171 }
172
173 fn punctuated_visit(
174 elem: &types::Type,
175 features: &types::Features,
David Tolnay157c7eb2019-02-15 13:21:48 -0800176 defs: &types::Definitions,
Carl Lerche058ff472019-02-13 16:23:52 -0800177 kind: Kind,
178 name: &Operand,
179 ) -> Option<TokenStream> {
180 let operand = match kind {
181 Visit | VisitMut => Borrowed(quote!(it)),
182 Fold => Owned(quote!(it)),
183 };
David Tolnay157c7eb2019-02-15 13:21:48 -0800184 let val = visit(elem, features, defs, kind, &operand)?;
Carl Lerche058ff472019-02-13 16:23:52 -0800185 Some(match kind {
186 Visit => {
187 let name = name.ref_tokens();
188 quote! {
189 for el in Punctuated::pairs(#name) {
190 let it = el.value();
191 #val
192 }
193 }
194 }
195 VisitMut => {
196 let name = name.ref_mut_tokens();
197 quote! {
198 for mut el in Punctuated::pairs_mut(#name) {
199 let it = el.value_mut();
200 #val
201 }
202 }
203 }
204 Fold => {
205 let name = name.owned_tokens();
206 quote! {
207 FoldHelper::lift(#name, |it| { #val })
208 }
209 }
210 })
211 }
212
213 fn option_visit(
214 elem: &types::Type,
215 features: &types::Features,
David Tolnay157c7eb2019-02-15 13:21:48 -0800216 defs: &types::Definitions,
Carl Lerche058ff472019-02-13 16:23:52 -0800217 kind: Kind,
218 name: &Operand,
219 ) -> Option<TokenStream> {
220 let it = match kind {
221 Visit | VisitMut => Borrowed(quote!(it)),
222 Fold => Owned(quote!(it)),
223 };
David Tolnay157c7eb2019-02-15 13:21:48 -0800224 let val = visit(elem, features, defs, kind, &it)?;
Carl Lerche058ff472019-02-13 16:23:52 -0800225 let name = name.owned_tokens();
226 Some(match kind {
227 Visit => quote! {
228 if let Some(ref it) = #name {
229 #val
230 }
231 },
232 VisitMut => quote! {
233 if let Some(ref mut it) = #name {
234 #val
235 }
236 },
237 Fold => quote! {
238 (#name).map(|it| { #val })
239 },
240 })
241 }
242
243 fn tuple_visit(
244 elems: &[types::Type],
245 features: &types::Features,
David Tolnay157c7eb2019-02-15 13:21:48 -0800246 defs: &types::Definitions,
Carl Lerche058ff472019-02-13 16:23:52 -0800247 kind: Kind,
248 name: &Operand,
249 ) -> Option<TokenStream> {
250 if elems.is_empty() {
251 return None;
252 }
253
254 let mut code = TokenStream::new();
255 for (i, elem) in elems.iter().enumerate() {
256 let name = name.tokens();
257 let i = Index::from(i);
258 let it = Owned(quote!((#name).#i));
259 let val =
David Tolnay157c7eb2019-02-15 13:21:48 -0800260 visit(elem, features, defs, kind, &it).unwrap_or_else(|| noop_visit(kind, &it));
Carl Lerche058ff472019-02-13 16:23:52 -0800261 code.append_all(val);
262 match kind {
263 Fold => code.append_all(quote!(,)),
264 Visit | VisitMut => code.append_all(quote!(;)),
265 }
266 }
267 Some(match kind {
268 Fold => quote! {
269 (#code)
270 },
271 Visit | VisitMut => code,
272 })
273 }
274
David Tolnay157c7eb2019-02-15 13:21:48 -0800275 fn token_punct_visit(repr: &str, kind: Kind, name: &Operand) -> TokenStream {
276 let ty: TokenStream = syn::parse_str(&format!("Token![{}]", repr)).unwrap();
Carl Lerche058ff472019-02-13 16:23:52 -0800277 let name = name.tokens();
278 match kind {
279 Fold => quote! {
280 #ty(tokens_helper(_visitor, &#name.spans))
281 },
282 Visit => quote! {
283 tokens_helper(_visitor, &#name.spans)
284 },
285 VisitMut => quote! {
286 tokens_helper(_visitor, &mut #name.spans)
287 },
288 }
289 }
290
David Tolnay157c7eb2019-02-15 13:21:48 -0800291 fn token_keyword_visit(repr: &str, kind: Kind, name: &Operand) -> TokenStream {
292 let ty: TokenStream = syn::parse_str(&format!("Token![{}]", repr)).unwrap();
Carl Lerche058ff472019-02-13 16:23:52 -0800293 let name = name.tokens();
294 match kind {
295 Fold => quote! {
296 #ty(tokens_helper(_visitor, &#name.span))
297 },
298 Visit => quote! {
299 tokens_helper(_visitor, &#name.span)
300 },
301 VisitMut => quote! {
302 tokens_helper(_visitor, &mut #name.span)
303 },
304 }
305 }
306
307 fn token_group_visit(ty: &str, kind: Kind, name: &Operand) -> TokenStream {
308 let ty = Ident::new(ty, Span::call_site());
309 let name = name.tokens();
310 match kind {
311 Fold => quote! {
312 #ty(tokens_helper(_visitor, &#name.span))
313 },
314 Visit => quote! {
315 tokens_helper(_visitor, &#name.span)
316 },
317 VisitMut => quote! {
318 tokens_helper(_visitor, &mut #name.span)
319 },
320 }
321 }
322
323 fn noop_visit(kind: Kind, name: &Operand) -> TokenStream {
324 match kind {
325 Fold => name.owned_tokens(),
326 Visit | VisitMut => {
327 let name = name.tokens();
328 quote! {
329 skip!(#name)
330 }
331 }
332 }
333 }
334
335 fn visit(
336 ty: &types::Type,
337 features: &types::Features,
David Tolnay157c7eb2019-02-15 13:21:48 -0800338 defs: &types::Definitions,
Carl Lerche058ff472019-02-13 16:23:52 -0800339 kind: Kind,
340 name: &Operand,
341 ) -> Option<TokenStream> {
342 match ty {
David Tolnay157c7eb2019-02-15 13:21:48 -0800343 types::Type::Box(t) => box_visit(&*t, features, defs, kind, name),
344 types::Type::Vec(t) => vec_visit(&*t, features, defs, kind, name),
David Tolnay485973a2019-02-15 14:42:48 -0800345 types::Type::Punctuated(p) => punctuated_visit(&p.element, features, defs, kind, name),
David Tolnay157c7eb2019-02-15 13:21:48 -0800346 types::Type::Option(t) => option_visit(&*t, features, defs, kind, name),
347 types::Type::Tuple(t) => tuple_visit(t, features, defs, kind, name),
Carl Lerche058ff472019-02-13 16:23:52 -0800348 types::Type::Token(t) => {
David Tolnay157c7eb2019-02-15 13:21:48 -0800349 let repr = &defs.tokens[t];
350 let is_keyword = repr.chars().next().unwrap().is_alphabetic();
351 if is_keyword {
352 Some(token_keyword_visit(repr, kind, name))
Carl Lerche058ff472019-02-13 16:23:52 -0800353 } else {
David Tolnay157c7eb2019-02-15 13:21:48 -0800354 Some(token_punct_visit(repr, kind, name))
Carl Lerche058ff472019-02-13 16:23:52 -0800355 }
356 }
David Tolnay295141b2019-02-15 12:45:33 -0800357 types::Type::Group(t) => Some(token_group_visit(&t[..], kind, name)),
David Tolnayd3076572019-02-15 13:32:44 -0800358 types::Type::Syn(t) => {
Carl Lerche058ff472019-02-13 16:23:52 -0800359 fn requires_full(features: &types::Features) -> bool {
David Tolnay440fe582019-02-15 20:23:14 -0800360 features.any.contains("full") && features.any.len() == 1
Carl Lerche058ff472019-02-13 16:23:52 -0800361 }
362
David Tolnay397bd0b2019-02-15 20:51:10 -0800363 let res = simple_visit(t, kind, name);
Carl Lerche058ff472019-02-13 16:23:52 -0800364
David Tolnayc2be7b22019-02-15 18:48:31 -0800365 let target = defs.types.iter().find(|ty| ty.ident == *t).unwrap();
Carl Lerche058ff472019-02-13 16:23:52 -0800366
367 Some(
David Tolnayc2be7b22019-02-15 18:48:31 -0800368 if requires_full(&target.features) && !requires_full(features) {
Carl Lerche058ff472019-02-13 16:23:52 -0800369 quote! {
370 full!(#res)
371 }
372 } else {
373 res
374 },
375 )
376 }
Carl Lerchecbf7cc12019-02-15 14:09:31 -0800377 types::Type::Ext(t) if super::TERMINAL_TYPES.contains(&&t[..]) => {
378 Some(simple_visit(t, kind, name))
379 }
Carl Lerche058ff472019-02-13 16:23:52 -0800380 types::Type::Ext(_) | types::Type::Std(_) => None,
381 }
382 }
383
384 fn visit_features(features: &types::Features) -> TokenStream {
David Tolnay440fe582019-02-15 20:23:14 -0800385 let features = &features.any;
Carl Lerche058ff472019-02-13 16:23:52 -0800386 match features.len() {
387 0 => quote!(),
David Tolnay440fe582019-02-15 20:23:14 -0800388 1 => quote!(#[cfg(feature = #(#features)*)]),
389 _ => quote!(#[cfg(any(#(feature = #features),*))]),
Carl Lerche058ff472019-02-13 16:23:52 -0800390 }
391 }
392
David Tolnay157c7eb2019-02-15 13:21:48 -0800393 pub fn generate(state: &mut State, s: &types::Node, defs: &types::Definitions) {
David Tolnayc2be7b22019-02-15 18:48:31 -0800394 let features = visit_features(&s.features);
395 let under_name = under_name(&s.ident);
396 let ty = Ident::new(&s.ident, Span::call_site());
Carl Lerche058ff472019-02-13 16:23:52 -0800397 let visit_fn = Ident::new(&format!("visit_{}", under_name), Span::call_site());
398 let visit_mut_fn = Ident::new(&format!("visit_{}_mut", under_name), Span::call_site());
399 let fold_fn = Ident::new(&format!("fold_{}", under_name), Span::call_site());
400
401 let mut visit_impl = TokenStream::new();
402 let mut visit_mut_impl = TokenStream::new();
403 let mut fold_impl = TokenStream::new();
404
David Tolnayc2be7b22019-02-15 18:48:31 -0800405 match &s.data {
406 types::Data::Enum(variants) => {
Carl Lerche058ff472019-02-13 16:23:52 -0800407 let mut visit_variants = TokenStream::new();
408 let mut visit_mut_variants = TokenStream::new();
409 let mut fold_variants = TokenStream::new();
410
David Tolnay75c5a172019-02-15 20:35:41 -0800411 for (variant, fields) in variants {
412 let variant_ident = Ident::new(variant, Span::call_site());
Carl Lerche058ff472019-02-13 16:23:52 -0800413
David Tolnay75c5a172019-02-15 20:35:41 -0800414 if fields.is_empty() {
Carl Lerche058ff472019-02-13 16:23:52 -0800415 visit_variants.append_all(quote! {
416 #ty::#variant_ident => {}
417 });
418 visit_mut_variants.append_all(quote! {
419 #ty::#variant_ident => {}
420 });
421 fold_variants.append_all(quote! {
422 #ty::#variant_ident => {
423 #ty::#variant_ident
424 }
425 });
426 } else {
427 let mut bind_visit_fields = TokenStream::new();
428 let mut bind_visit_mut_fields = TokenStream::new();
429 let mut bind_fold_fields = TokenStream::new();
430
431 let mut visit_fields = TokenStream::new();
432 let mut visit_mut_fields = TokenStream::new();
433 let mut fold_fields = TokenStream::new();
434
David Tolnay75c5a172019-02-15 20:35:41 -0800435 for (idx, ty) in fields.iter().enumerate() {
Carl Lerche058ff472019-02-13 16:23:52 -0800436 let name = format!("_binding_{}", idx);
437 let binding = Ident::new(&name, Span::call_site());
438
439 bind_visit_fields.append_all(quote! {
440 ref #binding,
441 });
442 bind_visit_mut_fields.append_all(quote! {
443 ref mut #binding,
444 });
445 bind_fold_fields.append_all(quote! {
446 #binding,
447 });
448
449 let borrowed_binding = Borrowed(quote!(#binding));
450 let owned_binding = Owned(quote!(#binding));
451
452 visit_fields.append_all(
David Tolnayc2be7b22019-02-15 18:48:31 -0800453 visit(ty, &s.features, defs, Visit, &borrowed_binding)
Carl Lerche058ff472019-02-13 16:23:52 -0800454 .unwrap_or_else(|| noop_visit(Visit, &borrowed_binding)),
455 );
456 visit_mut_fields.append_all(
David Tolnayc2be7b22019-02-15 18:48:31 -0800457 visit(ty, &s.features, defs, VisitMut, &borrowed_binding)
Carl Lerche058ff472019-02-13 16:23:52 -0800458 .unwrap_or_else(|| noop_visit(VisitMut, &borrowed_binding)),
459 );
460 fold_fields.append_all(
David Tolnayc2be7b22019-02-15 18:48:31 -0800461 visit(ty, &s.features, defs, Fold, &owned_binding)
Carl Lerche058ff472019-02-13 16:23:52 -0800462 .unwrap_or_else(|| noop_visit(Fold, &owned_binding)),
463 );
464
465 visit_fields.append_all(quote!(;));
466 visit_mut_fields.append_all(quote!(;));
467 fold_fields.append_all(quote!(,));
468 }
469
470 visit_variants.append_all(quote! {
471 #ty::#variant_ident(#bind_visit_fields) => {
472 #visit_fields
473 }
474 });
475
476 visit_mut_variants.append_all(quote! {
477 #ty::#variant_ident(#bind_visit_mut_fields) => {
478 #visit_mut_fields
479 }
480 });
481
482 fold_variants.append_all(quote! {
483 #ty::#variant_ident(#bind_fold_fields) => {
484 #ty::#variant_ident(
485 #fold_fields
486 )
487 }
488 });
489 }
490 }
491
492 visit_impl.append_all(quote! {
493 match *_i {
494 #visit_variants
495 }
496 });
497
498 visit_mut_impl.append_all(quote! {
499 match *_i {
500 #visit_mut_variants
501 }
502 });
503
504 fold_impl.append_all(quote! {
505 match _i {
506 #fold_variants
507 }
508 });
509 }
David Tolnayc2be7b22019-02-15 18:48:31 -0800510 types::Data::Struct(fields) => {
Carl Lerche058ff472019-02-13 16:23:52 -0800511 let mut fold_fields = TokenStream::new();
512
David Tolnayc2be7b22019-02-15 18:48:31 -0800513 for (field, ty) in fields {
David Tolnay485973a2019-02-15 14:42:48 -0800514 let id = Ident::new(&field, Span::call_site());
Carl Lerche058ff472019-02-13 16:23:52 -0800515 let ref_toks = Owned(quote!(_i.#id));
David Tolnayc2be7b22019-02-15 18:48:31 -0800516 let visit_field = visit(&ty, &s.features, defs, Visit, &ref_toks)
Carl Lerche058ff472019-02-13 16:23:52 -0800517 .unwrap_or_else(|| noop_visit(Visit, &ref_toks));
518 visit_impl.append_all(quote! {
519 #visit_field;
520 });
David Tolnayc2be7b22019-02-15 18:48:31 -0800521 let visit_mut_field = visit(&ty, &s.features, defs, VisitMut, &ref_toks)
David Tolnay47fe7402019-02-15 14:35:25 -0800522 .unwrap_or_else(|| noop_visit(VisitMut, &ref_toks));
Carl Lerche058ff472019-02-13 16:23:52 -0800523 visit_mut_impl.append_all(quote! {
524 #visit_mut_field;
525 });
David Tolnayc2be7b22019-02-15 18:48:31 -0800526 let fold = visit(&ty, &s.features, defs, Fold, &ref_toks)
Carl Lerche058ff472019-02-13 16:23:52 -0800527 .unwrap_or_else(|| noop_visit(Fold, &ref_toks));
528
529 fold_fields.append_all(quote! {
530 #id: #fold,
531 });
532 }
533
David Tolnayc2be7b22019-02-15 18:48:31 -0800534 if !fields.is_empty() {
Carl Lerche058ff472019-02-13 16:23:52 -0800535 fold_impl.append_all(quote! {
536 #ty {
537 #fold_fields
538 }
539 })
540 } else {
541 if ty == "Ident" {
542 fold_impl.append_all(quote! {
543 let mut _i = _i;
544 let span = _visitor.fold_span(_i.span());
545 _i.set_span(span);
546 });
547 }
548 fold_impl.append_all(quote! {
549 _i
550 });
551 }
552 }
David Tolnayc2be7b22019-02-15 18:48:31 -0800553 types::Data::Private => {
554 if ty == "Ident" {
555 fold_impl.append_all(quote! {
556 let mut _i = _i;
557 let span = _visitor.fold_span(_i.span());
558 _i.set_span(span);
559 });
560 }
561 fold_impl.append_all(quote! {
562 _i
563 });
Carl Lerche058ff472019-02-13 16:23:52 -0800564 }
565 }
566
David Tolnayc2be7b22019-02-15 18:48:31 -0800567 let include_fold_impl = match &s.data {
568 types::Data::Private => super::TERMINAL_TYPES.contains(&s.ident.as_str()),
569 types::Data::Struct(_) | types::Data::Enum(_) => true,
570 };
571
Carl Lerche058ff472019-02-13 16:23:52 -0800572 state.visit_trait.append_all(quote! {
573 #features
574 fn #visit_fn(&mut self, i: &'ast #ty) {
575 #visit_fn(self, i)
576 }
577 });
578
579 state.visit_impl.append_all(quote! {
580 #features
581 pub fn #visit_fn<'ast, V: Visit<'ast> + ?Sized>(
582 _visitor: &mut V, _i: &'ast #ty
583 ) {
584 #visit_impl
585 }
586 });
587
588 state.visit_mut_trait.append_all(quote! {
589 #features
590 fn #visit_mut_fn(&mut self, i: &mut #ty) {
591 #visit_mut_fn(self, i)
592 }
593 });
594
595 state.visit_mut_impl.append_all(quote! {
596 #features
597 pub fn #visit_mut_fn<V: VisitMut + ?Sized>(
598 _visitor: &mut V, _i: &mut #ty
599 ) {
600 #visit_mut_impl
601 }
602 });
603
604 state.fold_trait.append_all(quote! {
605 #features
606 fn #fold_fn(&mut self, i: #ty) -> #ty {
607 #fold_fn(self, i)
608 }
609 });
610
611 if include_fold_impl {
612 state.fold_impl.append_all(quote! {
613 #features
614 pub fn #fold_fn<V: Fold + ?Sized>(
615 _visitor: &mut V, _i: #ty
616 ) -> #ty {
617 #fold_impl
618 }
619 });
620 }
621 }
622}
623
624fn write_file(path: &str, content: TokenStream) {
625 let mut file = File::create(path).unwrap();
626 write!(
627 file,
628 "// THIS FILE IS AUTOMATICALLY GENERATED; DO NOT EDIT\n\n"
629 )
630 .unwrap();
631 let mut config = rustfmt::Config::default();
632 config.set().emit_mode(rustfmt::EmitMode::Stdout);
633 config.set().verbose(rustfmt::Verbosity::Quiet);
634 config.set().format_macro_matchers(true);
635 config.set().normalize_doc_attributes(true);
636 let mut session = rustfmt::Session::new(config, Some(&mut file));
637 session
638 .format(rustfmt::Input::Text(content.to_string()))
639 .unwrap();
640}
641
Carl Lerchecbf7cc12019-02-15 14:09:31 -0800642const TERMINAL_TYPES: &[&str] = &["Span", "Ident"];
643
David Tolnayf9bb8ff2019-02-15 13:10:14 -0800644pub fn generate(defs: &types::Definitions) {
David Tolnay4bc55232019-02-15 21:09:00 -0800645 let mut state = codegen::State::default();
646 for s in &defs.types {
647 codegen::generate(&mut state, s, defs);
648 }
649 for tt in TERMINAL_TYPES {
650 let s = types::Node {
David Tolnayc2be7b22019-02-15 18:48:31 -0800651 ident: tt.to_string(),
652 features: types::Features::default(),
653 data: types::Data::Private,
David Tolnay4bc55232019-02-15 21:09:00 -0800654 };
655 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}