summaryrefslogtreecommitdiffstats
path: root/vendor/syn/src/attr.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:20:39 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:20:39 +0000
commit1376c5a617be5c25655d0d7cb63e3beaa5a6e026 (patch)
tree3bb8d61aee02bc7a15eab3f36e3b921afc2075d0 /vendor/syn/src/attr.rs
parentReleasing progress-linux version 1.69.0+dfsg1-1~progress7.99u1. (diff)
downloadrustc-1376c5a617be5c25655d0d7cb63e3beaa5a6e026.tar.xz
rustc-1376c5a617be5c25655d0d7cb63e3beaa5a6e026.zip
Merging upstream version 1.70.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/syn/src/attr.rs')
-rw-r--r--vendor/syn/src/attr.rs656
1 files changed, 385 insertions, 271 deletions
diff --git a/vendor/syn/src/attr.rs b/vendor/syn/src/attr.rs
index bace94f43..34d5515a5 100644
--- a/vendor/syn/src/attr.rs
+++ b/vendor/syn/src/attr.rs
@@ -1,19 +1,15 @@
use super::*;
-use crate::punctuated::Punctuated;
use proc_macro2::TokenStream;
use std::iter;
use std::slice;
#[cfg(feature = "parsing")]
-use crate::parse::{Parse, ParseBuffer, ParseStream, Parser, Result};
+use crate::meta::{self, ParseNestedMeta};
#[cfg(feature = "parsing")]
-use crate::punctuated::Pair;
+use crate::parse::{Parse, ParseStream, Parser, Result};
ast_struct! {
- /// An attribute like `#[repr(transparent)]`.
- ///
- /// *This type is available only if Syn is built with the `"derive"` or `"full"`
- /// feature.*
+ /// An attribute, like `#[repr(transparent)]`.
///
/// <br>
///
@@ -23,27 +19,52 @@ ast_struct! {
///
/// - Outer attributes like `#[repr(transparent)]`. These appear outside or
/// in front of the item they describe.
+ ///
/// - Inner attributes like `#![feature(proc_macro)]`. These appear inside
/// of the item they describe, usually a module.
- /// - Outer doc comments like `/// # Example`.
- /// - Inner doc comments like `//! Please file an issue`.
- /// - Outer block comments `/** # Example */`.
- /// - Inner block comments `/*! Please file an issue */`.
+ ///
+ /// - Outer one-line doc comments like `/// Example`.
+ ///
+ /// - Inner one-line doc comments like `//! Please file an issue`.
+ ///
+ /// - Outer documentation blocks `/** Example */`.
+ ///
+ /// - Inner documentation blocks `/*! Please file an issue */`.
///
/// The `style` field of type `AttrStyle` distinguishes whether an attribute
- /// is outer or inner. Doc comments and block comments are promoted to
- /// attributes, as this is how they are processed by the compiler and by
- /// `macro_rules!` macros.
+ /// is outer or inner.
+ ///
+ /// Every attribute has a `path` that indicates the intended interpretation
+ /// of the rest of the attribute's contents. The path and the optional
+ /// additional contents are represented together in the `meta` field of the
+ /// attribute in three possible varieties:
+ ///
+ /// - Meta::Path &mdash; attributes whose information content conveys just a
+ /// path, for example the `#[test]` attribute.
///
- /// The `path` field gives the possibly colon-delimited path against which
- /// the attribute is resolved. It is equal to `"doc"` for desugared doc
- /// comments. The `tokens` field contains the rest of the attribute body as
- /// tokens.
+ /// - Meta::List &mdash; attributes that carry arbitrary tokens after the
+ /// path, surrounded by a delimiter (parenthesis, bracket, or brace). For
+ /// example `#[derive(Copy)]` or `#[precondition(x < 5)]`.
+ ///
+ /// - Meta::NameValue &mdash; attributes with an `=` sign after the path,
+ /// followed by a Rust expression. For example `#[path =
+ /// "sys/windows.rs"]`.
+ ///
+ /// All doc comments are represented in the NameValue style with a path of
+ /// "doc", as this is how they are processed by the compiler and by
+ /// `macro_rules!` macros.
///
/// ```text
- /// #[derive(Copy)] #[crate::precondition x < 5]
- /// ^^^^^^~~~~~~ ^^^^^^^^^^^^^^^^^^^ ~~~~~
- /// path tokens path tokens
+ /// #[derive(Copy, Clone)]
+ /// ~~~~~~Path
+ /// ^^^^^^^^^^^^^^^^^^^Meta::List
+ ///
+ /// #[path = "sys/windows.rs"]
+ /// ~~~~Path
+ /// ^^^^^^^^^^^^^^^^^^^^^^^Meta::NameValue
+ ///
+ /// #[test]
+ /// ^^^^Meta::Path
/// ```
///
/// <br>
@@ -93,18 +114,13 @@ ast_struct! {
///
/// The grammar of attributes in Rust is very flexible, which makes the
/// syntax tree not that useful on its own. In particular, arguments of the
- /// attribute are held in an arbitrary `tokens: TokenStream`. Macros are
- /// expected to check the `path` of the attribute, decide whether they
- /// recognize it, and then parse the remaining tokens according to whatever
- /// grammar they wish to require for that kind of attribute.
- ///
- /// If the attribute you are parsing is expected to conform to the
- /// conventional structured form of attribute, use [`parse_meta()`] to
- /// obtain that structured representation. If the attribute follows some
- /// other grammar of its own, use [`parse_args()`] to parse that into the
- /// expected data structure.
- ///
- /// [`parse_meta()`]: Attribute::parse_meta
+ /// `Meta::List` variety of attribute are held in an arbitrary `tokens:
+ /// TokenStream`. Macros are expected to check the `path` of the attribute,
+ /// decide whether they recognize it, and then parse the remaining tokens
+ /// according to whatever grammar they wish to require for that kind of
+ /// attribute. Use [`parse_args()`] to parse those tokens into the expected
+ /// data structure.
+ ///
/// [`parse_args()`]: Attribute::parse_args
///
/// <p><br></p>
@@ -150,65 +166,49 @@ ast_struct! {
pub pound_token: Token![#],
pub style: AttrStyle,
pub bracket_token: token::Bracket,
- pub path: Path,
- pub tokens: TokenStream,
+ pub meta: Meta,
}
}
impl Attribute {
- /// Parses the content of the attribute, consisting of the path and tokens,
- /// as a [`Meta`] if possible.
+ /// Returns the path that identifies the interpretation of this attribute.
///
- /// *This function is available only if Syn is built with the `"parsing"`
- /// feature.*
- #[cfg(feature = "parsing")]
- #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
- pub fn parse_meta(&self) -> Result<Meta> {
- fn clone_ident_segment(segment: &PathSegment) -> PathSegment {
- PathSegment {
- ident: segment.ident.clone(),
- arguments: PathArguments::None,
- }
- }
-
- let path = Path {
- leading_colon: self
- .path
- .leading_colon
- .as_ref()
- .map(|colon| Token![::](colon.spans)),
- segments: self
- .path
- .segments
- .pairs()
- .map(|pair| match pair {
- Pair::Punctuated(seg, punct) => {
- Pair::Punctuated(clone_ident_segment(seg), Token![::](punct.spans))
- }
- Pair::End(seg) => Pair::End(clone_ident_segment(seg)),
- })
- .collect(),
- };
-
- let parser = |input: ParseStream| parsing::parse_meta_after_path(path, input);
- parse::Parser::parse2(parser, self.tokens.clone())
+ /// For example this would return the `test` in `#[test]`, the `derive` in
+ /// `#[derive(Copy)]`, and the `path` in `#[path = "sys/windows.rs"]`.
+ pub fn path(&self) -> &Path {
+ self.meta.path()
}
/// Parse the arguments to the attribute as a syntax tree.
///
- /// This is similar to `syn::parse2::<T>(attr.tokens)` except that:
+ /// This is similar to pulling out the `TokenStream` from `Meta::List` and
+ /// doing `syn::parse2::<T>(meta_list.tokens)`, except that using
+ /// `parse_args` the error message has a more useful span when `tokens` is
+ /// empty.
///
- /// - the surrounding delimiters are *not* included in the input to the
- /// parser; and
- /// - the error message has a more useful span when `tokens` is empty.
+ /// The surrounding delimiters are *not* included in the input to the
+ /// parser.
///
/// ```text
/// #[my_attr(value < 5)]
/// ^^^^^^^^^ what gets parsed
/// ```
///
- /// *This function is available only if Syn is built with the `"parsing"`
- /// feature.*
+ /// # Example
+ ///
+ /// ```
+ /// use syn::{parse_quote, Attribute, Expr};
+ ///
+ /// let attr: Attribute = parse_quote! {
+ /// #[precondition(value < 5)]
+ /// };
+ ///
+ /// if attr.path().is_ident("precondition") {
+ /// let precondition: Expr = attr.parse_args()?;
+ /// // ...
+ /// }
+ /// # anyhow::Ok(())
+ /// ```
#[cfg(feature = "parsing")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
pub fn parse_args<T: Parse>(&self) -> Result<T> {
@@ -217,22 +217,182 @@ impl Attribute {
/// Parse the arguments to the attribute using the given parser.
///
- /// *This function is available only if Syn is built with the `"parsing"`
- /// feature.*
+ /// # Example
+ ///
+ /// ```
+ /// use syn::{parse_quote, Attribute};
+ ///
+ /// let attr: Attribute = parse_quote! {
+ /// #[inception { #[brrrrrrraaaaawwwwrwrrrmrmrmmrmrmmmmm] }]
+ /// };
+ ///
+ /// let bwom = attr.parse_args_with(Attribute::parse_outer)?;
+ ///
+ /// // Attribute does not have a Parse impl, so we couldn't directly do:
+ /// // let bwom: Attribute = attr.parse_args()?;
+ /// # anyhow::Ok(())
+ /// ```
#[cfg(feature = "parsing")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
pub fn parse_args_with<F: Parser>(&self, parser: F) -> Result<F::Output> {
- let parser = |input: ParseStream| {
- let args = enter_args(self, input)?;
- parse::parse_stream(parser, &args)
- };
- parser.parse2(self.tokens.clone())
+ match &self.meta {
+ Meta::Path(path) => Err(crate::error::new2(
+ path.segments.first().unwrap().ident.span(),
+ path.segments.last().unwrap().ident.span(),
+ format!(
+ "expected attribute arguments in parentheses: {}[{}(...)]",
+ parsing::DisplayAttrStyle(&self.style),
+ parsing::DisplayPath(path),
+ ),
+ )),
+ Meta::NameValue(meta) => Err(Error::new(
+ meta.eq_token.span,
+ format_args!(
+ "expected parentheses: {}[{}(...)]",
+ parsing::DisplayAttrStyle(&self.style),
+ parsing::DisplayPath(&meta.path),
+ ),
+ )),
+ Meta::List(meta) => meta.parse_args_with(parser),
+ }
+ }
+
+ /// Parse the arguments to the attribute, expecting it to follow the
+ /// conventional structure used by most of Rust's built-in attributes.
+ ///
+ /// The [*Meta Item Attribute Syntax*][syntax] section in the Rust reference
+ /// explains the convention in more detail. Not all attributes follow this
+ /// convention, so [`parse_args()`][Self::parse_args] is available if you
+ /// need to parse arbitrarily goofy attribute syntax.
+ ///
+ /// [syntax]: https://doc.rust-lang.org/reference/attributes.html#meta-item-attribute-syntax
+ ///
+ /// # Example
+ ///
+ /// We'll parse a struct, and then parse some of Rust's `#[repr]` attribute
+ /// syntax.
+ ///
+ /// ```
+ /// use syn::{parenthesized, parse_quote, token, ItemStruct, LitInt};
+ ///
+ /// let input: ItemStruct = parse_quote! {
+ /// #[repr(C, align(4))]
+ /// pub struct MyStruct(u16, u32);
+ /// };
+ ///
+ /// let mut repr_c = false;
+ /// let mut repr_transparent = false;
+ /// let mut repr_align = None::<usize>;
+ /// let mut repr_packed = None::<usize>;
+ /// for attr in &input.attrs {
+ /// if attr.path().is_ident("repr") {
+ /// attr.parse_nested_meta(|meta| {
+ /// // #[repr(C)]
+ /// if meta.path.is_ident("C") {
+ /// repr_c = true;
+ /// return Ok(());
+ /// }
+ ///
+ /// // #[repr(transparent)]
+ /// if meta.path.is_ident("transparent") {
+ /// repr_transparent = true;
+ /// return Ok(());
+ /// }
+ ///
+ /// // #[repr(align(N))]
+ /// if meta.path.is_ident("align") {
+ /// let content;
+ /// parenthesized!(content in meta.input);
+ /// let lit: LitInt = content.parse()?;
+ /// let n: usize = lit.base10_parse()?;
+ /// repr_align = Some(n);
+ /// return Ok(());
+ /// }
+ ///
+ /// // #[repr(packed)] or #[repr(packed(N))], omitted N means 1
+ /// if meta.path.is_ident("packed") {
+ /// if meta.input.peek(token::Paren) {
+ /// let content;
+ /// parenthesized!(content in meta.input);
+ /// let lit: LitInt = content.parse()?;
+ /// let n: usize = lit.base10_parse()?;
+ /// repr_packed = Some(n);
+ /// } else {
+ /// repr_packed = Some(1);
+ /// }
+ /// return Ok(());
+ /// }
+ ///
+ /// Err(meta.error("unrecognized repr"))
+ /// })?;
+ /// }
+ /// }
+ /// # anyhow::Ok(())
+ /// ```
+ ///
+ /// # Alternatives
+ ///
+ /// In some cases, for attributes which have nested layers of structured
+ /// content, the following less flexible approach might be more convenient:
+ ///
+ /// ```
+ /// # use syn::{parse_quote, ItemStruct};
+ /// #
+ /// # let input: ItemStruct = parse_quote! {
+ /// # #[repr(C, align(4))]
+ /// # pub struct MyStruct(u16, u32);
+ /// # };
+ /// #
+ /// use syn::punctuated::Punctuated;
+ /// use syn::{parenthesized, token, Error, LitInt, Meta, Token};
+ ///
+ /// let mut repr_c = false;
+ /// let mut repr_transparent = false;
+ /// let mut repr_align = None::<usize>;
+ /// let mut repr_packed = None::<usize>;
+ /// for attr in &input.attrs {
+ /// if attr.path().is_ident("repr") {
+ /// let nested = attr.parse_args_with(Punctuated::<Meta, Token![,]>::parse_terminated)?;
+ /// for meta in nested {
+ /// match meta {
+ /// // #[repr(C)]
+ /// Meta::Path(path) if path.is_ident("C") => {
+ /// repr_c = true;
+ /// }
+ ///
+ /// // #[repr(align(N))]
+ /// Meta::List(meta) if meta.path.is_ident("align") => {
+ /// let lit: LitInt = meta.parse_args()?;
+ /// let n: usize = lit.base10_parse()?;
+ /// repr_align = Some(n);
+ /// }
+ ///
+ /// /* ... */
+ ///
+ /// _ => {
+ /// return Err(Error::new_spanned(meta, "unrecognized repr"));
+ /// }
+ /// }
+ /// }
+ /// }
+ /// }
+ /// # Ok(())
+ /// ```
+ #[cfg(feature = "parsing")]
+ #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
+ pub fn parse_nested_meta(
+ &self,
+ logic: impl FnMut(ParseNestedMeta) -> Result<()>,
+ ) -> Result<()> {
+ self.parse_args_with(meta::parser(logic))
}
/// Parses zero or more outer attributes from the stream.
///
- /// *This function is available only if Syn is built with the `"parsing"`
- /// feature.*
+ /// # Example
+ ///
+ /// See
+ /// [*Parsing from tokens to Attribute*](#parsing-from-tokens-to-attribute).
#[cfg(feature = "parsing")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
pub fn parse_outer(input: ParseStream) -> Result<Vec<Self>> {
@@ -245,8 +405,10 @@ impl Attribute {
/// Parses zero or more inner attributes from the stream.
///
- /// *This function is available only if Syn is built with the `"parsing"`
- /// feature.*
+ /// # Example
+ ///
+ /// See
+ /// [*Parsing from tokens to Attribute*](#parsing-from-tokens-to-attribute).
#[cfg(feature = "parsing")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
pub fn parse_inner(input: ParseStream) -> Result<Vec<Self>> {
@@ -256,65 +418,10 @@ impl Attribute {
}
}
-#[cfg(feature = "parsing")]
-fn expected_parentheses(attr: &Attribute) -> String {
- let style = match attr.style {
- AttrStyle::Outer => "#",
- AttrStyle::Inner(_) => "#!",
- };
-
- let mut path = String::new();
- for segment in &attr.path.segments {
- if !path.is_empty() || attr.path.leading_colon.is_some() {
- path += "::";
- }
- path += &segment.ident.to_string();
- }
-
- format!("{}[{}(...)]", style, path)
-}
-
-#[cfg(feature = "parsing")]
-fn enter_args<'a>(attr: &Attribute, input: ParseStream<'a>) -> Result<ParseBuffer<'a>> {
- if input.is_empty() {
- let expected = expected_parentheses(attr);
- let msg = format!("expected attribute arguments in parentheses: {}", expected);
- return Err(crate::error::new2(
- attr.pound_token.span,
- attr.bracket_token.span,
- msg,
- ));
- } else if input.peek(Token![=]) {
- let expected = expected_parentheses(attr);
- let msg = format!("expected parentheses: {}", expected);
- return Err(input.error(msg));
- };
-
- let content;
- if input.peek(token::Paren) {
- parenthesized!(content in input);
- } else if input.peek(token::Bracket) {
- bracketed!(content in input);
- } else if input.peek(token::Brace) {
- braced!(content in input);
- } else {
- return Err(input.error("unexpected token in attribute arguments"));
- }
-
- if input.is_empty() {
- Ok(content)
- } else {
- Err(input.error("unexpected token in attribute arguments"))
- }
-}
-
ast_enum! {
/// Distinguishes between attributes that decorate an item and attributes
/// that are contained within an item.
///
- /// *This type is available only if Syn is built with the `"derive"` or `"full"`
- /// feature.*
- ///
/// # Outer attributes
///
/// - `#[repr(transparent)]`
@@ -336,9 +443,6 @@ ast_enum! {
ast_enum_of_structs! {
/// Content of a compile-time structured attribute.
///
- /// *This type is available only if Syn is built with the `"derive"` or `"full"`
- /// feature.*
- ///
/// ## Path
///
/// A meta path is like the `test` in `#[test]`.
@@ -371,32 +475,26 @@ ast_enum_of_structs! {
ast_struct! {
/// A structured list within an attribute, like `derive(Copy, Clone)`.
- ///
- /// *This type is available only if Syn is built with the `"derive"` or
- /// `"full"` feature.*
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
pub struct MetaList {
pub path: Path,
- pub paren_token: token::Paren,
- pub nested: Punctuated<NestedMeta, Token![,]>,
+ pub delimiter: MacroDelimiter,
+ pub tokens: TokenStream,
}
}
ast_struct! {
/// A name-value pair within an attribute, like `feature = "nightly"`.
- ///
- /// *This type is available only if Syn is built with the `"derive"` or
- /// `"full"` feature.*
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
pub struct MetaNameValue {
pub path: Path,
pub eq_token: Token![=],
- pub lit: Lit,
+ pub value: Expr,
}
}
impl Meta {
- /// Returns the identifier that begins this structured meta item.
+ /// Returns the path that begins this structured meta item.
///
/// For example this would return the `test` in `#[test]`, the `derive` in
/// `#[derive(Copy)]`, and the `path` in `#[path = "sys/windows.rs"]`.
@@ -407,63 +505,84 @@ impl Meta {
Meta::NameValue(meta) => &meta.path,
}
}
+
+ /// Error if this is a `Meta::List` or `Meta::NameValue`.
+ #[cfg(feature = "parsing")]
+ #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
+ pub fn require_path_only(&self) -> Result<&Path> {
+ let error_span = match self {
+ Meta::Path(path) => return Ok(path),
+ Meta::List(meta) => meta.delimiter.span().open(),
+ Meta::NameValue(meta) => meta.eq_token.span,
+ };
+ Err(Error::new(error_span, "unexpected token in attribute"))
+ }
+
+ /// Error if this is a `Meta::Path` or `Meta::NameValue`.
+ #[cfg(feature = "parsing")]
+ #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
+ pub fn require_list(&self) -> Result<&MetaList> {
+ match self {
+ Meta::List(meta) => Ok(meta),
+ Meta::Path(path) => Err(crate::error::new2(
+ path.segments.first().unwrap().ident.span(),
+ path.segments.last().unwrap().ident.span(),
+ format!(
+ "expected attribute arguments in parentheses: `{}(...)`",
+ parsing::DisplayPath(path),
+ ),
+ )),
+ Meta::NameValue(meta) => Err(Error::new(meta.eq_token.span, "expected `(`")),
+ }
+ }
+
+ /// Error if this is a `Meta::Path` or `Meta::List`.
+ #[cfg(feature = "parsing")]
+ #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
+ pub fn require_name_value(&self) -> Result<&MetaNameValue> {
+ match self {
+ Meta::NameValue(meta) => Ok(meta),
+ Meta::Path(path) => Err(crate::error::new2(
+ path.segments.first().unwrap().ident.span(),
+ path.segments.last().unwrap().ident.span(),
+ format!(
+ "expected a value for this attribute: `{} = ...`",
+ parsing::DisplayPath(path),
+ ),
+ )),
+ Meta::List(meta) => Err(Error::new(meta.delimiter.span().open(), "expected `=`")),
+ }
+ }
}
-ast_enum_of_structs! {
- /// Element of a compile-time attribute list.
- ///
- /// *This type is available only if Syn is built with the `"derive"` or `"full"`
- /// feature.*
- #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
- pub enum NestedMeta {
- /// A structured meta item, like the `Copy` in `#[derive(Copy)]` which
- /// would be a nested `Meta::Path`.
- Meta(Meta),
+impl MetaList {
+ /// See [`Attribute::parse_args`].
+ #[cfg(feature = "parsing")]
+ #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
+ pub fn parse_args<T: Parse>(&self) -> Result<T> {
+ self.parse_args_with(T::parse)
+ }
- /// A Rust literal, like the `"new_name"` in `#[rename("new_name")]`.
- Lit(Lit),
+ /// See [`Attribute::parse_args_with`].
+ #[cfg(feature = "parsing")]
+ #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
+ pub fn parse_args_with<F: Parser>(&self, parser: F) -> Result<F::Output> {
+ let scope = self.delimiter.span().close();
+ crate::parse::parse_scoped(parser, scope, self.tokens.clone())
+ }
+
+ /// See [`Attribute::parse_nested_meta`].
+ #[cfg(feature = "parsing")]
+ #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
+ pub fn parse_nested_meta(
+ &self,
+ logic: impl FnMut(ParseNestedMeta) -> Result<()>,
+ ) -> Result<()> {
+ self.parse_args_with(meta::parser(logic))
}
}
-/// Conventional argument type associated with an invocation of an attribute
-/// macro.
-///
-/// For example if we are developing an attribute macro that is intended to be
-/// invoked on function items as follows:
-///
-/// ```
-/// # const IGNORE: &str = stringify! {
-/// #[my_attribute(path = "/v1/refresh")]
-/// # };
-/// pub fn refresh() {
-/// /* ... */
-/// }
-/// ```
-///
-/// The implementation of this macro would want to parse its attribute arguments
-/// as type `AttributeArgs`.
-///
-/// ```
-/// # extern crate proc_macro;
-/// #
-/// use proc_macro::TokenStream;
-/// use syn::{parse_macro_input, AttributeArgs, ItemFn};
-///
-/// # const IGNORE: &str = stringify! {
-/// #[proc_macro_attribute]
-/// # };
-/// pub fn my_attribute(args: TokenStream, input: TokenStream) -> TokenStream {
-/// let args = parse_macro_input!(args as AttributeArgs);
-/// let input = parse_macro_input!(input as ItemFn);
-///
-/// /* ... */
-/// # "".parse().unwrap()
-/// }
-/// ```
-#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
-pub type AttributeArgs = Vec<NestedMeta>;
-
-pub trait FilterAttrs<'a> {
+pub(crate) trait FilterAttrs<'a> {
type Ret: Iterator<Item = &'a Attribute>;
fn outer(self) -> Self::Ret;
@@ -495,69 +614,43 @@ impl<'a> FilterAttrs<'a> for &'a [Attribute] {
}
#[cfg(feature = "parsing")]
-pub mod parsing {
+pub(crate) mod parsing {
use super::*;
- use crate::ext::IdentExt;
+ use crate::parse::discouraged::Speculative;
use crate::parse::{Parse, ParseStream, Result};
+ use std::fmt::{self, Display};
- pub fn parse_inner(input: ParseStream, attrs: &mut Vec<Attribute>) -> Result<()> {
+ pub(crate) fn parse_inner(input: ParseStream, attrs: &mut Vec<Attribute>) -> Result<()> {
while input.peek(Token![#]) && input.peek2(Token![!]) {
attrs.push(input.call(parsing::single_parse_inner)?);
}
Ok(())
}
- pub fn single_parse_inner(input: ParseStream) -> Result<Attribute> {
+ pub(crate) fn single_parse_inner(input: ParseStream) -> Result<Attribute> {
let content;
Ok(Attribute {
pound_token: input.parse()?,
style: AttrStyle::Inner(input.parse()?),
bracket_token: bracketed!(content in input),
- path: content.call(Path::parse_mod_style)?,
- tokens: content.parse()?,
+ meta: content.parse()?,
})
}
- pub fn single_parse_outer(input: ParseStream) -> Result<Attribute> {
+ pub(crate) fn single_parse_outer(input: ParseStream) -> Result<Attribute> {
let content;
Ok(Attribute {
pound_token: input.parse()?,
style: AttrStyle::Outer,
bracket_token: bracketed!(content in input),
- path: content.call(Path::parse_mod_style)?,
- tokens: content.parse()?,
- })
- }
-
- // Like Path::parse_mod_style but accepts keywords in the path.
- fn parse_meta_path(input: ParseStream) -> Result<Path> {
- Ok(Path {
- leading_colon: input.parse()?,
- segments: {
- let mut segments = Punctuated::new();
- while input.peek(Ident::peek_any) {
- let ident = Ident::parse_any(input)?;
- segments.push_value(PathSegment::from(ident));
- if !input.peek(Token![::]) {
- break;
- }
- let punct = input.parse()?;
- segments.push_punct(punct);
- }
- if segments.is_empty() {
- return Err(input.error("expected path"));
- } else if segments.trailing_punct() {
- return Err(input.error("expected path segment"));
- }
- segments
- },
+ meta: content.parse()?,
})
}
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
impl Parse for Meta {
fn parse(input: ParseStream) -> Result<Self> {
- let path = input.call(parse_meta_path)?;
+ let path = input.call(Path::parse_mod_style)?;
parse_meta_after_path(path, input)
}
}
@@ -565,7 +658,7 @@ pub mod parsing {
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
impl Parse for MetaList {
fn parse(input: ParseStream) -> Result<Self> {
- let path = input.call(parse_meta_path)?;
+ let path = input.call(Path::parse_mod_style)?;
parse_meta_list_after_path(path, input)
}
}
@@ -573,28 +666,13 @@ pub mod parsing {
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
impl Parse for MetaNameValue {
fn parse(input: ParseStream) -> Result<Self> {
- let path = input.call(parse_meta_path)?;
+ let path = input.call(Path::parse_mod_style)?;
parse_meta_name_value_after_path(path, input)
}
}
- #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
- impl Parse for NestedMeta {
- fn parse(input: ParseStream) -> Result<Self> {
- if input.peek(Lit) && !(input.peek(LitBool) && input.peek2(Token![=])) {
- input.parse().map(NestedMeta::Lit)
- } else if input.peek(Ident::peek_any)
- || input.peek(Token![::]) && input.peek3(Ident::peek_any)
- {
- input.parse().map(NestedMeta::Meta)
- } else {
- Err(input.error("expected identifier or literal"))
- }
- }
- }
-
- pub fn parse_meta_after_path(path: Path, input: ParseStream) -> Result<Meta> {
- if input.peek(token::Paren) {
+ pub(crate) fn parse_meta_after_path(path: Path, input: ParseStream) -> Result<Meta> {
+ if input.peek(token::Paren) || input.peek(token::Bracket) || input.peek(token::Brace) {
parse_meta_list_after_path(path, input).map(Meta::List)
} else if input.peek(Token![=]) {
parse_meta_name_value_after_path(path, input).map(Meta::NameValue)
@@ -604,21 +682,60 @@ pub mod parsing {
}
fn parse_meta_list_after_path(path: Path, input: ParseStream) -> Result<MetaList> {
- let content;
+ let (delimiter, tokens) = mac::parse_delimiter(input)?;
Ok(MetaList {
path,
- paren_token: parenthesized!(content in input),
- nested: content.parse_terminated(NestedMeta::parse)?,
+ delimiter,
+ tokens,
})
}
fn parse_meta_name_value_after_path(path: Path, input: ParseStream) -> Result<MetaNameValue> {
+ let eq_token: Token![=] = input.parse()?;
+ let ahead = input.fork();
+ let lit: Option<Lit> = ahead.parse()?;
+ let value = if let (Some(lit), true) = (lit, ahead.is_empty()) {
+ input.advance_to(&ahead);
+ Expr::Lit(ExprLit {
+ attrs: Vec::new(),
+ lit,
+ })
+ } else if input.peek(Token![#]) && input.peek2(token::Bracket) {
+ return Err(input.error("unexpected attribute inside of attribute"));
+ } else {
+ input.parse()?
+ };
Ok(MetaNameValue {
path,
- eq_token: input.parse()?,
- lit: input.parse()?,
+ eq_token,
+ value,
})
}
+
+ pub(super) struct DisplayAttrStyle<'a>(pub &'a AttrStyle);
+
+ impl<'a> Display for DisplayAttrStyle<'a> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str(match self.0 {
+ AttrStyle::Outer => "#",
+ AttrStyle::Inner(_) => "#!",
+ })
+ }
+ }
+
+ pub(super) struct DisplayPath<'a>(pub &'a Path);
+
+ impl<'a> Display for DisplayPath<'a> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ for (i, segment) in self.0.segments.iter().enumerate() {
+ if i > 0 || self.0.leading_colon.is_some() {
+ formatter.write_str("::")?;
+ }
+ write!(formatter, "{}", segment.ident)?;
+ }
+ Ok(())
+ }
+ }
}
#[cfg(feature = "printing")]
@@ -635,8 +752,7 @@ mod printing {
b.to_tokens(tokens);
}
self.bracket_token.surround(tokens, |tokens| {
- self.path.to_tokens(tokens);
- self.tokens.to_tokens(tokens);
+ self.meta.to_tokens(tokens);
});
}
}
@@ -645,9 +761,7 @@ mod printing {
impl ToTokens for MetaList {
fn to_tokens(&self, tokens: &mut TokenStream) {
self.path.to_tokens(tokens);
- self.paren_token.surround(tokens, |tokens| {
- self.nested.to_tokens(tokens);
- });
+ self.delimiter.surround(tokens, self.tokens.clone());
}
}
@@ -656,7 +770,7 @@ mod printing {
fn to_tokens(&self, tokens: &mut TokenStream) {
self.path.to_tokens(tokens);
self.eq_token.to_tokens(tokens);
- self.lit.to_tokens(tokens);
+ self.value.to_tokens(tokens);
}
}
}