From 04320634799da9325ff69500a3e05ced0945753d Mon Sep 17 00:00:00 2001 From: Roy Ivy III Date: Sat, 23 May 2020 12:09:40 -0500 Subject: [PATCH] change ~ add proc-macros module (uucore_procs) with `uucore_procs::main()` - `uucore_procs::main!(UUTIL_NAME)` allows simple, consistent instantiation of `main()` for uutils --- src/uucore/Cargo.toml | 3 ++ src/uucore/src/uucore_procs/Cargo.toml | 18 ++++++++ src/uucore/src/uucore_procs/src/lib.rs | 64 ++++++++++++++++++++++++++ 3 files changed, 85 insertions(+) create mode 100644 src/uucore/src/uucore_procs/Cargo.toml create mode 100644 src/uucore/src/uucore_procs/src/lib.rs diff --git a/src/uucore/Cargo.toml b/src/uucore/Cargo.toml index f26ba6418..309c7ebfa 100644 --- a/src/uucore/Cargo.toml +++ b/src/uucore/Cargo.toml @@ -18,6 +18,9 @@ travis-ci = { repository = "uutils/uucore" } [lib] path="src/lib/lib.rs" +[workspace] +members=["src/uucore_procs"] + [dependencies] dunce = "1.0.0" getopts = "<= 0.2.21" diff --git a/src/uucore/src/uucore_procs/Cargo.toml b/src/uucore/src/uucore_procs/Cargo.toml new file mode 100644 index 000000000..0e1f9eb6f --- /dev/null +++ b/src/uucore/src/uucore_procs/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "uucore_procs" +version = "0.0.2" +authors = [] +license = "MIT" +description = "`uucore` proc-macros for use by various uutils projects" + +[lib] +proc-macro = true + +[dependencies] +proc-macro2 = "1.0" +quote = "1.0" +syn = { version="1.0" } ## debug: use `features=["extra-traits"]` to add Debug traits to structs (for `println!("{:?}", ...)`) + +[features] +default = [] +debug = [] diff --git a/src/uucore/src/uucore_procs/src/lib.rs b/src/uucore/src/uucore_procs/src/lib.rs new file mode 100644 index 000000000..029dd0fe2 --- /dev/null +++ b/src/uucore/src/uucore_procs/src/lib.rs @@ -0,0 +1,64 @@ +extern crate proc_macro; + +// spell-checker:ignore () sigpipe uucore uumain + +// ref: @@ +// ref: [path construction from LitStr](https://oschwald.github.io/maxminddb-rust/syn/struct.LitStr.html) @@ + +struct Tokens { + expr: syn::Expr, +} + +impl syn::parse::Parse for Tokens { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + Ok(Tokens { + expr: input.parse()?, + }) + } +} + +#[proc_macro] +pub fn main(stream: proc_macro::TokenStream) -> proc_macro::TokenStream { + let Tokens { expr } = syn::parse_macro_input!(stream as Tokens); + // eprintln!("expr={:?}", expr); + let expr = match expr { + syn::Expr::Lit(expr) => { + // eprintln!("found Expr::Lit => {:?}", expr); + match expr.lit { + syn::Lit::Str(ref lit) => { + let mut s = lit.value(); + if !s.ends_with("::uumain") { + s += "::uumain"; + } + syn::LitStr::new(&s, proc_macro2::Span::call_site()) + .parse() + .unwrap() + } + _ => panic!(), + } + } + syn::Expr::Path(expr) => { + // eprintln!("found Expr::Path => {:?}", expr); + // let i = &expr.path.segments.last().unwrap().ident; + // eprintln!("... i => {:?}", i); + if &expr.path.segments.last().unwrap().ident.to_string() != "uumain" { + syn::parse_quote!( #expr::uumain ) + } else { + expr + } + } + _ => panic!(), + }; + let f = quote::quote! { #expr(uucore::args().collect()) }; + // eprintln!("f = {:?}", f); + let result = quote::quote! { + fn main() { + use std::io::Write; + uucore::panic::install_sigpipe_hook(); + let code = #f; + std::io::stdout().flush().expect("could not flush stdout"); + std::process::exit(code); + } + }; + proc_macro::TokenStream::from(result) +}