diff options
Diffstat (limited to 'vendor/syn/src/meta.rs')
-rw-r--r-- | vendor/syn/src/meta.rs | 426 |
1 files changed, 0 insertions, 426 deletions
diff --git a/vendor/syn/src/meta.rs b/vendor/syn/src/meta.rs deleted file mode 100644 index 66a0a46..0000000 --- a/vendor/syn/src/meta.rs +++ /dev/null @@ -1,426 +0,0 @@ -//! Facility for interpreting structured content inside of an `Attribute`. - -use crate::ext::IdentExt as _; -use crate::lit::Lit; -use crate::parse::{Error, ParseStream, Parser, Result}; -use crate::path::{Path, PathSegment}; -use crate::punctuated::Punctuated; -use proc_macro2::Ident; -use std::fmt::Display; - -/// Make a parser that is usable with `parse_macro_input!` in a -/// `#[proc_macro_attribute]` macro. -/// -/// *Warning:* When parsing attribute args **other than** the -/// `proc_macro::TokenStream` input of a `proc_macro_attribute`, you do **not** -/// need this function. In several cases your callers will get worse error -/// messages if you use this function, because the surrounding delimiter's span -/// is concealed from attribute macros by rustc. Use -/// [`Attribute::parse_nested_meta`] instead. -/// -/// [`Attribute::parse_nested_meta`]: crate::Attribute::parse_nested_meta -/// -/// # Example -/// -/// This example implements an attribute macro whose invocations look like this: -/// -/// ``` -/// # const IGNORE: &str = stringify! { -/// #[tea(kind = "EarlGrey", hot)] -/// struct Picard {...} -/// # }; -/// ``` -/// -/// The "parameters" supported by the attribute are: -/// -/// - `kind = "..."` -/// - `hot` -/// - `with(sugar, milk, ...)`, a comma-separated list of ingredients -/// -/// ``` -/// # extern crate proc_macro; -/// # -/// use proc_macro::TokenStream; -/// use syn::{parse_macro_input, LitStr, Path}; -/// -/// # const IGNORE: &str = stringify! { -/// #[proc_macro_attribute] -/// # }; -/// pub fn tea(args: TokenStream, input: TokenStream) -> TokenStream { -/// let mut kind: Option<LitStr> = None; -/// let mut hot: bool = false; -/// let mut with: Vec<Path> = Vec::new(); -/// let tea_parser = syn::meta::parser(|meta| { -/// if meta.path.is_ident("kind") { -/// kind = Some(meta.value()?.parse()?); -/// Ok(()) -/// } else if meta.path.is_ident("hot") { -/// hot = true; -/// Ok(()) -/// } else if meta.path.is_ident("with") { -/// meta.parse_nested_meta(|meta| { -/// with.push(meta.path); -/// Ok(()) -/// }) -/// } else { -/// Err(meta.error("unsupported tea property")) -/// } -/// }); -/// -/// parse_macro_input!(args with tea_parser); -/// eprintln!("kind={kind:?} hot={hot} with={with:?}"); -/// -/// /* ... */ -/// # TokenStream::new() -/// } -/// ``` -/// -/// The `syn::meta` library will take care of dealing with the commas including -/// trailing commas, and producing sensible error messages on unexpected input. -/// -/// ```console -/// error: expected `,` -/// --> src/main.rs:3:37 -/// | -/// 3 | #[tea(kind = "EarlGrey", with(sugar = "lol", milk))] -/// | ^ -/// ``` -/// -/// # Example -/// -/// Same as above but we factor out most of the logic into a separate function. -/// -/// ``` -/// # extern crate proc_macro; -/// # -/// use proc_macro::TokenStream; -/// use syn::meta::ParseNestedMeta; -/// use syn::parse::{Parser, Result}; -/// use syn::{parse_macro_input, LitStr, Path}; -/// -/// # const IGNORE: &str = stringify! { -/// #[proc_macro_attribute] -/// # }; -/// pub fn tea(args: TokenStream, input: TokenStream) -> TokenStream { -/// let mut attrs = TeaAttributes::default(); -/// let tea_parser = syn::meta::parser(|meta| attrs.parse(meta)); -/// parse_macro_input!(args with tea_parser); -/// -/// /* ... */ -/// # TokenStream::new() -/// } -/// -/// #[derive(Default)] -/// struct TeaAttributes { -/// kind: Option<LitStr>, -/// hot: bool, -/// with: Vec<Path>, -/// } -/// -/// impl TeaAttributes { -/// fn parse(&mut self, meta: ParseNestedMeta) -> Result<()> { -/// if meta.path.is_ident("kind") { -/// self.kind = Some(meta.value()?.parse()?); -/// Ok(()) -/// } else /* just like in last example */ -/// # { unimplemented!() } -/// -/// } -/// } -/// ``` -pub fn parser(logic: impl FnMut(ParseNestedMeta) -> Result<()>) -> impl Parser<Output = ()> { - |input: ParseStream| { - if input.is_empty() { - Ok(()) - } else { - parse_nested_meta(input, logic) - } - } -} - -/// Context for parsing a single property in the conventional syntax for -/// structured attributes. -/// -/// # Examples -/// -/// Refer to usage examples on the following two entry-points: -/// -/// - [`Attribute::parse_nested_meta`] if you have an entire `Attribute` to -/// parse. Always use this if possible. Generally this is able to produce -/// better error messages because `Attribute` holds span information for all -/// of the delimiters therein. -/// -/// - [`syn::meta::parser`] if you are implementing a `proc_macro_attribute` -/// macro and parsing the arguments to the attribute macro, i.e. the ones -/// written in the same attribute that dispatched the macro invocation. Rustc -/// does not pass span information for the surrounding delimiters into the -/// attribute macro invocation in this situation, so error messages might be -/// less precise. -/// -/// [`Attribute::parse_nested_meta`]: crate::Attribute::parse_nested_meta -/// [`syn::meta::parser`]: crate::meta::parser -#[non_exhaustive] -pub struct ParseNestedMeta<'a> { - pub path: Path, - pub input: ParseStream<'a>, -} - -impl<'a> ParseNestedMeta<'a> { - /// Used when parsing `key = "value"` syntax. - /// - /// All it does is advance `meta.input` past the `=` sign in the input. You - /// could accomplish the same effect by writing - /// `meta.parse::<Token![=]>()?`, so at most it is a minor convenience to - /// use `meta.value()?`. - /// - /// # Example - /// - /// ``` - /// use syn::{parse_quote, Attribute, LitStr}; - /// - /// let attr: Attribute = parse_quote! { - /// #[tea(kind = "EarlGrey")] - /// }; - /// // conceptually: - /// if attr.path().is_ident("tea") { // this parses the `tea` - /// attr.parse_nested_meta(|meta| { // this parses the `(` - /// if meta.path.is_ident("kind") { // this parses the `kind` - /// let value = meta.value()?; // this parses the `=` - /// let s: LitStr = value.parse()?; // this parses `"EarlGrey"` - /// if s.value() == "EarlGrey" { - /// // ... - /// } - /// Ok(()) - /// } else { - /// Err(meta.error("unsupported attribute")) - /// } - /// })?; - /// } - /// # anyhow::Ok(()) - /// ``` - pub fn value(&self) -> Result<ParseStream<'a>> { - self.input.parse::<Token![=]>()?; - Ok(self.input) - } - - /// Used when parsing `list(...)` syntax **if** the content inside the - /// nested parentheses is also expected to conform to Rust's structured - /// attribute convention. - /// - /// # Example - /// - /// ``` - /// use syn::{parse_quote, Attribute}; - /// - /// let attr: Attribute = parse_quote! { - /// #[tea(with(sugar, milk))] - /// }; - /// - /// if attr.path().is_ident("tea") { - /// attr.parse_nested_meta(|meta| { - /// if meta.path.is_ident("with") { - /// meta.parse_nested_meta(|meta| { // <--- - /// if meta.path.is_ident("sugar") { - /// // Here we can go even deeper if needed. - /// Ok(()) - /// } else if meta.path.is_ident("milk") { - /// Ok(()) - /// } else { - /// Err(meta.error("unsupported ingredient")) - /// } - /// }) - /// } else { - /// Err(meta.error("unsupported tea property")) - /// } - /// })?; - /// } - /// # anyhow::Ok(()) - /// ``` - /// - /// # Counterexample - /// - /// If you don't need `parse_nested_meta`'s help in parsing the content - /// written within the nested parentheses, keep in mind that you can always - /// just parse it yourself from the exposed ParseStream. Rust syntax permits - /// arbitrary tokens within those parentheses so for the crazier stuff, - /// `parse_nested_meta` is not what you want. - /// - /// ``` - /// use syn::{parenthesized, parse_quote, Attribute, LitInt}; - /// - /// let attr: Attribute = parse_quote! { - /// #[repr(align(32))] - /// }; - /// - /// let mut align: Option<LitInt> = None; - /// if attr.path().is_ident("repr") { - /// attr.parse_nested_meta(|meta| { - /// if meta.path.is_ident("align") { - /// let content; - /// parenthesized!(content in meta.input); - /// align = Some(content.parse()?); - /// Ok(()) - /// } else { - /// Err(meta.error("unsupported repr")) - /// } - /// })?; - /// } - /// # anyhow::Ok(()) - /// ``` - pub fn parse_nested_meta( - &self, - logic: impl FnMut(ParseNestedMeta) -> Result<()>, - ) -> Result<()> { - let content; - parenthesized!(content in self.input); - parse_nested_meta(&content, logic) - } - - /// Report that the attribute's content did not conform to expectations. - /// - /// The span of the resulting error will cover `meta.path` *and* everything - /// that has been parsed so far since it. - /// - /// There are 2 ways you might call this. First, if `meta.path` is not - /// something you recognize: - /// - /// ``` - /// # use syn::Attribute; - /// # - /// # fn example(attr: &Attribute) -> syn::Result<()> { - /// attr.parse_nested_meta(|meta| { - /// if meta.path.is_ident("kind") { - /// // ... - /// Ok(()) - /// } else { - /// Err(meta.error("unsupported tea property")) - /// } - /// })?; - /// # Ok(()) - /// # } - /// ``` - /// - /// In this case, it behaves exactly like - /// `syn::Error::new_spanned(&meta.path, "message...")`. - /// - /// ```console - /// error: unsupported tea property - /// --> src/main.rs:3:26 - /// | - /// 3 | #[tea(kind = "EarlGrey", wat = "foo")] - /// | ^^^ - /// ``` - /// - /// More usefully, the second place is if you've already parsed a value but - /// have decided not to accept the value: - /// - /// ``` - /// # use syn::Attribute; - /// # - /// # fn example(attr: &Attribute) -> syn::Result<()> { - /// use syn::Expr; - /// - /// attr.parse_nested_meta(|meta| { - /// if meta.path.is_ident("kind") { - /// let expr: Expr = meta.value()?.parse()?; - /// match expr { - /// Expr::Lit(expr) => /* ... */ - /// # unimplemented!(), - /// Expr::Path(expr) => /* ... */ - /// # unimplemented!(), - /// Expr::Macro(expr) => /* ... */ - /// # unimplemented!(), - /// _ => Err(meta.error("tea kind must be a string literal, path, or macro")), - /// } - /// } else /* as above */ - /// # { unimplemented!() } - /// - /// })?; - /// # Ok(()) - /// # } - /// ``` - /// - /// ```console - /// error: tea kind must be a string literal, path, or macro - /// --> src/main.rs:3:7 - /// | - /// 3 | #[tea(kind = async { replicator.await })] - /// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - /// ``` - /// - /// Often you may want to use `syn::Error::new_spanned` even in this - /// situation. In the above code, that would be: - /// - /// ``` - /// # use syn::{Error, Expr}; - /// # - /// # fn example(expr: Expr) -> syn::Result<()> { - /// match expr { - /// Expr::Lit(expr) => /* ... */ - /// # unimplemented!(), - /// Expr::Path(expr) => /* ... */ - /// # unimplemented!(), - /// Expr::Macro(expr) => /* ... */ - /// # unimplemented!(), - /// _ => Err(Error::new_spanned(expr, "unsupported expression type for `kind`")), - /// } - /// # } - /// ``` - /// - /// ```console - /// error: unsupported expression type for `kind` - /// --> src/main.rs:3:14 - /// | - /// 3 | #[tea(kind = async { replicator.await })] - /// | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - /// ``` - pub fn error(&self, msg: impl Display) -> Error { - let start_span = self.path.segments[0].ident.span(); - let end_span = self.input.cursor().prev_span(); - crate::error::new2(start_span, end_span, msg) - } -} - -pub(crate) fn parse_nested_meta( - input: ParseStream, - mut logic: impl FnMut(ParseNestedMeta) -> Result<()>, -) -> Result<()> { - loop { - let path = input.call(parse_meta_path)?; - logic(ParseNestedMeta { path, input })?; - if input.is_empty() { - return Ok(()); - } - input.parse::<Token![,]>()?; - if input.is_empty() { - return Ok(()); - } - } -} - -// 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(); - if input.peek(Ident::peek_any) { - let ident = Ident::parse_any(input)?; - segments.push_value(PathSegment::from(ident)); - } else if input.is_empty() { - return Err(input.error("expected nested attribute")); - } else if input.peek(Lit) { - return Err(input.error("unexpected literal in nested attribute, expected ident")); - } else { - return Err(input.error("unexpected token in nested attribute, expected ident")); - } - while input.peek(Token![::]) { - let punct = input.parse()?; - segments.push_punct(punct); - let ident = Ident::parse_any(input)?; - segments.push_value(PathSegment::from(ident)); - } - segments - }, - }) -} |