From 64d98f8ee037282c35007b64c2649055c56af1db Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:19:03 +0200 Subject: Merging upstream version 1.68.2+dfsg1. Signed-off-by: Daniel Baumann --- vendor/clap_derive/src/attr.rs | 222 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 222 insertions(+) create mode 100644 vendor/clap_derive/src/attr.rs (limited to 'vendor/clap_derive/src/attr.rs') diff --git a/vendor/clap_derive/src/attr.rs b/vendor/clap_derive/src/attr.rs new file mode 100644 index 000000000..e282a8f94 --- /dev/null +++ b/vendor/clap_derive/src/attr.rs @@ -0,0 +1,222 @@ +use std::iter::FromIterator; + +use proc_macro2::TokenStream; +use proc_macro_error::abort; +use proc_macro_error::ResultExt; +use quote::quote; +use quote::ToTokens; +use syn::spanned::Spanned; +use syn::{ + parenthesized, + parse::{Parse, ParseStream}, + punctuated::Punctuated, + Attribute, Expr, Ident, LitStr, Token, +}; + +use crate::utils::Sp; + +#[derive(Clone)] +pub struct ClapAttr { + pub kind: Sp, + pub name: Ident, + pub magic: Option, + pub value: Option, +} + +impl ClapAttr { + pub fn parse_all(all_attrs: &[Attribute]) -> Vec { + all_attrs + .iter() + .filter_map(|attr| { + let kind = if attr.path.is_ident("clap") { + Some(Sp::new(AttrKind::Clap, attr.path.span())) + } else if attr.path.is_ident("structopt") { + Some(Sp::new(AttrKind::StructOpt, attr.path.span())) + } else if attr.path.is_ident("command") { + Some(Sp::new(AttrKind::Command, attr.path.span())) + } else if attr.path.is_ident("group") { + Some(Sp::new(AttrKind::Group, attr.path.span())) + } else if attr.path.is_ident("arg") { + Some(Sp::new(AttrKind::Arg, attr.path.span())) + } else if attr.path.is_ident("value") { + Some(Sp::new(AttrKind::Value, attr.path.span())) + } else { + None + }; + kind.map(|k| (k, attr)) + }) + .flat_map(|(k, attr)| { + attr.parse_args_with(Punctuated::::parse_terminated) + .unwrap_or_abort() + .into_iter() + .map(move |mut a| { + a.kind = k; + a + }) + }) + .collect() + } + + pub fn value_or_abort(&self) -> &AttrValue { + self.value + .as_ref() + .unwrap_or_else(|| abort!(self.name, "attribute `{}` requires a value", self.name)) + } + + pub fn lit_str_or_abort(&self) -> &LitStr { + let value = self.value_or_abort(); + match value { + AttrValue::LitStr(tokens) => tokens, + AttrValue::Expr(_) | AttrValue::Call(_) => { + abort!( + self.name, + "attribute `{}` can only accept string literals", + self.name + ) + } + } + } +} + +impl Parse for ClapAttr { + fn parse(input: ParseStream) -> syn::Result { + let name: Ident = input.parse()?; + let name_str = name.to_string(); + + let magic = match name_str.as_str() { + "rename_all" => Some(MagicAttrName::RenameAll), + "rename_all_env" => Some(MagicAttrName::RenameAllEnv), + "skip" => Some(MagicAttrName::Skip), + "next_display_order" => Some(MagicAttrName::NextDisplayOrder), + "next_help_heading" => Some(MagicAttrName::NextHelpHeading), + "default_value_t" => Some(MagicAttrName::DefaultValueT), + "default_values_t" => Some(MagicAttrName::DefaultValuesT), + "default_value_os_t" => Some(MagicAttrName::DefaultValueOsT), + "default_values_os_t" => Some(MagicAttrName::DefaultValuesOsT), + "long" => Some(MagicAttrName::Long), + "short" => Some(MagicAttrName::Short), + "value_parser" => Some(MagicAttrName::ValueParser), + "action" => Some(MagicAttrName::Action), + "env" => Some(MagicAttrName::Env), + "flatten" => Some(MagicAttrName::Flatten), + "value_enum" => Some(MagicAttrName::ValueEnum), + "from_global" => Some(MagicAttrName::FromGlobal), + "subcommand" => Some(MagicAttrName::Subcommand), + "external_subcommand" => Some(MagicAttrName::ExternalSubcommand), + "verbatim_doc_comment" => Some(MagicAttrName::VerbatimDocComment), + "about" => Some(MagicAttrName::About), + "long_about" => Some(MagicAttrName::LongAbout), + "long_help" => Some(MagicAttrName::LongHelp), + "author" => Some(MagicAttrName::Author), + "version" => Some(MagicAttrName::Version), + _ => None, + }; + + let value = if input.peek(Token![=]) { + // `name = value` attributes. + let assign_token = input.parse::()?; // skip '=' + if input.peek(LitStr) { + let lit: LitStr = input.parse()?; + Some(AttrValue::LitStr(lit)) + } else { + match input.parse::() { + Ok(expr) => Some(AttrValue::Expr(expr)), + + Err(_) => abort! { + assign_token, + "expected `string literal` or `expression` after `=`" + }, + } + } + } else if input.peek(syn::token::Paren) { + // `name(...)` attributes. + let nested; + parenthesized!(nested in input); + + let method_args: Punctuated<_, Token![,]> = nested.parse_terminated(Expr::parse)?; + Some(AttrValue::Call(Vec::from_iter(method_args))) + } else { + None + }; + + Ok(Self { + kind: Sp::new(AttrKind::Clap, name.span()), + name, + magic, + value, + }) + } +} + +#[derive(Copy, Clone, PartialEq, Eq)] +pub enum MagicAttrName { + Short, + Long, + ValueParser, + Action, + Env, + Flatten, + ValueEnum, + FromGlobal, + Subcommand, + VerbatimDocComment, + ExternalSubcommand, + About, + LongAbout, + LongHelp, + Author, + Version, + RenameAllEnv, + RenameAll, + Skip, + DefaultValueT, + DefaultValuesT, + DefaultValueOsT, + DefaultValuesOsT, + NextDisplayOrder, + NextHelpHeading, +} + +#[derive(Clone)] +#[allow(clippy::large_enum_variant)] +pub enum AttrValue { + LitStr(LitStr), + Expr(Expr), + Call(Vec), +} + +impl ToTokens for AttrValue { + fn to_tokens(&self, tokens: &mut TokenStream) { + match self { + Self::LitStr(t) => t.to_tokens(tokens), + Self::Expr(t) => t.to_tokens(tokens), + Self::Call(t) => { + let t = quote!(#(#t),*); + t.to_tokens(tokens) + } + } + } +} + +#[derive(Copy, Clone, PartialEq, Eq)] +pub enum AttrKind { + Clap, + StructOpt, + Command, + Group, + Arg, + Value, +} + +impl AttrKind { + pub fn as_str(&self) -> &'static str { + match self { + Self::Clap => "clap", + Self::StructOpt => "structopt", + Self::Command => "command", + Self::Group => "group", + Self::Arg => "arg", + Self::Value => "value", + } + } +} -- cgit v1.2.3