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 (html_logo_url = "https://raw.githubusercontent.com/clap-rs/clap/master/assets/clap.png" )] |
16 | #![doc = include_str!("../README.md" )] |
17 | #![forbid (unsafe_code)] |
18 | |
19 | extern crate proc_macro; |
20 | |
21 | use proc_macro::TokenStream; |
22 | use syn::{parse_macro_input, DeriveInput}; |
23 | use syn::{Data, DataStruct, Fields}; |
24 | |
25 | #[macro_use ] |
26 | mod macros; |
27 | |
28 | mod attr; |
29 | mod derives; |
30 | mod dummies; |
31 | mod item; |
32 | mod utils; |
33 | |
34 | /// Generates the `ValueEnum` impl. |
35 | #[proc_macro_derive (ValueEnum, attributes(clap, value))] |
36 | pub fn value_enum(input: TokenStream) -> TokenStream { |
37 | let input: DeriveInput = parse_macro_input!(input); |
38 | derivesTokenStream::derive_value_enum(&input) |
39 | .unwrap_or_else(|err: Error| { |
40 | let dummy: TokenStream = dummies::value_enum(&input.ident); |
41 | to_compile_error(error:err, dummy) |
42 | }) |
43 | .into() |
44 | } |
45 | |
46 | /// Generates the `Parser` implementation. |
47 | /// |
48 | /// This is far less verbose than defining the `clap::Command` struct manually, |
49 | /// receiving an instance of `clap::ArgMatches` from conducting parsing, and then |
50 | /// implementing a conversion code to instantiate an instance of the user |
51 | /// context struct. |
52 | #[proc_macro_derive (Parser, attributes(clap, structopt, command, arg, group))] |
53 | pub fn parser(input: TokenStream) -> TokenStream { |
54 | let input: DeriveInput = parse_macro_input!(input); |
55 | derives::derive_parser(&input) |
56 | .unwrap_or_else(|err| { |
57 | let specific_dummy = match input.data { |
58 | Data::Struct(DataStruct { |
59 | fields: Fields::Named(ref _fields), |
60 | .. |
61 | }) => Some(dummies::args(&input.ident)), |
62 | Data::Struct(DataStruct { |
63 | fields: Fields::Unit, |
64 | .. |
65 | }) => Some(dummies::args(&input.ident)), |
66 | Data::Enum(_) => Some(dummies::subcommand(&input.ident)), |
67 | _ => None, |
68 | }; |
69 | let dummy = specific_dummy |
70 | .map(|specific_dummy| { |
71 | let parser_dummy = dummies::parser(&input.ident); |
72 | quote::quote! { |
73 | #parser_dummy |
74 | #specific_dummy |
75 | } |
76 | }) |
77 | .unwrap_or_else(|| quote::quote!()); |
78 | to_compile_error(err, dummy) |
79 | }) |
80 | .into() |
81 | } |
82 | |
83 | /// Generates the `Subcommand` impl. |
84 | #[proc_macro_derive (Subcommand, attributes(clap, command, arg, group))] |
85 | pub fn subcommand(input: TokenStream) -> TokenStream { |
86 | let input: DeriveInput = parse_macro_input!(input); |
87 | derivesTokenStream::derive_subcommand(&input) |
88 | .unwrap_or_else(|err: Error| { |
89 | let dummy: TokenStream = dummies::subcommand(&input.ident); |
90 | to_compile_error(error:err, dummy) |
91 | }) |
92 | .into() |
93 | } |
94 | |
95 | /// Generates the `Args` impl. |
96 | #[proc_macro_derive (Args, attributes(clap, command, arg, group))] |
97 | pub fn args(input: TokenStream) -> TokenStream { |
98 | let input: DeriveInput = parse_macro_input!(input); |
99 | derivesTokenStream::derive_args(&input) |
100 | .unwrap_or_else(|err: Error| { |
101 | let dummy: TokenStream = dummies::args(&input.ident); |
102 | to_compile_error(error:err, dummy) |
103 | }) |
104 | .into() |
105 | } |
106 | |
107 | fn to_compile_error( |
108 | error: syn::Error, |
109 | dummy: proc_macro2::TokenStream, |
110 | ) -> proc_macro2::TokenStream { |
111 | let compile_errors: TokenStream = error.to_compile_error(); |
112 | quote::quote!( |
113 | #dummy |
114 | #compile_errors |
115 | ) |
116 | } |
117 | |