#![feature(proc_macro, proc_macro_lib)]
#![allow(unused_imports, unused_variables)]
extern crate proc_macro;
#[macro_use]
extern crate syn;
#[macro_use]
extern crate quote;
use proc_macro::TokenStream;
use quote::ToTokens;
use std::collections::HashSet as Set;
use syn::fold::{self, Fold};
use syn::punctuated::Punctuated;
use syn::synom::Synom;
use syn::LitStr;
use syn::{
Expr, FnArg, Ident, ImplItem, ImplItemMethod, Item, ItemImpl, ItemStatic, Pat, Stmt, Type,
};
#[proc_macro_attribute]
pub fn thunderclap(_args: TokenStream, input: TokenStream) -> TokenStream {
let i: ItemImpl = match syn::parse(input.clone()) {
Ok(input) => input,
Err(e) => panic!("Error: '{}'", e),
};
let (name, app_token) = match *i.self_ty {
Type::Path(ref p) => {
let meh = p.path.segments[0].ident;
(format!("{}", p.path.segments[0].ident), quote!( #meh ))
}
_ => (format!("Unknown App"), quote!()),
};
let about = match i.attrs.first() {
Some(a) => String::from(
format!("{}", a.tts)
.replace("/", "")
.replace("\\", "")
.replace("\"", "")
.replace("=", "").trim(),
),
_ => String::new(),
};
let mut matches: Vec<quote::Tokens> = Vec::new();
let orignal = quote!(#i);
let mut app = quote! {
App::new(#name).about(#about).setting(AppSettings::SubcommandRequired)
};
for item in &i.items {
match item {
&ImplItem::Method(ref i) => {
let name = LitStr::new(&i.sig.ident.to_string(), i.sig.ident.span);
let func_id = &i.sig.ident;
let about = match i.attrs.first() {
Some(a) => String::from(
format!("{}", a.tts)
.replace("/", "")
.replace("\\", "")
.replace("\"", "")
.replace("=", "").trim(),
),
_ => String::new(),
};
let mut arguments = quote!();
let mut index: usize = 0;
let args = i.sig
.decl
.inputs
.iter()
.fold(quote!{}, |acc, arg| match arg {
&FnArg::Captured(ref arg) => match &arg.pat {
&Pat::Ident(ref i) => {
let n = format!("{}", i.ident);
arguments = quote! {
#arguments
m.value_of(#n).unwrap(),
};
index += 1;
quote! { #acc.arg(Arg::with_name(#n)) }
}
_ => quote!{ #acc },
},
_ => quote!{ #acc },
});
app = quote! {
#app.subcommand(
SubCommand::with_name(#name).about(#about)#args
)
};
matches.push(quote! { (#name, Some(m)) => #app_token :: #func_id ( #arguments ), });
}
_ => {}
}
}
let mut matchy = quote!{};
for m in &matches {
matchy = quote! {
#matchy
#m
};
}
matchy = quote! {
match args.subcommand() {
#matchy
_ => { },
}
};
let tokens = quote! {
#orignal
#[allow(unused)]
impl #app_token {
fn start() {
use clap::{App, SubCommand, Arg, AppSettings};
let app = #app;
let args = app.get_matches();
#matchy
}
}
};
tokens.into()
}