use bind_syn::Bind;
use proc_macro::TokenStream;
use quote::quote;
use syn::{
Expr,
ExprClosure,
Token,
parenthesized,
parse::{self, Parse, ParseStream},
parse_macro_input,
punctuated::Punctuated,
token,
};
struct BindInput {
paren : token::Paren,
binds : Punctuated<Bind,Token![,]>,
expr : Expr,
}
impl Parse for BindInput {
fn parse( input: ParseStream ) -> parse::Result<Self> {
let content;
let paren = parenthesized!( content in input );
let binds = Punctuated::parse_terminated( &content )?;
let expr = input.parse::<Expr>()?;
Ok( BindInput{ paren, binds, expr })
}
}
#[proc_macro]
pub fn bind( input: TokenStream ) -> TokenStream {
let BindInput{ paren, binds, expr } = parse_macro_input!( input as BindInput );
let _ = paren;
let binds = binds.iter();
let extrusive = if let Expr::Closure( expr_closure ) = &expr {
expr_closure.capture.is_some()
} else {
true
};
let expanded = if extrusive {
quote!{{
#(#binds)*
#expr
}}
} else {
if let Expr::Closure( ExprClosure{ attrs, lifetimes, constness, movability, asyncness,
capture, or1_token, inputs, or2_token, output, body })
= expr {
quote!{{
#(#attrs)* #lifetimes #constness #movability #asyncness
#capture #or1_token #inputs #or2_token #output {
#(#binds)*
#body
}
}}
} else {
unreachable!();
}
};
expanded.into()
}