desugars operator overloading
init
| -rw-r--r-- | .gitignore | 2 | ||||
| -rw-r--r-- | Cargo.toml | 16 | ||||
| -rw-r--r-- | LICENSE | 21 | ||||
| -rw-r--r-- | README.md | 7 | ||||
| -rw-r--r-- | src/lib.rs | 68 |
5 files changed, 114 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..869df07 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +Cargo.lock
\ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..e5cd65f --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "lower" +version = "0.1.0" +authors = ["bend-n <[email protected]>"] +description = "desugar math where the compiler wont" +edition = "2021" +repository = "https://github.com/bend-n/lower.git" +license = "MIT" + +[dependencies] +proc-macro2 = "1.0.78" +quote = "1.0.32" +syn = "2.0.15" + +[lib] +proc_macro = true @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 bendn + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..92deb2d --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +# lower + +lowers expressions to their "desugared" form. + +e.g + +`a * b + c` => `(a.mul(b)).add(c)`
\ No newline at end of file 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() +} |