extern crate proc_macro;
use proc_macro::TokenStream;
use quote::quote;
use syn::fold::{self, Fold};
use syn::parse::{Parse, ParseStream, Result};
use syn::{parse_macro_input, parse_quote, Attribute, BinOp, Expr, ItemFn};
#[derive(Debug)]
struct Args {}
impl Parse for Args {
fn parse(_input: ParseStream) -> Result<Self> {
Ok(Args {})
}
}
impl Args {
fn binary_op(&mut self, _attrs: Vec<Attribute>, left: Expr, op: &BinOp, right: Expr) -> Expr {
let left = match left {
Expr::Binary(e) => self.binary_op(e.attrs, *e.left, &e.op, *e.right),
_ => fold::fold_expr(self, left),
};
let right = match right {
Expr::Binary(e) => self.binary_op(e.attrs, *e.left, &e.op, *e.right),
_ => fold::fold_expr(self, right),
};
match op {
BinOp::Add(_op) => {
return parse_quote!(
#left.wrapping_add(#right)
);
}
BinOp::Sub(_op) => {
return parse_quote!(
#left.wrapping_sub(#right)
);
}
BinOp::Mul(_op) => {
return parse_quote!(
#left.wrapping_mul(#right)
);
}
_ => {
return parse_quote!(
#left #op #right
);
}
}
}
fn assign_op(&mut self, _attrs: Vec<Attribute>, left: Expr, op: &BinOp, right: Expr) -> Expr {
let left = match left {
Expr::Binary(e) => self.binary_op(e.attrs, *e.left, &e.op, *e.right),
_ => fold::fold_expr(self, left),
};
let right = match right {
Expr::Binary(e) => self.binary_op(e.attrs, *e.left, &e.op, *e.right),
_ => fold::fold_expr(self, right),
};
match op {
BinOp::AddEq(_op) => {
return parse_quote!(
#left = #left.wrapping_add(#right)
);
}
BinOp::SubEq(_op) => {
return parse_quote!(
#left = #left.wrapping_sub(#right)
);
}
BinOp::MulEq(_op) => {
return parse_quote!(
#left = #left.wrapping_mul(#right)
);
}
_ => {
return parse_quote!(
#left #op #right
);
}
}
}
}
impl Fold for Args {
fn fold_expr(&mut self, e: Expr) -> Expr {
match e {
Expr::Binary(e) => self.binary_op(e.attrs, *e.left, &e.op, *e.right),
Expr::AssignOp(e) => self.assign_op(e.attrs, *e.left, &e.op, *e.right),
_ => fold::fold_expr(self, e),
}
}
}
#[proc_macro_attribute]
pub fn wrappit(args: TokenStream, input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as ItemFn);
let mut args = parse_macro_input!(args as Args);
let output = args.fold_item_fn(input);
TokenStream::from(quote!(#output))
}