1 macro_rules! ast_struct {
2     (
3         [$($attrs_pub:tt)*]
4         struct $name:ident #full $($rest:tt)*
5     ) => {
6         #[cfg(feature = "full")]
7         $($attrs_pub)* struct $name $($rest)*
8 
9         #[cfg(not(feature = "full"))]
10         $($attrs_pub)* struct $name {
11             _noconstruct: ::std::marker::PhantomData<::proc_macro2::Span>,
12         }
13 
14         #[cfg(all(not(feature = "full"), feature = "printing"))]
15         impl ::quote::ToTokens for $name {
16             fn to_tokens(&self, _: &mut ::proc_macro2::TokenStream) {
17                 unreachable!()
18             }
19         }
20     };
21 
22     (
23         [$($attrs_pub:tt)*]
24         struct $name:ident $($rest:tt)*
25     ) => {
26         $($attrs_pub)* struct $name $($rest)*
27     };
28 
29     ($($t:tt)*) => {
30         strip_attrs_pub!(ast_struct!($($t)*));
31     };
32 }
33 
34 macro_rules! ast_enum {
35     // Drop the `#no_visit` attribute, if present.
36     (
37         [$($attrs_pub:tt)*]
38         enum $name:ident #no_visit $($rest:tt)*
39     ) => (
40         ast_enum!([$($attrs_pub)*] enum $name $($rest)*);
41     );
42 
43     (
44         [$($attrs_pub:tt)*]
45         enum $name:ident $($rest:tt)*
46     ) => (
47         $($attrs_pub)* enum $name $($rest)*
48     );
49 
50     ($($t:tt)*) => {
51         strip_attrs_pub!(ast_enum!($($t)*));
52     };
53 }
54 
55 macro_rules! ast_enum_of_structs {
56     (
57         $(#[$enum_attr:meta])*
58         $pub:ident $enum:ident $name:ident #$tag:ident $body:tt
59         $($remaining:tt)*
60     ) => {
61         ast_enum!($(#[$enum_attr])* $pub $enum $name #$tag $body);
62         ast_enum_of_structs_impl!($pub $enum $name $body $($remaining)*);
63     };
64 
65     (
66         $(#[$enum_attr:meta])*
67         $pub:ident $enum:ident $name:ident $body:tt
68         $($remaining:tt)*
69     ) => {
70         ast_enum!($(#[$enum_attr])* $pub $enum $name $body);
71         ast_enum_of_structs_impl!($pub $enum $name $body $($remaining)*);
72     };
73 }
74 
75 macro_rules! ast_enum_of_structs_impl {
76     (
77         $pub:ident $enum:ident $name:ident {
78             $(
79                 $(#[$variant_attr:meta])*
80                 $variant:ident $( ($($member:ident)::+) )*,
81             )*
82         }
83 
84         $($remaining:tt)*
85     ) => {
86         check_keyword_matches!(pub $pub);
87         check_keyword_matches!(enum $enum);
88 
89         $($(
90             ast_enum_from_struct!($name::$variant, $($member)::+);
91         )*)*
92 
93         #[cfg(feature = "printing")]
94         generate_to_tokens! {
95             $($remaining)*
96             ()
97             tokens
98             $name { $($variant $($($member)::+)*,)* }
99         }
100     };
101 }
102 
103 macro_rules! ast_enum_from_struct {
104     // No From<TokenStream> for verbatim variants.
105     ($name:ident::Verbatim, $member:ident) => {};
106 
107     // No From<TokenStream> for private variants.
108     ($name:ident::$variant:ident, crate::private) => {};
109 
110     ($name:ident::$variant:ident, $member:ident) => {
111         impl From<$member> for $name {
112             fn from(e: $member) -> $name {
113                 $name::$variant(e)
114             }
115         }
116     };
117 }
118 
119 #[cfg(feature = "printing")]
120 macro_rules! generate_to_tokens {
121     (do_not_generate_to_tokens $($foo:tt)*) => ();
122 
123     (($($arms:tt)*) $tokens:ident $name:ident { $variant:ident, $($next:tt)*}) => {
124         generate_to_tokens!(
125             ($($arms)* $name::$variant => {})
126             $tokens $name { $($next)* }
127         );
128     };
129 
130     (($($arms:tt)*) $tokens:ident $name:ident { $variant:ident $member:ident, $($next:tt)*}) => {
131         generate_to_tokens!(
132             ($($arms)* $name::$variant(_e) => _e.to_tokens($tokens),)
133             $tokens $name { $($next)* }
134         );
135     };
136 
137     (($($arms:tt)*) $tokens:ident $name:ident { $variant:ident crate::private, $($next:tt)*}) => {
138         generate_to_tokens!(
139             ($($arms)* $name::$variant(_) => unreachable!(),)
140             $tokens $name { $($next)* }
141         );
142     };
143 
144     (($($arms:tt)*) $tokens:ident $name:ident {}) => {
145         #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
146         impl ::quote::ToTokens for $name {
147             fn to_tokens(&self, $tokens: &mut ::proc_macro2::TokenStream) {
148                 match self {
149                     $($arms)*
150                 }
151             }
152         }
153     };
154 }
155 
156 macro_rules! strip_attrs_pub {
157     ($mac:ident!($(#[$m:meta])* $pub:ident $($t:tt)*)) => {
158         check_keyword_matches!(pub $pub);
159 
160         $mac!([$(#[$m])* $pub] $($t)*);
161     };
162 }
163 
164 macro_rules! check_keyword_matches {
165     (struct struct) => {};
166     (enum enum) => {};
167     (pub pub) => {};
168 }
169