1// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>,
2// Kevin Knapp (@kbknapp) <kbknapp@gmail.com>, and
3// Ana Hobden (@hoverbear) <operator@hoverbear.org>
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10//
11// This work was derived from Structopt (https://github.com/TeXitoi/structopt)
12// commit#ea76fa1b1b273e65e3b0b1046643715b49bec51f which is licensed under the
13// MIT/Apache 2.0 license.
14
15#![doc = include_str!("../README.md")]
16#![doc(html_logo_url = "https://raw.githubusercontent.com/clap-rs/clap/master/assets/clap.png")]
17#![cfg_attr(docsrs, feature(doc_auto_cfg))]
18#![forbid(unsafe_code)]
19#![warn(missing_docs)]
20#![warn(clippy::print_stderr)]
21#![warn(clippy::print_stdout)]
22
23use proc_macro::TokenStream;
24use syn::{parse_macro_input, DeriveInput};
25use syn::{Data, DataStruct, Fields};
26
27#[macro_use]
28mod macros;
29
30mod attr;
31mod derives;
32mod dummies;
33mod item;
34mod utils;
35
36/// Generates the `ValueEnum` impl.
37#[proc_macro_derive(ValueEnum, attributes(clap, value))]
38pub fn value_enum(input: TokenStream) -> TokenStream {
39 let input: DeriveInput = parse_macro_input!(input);
40 derivesTokenStream::derive_value_enum(&input)
41 .unwrap_or_else(|err: Error| {
42 let dummy: TokenStream = dummies::value_enum(&input.ident);
43 to_compile_error(error:err, dummy)
44 })
45 .into()
46}
47
48/// Generates the `Parser` implementation.
49///
50/// This is far less verbose than defining the `clap::Command` struct manually,
51/// receiving an instance of `clap::ArgMatches` from conducting parsing, and then
52/// implementing a conversion code to instantiate an instance of the user
53/// context struct.
54#[proc_macro_derive(Parser, attributes(clap, structopt, command, arg, group))]
55pub fn parser(input: TokenStream) -> TokenStream {
56 let input: DeriveInput = parse_macro_input!(input);
57 derives::derive_parser(&input)
58 .unwrap_or_else(|err| {
59 let specific_dummy = match input.data {
60 Data::Struct(DataStruct {
61 fields: Fields::Named(ref _fields),
62 ..
63 }) => Some(dummies::args(&input.ident)),
64 Data::Struct(DataStruct {
65 fields: Fields::Unit,
66 ..
67 }) => Some(dummies::args(&input.ident)),
68 Data::Enum(_) => Some(dummies::subcommand(&input.ident)),
69 _ => None,
70 };
71 let dummy = specific_dummy
72 .map(|specific_dummy| {
73 let parser_dummy = dummies::parser(&input.ident);
74 quote::quote! {
75 #parser_dummy
76 #specific_dummy
77 }
78 })
79 .unwrap_or_else(|| quote::quote!());
80 to_compile_error(err, dummy)
81 })
82 .into()
83}
84
85/// Generates the `Subcommand` impl.
86#[proc_macro_derive(Subcommand, attributes(clap, command, arg, group))]
87pub fn subcommand(input: TokenStream) -> TokenStream {
88 let input: DeriveInput = parse_macro_input!(input);
89 derivesTokenStream::derive_subcommand(&input)
90 .unwrap_or_else(|err: Error| {
91 let dummy: TokenStream = dummies::subcommand(&input.ident);
92 to_compile_error(error:err, dummy)
93 })
94 .into()
95}
96
97/// Generates the `Args` impl.
98#[proc_macro_derive(Args, attributes(clap, command, arg, group))]
99pub fn args(input: TokenStream) -> TokenStream {
100 let input: DeriveInput = parse_macro_input!(input);
101 derivesTokenStream::derive_args(&input)
102 .unwrap_or_else(|err: Error| {
103 let dummy: TokenStream = dummies::args(&input.ident);
104 to_compile_error(error:err, dummy)
105 })
106 .into()
107}
108
109fn to_compile_error(
110 error: syn::Error,
111 dummy: proc_macro2::TokenStream,
112) -> proc_macro2::TokenStream {
113 let compile_errors: TokenStream = error.to_compile_error();
114 quote::quote!(
115 #dummy
116 #compile_errors
117 )
118}
119