blob: 65ffb0865553a3c57756aa33273f5189914ee70f [file] [log] [blame]
Carl Lerche058ff472019-02-13 16:23:52 -08001use proc_macro2::TokenStream;
David Tolnay397bd0b2019-02-15 20:51:10 -08002use quote::quote;
3use rustfmt_nightly as rustfmt;
David Tolnay950cc122019-05-07 14:21:13 -07004use syn_codegen as types;
Carl Lerche058ff472019-02-13 16:23:52 -08005
6use std::fs::File;
7use std::io::Write;
8
9const FOLD_SRC: &str = "../src/gen/fold.rs";
10const VISIT_SRC: &str = "../src/gen/visit.rs";
11const VISIT_MUT_SRC: &str = "../src/gen/visit_mut.rs";
12
13mod codegen {
Carl Lerche058ff472019-02-13 16:23:52 -080014 use inflections::Inflect;
15 use proc_macro2::{Span, TokenStream};
David Tolnay397bd0b2019-02-15 20:51:10 -080016 use quote::{quote, TokenStreamExt};
Carl Lerche058ff472019-02-13 16:23:52 -080017 use syn::*;
David Tolnay950cc122019-05-07 14:21:13 -070018 use syn_codegen as types;
Carl Lerche058ff472019-02-13 16:23:52 -080019
20 #[derive(Default)]
21 pub struct State {
22 pub visit_trait: TokenStream,
23 pub visit_impl: TokenStream,
24 pub visit_mut_trait: TokenStream,
25 pub visit_mut_impl: TokenStream,
26 pub fold_trait: TokenStream,
27 pub fold_impl: TokenStream,
28 }
29
30 fn under_name(name: &str) -> Ident {
31 Ident::new(&name.to_snake_case(), Span::call_site())
32 }
33
34 #[derive(Debug, Eq, PartialEq, Copy, Clone)]
35 enum Kind {
36 Visit,
37 VisitMut,
38 Fold,
39 }
40
41 enum Operand {
42 Borrowed(TokenStream),
43 Owned(TokenStream),
44 }
45
46 use self::Kind::*;
47 use self::Operand::*;
48
49 impl Operand {
50 fn tokens(&self) -> &TokenStream {
51 match *self {
52 Borrowed(ref n) | Owned(ref n) => n,
53 }
54 }
55
56 fn ref_tokens(&self) -> TokenStream {
57 match *self {
58 Borrowed(ref n) => n.clone(),
59 Owned(ref n) => quote!(&#n),
60 }
61 }
62
63 fn ref_mut_tokens(&self) -> TokenStream {
64 match *self {
65 Borrowed(ref n) => n.clone(),
66 Owned(ref n) => quote!(&mut #n),
67 }
68 }
69
70 fn owned_tokens(&self) -> TokenStream {
71 match *self {
72 Borrowed(ref n) => quote!(*#n),
73 Owned(ref n) => n.clone(),
74 }
75 }
76 }
77
78 fn simple_visit(item: &str, kind: Kind, name: &Operand) -> TokenStream {
79 let ident = under_name(item);
80
81 match kind {
82 Visit => {
83 let method = Ident::new(&format!("visit_{}", ident), Span::call_site());
84 let name = name.ref_tokens();
85 quote! {
86 _visitor.#method(#name)
87 }
88 }
89 VisitMut => {
90 let method = Ident::new(&format!("visit_{}_mut", ident), Span::call_site());
91 let name = name.ref_mut_tokens();
92 quote! {
93 _visitor.#method(#name)
94 }
95 }
96 Fold => {
97 let method = Ident::new(&format!("fold_{}", ident), Span::call_site());
98 let name = name.owned_tokens();
99 quote! {
100 _visitor.#method(#name)
101 }
102 }
103 }
104 }
105
106 fn box_visit(
107 elem: &types::Type,
108 features: &types::Features,
David Tolnay157c7eb2019-02-15 13:21:48 -0800109 defs: &types::Definitions,
Carl Lerche058ff472019-02-13 16:23:52 -0800110 kind: Kind,
111 name: &Operand,
112 ) -> Option<TokenStream> {
113 let name = name.owned_tokens();
David Tolnay157c7eb2019-02-15 13:21:48 -0800114 let res = visit(elem, features, defs, kind, &Owned(quote!(*#name)))?;
Carl Lerche058ff472019-02-13 16:23:52 -0800115 Some(match kind {
116 Fold => quote! {
117 Box::new(#res)
118 },
119 Visit | VisitMut => res,
120 })
121 }
122
123 fn vec_visit(
124 elem: &types::Type,
125 features: &types::Features,
David Tolnay157c7eb2019-02-15 13:21:48 -0800126 defs: &types::Definitions,
Carl Lerche058ff472019-02-13 16:23:52 -0800127 kind: Kind,
128 name: &Operand,
129 ) -> Option<TokenStream> {
130 let operand = match kind {
131 Visit | VisitMut => Borrowed(quote!(it)),
132 Fold => Owned(quote!(it)),
133 };
David Tolnay157c7eb2019-02-15 13:21:48 -0800134 let val = visit(elem, features, defs, kind, &operand)?;
Carl Lerche058ff472019-02-13 16:23:52 -0800135 Some(match kind {
136 Visit => {
137 let name = name.ref_tokens();
138 quote! {
139 for it in #name {
140 #val
141 }
142 }
143 }
144 VisitMut => {
145 let name = name.ref_mut_tokens();
146 quote! {
147 for it in #name {
148 #val
149 }
150 }
151 }
152 Fold => {
153 let name = name.owned_tokens();
154 quote! {
155 FoldHelper::lift(#name, |it| { #val })
156 }
157 }
158 })
159 }
160
161 fn punctuated_visit(
162 elem: &types::Type,
163 features: &types::Features,
David Tolnay157c7eb2019-02-15 13:21:48 -0800164 defs: &types::Definitions,
Carl Lerche058ff472019-02-13 16:23:52 -0800165 kind: Kind,
166 name: &Operand,
167 ) -> Option<TokenStream> {
168 let operand = match kind {
169 Visit | VisitMut => Borrowed(quote!(it)),
170 Fold => Owned(quote!(it)),
171 };
David Tolnay157c7eb2019-02-15 13:21:48 -0800172 let val = visit(elem, features, defs, kind, &operand)?;
Carl Lerche058ff472019-02-13 16:23:52 -0800173 Some(match kind {
174 Visit => {
175 let name = name.ref_tokens();
176 quote! {
177 for el in Punctuated::pairs(#name) {
178 let it = el.value();
179 #val
180 }
181 }
182 }
183 VisitMut => {
184 let name = name.ref_mut_tokens();
185 quote! {
186 for mut el in Punctuated::pairs_mut(#name) {
187 let it = el.value_mut();
188 #val
189 }
190 }
191 }
192 Fold => {
193 let name = name.owned_tokens();
194 quote! {
195 FoldHelper::lift(#name, |it| { #val })
196 }
197 }
198 })
199 }
200
201 fn option_visit(
202 elem: &types::Type,
203 features: &types::Features,
David Tolnay157c7eb2019-02-15 13:21:48 -0800204 defs: &types::Definitions,
Carl Lerche058ff472019-02-13 16:23:52 -0800205 kind: Kind,
206 name: &Operand,
207 ) -> Option<TokenStream> {
208 let it = match kind {
209 Visit | VisitMut => Borrowed(quote!(it)),
210 Fold => Owned(quote!(it)),
211 };
David Tolnay157c7eb2019-02-15 13:21:48 -0800212 let val = visit(elem, features, defs, kind, &it)?;
Carl Lerche058ff472019-02-13 16:23:52 -0800213 let name = name.owned_tokens();
214 Some(match kind {
215 Visit => quote! {
216 if let Some(ref it) = #name {
217 #val
218 }
219 },
220 VisitMut => quote! {
221 if let Some(ref mut it) = #name {
222 #val
223 }
224 },
225 Fold => quote! {
226 (#name).map(|it| { #val })
227 },
228 })
229 }
230
231 fn tuple_visit(
232 elems: &[types::Type],
233 features: &types::Features,
David Tolnay157c7eb2019-02-15 13:21:48 -0800234 defs: &types::Definitions,
Carl Lerche058ff472019-02-13 16:23:52 -0800235 kind: Kind,
236 name: &Operand,
237 ) -> Option<TokenStream> {
238 if elems.is_empty() {
239 return None;
240 }
241
242 let mut code = TokenStream::new();
243 for (i, elem) in elems.iter().enumerate() {
244 let name = name.tokens();
245 let i = Index::from(i);
246 let it = Owned(quote!((#name).#i));
247 let val =
David Tolnay157c7eb2019-02-15 13:21:48 -0800248 visit(elem, features, defs, kind, &it).unwrap_or_else(|| noop_visit(kind, &it));
Carl Lerche058ff472019-02-13 16:23:52 -0800249 code.append_all(val);
250 match kind {
251 Fold => code.append_all(quote!(,)),
252 Visit | VisitMut => code.append_all(quote!(;)),
253 }
254 }
255 Some(match kind {
256 Fold => quote! {
257 (#code)
258 },
259 Visit | VisitMut => code,
260 })
261 }
262
David Tolnay157c7eb2019-02-15 13:21:48 -0800263 fn token_punct_visit(repr: &str, kind: Kind, name: &Operand) -> TokenStream {
264 let ty: TokenStream = syn::parse_str(&format!("Token![{}]", repr)).unwrap();
Carl Lerche058ff472019-02-13 16:23:52 -0800265 let name = name.tokens();
266 match kind {
267 Fold => quote! {
268 #ty(tokens_helper(_visitor, &#name.spans))
269 },
270 Visit => quote! {
271 tokens_helper(_visitor, &#name.spans)
272 },
273 VisitMut => quote! {
274 tokens_helper(_visitor, &mut #name.spans)
275 },
276 }
277 }
278
David Tolnay157c7eb2019-02-15 13:21:48 -0800279 fn token_keyword_visit(repr: &str, kind: Kind, name: &Operand) -> TokenStream {
280 let ty: TokenStream = syn::parse_str(&format!("Token![{}]", repr)).unwrap();
Carl Lerche058ff472019-02-13 16:23:52 -0800281 let name = name.tokens();
282 match kind {
283 Fold => quote! {
284 #ty(tokens_helper(_visitor, &#name.span))
285 },
286 Visit => quote! {
287 tokens_helper(_visitor, &#name.span)
288 },
289 VisitMut => quote! {
290 tokens_helper(_visitor, &mut #name.span)
291 },
292 }
293 }
294
295 fn token_group_visit(ty: &str, kind: Kind, name: &Operand) -> TokenStream {
296 let ty = Ident::new(ty, Span::call_site());
297 let name = name.tokens();
298 match kind {
299 Fold => quote! {
300 #ty(tokens_helper(_visitor, &#name.span))
301 },
302 Visit => quote! {
303 tokens_helper(_visitor, &#name.span)
304 },
305 VisitMut => quote! {
306 tokens_helper(_visitor, &mut #name.span)
307 },
308 }
309 }
310
311 fn noop_visit(kind: Kind, name: &Operand) -> TokenStream {
312 match kind {
313 Fold => name.owned_tokens(),
314 Visit | VisitMut => {
315 let name = name.tokens();
316 quote! {
317 skip!(#name)
318 }
319 }
320 }
321 }
322
323 fn visit(
324 ty: &types::Type,
325 features: &types::Features,
David Tolnay157c7eb2019-02-15 13:21:48 -0800326 defs: &types::Definitions,
Carl Lerche058ff472019-02-13 16:23:52 -0800327 kind: Kind,
328 name: &Operand,
329 ) -> Option<TokenStream> {
330 match ty {
David Tolnay157c7eb2019-02-15 13:21:48 -0800331 types::Type::Box(t) => box_visit(&*t, features, defs, kind, name),
332 types::Type::Vec(t) => vec_visit(&*t, features, defs, kind, name),
David Tolnay485973a2019-02-15 14:42:48 -0800333 types::Type::Punctuated(p) => punctuated_visit(&p.element, features, defs, kind, name),
David Tolnay157c7eb2019-02-15 13:21:48 -0800334 types::Type::Option(t) => option_visit(&*t, features, defs, kind, name),
335 types::Type::Tuple(t) => tuple_visit(t, features, defs, kind, name),
Carl Lerche058ff472019-02-13 16:23:52 -0800336 types::Type::Token(t) => {
David Tolnay157c7eb2019-02-15 13:21:48 -0800337 let repr = &defs.tokens[t];
338 let is_keyword = repr.chars().next().unwrap().is_alphabetic();
339 if is_keyword {
340 Some(token_keyword_visit(repr, kind, name))
Carl Lerche058ff472019-02-13 16:23:52 -0800341 } else {
David Tolnay157c7eb2019-02-15 13:21:48 -0800342 Some(token_punct_visit(repr, kind, name))
Carl Lerche058ff472019-02-13 16:23:52 -0800343 }
344 }
David Tolnay295141b2019-02-15 12:45:33 -0800345 types::Type::Group(t) => Some(token_group_visit(&t[..], kind, name)),
David Tolnayd3076572019-02-15 13:32:44 -0800346 types::Type::Syn(t) => {
Carl Lerche058ff472019-02-13 16:23:52 -0800347 fn requires_full(features: &types::Features) -> bool {
David Tolnay440fe582019-02-15 20:23:14 -0800348 features.any.contains("full") && features.any.len() == 1
Carl Lerche058ff472019-02-13 16:23:52 -0800349 }
350
David Tolnay397bd0b2019-02-15 20:51:10 -0800351 let res = simple_visit(t, kind, name);
Carl Lerche058ff472019-02-13 16:23:52 -0800352
David Tolnayc2be7b22019-02-15 18:48:31 -0800353 let target = defs.types.iter().find(|ty| ty.ident == *t).unwrap();
Carl Lerche058ff472019-02-13 16:23:52 -0800354
355 Some(
David Tolnayc2be7b22019-02-15 18:48:31 -0800356 if requires_full(&target.features) && !requires_full(features) {
Carl Lerche058ff472019-02-13 16:23:52 -0800357 quote! {
358 full!(#res)
359 }
360 } else {
361 res
362 },
363 )
364 }
Carl Lerchecbf7cc12019-02-15 14:09:31 -0800365 types::Type::Ext(t) if super::TERMINAL_TYPES.contains(&&t[..]) => {
366 Some(simple_visit(t, kind, name))
367 }
Carl Lerche058ff472019-02-13 16:23:52 -0800368 types::Type::Ext(_) | types::Type::Std(_) => None,
369 }
370 }
371
372 fn visit_features(features: &types::Features) -> TokenStream {
David Tolnay440fe582019-02-15 20:23:14 -0800373 let features = &features.any;
Carl Lerche058ff472019-02-13 16:23:52 -0800374 match features.len() {
375 0 => quote!(),
David Tolnay440fe582019-02-15 20:23:14 -0800376 1 => quote!(#[cfg(feature = #(#features)*)]),
377 _ => quote!(#[cfg(any(#(feature = #features),*))]),
Carl Lerche058ff472019-02-13 16:23:52 -0800378 }
379 }
380
David Tolnay157c7eb2019-02-15 13:21:48 -0800381 pub fn generate(state: &mut State, s: &types::Node, defs: &types::Definitions) {
David Tolnayc2be7b22019-02-15 18:48:31 -0800382 let features = visit_features(&s.features);
383 let under_name = under_name(&s.ident);
384 let ty = Ident::new(&s.ident, Span::call_site());
Carl Lerche058ff472019-02-13 16:23:52 -0800385 let visit_fn = Ident::new(&format!("visit_{}", under_name), Span::call_site());
386 let visit_mut_fn = Ident::new(&format!("visit_{}_mut", under_name), Span::call_site());
387 let fold_fn = Ident::new(&format!("fold_{}", under_name), Span::call_site());
388
389 let mut visit_impl = TokenStream::new();
390 let mut visit_mut_impl = TokenStream::new();
391 let mut fold_impl = TokenStream::new();
392
David Tolnayc2be7b22019-02-15 18:48:31 -0800393 match &s.data {
394 types::Data::Enum(variants) => {
Carl Lerche058ff472019-02-13 16:23:52 -0800395 let mut visit_variants = TokenStream::new();
396 let mut visit_mut_variants = TokenStream::new();
397 let mut fold_variants = TokenStream::new();
398
David Tolnay75c5a172019-02-15 20:35:41 -0800399 for (variant, fields) in variants {
400 let variant_ident = Ident::new(variant, Span::call_site());
Carl Lerche058ff472019-02-13 16:23:52 -0800401
David Tolnay75c5a172019-02-15 20:35:41 -0800402 if fields.is_empty() {
Carl Lerche058ff472019-02-13 16:23:52 -0800403 visit_variants.append_all(quote! {
404 #ty::#variant_ident => {}
405 });
406 visit_mut_variants.append_all(quote! {
407 #ty::#variant_ident => {}
408 });
409 fold_variants.append_all(quote! {
410 #ty::#variant_ident => {
411 #ty::#variant_ident
412 }
413 });
414 } else {
415 let mut bind_visit_fields = TokenStream::new();
416 let mut bind_visit_mut_fields = TokenStream::new();
417 let mut bind_fold_fields = TokenStream::new();
418
419 let mut visit_fields = TokenStream::new();
420 let mut visit_mut_fields = TokenStream::new();
421 let mut fold_fields = TokenStream::new();
422
David Tolnay75c5a172019-02-15 20:35:41 -0800423 for (idx, ty) in fields.iter().enumerate() {
Carl Lerche058ff472019-02-13 16:23:52 -0800424 let name = format!("_binding_{}", idx);
425 let binding = Ident::new(&name, Span::call_site());
426
427 bind_visit_fields.append_all(quote! {
428 ref #binding,
429 });
430 bind_visit_mut_fields.append_all(quote! {
431 ref mut #binding,
432 });
433 bind_fold_fields.append_all(quote! {
434 #binding,
435 });
436
437 let borrowed_binding = Borrowed(quote!(#binding));
438 let owned_binding = Owned(quote!(#binding));
439
440 visit_fields.append_all(
David Tolnayc2be7b22019-02-15 18:48:31 -0800441 visit(ty, &s.features, defs, Visit, &borrowed_binding)
Carl Lerche058ff472019-02-13 16:23:52 -0800442 .unwrap_or_else(|| noop_visit(Visit, &borrowed_binding)),
443 );
444 visit_mut_fields.append_all(
David Tolnayc2be7b22019-02-15 18:48:31 -0800445 visit(ty, &s.features, defs, VisitMut, &borrowed_binding)
Carl Lerche058ff472019-02-13 16:23:52 -0800446 .unwrap_or_else(|| noop_visit(VisitMut, &borrowed_binding)),
447 );
448 fold_fields.append_all(
David Tolnayc2be7b22019-02-15 18:48:31 -0800449 visit(ty, &s.features, defs, Fold, &owned_binding)
Carl Lerche058ff472019-02-13 16:23:52 -0800450 .unwrap_or_else(|| noop_visit(Fold, &owned_binding)),
451 );
452
453 visit_fields.append_all(quote!(;));
454 visit_mut_fields.append_all(quote!(;));
455 fold_fields.append_all(quote!(,));
456 }
457
458 visit_variants.append_all(quote! {
459 #ty::#variant_ident(#bind_visit_fields) => {
460 #visit_fields
461 }
462 });
463
464 visit_mut_variants.append_all(quote! {
465 #ty::#variant_ident(#bind_visit_mut_fields) => {
466 #visit_mut_fields
467 }
468 });
469
470 fold_variants.append_all(quote! {
471 #ty::#variant_ident(#bind_fold_fields) => {
472 #ty::#variant_ident(
473 #fold_fields
474 )
475 }
476 });
477 }
478 }
479
480 visit_impl.append_all(quote! {
481 match *_i {
482 #visit_variants
483 }
484 });
485
486 visit_mut_impl.append_all(quote! {
487 match *_i {
488 #visit_mut_variants
489 }
490 });
491
492 fold_impl.append_all(quote! {
493 match _i {
494 #fold_variants
495 }
496 });
497 }
David Tolnayc2be7b22019-02-15 18:48:31 -0800498 types::Data::Struct(fields) => {
Carl Lerche058ff472019-02-13 16:23:52 -0800499 let mut fold_fields = TokenStream::new();
500
David Tolnayc2be7b22019-02-15 18:48:31 -0800501 for (field, ty) in fields {
David Tolnay485973a2019-02-15 14:42:48 -0800502 let id = Ident::new(&field, Span::call_site());
Carl Lerche058ff472019-02-13 16:23:52 -0800503 let ref_toks = Owned(quote!(_i.#id));
David Tolnayc2be7b22019-02-15 18:48:31 -0800504 let visit_field = visit(&ty, &s.features, defs, Visit, &ref_toks)
Carl Lerche058ff472019-02-13 16:23:52 -0800505 .unwrap_or_else(|| noop_visit(Visit, &ref_toks));
506 visit_impl.append_all(quote! {
507 #visit_field;
508 });
David Tolnayc2be7b22019-02-15 18:48:31 -0800509 let visit_mut_field = visit(&ty, &s.features, defs, VisitMut, &ref_toks)
David Tolnay47fe7402019-02-15 14:35:25 -0800510 .unwrap_or_else(|| noop_visit(VisitMut, &ref_toks));
Carl Lerche058ff472019-02-13 16:23:52 -0800511 visit_mut_impl.append_all(quote! {
512 #visit_mut_field;
513 });
David Tolnayc2be7b22019-02-15 18:48:31 -0800514 let fold = visit(&ty, &s.features, defs, Fold, &ref_toks)
Carl Lerche058ff472019-02-13 16:23:52 -0800515 .unwrap_or_else(|| noop_visit(Fold, &ref_toks));
516
517 fold_fields.append_all(quote! {
518 #id: #fold,
519 });
520 }
521
David Tolnayc2be7b22019-02-15 18:48:31 -0800522 if !fields.is_empty() {
Carl Lerche058ff472019-02-13 16:23:52 -0800523 fold_impl.append_all(quote! {
524 #ty {
525 #fold_fields
526 }
527 })
528 } else {
529 if ty == "Ident" {
530 fold_impl.append_all(quote! {
531 let mut _i = _i;
532 let span = _visitor.fold_span(_i.span());
533 _i.set_span(span);
534 });
535 }
536 fold_impl.append_all(quote! {
537 _i
538 });
539 }
540 }
David Tolnayc2be7b22019-02-15 18:48:31 -0800541 types::Data::Private => {
542 if ty == "Ident" {
543 fold_impl.append_all(quote! {
544 let mut _i = _i;
545 let span = _visitor.fold_span(_i.span());
546 _i.set_span(span);
547 });
548 }
549 fold_impl.append_all(quote! {
550 _i
551 });
Carl Lerche058ff472019-02-13 16:23:52 -0800552 }
553 }
554
David Tolnayc2be7b22019-02-15 18:48:31 -0800555 let include_fold_impl = match &s.data {
556 types::Data::Private => super::TERMINAL_TYPES.contains(&s.ident.as_str()),
557 types::Data::Struct(_) | types::Data::Enum(_) => true,
558 };
559
Carl Lerche058ff472019-02-13 16:23:52 -0800560 state.visit_trait.append_all(quote! {
561 #features
562 fn #visit_fn(&mut self, i: &'ast #ty) {
563 #visit_fn(self, i)
564 }
565 });
566
567 state.visit_impl.append_all(quote! {
568 #features
569 pub fn #visit_fn<'ast, V: Visit<'ast> + ?Sized>(
570 _visitor: &mut V, _i: &'ast #ty
571 ) {
572 #visit_impl
573 }
574 });
575
576 state.visit_mut_trait.append_all(quote! {
577 #features
578 fn #visit_mut_fn(&mut self, i: &mut #ty) {
579 #visit_mut_fn(self, i)
580 }
581 });
582
583 state.visit_mut_impl.append_all(quote! {
584 #features
585 pub fn #visit_mut_fn<V: VisitMut + ?Sized>(
586 _visitor: &mut V, _i: &mut #ty
587 ) {
588 #visit_mut_impl
589 }
590 });
591
592 state.fold_trait.append_all(quote! {
593 #features
594 fn #fold_fn(&mut self, i: #ty) -> #ty {
595 #fold_fn(self, i)
596 }
597 });
598
599 if include_fold_impl {
600 state.fold_impl.append_all(quote! {
601 #features
602 pub fn #fold_fn<V: Fold + ?Sized>(
603 _visitor: &mut V, _i: #ty
604 ) -> #ty {
605 #fold_impl
606 }
607 });
608 }
609 }
610}
611
612fn write_file(path: &str, content: TokenStream) {
613 let mut file = File::create(path).unwrap();
614 write!(
615 file,
616 "// THIS FILE IS AUTOMATICALLY GENERATED; DO NOT EDIT\n\n"
617 )
618 .unwrap();
619 let mut config = rustfmt::Config::default();
620 config.set().emit_mode(rustfmt::EmitMode::Stdout);
621 config.set().verbose(rustfmt::Verbosity::Quiet);
622 config.set().format_macro_matchers(true);
623 config.set().normalize_doc_attributes(true);
624 let mut session = rustfmt::Session::new(config, Some(&mut file));
625 session
626 .format(rustfmt::Input::Text(content.to_string()))
627 .unwrap();
628}
629
Carl Lerchecbf7cc12019-02-15 14:09:31 -0800630const TERMINAL_TYPES: &[&str] = &["Span", "Ident"];
631
David Tolnayf9bb8ff2019-02-15 13:10:14 -0800632pub fn generate(defs: &types::Definitions) {
David Tolnay4bc55232019-02-15 21:09:00 -0800633 let mut state = codegen::State::default();
634 for s in &defs.types {
635 codegen::generate(&mut state, s, defs);
636 }
637 for tt in TERMINAL_TYPES {
638 let s = types::Node {
David Tolnayc2be7b22019-02-15 18:48:31 -0800639 ident: tt.to_string(),
640 features: types::Features::default(),
641 data: types::Data::Private,
David Tolnay4bc55232019-02-15 21:09:00 -0800642 };
643 codegen::generate(&mut state, &s, defs);
Carl Lerche058ff472019-02-13 16:23:52 -0800644 }
645
646 let full_macro = quote! {
647 #[cfg(feature = "full")]
648 macro_rules! full {
649 ($e:expr) => {
650 $e
651 };
652 }
653
654 #[cfg(all(feature = "derive", not(feature = "full")))]
655 macro_rules! full {
656 ($e:expr) => {
657 unreachable!()
658 };
659 }
660 };
661
662 let skip_macro = quote! {
663 #[cfg(any(feature = "full", feature = "derive"))]
664 macro_rules! skip {
665 ($($tt:tt)*) => {};
666 }
667 };
668
669 let fold_trait = state.fold_trait;
670 let fold_impl = state.fold_impl;
671 write_file(
672 FOLD_SRC,
673 quote! {
674 // Unreachable code is generated sometimes without the full feature.
675 #![allow(unreachable_code)]
676
677 use *;
678 #[cfg(any(feature = "full", feature = "derive"))]
679 use token::{Brace, Bracket, Paren, Group};
680 use proc_macro2::Span;
681 #[cfg(any(feature = "full", feature = "derive"))]
682 use gen::helper::fold::*;
683
684 #full_macro
685
686 /// Syntax tree traversal to transform the nodes of an owned syntax tree.
687 ///
688 /// See the [module documentation] for details.
689 ///
690 /// [module documentation]: index.html
691 ///
692 /// *This trait is available if Syn is built with the `"fold"` feature.*
693 pub trait Fold {
694 #fold_trait
695 }
696
697 #[cfg(any(feature = "full", feature = "derive"))]
698 macro_rules! fold_span_only {
699 ($f:ident : $t:ident) => {
700 pub fn $f<V: Fold + ?Sized>(_visitor: &mut V, mut _i: $t) -> $t {
701 let span = _visitor.fold_span(_i.span());
702 _i.set_span(span);
703 _i
704 }
705 }
706 }
707
708 #[cfg(any(feature = "full", feature = "derive"))]
709 fold_span_only!(fold_lit_byte: LitByte);
710 #[cfg(any(feature = "full", feature = "derive"))]
711 fold_span_only!(fold_lit_byte_str: LitByteStr);
712 #[cfg(any(feature = "full", feature = "derive"))]
713 fold_span_only!(fold_lit_char: LitChar);
714 #[cfg(any(feature = "full", feature = "derive"))]
715 fold_span_only!(fold_lit_float: LitFloat);
716 #[cfg(any(feature = "full", feature = "derive"))]
717 fold_span_only!(fold_lit_int: LitInt);
718 #[cfg(any(feature = "full", feature = "derive"))]
719 fold_span_only!(fold_lit_str: LitStr);
720
721 #fold_impl
722 },
723 );
724
725 let visit_trait = state.visit_trait;
726 let visit_impl = state.visit_impl;
727 write_file(
728 VISIT_SRC,
729 quote! {
730 #![cfg_attr(feature = "cargo-clippy", allow(trivially_copy_pass_by_ref))]
731
732 use *;
733 #[cfg(any(feature = "full", feature = "derive"))]
734 use punctuated::Punctuated;
735 use proc_macro2::Span;
736 #[cfg(any(feature = "full", feature = "derive"))]
737 use gen::helper::visit::*;
738
739 #full_macro
740 #skip_macro
741
742 /// Syntax tree traversal to walk a shared borrow of a syntax tree.
743 ///
744 /// See the [module documentation] for details.
745 ///
746 /// [module documentation]: index.html
747 ///
748 /// *This trait is available if Syn is built with the `"visit"` feature.*
749 pub trait Visit<'ast> {
750 #visit_trait
751 }
752
753 #visit_impl
754 },
755 );
756
757 let visit_mut_trait = state.visit_mut_trait;
758 let visit_mut_impl = state.visit_mut_impl;
759 write_file(
760 VISIT_MUT_SRC,
761 quote! {
762 use *;
763 #[cfg(any(feature = "full", feature = "derive"))]
764 use punctuated::Punctuated;
765 use proc_macro2::Span;
766 #[cfg(any(feature = "full", feature = "derive"))]
767 use gen::helper::visit_mut::*;
768
769 #full_macro
770 #skip_macro
771
772 /// Syntax tree traversal to mutate an exclusive borrow of a syntax tree in
773 /// place.
774 ///
775 /// See the [module documentation] for details.
776 ///
777 /// [module documentation]: index.html
778 ///
779 /// *This trait is available if Syn is built with the `"visit-mut"` feature.*
780 pub trait VisitMut {
781 #visit_mut_trait
782 }
783
784 #visit_mut_impl
785 },
786 );
787}