1 use super::*; 2 use punctuated::Punctuated; 3 4 ast_struct! { 5 /// An enum variant. 6 /// 7 /// *This type is available if Syn is built with the `"derive"` or `"full"` 8 /// feature.* 9 pub struct Variant { 10 /// Attributes tagged on the variant. 11 pub attrs: Vec<Attribute>, 12 13 /// Name of the variant. 14 pub ident: Ident, 15 16 /// Content stored in the variant. 17 pub fields: Fields, 18 19 /// Explicit discriminant: `Variant = 1` 20 pub discriminant: Option<(Token![=], Expr)>, 21 } 22 } 23 24 ast_enum_of_structs! { 25 /// Data stored within an enum variant or struct. 26 /// 27 /// *This type is available if Syn is built with the `"derive"` or `"full"` 28 /// feature.* 29 /// 30 /// # Syntax tree enum 31 /// 32 /// This type is a [syntax tree enum]. 33 /// 34 /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums 35 // 36 // TODO: change syntax-tree-enum link to an intra rustdoc link, currently 37 // blocked on https://github.com/rust-lang/rust/issues/62833 38 pub enum Fields { 39 /// Named fields of a struct or struct variant such as `Point { x: f64, 40 /// y: f64 }`. 41 /// 42 /// *This type is available if Syn is built with the `"derive"` or 43 /// `"full"` feature.* 44 pub Named(FieldsNamed { 45 pub brace_token: token::Brace, 46 pub named: Punctuated<Field, Token![,]>, 47 }), 48 49 /// Unnamed fields of a tuple struct or tuple variant such as `Some(T)`. 50 /// 51 /// *This type is available if Syn is built with the `"derive"` or 52 /// `"full"` feature.* 53 pub Unnamed(FieldsUnnamed { 54 pub paren_token: token::Paren, 55 pub unnamed: Punctuated<Field, Token![,]>, 56 }), 57 58 /// Unit struct or unit variant such as `None`. 59 pub Unit, 60 } 61 } 62 63 impl Fields { 64 /// Get an iterator over the borrowed [`Field`] items in this object. This 65 /// iterator can be used to iterate over a named or unnamed struct or 66 /// variant's fields uniformly. iter(&self) -> punctuated::Iter<Field>67 pub fn iter(&self) -> punctuated::Iter<Field> { 68 match *self { 69 Fields::Unit => private::empty_punctuated_iter(), 70 Fields::Named(ref f) => f.named.iter(), 71 Fields::Unnamed(ref f) => f.unnamed.iter(), 72 } 73 } 74 75 /// Get an iterator over the mutably borrowed [`Field`] items in this 76 /// object. This iterator can be used to iterate over a named or unnamed 77 /// struct or variant's fields uniformly. iter_mut(&mut self) -> punctuated::IterMut<Field>78 pub fn iter_mut(&mut self) -> punctuated::IterMut<Field> { 79 match *self { 80 Fields::Unit => private::empty_punctuated_iter_mut(), 81 Fields::Named(ref mut f) => f.named.iter_mut(), 82 Fields::Unnamed(ref mut f) => f.unnamed.iter_mut(), 83 } 84 } 85 } 86 87 impl<'a> IntoIterator for &'a Fields { 88 type Item = &'a Field; 89 type IntoIter = punctuated::Iter<'a, Field>; 90 into_iter(self) -> Self::IntoIter91 fn into_iter(self) -> Self::IntoIter { 92 self.iter() 93 } 94 } 95 96 impl<'a> IntoIterator for &'a mut Fields { 97 type Item = &'a mut Field; 98 type IntoIter = punctuated::IterMut<'a, Field>; 99 into_iter(self) -> Self::IntoIter100 fn into_iter(self) -> Self::IntoIter { 101 self.iter_mut() 102 } 103 } 104 105 ast_struct! { 106 /// A field of a struct or enum variant. 107 /// 108 /// *This type is available if Syn is built with the `"derive"` or `"full"` 109 /// feature.* 110 pub struct Field { 111 /// Attributes tagged on the field. 112 pub attrs: Vec<Attribute>, 113 114 /// Visibility of the field. 115 pub vis: Visibility, 116 117 /// Name of the field, if any. 118 /// 119 /// Fields of tuple structs have no names. 120 pub ident: Option<Ident>, 121 122 pub colon_token: Option<Token![:]>, 123 124 /// Type of the field. 125 pub ty: Type, 126 } 127 } 128 129 ast_enum_of_structs! { 130 /// The visibility level of an item: inherited or `pub` or 131 /// `pub(restricted)`. 132 /// 133 /// *This type is available if Syn is built with the `"derive"` or `"full"` 134 /// feature.* 135 /// 136 /// # Syntax tree enum 137 /// 138 /// This type is a [syntax tree enum]. 139 /// 140 /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums 141 // 142 // TODO: change syntax-tree-enum link to an intra rustdoc link, currently 143 // blocked on https://github.com/rust-lang/rust/issues/62833 144 pub enum Visibility { 145 /// A public visibility level: `pub`. 146 /// 147 /// *This type is available if Syn is built with the `"derive"` or 148 /// `"full"` feature.* 149 pub Public(VisPublic { 150 pub pub_token: Token![pub], 151 }), 152 153 /// A crate-level visibility: `crate`. 154 /// 155 /// *This type is available if Syn is built with the `"derive"` or 156 /// `"full"` feature.* 157 pub Crate(VisCrate { 158 pub crate_token: Token![crate], 159 }), 160 161 /// A visibility level restricted to some path: `pub(self)` or 162 /// `pub(super)` or `pub(crate)` or `pub(in some::module)`. 163 /// 164 /// *This type is available if Syn is built with the `"derive"` or 165 /// `"full"` feature.* 166 pub Restricted(VisRestricted { 167 pub pub_token: Token![pub], 168 pub paren_token: token::Paren, 169 pub in_token: Option<Token![in]>, 170 pub path: Box<Path>, 171 }), 172 173 /// An inherited visibility, which usually means private. 174 pub Inherited, 175 } 176 } 177 178 #[cfg(feature = "parsing")] 179 pub mod parsing { 180 use super::*; 181 182 use ext::IdentExt; 183 use parse::{Parse, ParseStream, Result}; 184 185 impl Parse for Variant { parse(input: ParseStream) -> Result<Self>186 fn parse(input: ParseStream) -> Result<Self> { 187 Ok(Variant { 188 attrs: input.call(Attribute::parse_outer)?, 189 ident: input.parse()?, 190 fields: { 191 if input.peek(token::Brace) { 192 Fields::Named(input.parse()?) 193 } else if input.peek(token::Paren) { 194 Fields::Unnamed(input.parse()?) 195 } else { 196 Fields::Unit 197 } 198 }, 199 discriminant: { 200 if input.peek(Token![=]) { 201 let eq_token: Token![=] = input.parse()?; 202 let discriminant: Expr = input.parse()?; 203 Some((eq_token, discriminant)) 204 } else { 205 None 206 } 207 }, 208 }) 209 } 210 } 211 212 impl Parse for FieldsNamed { parse(input: ParseStream) -> Result<Self>213 fn parse(input: ParseStream) -> Result<Self> { 214 let content; 215 Ok(FieldsNamed { 216 brace_token: braced!(content in input), 217 named: content.parse_terminated(Field::parse_named)?, 218 }) 219 } 220 } 221 222 impl Parse for FieldsUnnamed { parse(input: ParseStream) -> Result<Self>223 fn parse(input: ParseStream) -> Result<Self> { 224 let content; 225 Ok(FieldsUnnamed { 226 paren_token: parenthesized!(content in input), 227 unnamed: content.parse_terminated(Field::parse_unnamed)?, 228 }) 229 } 230 } 231 232 impl Field { 233 /// Parses a named (braced struct) field. parse_named(input: ParseStream) -> Result<Self>234 pub fn parse_named(input: ParseStream) -> Result<Self> { 235 Ok(Field { 236 attrs: input.call(Attribute::parse_outer)?, 237 vis: input.parse()?, 238 ident: Some(input.parse()?), 239 colon_token: Some(input.parse()?), 240 ty: input.parse()?, 241 }) 242 } 243 244 /// Parses an unnamed (tuple struct) field. parse_unnamed(input: ParseStream) -> Result<Self>245 pub fn parse_unnamed(input: ParseStream) -> Result<Self> { 246 Ok(Field { 247 attrs: input.call(Attribute::parse_outer)?, 248 vis: input.parse()?, 249 ident: None, 250 colon_token: None, 251 ty: input.parse()?, 252 }) 253 } 254 } 255 256 impl Parse for Visibility { parse(input: ParseStream) -> Result<Self>257 fn parse(input: ParseStream) -> Result<Self> { 258 if input.peek(Token![pub]) { 259 Self::parse_pub(input) 260 } else if input.peek(Token![crate]) { 261 Self::parse_crate(input) 262 } else { 263 Ok(Visibility::Inherited) 264 } 265 } 266 } 267 268 impl Visibility { parse_pub(input: ParseStream) -> Result<Self>269 fn parse_pub(input: ParseStream) -> Result<Self> { 270 let pub_token = input.parse::<Token![pub]>()?; 271 272 if input.peek(token::Paren) { 273 // TODO: optimize using advance_to 274 let ahead = input.fork(); 275 let mut content; 276 parenthesized!(content in ahead); 277 278 if content.peek(Token![crate]) 279 || content.peek(Token![self]) 280 || content.peek(Token![super]) 281 { 282 return Ok(Visibility::Restricted(VisRestricted { 283 pub_token: pub_token, 284 paren_token: parenthesized!(content in input), 285 in_token: None, 286 path: Box::new(Path::from(content.call(Ident::parse_any)?)), 287 })); 288 } else if content.peek(Token![in]) { 289 return Ok(Visibility::Restricted(VisRestricted { 290 pub_token: pub_token, 291 paren_token: parenthesized!(content in input), 292 in_token: Some(content.parse()?), 293 path: Box::new(content.call(Path::parse_mod_style)?), 294 })); 295 } 296 } 297 298 Ok(Visibility::Public(VisPublic { 299 pub_token: pub_token, 300 })) 301 } 302 parse_crate(input: ParseStream) -> Result<Self>303 fn parse_crate(input: ParseStream) -> Result<Self> { 304 if input.peek2(Token![::]) { 305 Ok(Visibility::Inherited) 306 } else { 307 Ok(Visibility::Crate(VisCrate { 308 crate_token: input.parse()?, 309 })) 310 } 311 } 312 } 313 } 314 315 #[cfg(feature = "printing")] 316 mod printing { 317 use super::*; 318 319 use proc_macro2::TokenStream; 320 use quote::{ToTokens, TokenStreamExt}; 321 322 use print::TokensOrDefault; 323 324 impl ToTokens for Variant { to_tokens(&self, tokens: &mut TokenStream)325 fn to_tokens(&self, tokens: &mut TokenStream) { 326 tokens.append_all(&self.attrs); 327 self.ident.to_tokens(tokens); 328 self.fields.to_tokens(tokens); 329 if let Some((ref eq_token, ref disc)) = self.discriminant { 330 eq_token.to_tokens(tokens); 331 disc.to_tokens(tokens); 332 } 333 } 334 } 335 336 impl ToTokens for FieldsNamed { to_tokens(&self, tokens: &mut TokenStream)337 fn to_tokens(&self, tokens: &mut TokenStream) { 338 self.brace_token.surround(tokens, |tokens| { 339 self.named.to_tokens(tokens); 340 }); 341 } 342 } 343 344 impl ToTokens for FieldsUnnamed { to_tokens(&self, tokens: &mut TokenStream)345 fn to_tokens(&self, tokens: &mut TokenStream) { 346 self.paren_token.surround(tokens, |tokens| { 347 self.unnamed.to_tokens(tokens); 348 }); 349 } 350 } 351 352 impl ToTokens for Field { to_tokens(&self, tokens: &mut TokenStream)353 fn to_tokens(&self, tokens: &mut TokenStream) { 354 tokens.append_all(&self.attrs); 355 self.vis.to_tokens(tokens); 356 if let Some(ref ident) = self.ident { 357 ident.to_tokens(tokens); 358 TokensOrDefault(&self.colon_token).to_tokens(tokens); 359 } 360 self.ty.to_tokens(tokens); 361 } 362 } 363 364 impl ToTokens for VisPublic { to_tokens(&self, tokens: &mut TokenStream)365 fn to_tokens(&self, tokens: &mut TokenStream) { 366 self.pub_token.to_tokens(tokens) 367 } 368 } 369 370 impl ToTokens for VisCrate { to_tokens(&self, tokens: &mut TokenStream)371 fn to_tokens(&self, tokens: &mut TokenStream) { 372 self.crate_token.to_tokens(tokens); 373 } 374 } 375 376 impl ToTokens for VisRestricted { to_tokens(&self, tokens: &mut TokenStream)377 fn to_tokens(&self, tokens: &mut TokenStream) { 378 self.pub_token.to_tokens(tokens); 379 self.paren_token.surround(tokens, |tokens| { 380 // TODO: If we have a path which is not "self" or "super" or 381 // "crate", automatically add the "in" token. 382 self.in_token.to_tokens(tokens); 383 self.path.to_tokens(tokens); 384 }); 385 } 386 } 387 } 388