change ~ add proc-macros module (uucore_procs) with uucore_procs::main()

- `uucore_procs::main!(UUTIL_NAME)` allows simple, consistent instantiation of `main()` for uutils
This commit is contained in:
Roy Ivy III 2020-05-23 12:09:40 -05:00
parent 503cc53014
commit 0432063479
3 changed files with 85 additions and 0 deletions

View file

@ -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"

View file

@ -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 = []

View file

@ -0,0 +1,64 @@
extern crate proc_macro;
// spell-checker:ignore () sigpipe uucore uumain
// ref: <https://dev.to/naufraghi/procedural-macro-in-rust-101-k3f> @@ <http://archive.is/Vbr5e>
// ref: [path construction from LitStr](https://oschwald.github.io/maxminddb-rust/syn/struct.LitStr.html) @@ <http://archive.is/8YDua>
struct Tokens {
expr: syn::Expr,
}
impl syn::parse::Parse for Tokens {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
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)
}