1 #[cfg(feature = "parsing")] 2 use crate::error::Error; 3 #[cfg(feature = "parsing")] 4 use crate::error::Result; 5 use crate::expr::Expr; 6 use crate::mac::MacroDelimiter; 7 #[cfg(feature = "parsing")] 8 use crate::meta::{self, ParseNestedMeta}; 9 #[cfg(feature = "parsing")] 10 use crate::parse::{Parse, ParseStream, Parser}; 11 use crate::path::Path; 12 use crate::token; 13 use proc_macro2::TokenStream; 14 #[cfg(feature = "printing")] 15 use std::iter; 16 #[cfg(feature = "printing")] 17 use std::slice; 18 19 ast_struct! { 20 /// An attribute, like `#[repr(transparent)]`. 21 /// 22 /// <br> 23 /// 24 /// # Syntax 25 /// 26 /// Rust has six types of attributes. 27 /// 28 /// - Outer attributes like `#[repr(transparent)]`. These appear outside or 29 /// in front of the item they describe. 30 /// 31 /// - Inner attributes like `#![feature(proc_macro)]`. These appear inside 32 /// of the item they describe, usually a module. 33 /// 34 /// - Outer one-line doc comments like `/// Example`. 35 /// 36 /// - Inner one-line doc comments like `//! Please file an issue`. 37 /// 38 /// - Outer documentation blocks `/** Example */`. 39 /// 40 /// - Inner documentation blocks `/*! Please file an issue */`. 41 /// 42 /// The `style` field of type `AttrStyle` distinguishes whether an attribute 43 /// is outer or inner. 44 /// 45 /// Every attribute has a `path` that indicates the intended interpretation 46 /// of the rest of the attribute's contents. The path and the optional 47 /// additional contents are represented together in the `meta` field of the 48 /// attribute in three possible varieties: 49 /// 50 /// - Meta::Path — attributes whose information content conveys just a 51 /// path, for example the `#[test]` attribute. 52 /// 53 /// - Meta::List — attributes that carry arbitrary tokens after the 54 /// path, surrounded by a delimiter (parenthesis, bracket, or brace). For 55 /// example `#[derive(Copy)]` or `#[precondition(x < 5)]`. 56 /// 57 /// - Meta::NameValue — attributes with an `=` sign after the path, 58 /// followed by a Rust expression. For example `#[path = 59 /// "sys/windows.rs"]`. 60 /// 61 /// All doc comments are represented in the NameValue style with a path of 62 /// "doc", as this is how they are processed by the compiler and by 63 /// `macro_rules!` macros. 64 /// 65 /// ```text 66 /// #[derive(Copy, Clone)] 67 /// ~~~~~~Path 68 /// ^^^^^^^^^^^^^^^^^^^Meta::List 69 /// 70 /// #[path = "sys/windows.rs"] 71 /// ~~~~Path 72 /// ^^^^^^^^^^^^^^^^^^^^^^^Meta::NameValue 73 /// 74 /// #[test] 75 /// ^^^^Meta::Path 76 /// ``` 77 /// 78 /// <br> 79 /// 80 /// # Parsing from tokens to Attribute 81 /// 82 /// This type does not implement the [`Parse`] trait and thus cannot be 83 /// parsed directly by [`ParseStream::parse`]. Instead use 84 /// [`ParseStream::call`] with one of the two parser functions 85 /// [`Attribute::parse_outer`] or [`Attribute::parse_inner`] depending on 86 /// which you intend to parse. 87 /// 88 /// [`Parse`]: crate::parse::Parse 89 /// [`ParseStream::parse`]: crate::parse::ParseBuffer::parse 90 /// [`ParseStream::call`]: crate::parse::ParseBuffer::call 91 /// 92 /// ``` 93 /// use syn::{Attribute, Ident, Result, Token}; 94 /// use syn::parse::{Parse, ParseStream}; 95 /// 96 /// // Parses a unit struct with attributes. 97 /// // 98 /// // #[path = "s.tmpl"] 99 /// // struct S; 100 /// struct UnitStruct { 101 /// attrs: Vec<Attribute>, 102 /// struct_token: Token![struct], 103 /// name: Ident, 104 /// semi_token: Token![;], 105 /// } 106 /// 107 /// impl Parse for UnitStruct { 108 /// fn parse(input: ParseStream) -> Result<Self> { 109 /// Ok(UnitStruct { 110 /// attrs: input.call(Attribute::parse_outer)?, 111 /// struct_token: input.parse()?, 112 /// name: input.parse()?, 113 /// semi_token: input.parse()?, 114 /// }) 115 /// } 116 /// } 117 /// ``` 118 /// 119 /// <p><br></p> 120 /// 121 /// # Parsing from Attribute to structured arguments 122 /// 123 /// The grammar of attributes in Rust is very flexible, which makes the 124 /// syntax tree not that useful on its own. In particular, arguments of the 125 /// `Meta::List` variety of attribute are held in an arbitrary `tokens: 126 /// TokenStream`. Macros are expected to check the `path` of the attribute, 127 /// decide whether they recognize it, and then parse the remaining tokens 128 /// according to whatever grammar they wish to require for that kind of 129 /// attribute. Use [`parse_args()`] to parse those tokens into the expected 130 /// data structure. 131 /// 132 /// [`parse_args()`]: Attribute::parse_args 133 /// 134 /// <p><br></p> 135 /// 136 /// # Doc comments 137 /// 138 /// The compiler transforms doc comments, such as `/// comment` and `/*! 139 /// comment */`, into attributes before macros are expanded. Each comment is 140 /// expanded into an attribute of the form `#[doc = r"comment"]`. 141 /// 142 /// As an example, the following `mod` items are expanded identically: 143 /// 144 /// ``` 145 /// # use syn::{ItemMod, parse_quote}; 146 /// let doc: ItemMod = parse_quote! { 147 /// /// Single line doc comments 148 /// /// We write so many! 149 /// /** 150 /// * Multi-line comments... 151 /// * May span many lines 152 /// */ 153 /// mod example { 154 /// //! Of course, they can be inner too 155 /// /*! And fit in a single line */ 156 /// } 157 /// }; 158 /// let attr: ItemMod = parse_quote! { 159 /// #[doc = r" Single line doc comments"] 160 /// #[doc = r" We write so many!"] 161 /// #[doc = r" 162 /// * Multi-line comments... 163 /// * May span many lines 164 /// "] 165 /// mod example { 166 /// #![doc = r" Of course, they can be inner too"] 167 /// #![doc = r" And fit in a single line "] 168 /// } 169 /// }; 170 /// assert_eq!(doc, attr); 171 /// ``` 172 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] 173 pub struct Attribute { 174 pub pound_token: Token![#], 175 pub style: AttrStyle, 176 pub bracket_token: token::Bracket, 177 pub meta: Meta, 178 } 179 } 180 181 impl Attribute { 182 /// Returns the path that identifies the interpretation of this attribute. 183 /// 184 /// For example this would return the `test` in `#[test]`, the `derive` in 185 /// `#[derive(Copy)]`, and the `path` in `#[path = "sys/windows.rs"]`. path(&self) -> &Path186 pub fn path(&self) -> &Path { 187 self.meta.path() 188 } 189 190 /// Parse the arguments to the attribute as a syntax tree. 191 /// 192 /// This is similar to pulling out the `TokenStream` from `Meta::List` and 193 /// doing `syn::parse2::<T>(meta_list.tokens)`, except that using 194 /// `parse_args` the error message has a more useful span when `tokens` is 195 /// empty. 196 /// 197 /// The surrounding delimiters are *not* included in the input to the 198 /// parser. 199 /// 200 /// ```text 201 /// #[my_attr(value < 5)] 202 /// ^^^^^^^^^ what gets parsed 203 /// ``` 204 /// 205 /// # Example 206 /// 207 /// ``` 208 /// use syn::{parse_quote, Attribute, Expr}; 209 /// 210 /// let attr: Attribute = parse_quote! { 211 /// #[precondition(value < 5)] 212 /// }; 213 /// 214 /// if attr.path().is_ident("precondition") { 215 /// let precondition: Expr = attr.parse_args()?; 216 /// // ... 217 /// } 218 /// # anyhow::Ok(()) 219 /// ``` 220 #[cfg(feature = "parsing")] 221 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] parse_args<T: Parse>(&self) -> Result<T>222 pub fn parse_args<T: Parse>(&self) -> Result<T> { 223 self.parse_args_with(T::parse) 224 } 225 226 /// Parse the arguments to the attribute using the given parser. 227 /// 228 /// # Example 229 /// 230 /// ``` 231 /// use syn::{parse_quote, Attribute}; 232 /// 233 /// let attr: Attribute = parse_quote! { 234 /// #[inception { #[brrrrrrraaaaawwwwrwrrrmrmrmmrmrmmmmm] }] 235 /// }; 236 /// 237 /// let bwom = attr.parse_args_with(Attribute::parse_outer)?; 238 /// 239 /// // Attribute does not have a Parse impl, so we couldn't directly do: 240 /// // let bwom: Attribute = attr.parse_args()?; 241 /// # anyhow::Ok(()) 242 /// ``` 243 #[cfg(feature = "parsing")] 244 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] parse_args_with<F: Parser>(&self, parser: F) -> Result<F::Output>245 pub fn parse_args_with<F: Parser>(&self, parser: F) -> Result<F::Output> { 246 match &self.meta { 247 Meta::Path(path) => Err(crate::error::new2( 248 path.segments.first().unwrap().ident.span(), 249 path.segments.last().unwrap().ident.span(), 250 format!( 251 "expected attribute arguments in parentheses: {}[{}(...)]", 252 parsing::DisplayAttrStyle(&self.style), 253 parsing::DisplayPath(path), 254 ), 255 )), 256 Meta::NameValue(meta) => Err(Error::new( 257 meta.eq_token.span, 258 format_args!( 259 "expected parentheses: {}[{}(...)]", 260 parsing::DisplayAttrStyle(&self.style), 261 parsing::DisplayPath(&meta.path), 262 ), 263 )), 264 Meta::List(meta) => meta.parse_args_with(parser), 265 } 266 } 267 268 /// Parse the arguments to the attribute, expecting it to follow the 269 /// conventional structure used by most of Rust's built-in attributes. 270 /// 271 /// The [*Meta Item Attribute Syntax*][syntax] section in the Rust reference 272 /// explains the convention in more detail. Not all attributes follow this 273 /// convention, so [`parse_args()`][Self::parse_args] is available if you 274 /// need to parse arbitrarily goofy attribute syntax. 275 /// 276 /// [syntax]: https://doc.rust-lang.org/reference/attributes.html#meta-item-attribute-syntax 277 /// 278 /// # Example 279 /// 280 /// We'll parse a struct, and then parse some of Rust's `#[repr]` attribute 281 /// syntax. 282 /// 283 /// ``` 284 /// use syn::{parenthesized, parse_quote, token, ItemStruct, LitInt}; 285 /// 286 /// let input: ItemStruct = parse_quote! { 287 /// #[repr(C, align(4))] 288 /// pub struct MyStruct(u16, u32); 289 /// }; 290 /// 291 /// let mut repr_c = false; 292 /// let mut repr_transparent = false; 293 /// let mut repr_align = None::<usize>; 294 /// let mut repr_packed = None::<usize>; 295 /// for attr in &input.attrs { 296 /// if attr.path().is_ident("repr") { 297 /// attr.parse_nested_meta(|meta| { 298 /// // #[repr(C)] 299 /// if meta.path.is_ident("C") { 300 /// repr_c = true; 301 /// return Ok(()); 302 /// } 303 /// 304 /// // #[repr(transparent)] 305 /// if meta.path.is_ident("transparent") { 306 /// repr_transparent = true; 307 /// return Ok(()); 308 /// } 309 /// 310 /// // #[repr(align(N))] 311 /// if meta.path.is_ident("align") { 312 /// let content; 313 /// parenthesized!(content in meta.input); 314 /// let lit: LitInt = content.parse()?; 315 /// let n: usize = lit.base10_parse()?; 316 /// repr_align = Some(n); 317 /// return Ok(()); 318 /// } 319 /// 320 /// // #[repr(packed)] or #[repr(packed(N))], omitted N means 1 321 /// if meta.path.is_ident("packed") { 322 /// if meta.input.peek(token::Paren) { 323 /// let content; 324 /// parenthesized!(content in meta.input); 325 /// let lit: LitInt = content.parse()?; 326 /// let n: usize = lit.base10_parse()?; 327 /// repr_packed = Some(n); 328 /// } else { 329 /// repr_packed = Some(1); 330 /// } 331 /// return Ok(()); 332 /// } 333 /// 334 /// Err(meta.error("unrecognized repr")) 335 /// })?; 336 /// } 337 /// } 338 /// # anyhow::Ok(()) 339 /// ``` 340 /// 341 /// # Alternatives 342 /// 343 /// In some cases, for attributes which have nested layers of structured 344 /// content, the following less flexible approach might be more convenient: 345 /// 346 /// ``` 347 /// # use syn::{parse_quote, ItemStruct}; 348 /// # 349 /// # let input: ItemStruct = parse_quote! { 350 /// # #[repr(C, align(4))] 351 /// # pub struct MyStruct(u16, u32); 352 /// # }; 353 /// # 354 /// use syn::punctuated::Punctuated; 355 /// use syn::{parenthesized, token, Error, LitInt, Meta, Token}; 356 /// 357 /// let mut repr_c = false; 358 /// let mut repr_transparent = false; 359 /// let mut repr_align = None::<usize>; 360 /// let mut repr_packed = None::<usize>; 361 /// for attr in &input.attrs { 362 /// if attr.path().is_ident("repr") { 363 /// let nested = attr.parse_args_with(Punctuated::<Meta, Token![,]>::parse_terminated)?; 364 /// for meta in nested { 365 /// match meta { 366 /// // #[repr(C)] 367 /// Meta::Path(path) if path.is_ident("C") => { 368 /// repr_c = true; 369 /// } 370 /// 371 /// // #[repr(align(N))] 372 /// Meta::List(meta) if meta.path.is_ident("align") => { 373 /// let lit: LitInt = meta.parse_args()?; 374 /// let n: usize = lit.base10_parse()?; 375 /// repr_align = Some(n); 376 /// } 377 /// 378 /// /* ... */ 379 /// 380 /// _ => { 381 /// return Err(Error::new_spanned(meta, "unrecognized repr")); 382 /// } 383 /// } 384 /// } 385 /// } 386 /// } 387 /// # Ok(()) 388 /// ``` 389 #[cfg(feature = "parsing")] 390 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] parse_nested_meta( &self, logic: impl FnMut(ParseNestedMeta) -> Result<()>, ) -> Result<()>391 pub fn parse_nested_meta( 392 &self, 393 logic: impl FnMut(ParseNestedMeta) -> Result<()>, 394 ) -> Result<()> { 395 self.parse_args_with(meta::parser(logic)) 396 } 397 398 /// Parses zero or more outer attributes from the stream. 399 /// 400 /// # Example 401 /// 402 /// See 403 /// [*Parsing from tokens to Attribute*](#parsing-from-tokens-to-attribute). 404 #[cfg(feature = "parsing")] 405 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] parse_outer(input: ParseStream) -> Result<Vec<Self>>406 pub fn parse_outer(input: ParseStream) -> Result<Vec<Self>> { 407 let mut attrs = Vec::new(); 408 while input.peek(Token![#]) { 409 attrs.push(input.call(parsing::single_parse_outer)?); 410 } 411 Ok(attrs) 412 } 413 414 /// Parses zero or more inner attributes from the stream. 415 /// 416 /// # Example 417 /// 418 /// See 419 /// [*Parsing from tokens to Attribute*](#parsing-from-tokens-to-attribute). 420 #[cfg(feature = "parsing")] 421 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] parse_inner(input: ParseStream) -> Result<Vec<Self>>422 pub fn parse_inner(input: ParseStream) -> Result<Vec<Self>> { 423 let mut attrs = Vec::new(); 424 parsing::parse_inner(input, &mut attrs)?; 425 Ok(attrs) 426 } 427 } 428 429 ast_enum! { 430 /// Distinguishes between attributes that decorate an item and attributes 431 /// that are contained within an item. 432 /// 433 /// # Outer attributes 434 /// 435 /// - `#[repr(transparent)]` 436 /// - `/// # Example` 437 /// - `/** Please file an issue */` 438 /// 439 /// # Inner attributes 440 /// 441 /// - `#![feature(proc_macro)]` 442 /// - `//! # Example` 443 /// - `/*! Please file an issue */` 444 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] 445 pub enum AttrStyle { 446 Outer, 447 Inner(Token![!]), 448 } 449 } 450 451 ast_enum_of_structs! { 452 /// Content of a compile-time structured attribute. 453 /// 454 /// ## Path 455 /// 456 /// A meta path is like the `test` in `#[test]`. 457 /// 458 /// ## List 459 /// 460 /// A meta list is like the `derive(Copy)` in `#[derive(Copy)]`. 461 /// 462 /// ## NameValue 463 /// 464 /// A name-value meta is like the `path = "..."` in `#[path = 465 /// "sys/windows.rs"]`. 466 /// 467 /// # Syntax tree enum 468 /// 469 /// This type is a [syntax tree enum]. 470 /// 471 /// [syntax tree enum]: crate::expr::Expr#syntax-tree-enums 472 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] 473 pub enum Meta { 474 Path(Path), 475 476 /// A structured list within an attribute, like `derive(Copy, Clone)`. 477 List(MetaList), 478 479 /// A name-value pair within an attribute, like `feature = "nightly"`. 480 NameValue(MetaNameValue), 481 } 482 } 483 484 ast_struct! { 485 /// A structured list within an attribute, like `derive(Copy, Clone)`. 486 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] 487 pub struct MetaList { 488 pub path: Path, 489 pub delimiter: MacroDelimiter, 490 pub tokens: TokenStream, 491 } 492 } 493 494 ast_struct! { 495 /// A name-value pair within an attribute, like `feature = "nightly"`. 496 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] 497 pub struct MetaNameValue { 498 pub path: Path, 499 pub eq_token: Token![=], 500 pub value: Expr, 501 } 502 } 503 504 impl Meta { 505 /// Returns the path that begins this structured meta item. 506 /// 507 /// For example this would return the `test` in `#[test]`, the `derive` in 508 /// `#[derive(Copy)]`, and the `path` in `#[path = "sys/windows.rs"]`. path(&self) -> &Path509 pub fn path(&self) -> &Path { 510 match self { 511 Meta::Path(path) => path, 512 Meta::List(meta) => &meta.path, 513 Meta::NameValue(meta) => &meta.path, 514 } 515 } 516 517 /// Error if this is a `Meta::List` or `Meta::NameValue`. 518 #[cfg(feature = "parsing")] 519 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] require_path_only(&self) -> Result<&Path>520 pub fn require_path_only(&self) -> Result<&Path> { 521 let error_span = match self { 522 Meta::Path(path) => return Ok(path), 523 Meta::List(meta) => meta.delimiter.span().open(), 524 Meta::NameValue(meta) => meta.eq_token.span, 525 }; 526 Err(Error::new(error_span, "unexpected token in attribute")) 527 } 528 529 /// Error if this is a `Meta::Path` or `Meta::NameValue`. 530 #[cfg(feature = "parsing")] 531 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] require_list(&self) -> Result<&MetaList>532 pub fn require_list(&self) -> Result<&MetaList> { 533 match self { 534 Meta::List(meta) => Ok(meta), 535 Meta::Path(path) => Err(crate::error::new2( 536 path.segments.first().unwrap().ident.span(), 537 path.segments.last().unwrap().ident.span(), 538 format!( 539 "expected attribute arguments in parentheses: `{}(...)`", 540 parsing::DisplayPath(path), 541 ), 542 )), 543 Meta::NameValue(meta) => Err(Error::new(meta.eq_token.span, "expected `(`")), 544 } 545 } 546 547 /// Error if this is a `Meta::Path` or `Meta::List`. 548 #[cfg(feature = "parsing")] 549 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] require_name_value(&self) -> Result<&MetaNameValue>550 pub fn require_name_value(&self) -> Result<&MetaNameValue> { 551 match self { 552 Meta::NameValue(meta) => Ok(meta), 553 Meta::Path(path) => Err(crate::error::new2( 554 path.segments.first().unwrap().ident.span(), 555 path.segments.last().unwrap().ident.span(), 556 format!( 557 "expected a value for this attribute: `{} = ...`", 558 parsing::DisplayPath(path), 559 ), 560 )), 561 Meta::List(meta) => Err(Error::new(meta.delimiter.span().open(), "expected `=`")), 562 } 563 } 564 } 565 566 impl MetaList { 567 /// See [`Attribute::parse_args`]. 568 #[cfg(feature = "parsing")] 569 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] parse_args<T: Parse>(&self) -> Result<T>570 pub fn parse_args<T: Parse>(&self) -> Result<T> { 571 self.parse_args_with(T::parse) 572 } 573 574 /// See [`Attribute::parse_args_with`]. 575 #[cfg(feature = "parsing")] 576 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] parse_args_with<F: Parser>(&self, parser: F) -> Result<F::Output>577 pub fn parse_args_with<F: Parser>(&self, parser: F) -> Result<F::Output> { 578 let scope = self.delimiter.span().close(); 579 crate::parse::parse_scoped(parser, scope, self.tokens.clone()) 580 } 581 582 /// See [`Attribute::parse_nested_meta`]. 583 #[cfg(feature = "parsing")] 584 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] parse_nested_meta( &self, logic: impl FnMut(ParseNestedMeta) -> Result<()>, ) -> Result<()>585 pub fn parse_nested_meta( 586 &self, 587 logic: impl FnMut(ParseNestedMeta) -> Result<()>, 588 ) -> Result<()> { 589 self.parse_args_with(meta::parser(logic)) 590 } 591 } 592 593 #[cfg(feature = "printing")] 594 pub(crate) trait FilterAttrs<'a> { 595 type Ret: Iterator<Item = &'a Attribute>; 596 outer(self) -> Self::Ret597 fn outer(self) -> Self::Ret; 598 #[cfg(feature = "full")] inner(self) -> Self::Ret599 fn inner(self) -> Self::Ret; 600 } 601 602 #[cfg(feature = "printing")] 603 impl<'a> FilterAttrs<'a> for &'a [Attribute] { 604 type Ret = iter::Filter<slice::Iter<'a, Attribute>, fn(&&Attribute) -> bool>; 605 outer(self) -> Self::Ret606 fn outer(self) -> Self::Ret { 607 fn is_outer(attr: &&Attribute) -> bool { 608 match attr.style { 609 AttrStyle::Outer => true, 610 AttrStyle::Inner(_) => false, 611 } 612 } 613 self.iter().filter(is_outer) 614 } 615 616 #[cfg(feature = "full")] inner(self) -> Self::Ret617 fn inner(self) -> Self::Ret { 618 fn is_inner(attr: &&Attribute) -> bool { 619 match attr.style { 620 AttrStyle::Inner(_) => true, 621 AttrStyle::Outer => false, 622 } 623 } 624 self.iter().filter(is_inner) 625 } 626 } 627 628 #[cfg(feature = "parsing")] 629 pub(crate) mod parsing { 630 use crate::attr::{AttrStyle, Attribute, Meta, MetaList, MetaNameValue}; 631 use crate::error::Result; 632 use crate::expr::{Expr, ExprLit}; 633 use crate::lit::Lit; 634 use crate::parse::discouraged::Speculative as _; 635 use crate::parse::{Parse, ParseStream}; 636 use crate::path::Path; 637 use crate::{mac, token}; 638 use std::fmt::{self, Display}; 639 parse_inner(input: ParseStream, attrs: &mut Vec<Attribute>) -> Result<()>640 pub(crate) fn parse_inner(input: ParseStream, attrs: &mut Vec<Attribute>) -> Result<()> { 641 while input.peek(Token![#]) && input.peek2(Token![!]) { 642 attrs.push(input.call(single_parse_inner)?); 643 } 644 Ok(()) 645 } 646 single_parse_inner(input: ParseStream) -> Result<Attribute>647 pub(crate) fn single_parse_inner(input: ParseStream) -> Result<Attribute> { 648 let content; 649 Ok(Attribute { 650 pound_token: input.parse()?, 651 style: AttrStyle::Inner(input.parse()?), 652 bracket_token: bracketed!(content in input), 653 meta: content.parse()?, 654 }) 655 } 656 single_parse_outer(input: ParseStream) -> Result<Attribute>657 pub(crate) fn single_parse_outer(input: ParseStream) -> Result<Attribute> { 658 let content; 659 Ok(Attribute { 660 pound_token: input.parse()?, 661 style: AttrStyle::Outer, 662 bracket_token: bracketed!(content in input), 663 meta: content.parse()?, 664 }) 665 } 666 667 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] 668 impl Parse for Meta { parse(input: ParseStream) -> Result<Self>669 fn parse(input: ParseStream) -> Result<Self> { 670 let path = input.call(Path::parse_mod_style)?; 671 parse_meta_after_path(path, input) 672 } 673 } 674 675 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] 676 impl Parse for MetaList { parse(input: ParseStream) -> Result<Self>677 fn parse(input: ParseStream) -> Result<Self> { 678 let path = input.call(Path::parse_mod_style)?; 679 parse_meta_list_after_path(path, input) 680 } 681 } 682 683 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] 684 impl Parse for MetaNameValue { parse(input: ParseStream) -> Result<Self>685 fn parse(input: ParseStream) -> Result<Self> { 686 let path = input.call(Path::parse_mod_style)?; 687 parse_meta_name_value_after_path(path, input) 688 } 689 } 690 parse_meta_after_path(path: Path, input: ParseStream) -> Result<Meta>691 pub(crate) fn parse_meta_after_path(path: Path, input: ParseStream) -> Result<Meta> { 692 if input.peek(token::Paren) || input.peek(token::Bracket) || input.peek(token::Brace) { 693 parse_meta_list_after_path(path, input).map(Meta::List) 694 } else if input.peek(Token![=]) { 695 parse_meta_name_value_after_path(path, input).map(Meta::NameValue) 696 } else { 697 Ok(Meta::Path(path)) 698 } 699 } 700 parse_meta_list_after_path(path: Path, input: ParseStream) -> Result<MetaList>701 fn parse_meta_list_after_path(path: Path, input: ParseStream) -> Result<MetaList> { 702 let (delimiter, tokens) = mac::parse_delimiter(input)?; 703 Ok(MetaList { 704 path, 705 delimiter, 706 tokens, 707 }) 708 } 709 parse_meta_name_value_after_path(path: Path, input: ParseStream) -> Result<MetaNameValue>710 fn parse_meta_name_value_after_path(path: Path, input: ParseStream) -> Result<MetaNameValue> { 711 let eq_token: Token![=] = input.parse()?; 712 let ahead = input.fork(); 713 let lit: Option<Lit> = ahead.parse()?; 714 let value = if let (Some(lit), true) = (lit, ahead.is_empty()) { 715 input.advance_to(&ahead); 716 Expr::Lit(ExprLit { 717 attrs: Vec::new(), 718 lit, 719 }) 720 } else if input.peek(Token![#]) && input.peek2(token::Bracket) { 721 return Err(input.error("unexpected attribute inside of attribute")); 722 } else { 723 input.parse()? 724 }; 725 Ok(MetaNameValue { 726 path, 727 eq_token, 728 value, 729 }) 730 } 731 732 pub(super) struct DisplayAttrStyle<'a>(pub &'a AttrStyle); 733 734 impl<'a> Display for DisplayAttrStyle<'a> { fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result735 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 736 formatter.write_str(match self.0 { 737 AttrStyle::Outer => "#", 738 AttrStyle::Inner(_) => "#!", 739 }) 740 } 741 } 742 743 pub(super) struct DisplayPath<'a>(pub &'a Path); 744 745 impl<'a> Display for DisplayPath<'a> { fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result746 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 747 for (i, segment) in self.0.segments.iter().enumerate() { 748 if i > 0 || self.0.leading_colon.is_some() { 749 formatter.write_str("::")?; 750 } 751 write!(formatter, "{}", segment.ident)?; 752 } 753 Ok(()) 754 } 755 } 756 } 757 758 #[cfg(feature = "printing")] 759 mod printing { 760 use crate::attr::{AttrStyle, Attribute, MetaList, MetaNameValue}; 761 use proc_macro2::TokenStream; 762 use quote::ToTokens; 763 764 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 765 impl ToTokens for Attribute { to_tokens(&self, tokens: &mut TokenStream)766 fn to_tokens(&self, tokens: &mut TokenStream) { 767 self.pound_token.to_tokens(tokens); 768 if let AttrStyle::Inner(b) = &self.style { 769 b.to_tokens(tokens); 770 } 771 self.bracket_token.surround(tokens, |tokens| { 772 self.meta.to_tokens(tokens); 773 }); 774 } 775 } 776 777 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 778 impl ToTokens for MetaList { to_tokens(&self, tokens: &mut TokenStream)779 fn to_tokens(&self, tokens: &mut TokenStream) { 780 self.path.to_tokens(tokens); 781 self.delimiter.surround(tokens, self.tokens.clone()); 782 } 783 } 784 785 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 786 impl ToTokens for MetaNameValue { to_tokens(&self, tokens: &mut TokenStream)787 fn to_tokens(&self, tokens: &mut TokenStream) { 788 self.path.to_tokens(tokens); 789 self.eq_token.to_tokens(tokens); 790 self.value.to_tokens(tokens); 791 } 792 } 793 } 794