desugars operator overloading
Diffstat (limited to 'src/lib.rs')
-rw-r--r--src/lib.rs68
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()
+}