blob: 527662e7e48492936e67ff0b462b68e49ea7202e [file] [log] [blame]
David Tolnaycec98a72019-05-08 15:23:19 -07001use crate::file;
David Tolnay397bd0b2019-02-15 20:51:10 -08002use quote::quote;
David Tolnay950cc122019-05-07 14:21:13 -07003use syn_codegen as types;
Carl Lerche058ff472019-02-13 16:23:52 -08004
Carl Lerche058ff472019-02-13 16:23:52 -08005const FOLD_SRC: &str = "../src/gen/fold.rs";
6const VISIT_SRC: &str = "../src/gen/visit.rs";
7const VISIT_MUT_SRC: &str = "../src/gen/visit_mut.rs";
8
9mod codegen {
Carl Lerche058ff472019-02-13 16:23:52 -080010 use inflections::Inflect;
11 use proc_macro2::{Span, TokenStream};
David Tolnay397bd0b2019-02-15 20:51:10 -080012 use quote::{quote, TokenStreamExt};
Carl Lerche058ff472019-02-13 16:23:52 -080013 use syn::*;
David Tolnay950cc122019-05-07 14:21:13 -070014 use syn_codegen as types;
Carl Lerche058ff472019-02-13 16:23:52 -080015
16 #[derive(Default)]
17 pub struct State {
18 pub visit_trait: TokenStream,
19 pub visit_impl: TokenStream,
20 pub visit_mut_trait: TokenStream,
21 pub visit_mut_impl: TokenStream,
22 pub fold_trait: TokenStream,
23 pub fold_impl: TokenStream,
24 }
25
26 fn under_name(name: &str) -> Ident {
27 Ident::new(&name.to_snake_case(), Span::call_site())
28 }
29
30 #[derive(Debug, Eq, PartialEq, Copy, Clone)]
31 enum Kind {
32 Visit,
33 VisitMut,
34 Fold,
35 }
36
37 enum Operand {
38 Borrowed(TokenStream),
39 Owned(TokenStream),
40 }
41
42 use self::Kind::*;
43 use self::Operand::*;
44
45 impl Operand {
46 fn tokens(&self) -> &TokenStream {
47 match *self {
48 Borrowed(ref n) | Owned(ref n) => n,
49 }
50 }
51
52 fn ref_tokens(&self) -> TokenStream {
53 match *self {
54 Borrowed(ref n) => n.clone(),
55 Owned(ref n) => quote!(&#n),
56 }
57 }
58
59 fn ref_mut_tokens(&self) -> TokenStream {
60 match *self {
61 Borrowed(ref n) => n.clone(),
62 Owned(ref n) => quote!(&mut #n),
63 }
64 }
65
66 fn owned_tokens(&self) -> TokenStream {
67 match *self {
68 Borrowed(ref n) => quote!(*#n),
69 Owned(ref n) => n.clone(),
70 }
71 }
72 }
73
74 fn simple_visit(item: &str, kind: Kind, name: &Operand) -> TokenStream {
75 let ident = under_name(item);
76
77 match kind {
78 Visit => {
79 let method = Ident::new(&format!("visit_{}", ident), Span::call_site());
80 let name = name.ref_tokens();
81 quote! {
82 _visitor.#method(#name)
83 }
84 }
85 VisitMut => {
86 let method = Ident::new(&format!("visit_{}_mut", ident), Span::call_site());
87 let name = name.ref_mut_tokens();
88 quote! {
89 _visitor.#method(#name)
90 }
91 }
92 Fold => {
93 let method = Ident::new(&format!("fold_{}", ident), Span::call_site());
94 let name = name.owned_tokens();
95 quote! {
96 _visitor.#method(#name)
97 }
98 }
99 }
100 }
101
102 fn box_visit(
103 elem: &types::Type,
104 features: &types::Features,
David Tolnay157c7eb2019-02-15 13:21:48 -0800105 defs: &types::Definitions,
Carl Lerche058ff472019-02-13 16:23:52 -0800106 kind: Kind,
107 name: &Operand,
108 ) -> Option<TokenStream> {
109 let name = name.owned_tokens();
David Tolnay157c7eb2019-02-15 13:21:48 -0800110 let res = visit(elem, features, defs, kind, &Owned(quote!(*#name)))?;
Carl Lerche058ff472019-02-13 16:23:52 -0800111 Some(match kind {
112 Fold => quote! {
113 Box::new(#res)
114 },
115 Visit | VisitMut => res,
116 })
117 }
118
119 fn vec_visit(
120 elem: &types::Type,
121 features: &types::Features,
David Tolnay157c7eb2019-02-15 13:21:48 -0800122 defs: &types::Definitions,
Carl Lerche058ff472019-02-13 16:23:52 -0800123 kind: Kind,
124 name: &Operand,
125 ) -> Option<TokenStream> {
126 let operand = match kind {
127 Visit | VisitMut => Borrowed(quote!(it)),
128 Fold => Owned(quote!(it)),
129 };
David Tolnay157c7eb2019-02-15 13:21:48 -0800130 let val = visit(elem, features, defs, kind, &operand)?;
Carl Lerche058ff472019-02-13 16:23:52 -0800131 Some(match kind {
132 Visit => {
133 let name = name.ref_tokens();
134 quote! {
135 for it in #name {
136 #val
137 }
138 }
139 }
140 VisitMut => {
141 let name = name.ref_mut_tokens();
142 quote! {
143 for it in #name {
144 #val
145 }
146 }
147 }
148 Fold => {
149 let name = name.owned_tokens();
150 quote! {
151 FoldHelper::lift(#name, |it| { #val })
152 }
153 }
154 })
155 }
156
157 fn punctuated_visit(
158 elem: &types::Type,
159 features: &types::Features,
David Tolnay157c7eb2019-02-15 13:21:48 -0800160 defs: &types::Definitions,
Carl Lerche058ff472019-02-13 16:23:52 -0800161 kind: Kind,
162 name: &Operand,
163 ) -> Option<TokenStream> {
164 let operand = match kind {
165 Visit | VisitMut => Borrowed(quote!(it)),
166 Fold => Owned(quote!(it)),
167 };
David Tolnay157c7eb2019-02-15 13:21:48 -0800168 let val = visit(elem, features, defs, kind, &operand)?;
Carl Lerche058ff472019-02-13 16:23:52 -0800169 Some(match kind {
170 Visit => {
171 let name = name.ref_tokens();
172 quote! {
173 for el in Punctuated::pairs(#name) {
174 let it = el.value();
175 #val
176 }
177 }
178 }
179 VisitMut => {
180 let name = name.ref_mut_tokens();
181 quote! {
182 for mut el in Punctuated::pairs_mut(#name) {
183 let it = el.value_mut();
184 #val
185 }
186 }
187 }
188 Fold => {
189 let name = name.owned_tokens();
190 quote! {
191 FoldHelper::lift(#name, |it| { #val })
192 }
193 }
194 })
195 }
196
197 fn option_visit(
198 elem: &types::Type,
199 features: &types::Features,
David Tolnay157c7eb2019-02-15 13:21:48 -0800200 defs: &types::Definitions,
Carl Lerche058ff472019-02-13 16:23:52 -0800201 kind: Kind,
202 name: &Operand,
203 ) -> Option<TokenStream> {
204 let it = match kind {
205 Visit | VisitMut => Borrowed(quote!(it)),
206 Fold => Owned(quote!(it)),
207 };
David Tolnay157c7eb2019-02-15 13:21:48 -0800208 let val = visit(elem, features, defs, kind, &it)?;
Carl Lerche058ff472019-02-13 16:23:52 -0800209 let name = name.owned_tokens();
210 Some(match kind {
211 Visit => quote! {
212 if let Some(ref it) = #name {
213 #val
214 }
215 },
216 VisitMut => quote! {
217 if let Some(ref mut it) = #name {
218 #val
219 }
220 },
221 Fold => quote! {
222 (#name).map(|it| { #val })
223 },
224 })
225 }
226
227 fn tuple_visit(
228 elems: &[types::Type],
229 features: &types::Features,
David Tolnay157c7eb2019-02-15 13:21:48 -0800230 defs: &types::Definitions,
Carl Lerche058ff472019-02-13 16:23:52 -0800231 kind: Kind,
232 name: &Operand,
233 ) -> Option<TokenStream> {
234 if elems.is_empty() {
235 return None;
236 }
237
238 let mut code = TokenStream::new();
239 for (i, elem) in elems.iter().enumerate() {
240 let name = name.tokens();
241 let i = Index::from(i);
242 let it = Owned(quote!((#name).#i));
243 let val =
David Tolnay157c7eb2019-02-15 13:21:48 -0800244 visit(elem, features, defs, kind, &it).unwrap_or_else(|| noop_visit(kind, &it));
Carl Lerche058ff472019-02-13 16:23:52 -0800245 code.append_all(val);
246 match kind {
247 Fold => code.append_all(quote!(,)),
248 Visit | VisitMut => code.append_all(quote!(;)),
249 }
250 }
251 Some(match kind {
252 Fold => quote! {
253 (#code)
254 },
255 Visit | VisitMut => code,
256 })
257 }
258
David Tolnay157c7eb2019-02-15 13:21:48 -0800259 fn token_punct_visit(repr: &str, kind: Kind, name: &Operand) -> TokenStream {
260 let ty: TokenStream = syn::parse_str(&format!("Token![{}]", repr)).unwrap();
Carl Lerche058ff472019-02-13 16:23:52 -0800261 let name = name.tokens();
262 match kind {
263 Fold => quote! {
264 #ty(tokens_helper(_visitor, &#name.spans))
265 },
266 Visit => quote! {
267 tokens_helper(_visitor, &#name.spans)
268 },
269 VisitMut => quote! {
270 tokens_helper(_visitor, &mut #name.spans)
271 },
272 }
273 }
274
David Tolnay157c7eb2019-02-15 13:21:48 -0800275 fn token_keyword_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.span))
281 },
282 Visit => quote! {
283 tokens_helper(_visitor, &#name.span)
284 },
285 VisitMut => quote! {
286 tokens_helper(_visitor, &mut #name.span)
287 },
288 }
289 }
290
291 fn token_group_visit(ty: &str, kind: Kind, name: &Operand) -> TokenStream {
292 let ty = Ident::new(ty, Span::call_site());
293 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 noop_visit(kind: Kind, name: &Operand) -> TokenStream {
308 match kind {
309 Fold => name.owned_tokens(),
310 Visit | VisitMut => {
311 let name = name.tokens();
312 quote! {
313 skip!(#name)
314 }
315 }
316 }
317 }
318
319 fn visit(
320 ty: &types::Type,
321 features: &types::Features,
David Tolnay157c7eb2019-02-15 13:21:48 -0800322 defs: &types::Definitions,
Carl Lerche058ff472019-02-13 16:23:52 -0800323 kind: Kind,
324 name: &Operand,
325 ) -> Option<TokenStream> {
326 match ty {
David Tolnay157c7eb2019-02-15 13:21:48 -0800327 types::Type::Box(t) => box_visit(&*t, features, defs, kind, name),
328 types::Type::Vec(t) => vec_visit(&*t, features, defs, kind, name),
David Tolnay485973a2019-02-15 14:42:48 -0800329 types::Type::Punctuated(p) => punctuated_visit(&p.element, features, defs, kind, name),
David Tolnay157c7eb2019-02-15 13:21:48 -0800330 types::Type::Option(t) => option_visit(&*t, features, defs, kind, name),
331 types::Type::Tuple(t) => tuple_visit(t, features, defs, kind, name),
Carl Lerche058ff472019-02-13 16:23:52 -0800332 types::Type::Token(t) => {
David Tolnay157c7eb2019-02-15 13:21:48 -0800333 let repr = &defs.tokens[t];
334 let is_keyword = repr.chars().next().unwrap().is_alphabetic();
335 if is_keyword {
336 Some(token_keyword_visit(repr, kind, name))
Carl Lerche058ff472019-02-13 16:23:52 -0800337 } else {
David Tolnay157c7eb2019-02-15 13:21:48 -0800338 Some(token_punct_visit(repr, kind, name))
Carl Lerche058ff472019-02-13 16:23:52 -0800339 }
340 }
David Tolnay295141b2019-02-15 12:45:33 -0800341 types::Type::Group(t) => Some(token_group_visit(&t[..], kind, name)),
David Tolnayd3076572019-02-15 13:32:44 -0800342 types::Type::Syn(t) => {
Carl Lerche058ff472019-02-13 16:23:52 -0800343 fn requires_full(features: &types::Features) -> bool {
David Tolnay440fe582019-02-15 20:23:14 -0800344 features.any.contains("full") && features.any.len() == 1
Carl Lerche058ff472019-02-13 16:23:52 -0800345 }
346
David Tolnay397bd0b2019-02-15 20:51:10 -0800347 let res = simple_visit(t, kind, name);
Carl Lerche058ff472019-02-13 16:23:52 -0800348
David Tolnayc2be7b22019-02-15 18:48:31 -0800349 let target = defs.types.iter().find(|ty| ty.ident == *t).unwrap();
Carl Lerche058ff472019-02-13 16:23:52 -0800350
351 Some(
David Tolnayc2be7b22019-02-15 18:48:31 -0800352 if requires_full(&target.features) && !requires_full(features) {
Carl Lerche058ff472019-02-13 16:23:52 -0800353 quote! {
354 full!(#res)
355 }
356 } else {
357 res
358 },
359 )
360 }
Carl Lerchecbf7cc12019-02-15 14:09:31 -0800361 types::Type::Ext(t) if super::TERMINAL_TYPES.contains(&&t[..]) => {
362 Some(simple_visit(t, kind, name))
363 }
Carl Lerche058ff472019-02-13 16:23:52 -0800364 types::Type::Ext(_) | types::Type::Std(_) => None,
365 }
366 }
367
368 fn visit_features(features: &types::Features) -> TokenStream {
David Tolnay440fe582019-02-15 20:23:14 -0800369 let features = &features.any;
Carl Lerche058ff472019-02-13 16:23:52 -0800370 match features.len() {
371 0 => quote!(),
David Tolnay440fe582019-02-15 20:23:14 -0800372 1 => quote!(#[cfg(feature = #(#features)*)]),
373 _ => quote!(#[cfg(any(#(feature = #features),*))]),
Carl Lerche058ff472019-02-13 16:23:52 -0800374 }
375 }
376
David Tolnay157c7eb2019-02-15 13:21:48 -0800377 pub fn generate(state: &mut State, s: &types::Node, defs: &types::Definitions) {
David Tolnayc2be7b22019-02-15 18:48:31 -0800378 let features = visit_features(&s.features);
379 let under_name = under_name(&s.ident);
380 let ty = Ident::new(&s.ident, Span::call_site());
Carl Lerche058ff472019-02-13 16:23:52 -0800381 let visit_fn = Ident::new(&format!("visit_{}", under_name), Span::call_site());
382 let visit_mut_fn = Ident::new(&format!("visit_{}_mut", under_name), Span::call_site());
383 let fold_fn = Ident::new(&format!("fold_{}", under_name), Span::call_site());
384
385 let mut visit_impl = TokenStream::new();
386 let mut visit_mut_impl = TokenStream::new();
387 let mut fold_impl = TokenStream::new();
388
David Tolnayc2be7b22019-02-15 18:48:31 -0800389 match &s.data {
390 types::Data::Enum(variants) => {
Carl Lerche058ff472019-02-13 16:23:52 -0800391 let mut visit_variants = TokenStream::new();
392 let mut visit_mut_variants = TokenStream::new();
393 let mut fold_variants = TokenStream::new();
394
David Tolnay75c5a172019-02-15 20:35:41 -0800395 for (variant, fields) in variants {
396 let variant_ident = Ident::new(variant, Span::call_site());
Carl Lerche058ff472019-02-13 16:23:52 -0800397
David Tolnay75c5a172019-02-15 20:35:41 -0800398 if fields.is_empty() {
Carl Lerche058ff472019-02-13 16:23:52 -0800399 visit_variants.append_all(quote! {
400 #ty::#variant_ident => {}
401 });
402 visit_mut_variants.append_all(quote! {
403 #ty::#variant_ident => {}
404 });
405 fold_variants.append_all(quote! {
406 #ty::#variant_ident => {
407 #ty::#variant_ident
408 }
409 });
410 } else {
411 let mut bind_visit_fields = TokenStream::new();
412 let mut bind_visit_mut_fields = TokenStream::new();
413 let mut bind_fold_fields = TokenStream::new();
414
415 let mut visit_fields = TokenStream::new();
416 let mut visit_mut_fields = TokenStream::new();
417 let mut fold_fields = TokenStream::new();
418
David Tolnay75c5a172019-02-15 20:35:41 -0800419 for (idx, ty) in fields.iter().enumerate() {
Carl Lerche058ff472019-02-13 16:23:52 -0800420 let name = format!("_binding_{}", idx);
421 let binding = Ident::new(&name, Span::call_site());
422
423 bind_visit_fields.append_all(quote! {
424 ref #binding,
425 });
426 bind_visit_mut_fields.append_all(quote! {
427 ref mut #binding,
428 });
429 bind_fold_fields.append_all(quote! {
430 #binding,
431 });
432
433 let borrowed_binding = Borrowed(quote!(#binding));
434 let owned_binding = Owned(quote!(#binding));
435
436 visit_fields.append_all(
David Tolnayc2be7b22019-02-15 18:48:31 -0800437 visit(ty, &s.features, defs, Visit, &borrowed_binding)
Carl Lerche058ff472019-02-13 16:23:52 -0800438 .unwrap_or_else(|| noop_visit(Visit, &borrowed_binding)),
439 );
440 visit_mut_fields.append_all(
David Tolnayc2be7b22019-02-15 18:48:31 -0800441 visit(ty, &s.features, defs, VisitMut, &borrowed_binding)
Carl Lerche058ff472019-02-13 16:23:52 -0800442 .unwrap_or_else(|| noop_visit(VisitMut, &borrowed_binding)),
443 );
444 fold_fields.append_all(
David Tolnayc2be7b22019-02-15 18:48:31 -0800445 visit(ty, &s.features, defs, Fold, &owned_binding)
Carl Lerche058ff472019-02-13 16:23:52 -0800446 .unwrap_or_else(|| noop_visit(Fold, &owned_binding)),
447 );
448
449 visit_fields.append_all(quote!(;));
450 visit_mut_fields.append_all(quote!(;));
451 fold_fields.append_all(quote!(,));
452 }
453
454 visit_variants.append_all(quote! {
455 #ty::#variant_ident(#bind_visit_fields) => {
456 #visit_fields
457 }
458 });
459
460 visit_mut_variants.append_all(quote! {
461 #ty::#variant_ident(#bind_visit_mut_fields) => {
462 #visit_mut_fields
463 }
464 });
465
466 fold_variants.append_all(quote! {
467 #ty::#variant_ident(#bind_fold_fields) => {
468 #ty::#variant_ident(
469 #fold_fields
470 )
471 }
472 });
473 }
474 }
475
476 visit_impl.append_all(quote! {
477 match *_i {
478 #visit_variants
479 }
480 });
481
482 visit_mut_impl.append_all(quote! {
483 match *_i {
484 #visit_mut_variants
485 }
486 });
487
488 fold_impl.append_all(quote! {
489 match _i {
490 #fold_variants
491 }
492 });
493 }
David Tolnayc2be7b22019-02-15 18:48:31 -0800494 types::Data::Struct(fields) => {
Carl Lerche058ff472019-02-13 16:23:52 -0800495 let mut fold_fields = TokenStream::new();
496
David Tolnayc2be7b22019-02-15 18:48:31 -0800497 for (field, ty) in fields {
David Tolnay485973a2019-02-15 14:42:48 -0800498 let id = Ident::new(&field, Span::call_site());
Carl Lerche058ff472019-02-13 16:23:52 -0800499 let ref_toks = Owned(quote!(_i.#id));
David Tolnayc2be7b22019-02-15 18:48:31 -0800500 let visit_field = visit(&ty, &s.features, defs, Visit, &ref_toks)
Carl Lerche058ff472019-02-13 16:23:52 -0800501 .unwrap_or_else(|| noop_visit(Visit, &ref_toks));
502 visit_impl.append_all(quote! {
503 #visit_field;
504 });
David Tolnayc2be7b22019-02-15 18:48:31 -0800505 let visit_mut_field = visit(&ty, &s.features, defs, VisitMut, &ref_toks)
David Tolnay47fe7402019-02-15 14:35:25 -0800506 .unwrap_or_else(|| noop_visit(VisitMut, &ref_toks));
Carl Lerche058ff472019-02-13 16:23:52 -0800507 visit_mut_impl.append_all(quote! {
508 #visit_mut_field;
509 });
David Tolnayc2be7b22019-02-15 18:48:31 -0800510 let fold = visit(&ty, &s.features, defs, Fold, &ref_toks)
Carl Lerche058ff472019-02-13 16:23:52 -0800511 .unwrap_or_else(|| noop_visit(Fold, &ref_toks));
512
513 fold_fields.append_all(quote! {
514 #id: #fold,
515 });
516 }
517
David Tolnayc2be7b22019-02-15 18:48:31 -0800518 if !fields.is_empty() {
Carl Lerche058ff472019-02-13 16:23:52 -0800519 fold_impl.append_all(quote! {
520 #ty {
521 #fold_fields
522 }
523 })
524 } else {
525 if ty == "Ident" {
526 fold_impl.append_all(quote! {
527 let mut _i = _i;
528 let span = _visitor.fold_span(_i.span());
529 _i.set_span(span);
530 });
531 }
532 fold_impl.append_all(quote! {
533 _i
534 });
535 }
536 }
David Tolnayc2be7b22019-02-15 18:48:31 -0800537 types::Data::Private => {
538 if ty == "Ident" {
539 fold_impl.append_all(quote! {
540 let mut _i = _i;
541 let span = _visitor.fold_span(_i.span());
542 _i.set_span(span);
543 });
544 }
545 fold_impl.append_all(quote! {
546 _i
547 });
Carl Lerche058ff472019-02-13 16:23:52 -0800548 }
549 }
550
David Tolnayc2be7b22019-02-15 18:48:31 -0800551 let include_fold_impl = match &s.data {
552 types::Data::Private => super::TERMINAL_TYPES.contains(&s.ident.as_str()),
553 types::Data::Struct(_) | types::Data::Enum(_) => true,
554 };
555
Carl Lerche058ff472019-02-13 16:23:52 -0800556 state.visit_trait.append_all(quote! {
557 #features
558 fn #visit_fn(&mut self, i: &'ast #ty) {
559 #visit_fn(self, i)
560 }
561 });
562
563 state.visit_impl.append_all(quote! {
564 #features
565 pub fn #visit_fn<'ast, V: Visit<'ast> + ?Sized>(
566 _visitor: &mut V, _i: &'ast #ty
567 ) {
568 #visit_impl
569 }
570 });
571
572 state.visit_mut_trait.append_all(quote! {
573 #features
574 fn #visit_mut_fn(&mut self, i: &mut #ty) {
575 #visit_mut_fn(self, i)
576 }
577 });
578
579 state.visit_mut_impl.append_all(quote! {
580 #features
581 pub fn #visit_mut_fn<V: VisitMut + ?Sized>(
582 _visitor: &mut V, _i: &mut #ty
583 ) {
584 #visit_mut_impl
585 }
586 });
587
588 state.fold_trait.append_all(quote! {
589 #features
590 fn #fold_fn(&mut self, i: #ty) -> #ty {
591 #fold_fn(self, i)
592 }
593 });
594
595 if include_fold_impl {
596 state.fold_impl.append_all(quote! {
597 #features
598 pub fn #fold_fn<V: Fold + ?Sized>(
599 _visitor: &mut V, _i: #ty
600 ) -> #ty {
601 #fold_impl
602 }
603 });
604 }
605 }
606}
607
Carl Lerchecbf7cc12019-02-15 14:09:31 -0800608const TERMINAL_TYPES: &[&str] = &["Span", "Ident"];
609
David Tolnayf9bb8ff2019-02-15 13:10:14 -0800610pub fn generate(defs: &types::Definitions) {
David Tolnay4bc55232019-02-15 21:09:00 -0800611 let mut state = codegen::State::default();
612 for s in &defs.types {
613 codegen::generate(&mut state, s, defs);
614 }
615 for tt in TERMINAL_TYPES {
616 let s = types::Node {
David Tolnayc2be7b22019-02-15 18:48:31 -0800617 ident: tt.to_string(),
618 features: types::Features::default(),
619 data: types::Data::Private,
David Tolnay4bc55232019-02-15 21:09:00 -0800620 };
621 codegen::generate(&mut state, &s, defs);
Carl Lerche058ff472019-02-13 16:23:52 -0800622 }
623
624 let full_macro = quote! {
625 #[cfg(feature = "full")]
626 macro_rules! full {
627 ($e:expr) => {
628 $e
629 };
630 }
631
632 #[cfg(all(feature = "derive", not(feature = "full")))]
633 macro_rules! full {
634 ($e:expr) => {
635 unreachable!()
636 };
637 }
638 };
639
640 let skip_macro = quote! {
641 #[cfg(any(feature = "full", feature = "derive"))]
642 macro_rules! skip {
643 ($($tt:tt)*) => {};
644 }
645 };
646
647 let fold_trait = state.fold_trait;
648 let fold_impl = state.fold_impl;
David Tolnaycec98a72019-05-08 15:23:19 -0700649 file::write(
Carl Lerche058ff472019-02-13 16:23:52 -0800650 FOLD_SRC,
651 quote! {
652 // Unreachable code is generated sometimes without the full feature.
653 #![allow(unreachable_code)]
654
655 use *;
656 #[cfg(any(feature = "full", feature = "derive"))]
657 use token::{Brace, Bracket, Paren, Group};
658 use proc_macro2::Span;
659 #[cfg(any(feature = "full", feature = "derive"))]
660 use gen::helper::fold::*;
661
662 #full_macro
663
664 /// Syntax tree traversal to transform the nodes of an owned syntax tree.
665 ///
666 /// See the [module documentation] for details.
667 ///
668 /// [module documentation]: index.html
669 ///
670 /// *This trait is available if Syn is built with the `"fold"` feature.*
671 pub trait Fold {
672 #fold_trait
673 }
674
675 #[cfg(any(feature = "full", feature = "derive"))]
676 macro_rules! fold_span_only {
677 ($f:ident : $t:ident) => {
678 pub fn $f<V: Fold + ?Sized>(_visitor: &mut V, mut _i: $t) -> $t {
679 let span = _visitor.fold_span(_i.span());
680 _i.set_span(span);
681 _i
682 }
683 }
684 }
685
686 #[cfg(any(feature = "full", feature = "derive"))]
687 fold_span_only!(fold_lit_byte: LitByte);
688 #[cfg(any(feature = "full", feature = "derive"))]
689 fold_span_only!(fold_lit_byte_str: LitByteStr);
690 #[cfg(any(feature = "full", feature = "derive"))]
691 fold_span_only!(fold_lit_char: LitChar);
692 #[cfg(any(feature = "full", feature = "derive"))]
693 fold_span_only!(fold_lit_float: LitFloat);
694 #[cfg(any(feature = "full", feature = "derive"))]
695 fold_span_only!(fold_lit_int: LitInt);
696 #[cfg(any(feature = "full", feature = "derive"))]
697 fold_span_only!(fold_lit_str: LitStr);
698
699 #fold_impl
700 },
701 );
702
703 let visit_trait = state.visit_trait;
704 let visit_impl = state.visit_impl;
David Tolnaycec98a72019-05-08 15:23:19 -0700705 file::write(
Carl Lerche058ff472019-02-13 16:23:52 -0800706 VISIT_SRC,
707 quote! {
708 #![cfg_attr(feature = "cargo-clippy", allow(trivially_copy_pass_by_ref))]
709
710 use *;
711 #[cfg(any(feature = "full", feature = "derive"))]
712 use punctuated::Punctuated;
713 use proc_macro2::Span;
714 #[cfg(any(feature = "full", feature = "derive"))]
715 use gen::helper::visit::*;
716
717 #full_macro
718 #skip_macro
719
720 /// Syntax tree traversal to walk a shared borrow of a syntax tree.
721 ///
722 /// See the [module documentation] for details.
723 ///
724 /// [module documentation]: index.html
725 ///
726 /// *This trait is available if Syn is built with the `"visit"` feature.*
727 pub trait Visit<'ast> {
728 #visit_trait
729 }
730
731 #visit_impl
732 },
733 );
734
735 let visit_mut_trait = state.visit_mut_trait;
736 let visit_mut_impl = state.visit_mut_impl;
David Tolnaycec98a72019-05-08 15:23:19 -0700737 file::write(
Carl Lerche058ff472019-02-13 16:23:52 -0800738 VISIT_MUT_SRC,
739 quote! {
740 use *;
741 #[cfg(any(feature = "full", feature = "derive"))]
742 use punctuated::Punctuated;
743 use proc_macro2::Span;
744 #[cfg(any(feature = "full", feature = "derive"))]
745 use gen::helper::visit_mut::*;
746
747 #full_macro
748 #skip_macro
749
750 /// Syntax tree traversal to mutate an exclusive borrow of a syntax tree in
751 /// place.
752 ///
753 /// See the [module documentation] for details.
754 ///
755 /// [module documentation]: index.html
756 ///
757 /// *This trait is available if Syn is built with the `"visit-mut"` feature.*
758 pub trait VisitMut {
759 #visit_mut_trait
760 }
761
762 #visit_mut_impl
763 },
764 );
765}