1use proc_macro2::TokenStream;
16use quote::quote;
17use syn::Ident;
18use syn::Variant;
19use syn::{
20 self, Data, DataStruct, DeriveInput, Field, Fields, Generics, punctuated::Punctuated,
21 token::Comma,
22};
23
24use crate::derives::args::collect_args_fields;
25use crate::derives::{args, into_app, subcommand};
26use crate::item::Item;
27use crate::item::Name;
28
29pub(crate) fn derive_parser(input: &DeriveInput) -> Result<TokenStream, syn::Error> {
30 let ident = &input.ident;
31 let pkg_name = std::env::var("CARGO_PKG_NAME").ok().unwrap_or_default();
32
33 let pkg_name_tokens = if pkg_name.is_empty() {
34 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&pkg_name, &mut _s);
_s
}quote!(#pkg_name)
35 } else {
36 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "let");
::quote::__private::push_underscore(&mut _s);
::quote::__private::push_eq(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "core");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "env");
::quote::__private::push_bang(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::parse(&mut _s, "\"CARGO_PKG_NAME\"");
_s
});
::quote::__private::push_semi(&mut _s);
::quote::ToTokens::to_tokens(&pkg_name, &mut _s);
_s
});
_s
}quote!({
37 let _ = ::core::env!("CARGO_PKG_NAME");
38 #pkg_name })
39 };
40
41 match input.data {
42 Data::Struct(DataStruct {
43 fields: Fields::Named(ref fields),
44 ..
45 }) => {
46 let name = Name::Assigned(pkg_name_tokens.clone());
47 let item = Item::from_args_struct(input, name)?;
48 let fields = collect_args_fields(&item, fields)?;
49 gen_for_struct(&item, ident, &input.generics, &fields)
50 }
51 Data::Struct(DataStruct {
52 fields: Fields::Unit,
53 ..
54 }) => {
55 let name = Name::Assigned(pkg_name_tokens.clone());
56 let item = Item::from_args_struct(input, name)?;
57 let fields = Punctuated::<Field, Comma>::new();
58 let fields = fields
59 .iter()
60 .map(|field| {
61 let item = Item::from_args_field(field, item.casing(), item.env_casing())?;
62 Ok((field, item))
63 })
64 .collect::<Result<Vec<_>, syn::Error>>()?;
65 gen_for_struct(&item, ident, &input.generics, &fields)
66 }
67 Data::Enum(ref e) => {
68 let name = Name::Assigned(pkg_name_tokens);
69 let item = Item::from_subcommand_enum(input, name)?;
70 let variants = e
71 .variants
72 .iter()
73 .map(|variant| {
74 let item =
75 Item::from_subcommand_variant(variant, item.casing(), item.env_casing())?;
76 Ok((variant, item))
77 })
78 .collect::<Result<Vec<_>, syn::Error>>()?;
79 gen_for_enum(&item, ident, &input.generics, &variants)
80 }
81 _ => {
let span = proc_macro2::Span::call_site();
{
return Err({
#[allow(unused_imports)]
use crate::utils::error::*;
let msg =
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`#[derive(Parser)]` only supports non-tuple structs and enums"))
});
span.EXPECTED_Span_OR_ToTokens(msg)
});
}
}abort_call_site!("`#[derive(Parser)]` only supports non-tuple structs and enums"),
82 }
83}
84
85fn gen_for_struct(
86 item: &Item,
87 item_name: &Ident,
88 generics: &Generics,
89 fields: &[(&Field, Item)],
90) -> Result<TokenStream, syn::Error> {
91 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
92
93 let into_app = into_app::gen_for_struct(item, item_name, generics)?;
94 let args = args::gen_for_struct(item, item_name, generics, fields)?;
95
96 Ok({
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_pound(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Bracket,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "automatically_derived");
_s
});
::quote::__private::push_pound(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Bracket,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "allow");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s,
"unused_qualifications");
::quote::__private::push_comma(&mut _s);
::quote::__private::push_ident(&mut _s, "clippy");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "redundant_locals");
::quote::__private::push_comma(&mut _s);
_s
});
_s
});
::quote::__private::push_ident(&mut _s, "impl");
::quote::ToTokens::to_tokens(&impl_generics, &mut _s);
::quote::__private::push_ident(&mut _s, "clap");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "Parser");
::quote::__private::push_ident(&mut _s, "for");
::quote::ToTokens::to_tokens(&item_name, &mut _s);
::quote::ToTokens::to_tokens(&ty_generics, &mut _s);
::quote::ToTokens::to_tokens(&where_clause, &mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
::quote::__private::TokenStream::new());
::quote::ToTokens::to_tokens(&into_app, &mut _s);
::quote::ToTokens::to_tokens(&args, &mut _s);
_s
}quote! {
97 #[automatically_derived]
98 #[allow(
99 unused_qualifications,
100 clippy::redundant_locals,
101 )]
102 impl #impl_generics clap::Parser for #item_name #ty_generics #where_clause {}
103
104 #into_app
105 #args
106 })
107}
108
109fn gen_for_enum(
110 item: &Item,
111 item_name: &Ident,
112 generics: &Generics,
113 variants: &[(&Variant, Item)],
114) -> Result<TokenStream, syn::Error> {
115 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
116
117 let into_app = into_app::gen_for_enum(item, item_name, generics)?;
118 let subcommand = subcommand::gen_for_enum(item, item_name, generics, variants)?;
119
120 Ok({
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_pound(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Bracket,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "automatically_derived");
_s
});
::quote::__private::push_ident(&mut _s, "impl");
::quote::ToTokens::to_tokens(&impl_generics, &mut _s);
::quote::__private::push_ident(&mut _s, "clap");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "Parser");
::quote::__private::push_ident(&mut _s, "for");
::quote::ToTokens::to_tokens(&item_name, &mut _s);
::quote::ToTokens::to_tokens(&ty_generics, &mut _s);
::quote::ToTokens::to_tokens(&where_clause, &mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
::quote::__private::TokenStream::new());
::quote::ToTokens::to_tokens(&into_app, &mut _s);
::quote::ToTokens::to_tokens(&subcommand, &mut _s);
_s
}quote! {
121 #[automatically_derived]
122 impl #impl_generics clap::Parser for #item_name #ty_generics #where_clause {}
123
124 #into_app
125 #subcommand
126 })
127}