desugars operator overloading
Diffstat (limited to 'src/lib.rs')
| -rw-r--r-- | src/lib.rs | 68 |
1 files changed, 68 insertions, 0 deletions
diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..2d2b9b6 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,68 @@ +//! a lil macro crate. +//! +//! provides a handy macro for converting `a + b` to `a.add(b)` for when you cant easily overload the `Add` trait. +use proc_macro::TokenStream; +use quote::quote; +use syn::{parse_macro_input, spanned::Spanned, Expr, ExprBinary, ExprUnary}; + +fn walk(e: Expr) -> proc_macro2::TokenStream { + match e { + Expr::Binary(ExprBinary { + left, op, right, .. + }) => { + let left = walk(*left); + let right = walk(*right); + use syn::BinOp::*; + match op { + Add(_) => quote!((#left).add(#right)), + Sub(_) => quote!((#left).sub(#right)), + Mul(_) => quote!((#left).mul(#right)), + Div(_) => quote!((#left).div(#right)), + Rem(_) => quote!((#left).rem(#right)), + And(_) => quote!((#left).and(#right)), + Or(_) => quote!((#left).or(#right)), + BitXor(_) => quote!((#left).bitxor(#right)), + BitAnd(_) => quote!((#left).bitand(#right)), + BitOr(_) => quote!((#left).bitor(#right)), + Shl(_) => quote!((#left).shl(#right)), + Shr(_) => quote!((#left).shr(#right)), + Eq(_) => quote!((#left).eq(#right)), + Lt(_) => quote!((#left).lt(#right)), + Le(_) => quote!((#left).le(#right)), + Ne(_) => quote!((#left).ne(#right)), + Ge(_) => quote!((#left).ge(#right)), + Gt(_) => quote!((#left).gt(#right)), + // don't support assigning ops + e => syn::Error::new(e.span(), format!("{}", quote!(op #e not supported))) + .to_compile_error(), + } + } + Expr::Unary(ExprUnary { op, expr, .. }) => { + let x = walk(*expr); + match op { + syn::UnOp::Deref(_) => quote!((#x).deref()), + syn::UnOp::Not(_) => quote!((#x).not()), + syn::UnOp::Neg(_) => quote!((#x).neg()), + e => syn::Error::new( + e.span(), + "it would appear a new operation has been added! please tell me.", + ) + .to_compile_error(), + } + } + e => quote!(#e), + } +} + +/// Lower math to method calls. +/// ``` +/// # use std::ops::*; +/// let [a, b, c] = [5i32, 6, 7]; +/// assert_eq!(lower::math! { a * *&b + -c }, a * *&b + -c); +/// // expands to +/// // a.mul((&b).deref()).add(c.neg()) +/// ``` +#[proc_macro] +pub fn math(input: TokenStream) -> TokenStream { + walk(parse_macro_input!(input as Expr)).into() +} |