use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, Expr, ExprBinary, BinOp, Lit, ExprLit};
#[proc_macro_attribute]
pub fn macro_optim(_attr: TokenStream, item: TokenStream) -> TokenStream {
let expr = parse_macro_input!(item as Expr);
let optimized = optimize_expr(expr);
quote! { #optimized }.into()
}
fn optimize_expr(expr: Expr) -> Expr {
match expr {
Expr::Binary(ExprBinary { attrs, left, op, right }) => {
let left = Box::new(optimize_expr(*left));
let right = Box::new(optimize_expr(*right));
match (&*left, &op, &*right) {
(Expr::Lit(ExprLit { lit: Lit::Int(l), .. }), BinOp::Add(_), Expr::Lit(ExprLit { lit: Lit::Int(r), .. })) => {
let l_val = l.base10_parse::<i64>().unwrap();
let r_val = r.base10_parse::<i64>().unwrap();
return Expr::Lit(ExprLit {
attrs: vec![],
lit: Lit::Int(syn::LitInt::new(&(l_val + r_val).to_string(), proc_macro2::Span::call_site())),
});
},
(Expr::Lit(ExprLit { lit: Lit::Int(l), .. }), BinOp::Mul(_), Expr::Lit(ExprLit { lit: Lit::Int(r), .. })) => {
let l_val = l.base10_parse::<i64>().unwrap();
let r_val = r.base10_parse::<i64>().unwrap();
return Expr::Lit(ExprLit {
attrs: vec![],
lit: Lit::Int(syn::LitInt::new(&(l_val * r_val).to_string(), proc_macro2::Span::call_site())),
});
},
(Expr::Lit(ExprLit { lit: Lit::Float(l), .. }), BinOp::Add(_), Expr::Lit(ExprLit { lit: Lit::Float(r), .. })) => {
let l_val = l.base10_parse::<f64>().unwrap();
let r_val = r.base10_parse::<f64>().unwrap();
return Expr::Lit(ExprLit {
attrs: vec![],
lit: Lit::Float(syn::LitFloat::new(&(l_val + r_val).to_string(), proc_macro2::Span::call_site())),
});
},
(Expr::Lit(ExprLit { lit: Lit::Float(l), .. }), BinOp::Mul(_), Expr::Lit(ExprLit { lit: Lit::Float(r), .. })) => {
let l_val = l.base10_parse::<f64>().unwrap();
let r_val = r.base10_parse::<f64>().unwrap();
return Expr::Lit(ExprLit {
attrs: vec![],
lit: Lit::Float(syn::LitFloat::new(&(l_val * r_val).to_string(), proc_macro2::Span::call_site())),
});
},
_ => {}
}
Expr::Binary(ExprBinary { attrs, left, op, right })
},
_ => expr,
}
}