desugars operator overloading
bendn 2024-02-17
commit 9cb59f0
-rw-r--r--.gitignore2
-rw-r--r--Cargo.toml16
-rw-r--r--LICENSE21
-rw-r--r--README.md7
-rw-r--r--src/lib.rs68
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
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..2f002a4
--- /dev/null
+++ b/LICENSE
@@ -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()
+}