├── .gitignore ├── Cargo.toml ├── LICENSE ├── README.md ├── all-examples.sh ├── examples ├── args.rs ├── class.rs ├── concat.rs ├── control-flow.rs ├── factorial.rs ├── interrop-java.rs ├── interrop-rust.rs ├── switch.rs └── types.rs └── src └── lib.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | Cargo.lock 4 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["jD91mZM2 "] 3 | description = "A Rust macro that parses Java-like syntax and runs it as a Rust program" 4 | license-file = "LICENSE" 5 | name = "jrust" 6 | readme = "README.md" 7 | repository = "https://gitlab.com/jD91mZM2/jrust" 8 | version = "0.2.0" 9 | 10 | [dependencies] 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 jD91mZM2 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # jRust ![Crates.io](https://img.shields.io/crates/v/jrust.svg) 2 | 3 | *What is this madness?* 4 | 5 | This, my friends, is a Rust macro that parses Java-like syntax and runs it as a Rust program. 6 | 7 | **Warning: Very early release.** I just wanted to get a prototype working so I 8 | could reserve the name on crates.io. Of course I'll work more on this very 9 | useful library later. 10 | 11 | ## Why 12 | 13 | **"Science isn't about WHY, it's about WHY NOT? WHY is so much of our science 14 | dangerous, WHY NOT marry safe science if you love it so much. In fact, why not 15 | invent a special safety door that won't kick you on the butt on the way out 16 | because *you are fired*."** 17 | 18 | - Cave Johnsson, Portal 2 19 | 20 | The whole idea of this project was invented by [@nilset](https://github.com/nilset). 21 | 22 | ## Example 23 | 24 | ```Java 25 | java! { 26 | public class Value { 27 | int val; 28 | 29 | --- 30 | 31 | public Value(this, int val) { 32 | (this.val) = val; 33 | } 34 | 35 | public void print(this) { 36 | System.out.println((this.val)); 37 | } 38 | } 39 | } 40 | ``` 41 | 42 | Note: This is not 1:1 Java, because of some limitations. Emphasis on the 43 | `this`, which is there to combat Rust's macro hygiene. 44 | 45 | Generated rust: 46 | 47 | *This can be inspected using [cargo-expand](https://github.com/dtolnay/cargo-expand)* 48 | 49 | ```Rust 50 | #[derive(Clone, Debug, Default)] 51 | pub struct Value { 52 | val: i32, 53 | } 54 | impl Value { 55 | pub fn init(this: &mut Self, val: i32) { 56 | this.val = val; 57 | } 58 | pub fn new(val: i32) -> Self { 59 | let mut me = Self::default(); 60 | Self::init(&mut me, val); 61 | me 62 | } 63 | } 64 | impl Value { 65 | pub fn print(this: &mut Self) -> () { 66 | println!("{}", this.val); 67 | } 68 | } 69 | ``` 70 | 71 | Obviously this isn't perfect. Clean code, speed, etc are things I will strive 72 | for but they are not a priority. 73 | -------------------------------------------------------------------------------- /all-examples.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cd examples/ 4 | 5 | for example in *.rs; do 6 | example="$(echo -n "$example" | rev | cut -c 4- | rev)" 7 | echo "Trying example $example..." 8 | cargo run --example "$example" -- Hello World 9 | done 10 | -------------------------------------------------------------------------------- /examples/args.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate jrust; 3 | 4 | java! { 5 | package main; 6 | 7 | public class Main { 8 | public static void main(String[] args) { 9 | // Notice how accessing the length is with .length, and how no 10 | // casts are needed! 11 | 12 | int length = (args.length); 13 | for ((int i = 0;); (i < length); (i++;)) { 14 | System.out.println(args[i]); 15 | } 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /examples/class.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate jrust; 3 | 4 | java! { 5 | package main; 6 | 7 | public class Main { 8 | int field; 9 | 10 | --- 11 | 12 | public Main(this, int val) { 13 | (this.field) = (val); 14 | Main.print(this); 15 | } 16 | 17 | public void print(this) { 18 | System.out.print("Main("); 19 | System.out.print((this.field)); 20 | System.out.println(")"); 21 | } 22 | 23 | public void add(this, int val) { 24 | (this.field) += val; 25 | } 26 | 27 | public static void main(String[] args) { 28 | Main main = (new Main(3)); 29 | Main.add(main, 5); 30 | Main.print(main); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /examples/concat.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate jrust; 3 | 4 | java! { 5 | package main; 6 | 7 | public class Main { 8 | public static void main(String[] args) { 9 | System.out.println(("Hello ") + ("World")); 10 | System.out.println(("Hello ") + (1) + (" World")); 11 | System.out.println(("Hello ") + (1) + (2)); 12 | System.out.println(("Hello ") + ((1) + (2))); 13 | System.out.println(("Hello ") + (1 + 2)); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /examples/control-flow.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate jrust; 3 | 4 | java! { 5 | package main; 6 | 7 | public class Main { 8 | public static void main(String[] args) { 9 | System.out.println("Testing for loops..."); 10 | 11 | for ((int i = 0;); (i < 5); (i++;)) { 12 | if (i == 0) { 13 | System.out.println("i is 0"); 14 | } else if (i == 1) { 15 | System.out.println("i is 1"); 16 | } else { 17 | System.out.println("i is something"); 18 | }; 19 | } 20 | 21 | System.out.println("Testing while loops..."); 22 | 23 | int i = 0; 24 | 25 | while (i < 5) { 26 | System.out.println(("i = ") + (i)); 27 | i++; 28 | } 29 | 30 | while (true) { 31 | if (i == 7) { 32 | (i) = 9; 33 | System.out.println("continuing!"); 34 | continue; 35 | }; 36 | 37 | System.out.println(("forever: i = ") + (i)); 38 | 39 | if ((i++) >= (10)) { 40 | System.out.println("breaking!"); 41 | break; 42 | }; 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /examples/factorial.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate jrust; 3 | 4 | java! { 5 | package main; 6 | 7 | public class Main { 8 | public static int fac(int val) { 9 | if (val == 0) { 10 | return 1; 11 | } else { 12 | return ((val) * (fac(val - 1))); 13 | }; 14 | } 15 | 16 | public static void main(String[] args) { 17 | System.out.println(fac(5)); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /examples/interrop-java.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate jrust; 3 | 4 | java! { 5 | public class Value { 6 | int val; 7 | 8 | --- 9 | 10 | public Value(this, int val) { 11 | (this.val) = val; 12 | } 13 | 14 | public void print(this) { 15 | System.out.println((this.val)); 16 | } 17 | } 18 | } 19 | 20 | fn main() { 21 | let mut value = Value::new(42); 22 | Value::print(&mut value); 23 | } 24 | -------------------------------------------------------------------------------- /examples/interrop-rust.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate jrust; 3 | 4 | pub struct Value(i32); 5 | 6 | impl Value { 7 | pub fn new(val: i32) -> Self { 8 | Value(val) 9 | } 10 | pub fn print(&mut self) { 11 | println!("{}", self.0); 12 | } 13 | } 14 | 15 | java! { 16 | package main; 17 | 18 | public class Main { 19 | public static void main(String[] args) { 20 | Value val = (new Value(5)); 21 | Value.print(val); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /examples/switch.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate jrust; 3 | 4 | java! { 5 | package main; 6 | 7 | public class Main { 8 | public static void main(String[] args) { 9 | for ((int i = 0;); (i < 10); (i++;)) { 10 | System.out.print(("testing ") + (i) + ("... ")); 11 | 12 | switch (i) { 13 | case (1) { 14 | System.out.println("i is 1"); 15 | break; 16 | } 17 | case (2) {} 18 | case (3) { 19 | System.out.println("i >= 3"); 20 | } 21 | case (4) { 22 | System.out.println("i is between 2 and 4 (inclusive)"); 23 | break; 24 | } 25 | case (5) { 26 | System.out.println("i is 5"); 27 | break; 28 | } 29 | default { 30 | System.out.println("i is something... i guess"); 31 | //break; 32 | } 33 | } 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /examples/types.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate jrust; 3 | 4 | java! { 5 | package main; 6 | 7 | public class Main { 8 | public static void main(String[] args) { 9 | // Notice how no casts are needed! 10 | 11 | byte a = 1; 12 | (a) -= 1; 13 | short b = 0; 14 | (b) += 1; 15 | 16 | int c = 2; 17 | long d = 3; 18 | 19 | if (a < b) { 20 | System.out.println("a < b"); 21 | }; 22 | if (b < c) { 23 | System.out.println("b < c"); 24 | }; 25 | if (c < d) { 26 | System.out.println("c < d"); 27 | }; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #[macro_export] 2 | macro_rules! java_inner { 3 | (toplevel {}) => {}; 4 | (toplevel { package $name:ident; $($remaining:tt)* }) => { 5 | java_inner!(toplevel { $($remaining)* }); 6 | }; 7 | (toplevel { public class $name:ident { 8 | $($kind:ident $var:ident;)* 9 | --- 10 | $($inner:tt)* 11 | } $($remaining:tt)* }) => { 12 | #[derive(Clone, Debug, Default)] 13 | pub struct $name { 14 | $($var: java_inner!(kind $kind)),* 15 | } 16 | java_inner!(class($name) { $($inner)* }); 17 | java_inner!(toplevel { $($remaining)* }); 18 | }; 19 | (toplevel { public class $name:ident { 20 | $($inner:tt)* 21 | } $($remaining:tt)* }) => { 22 | java_inner!(toplevel { public class $name { 23 | --- 24 | $($inner)* 25 | } }); 26 | }; 27 | 28 | (class($class:ident) {}) => {}; 29 | (class($class:ident) { public static void main(String[] $args:ident) { 30 | $($inner:tt)* 31 | } $($remaining:tt)* }) => { 32 | fn main() { 33 | #[allow(unused_mut, unused_variables)] 34 | let mut $args: Vec = std::env::args().skip(1).collect(); 35 | java_inner!(stmt($class) { $($inner)* }); 36 | } 37 | java_inner!(class($class) { $($remaining)* }); 38 | }; 39 | (class($class:ident) { public $constructor:ident($self:ident$(, $kind:ident $var:ident)*) { 40 | $($inner:tt)* 41 | } $($remaining:tt)* }) => { 42 | impl $class { 43 | pub fn init($self: &mut Self, $($var: java_inner!(kind $kind)),*) { 44 | java_inner!(stmt($class) { $($inner)* }); 45 | } 46 | pub fn new($($var: java_inner!(kind $kind)),*) -> Self { 47 | assert_eq!(stringify!($class), stringify!($constructor), "constructor does not share name with class"); 48 | let mut me = Self::default(); 49 | Self::init(&mut me, $($var),*); 50 | me 51 | } 52 | } 53 | java_inner!(class($class) { $($remaining)* }); 54 | }; 55 | (class($class:ident) { public $ret:ident $fn:ident($self:ident$(, $kind:ident $var:ident)*) { 56 | $($inner:tt)* 57 | } $($remaining:tt)* }) => { 58 | impl $class { 59 | pub fn $fn($self: &mut Self, $($var: java_inner!(kind $kind)),*) -> java_inner!(kind $ret) { 60 | java_inner!(stmt($class) { $($inner)* }); 61 | } 62 | } 63 | java_inner!(class($class) { $($remaining)* }); 64 | }; 65 | (class($class:ident) { public static $ret:ident $fn:ident($($kind:ident $var:ident),*) { 66 | $($inner:tt)* 67 | } $($remaining:tt)* }) => { 68 | impl $class { 69 | pub fn $fn($($var: java_inner!(kind $kind)),*) -> java_inner!(kind $ret) { 70 | java_inner!(stmt($class) { $($inner)* }); 71 | } 72 | } 73 | java_inner!(class($class) { $($remaining)* }); 74 | }; 75 | 76 | (stmt($class:ident) {}) => {}; 77 | (stmt($class:ident) { System.out.println($($out:tt)*); $($remaining:tt)* }) => { 78 | println!("{}", java_inner!(expr($class) { $($out)* })); 79 | java_inner!(stmt($class) { $($remaining)* }); 80 | }; 81 | (stmt($class:ident) { System.out.println_debug($($out:tt)*); $($remaining:tt)* }) => { 82 | println!("{:?}", java_inner!(expr($class) { $($out)* })); 83 | java_inner!(stmt($class) { $($remaining)* }); 84 | }; 85 | (stmt($class:ident) { System.out.print($($out:tt)*); $($remaining:tt)* }) => { 86 | print!("{}", java_inner!(expr($class) { $($out)* })); 87 | java_inner!(stmt($class) { $($remaining)* }); 88 | }; 89 | (stmt($class:ident) { $kind:ident $name:ident = ($($value:tt)*); $($remaining:tt)* }) => { 90 | #[allow(unused_mut)] 91 | let mut $name: java_inner!(kind $kind) = java_inner!(expr($class) { $($value)* }); 92 | java_inner!(stmt($class) { $($remaining)* }); 93 | }; 94 | (stmt($class:ident) { $kind:ident $name:ident = $value:expr; $($remaining:tt)* }) => { 95 | java_inner!(stmt($class) { $kind $name = ($value); $($remaining)* }); 96 | }; 97 | (stmt($class:ident) { ($name:expr) = ($($val:tt)*); $($remaining:tt)* }) => { 98 | $name = java_inner!(expr($class) { $($val)* }); 99 | java_inner!(stmt($class) { $($remaining)* }); 100 | }; 101 | (stmt($class:ident) { ($name:expr) = $val:expr; $($remaining:tt)* }) => { 102 | java_inner!(stmt($class) { ($name) = ($val); $($remaining)* }); 103 | }; 104 | (stmt($class:ident) { $name:ident = $val:expr; $($remaining:tt)* }) => { 105 | java_inner!(stmt($class) { ($name) = ($val); $($remaining)* }); 106 | }; 107 | (stmt($class:ident) { ($name:expr) += $val:expr; $($remaining:tt)* }) => { 108 | $name += $val; 109 | java_inner!(stmt($class) { $($remaining)* }); 110 | }; 111 | (stmt($class:ident) { ($name:expr) -= $val:expr; $($remaining:tt)* }) => { 112 | $name -= java_inner!(expr($class) { $val }); 113 | java_inner!(stmt($class) { $($remaining)* }); 114 | }; 115 | (stmt($class:ident) { $name:ident++; $($remaining:tt)* }) => { 116 | $name += 1; 117 | java_inner!(stmt($class) { $($remaining)* }); 118 | }; 119 | (stmt($class:ident) { $name:ident--; $($remaining:tt)* }) => { 120 | $name -= 1; 121 | java_inner!(stmt($class) { $($remaining)* }); 122 | }; 123 | (stmt($class:ident) { return ($($val:tt)*); $($remaining:tt)* }) => { 124 | return java_inner!(expr($class) { $($val)* }) as _; 125 | // Useless, but'll generate the nice "unused code" warning that 126 | // actually applies here and isn't caused by the macro itself. 127 | java_inner!(stmt($class) { $($remaining)* }); 128 | }; 129 | (stmt($class:ident) { return $val:expr; $($remaining:tt)* }) => { 130 | java_inner!(stmt($class) { return ($val); $($remaining)* }); 131 | }; 132 | (stmt($class:ident) { break; $($remaining:tt)* }) => { 133 | break; 134 | // Useless, but'll generate the nice "unused code" warning that 135 | // actually applies here and isn't caused by the macro itself. 136 | java_inner!(stmt($class) { $($remaining)* }); 137 | }; 138 | (stmt($class:ident) { continue; $($remaining:tt)* }) => { 139 | continue; 140 | // Useless, but'll generate the nice "unused code" warning that 141 | // actually applies here and isn't caused by the macro itself. 142 | java_inner!(stmt($class) { $($remaining)* }); 143 | }; 144 | (stmt($class:ident) { for (($($pre:tt)*); ($($cond:tt)*); ($($post:tt)*)) { 145 | $($inner:tt)* 146 | } $($remaining:tt)* }) => { 147 | java_inner!(stmt($class) { $($pre)* }); 148 | while java_inner!(expr($class) { $($cond)* }) { 149 | java_inner!(stmt($class) { $($inner)* }); 150 | java_inner!(stmt($class) { $($post)* }); 151 | } 152 | java_inner!(stmt($class) { $($remaining)* }); 153 | }; 154 | (stmt($class:ident) { if ($($cond:tt)*) { 155 | $($success:tt)* 156 | } $(else if ($($elseif_cond:tt)*) { 157 | $($elseif_success:tt)* 158 | // Else is not optional but we can use * as a hack 159 | })* $(else { 160 | $($otherwise:tt)* 161 | })*; $($remaining:tt)* }) => { 162 | if java_inner!(expr($class) { $($cond)* }) { 163 | java_inner!(stmt($class) { $($success)* }); 164 | } $(else if java_inner!(expr($class) { $($elseif_cond)* }) { 165 | java_inner!(stmt($class) { $($elseif_success)* }); 166 | })* $(else { 167 | java_inner!(stmt($class) { $($otherwise)* }); 168 | })* 169 | java_inner!(stmt($class) { $($remaining)* }); 170 | }; 171 | (stmt($class:ident) { switch($($search:tt)*) { 172 | $(case ($match:expr) { 173 | $($success:tt)* 174 | })* 175 | // Should only be one default but rust doesn't have optional macro args yet AFAIK 176 | $(default { 177 | $($default:tt)* 178 | })* 179 | } $($remaining:tt)* }) => { 180 | loop { 181 | #[allow(unused_assignments)] 182 | let mut fallthrough = false; 183 | let search = java_inner!(expr($class) { $($search)* }); 184 | 185 | $( 186 | if fallthrough || search == $match { 187 | #[allow(unused_assignments)] 188 | { fallthrough = true; } 189 | java_inner!(stmt($class) { $($success)* }); 190 | } 191 | )* 192 | 193 | $(java_inner!(stmt($class) { $($default)* });)* 194 | #[allow(unreachable_code)] 195 | { break; } 196 | } 197 | java_inner!(stmt($class) { $($remaining)* }); 198 | }; 199 | (stmt($class:ident) { while ($($cond:tt)*) { 200 | $($inner:tt)* 201 | } $($remaining:tt)* }) => { 202 | while java_inner!(expr($class) { $($cond)* }) { 203 | java_inner!(stmt($class) { $($inner)* }); 204 | } 205 | java_inner!(stmt($class) { $($remaining)* }); 206 | }; 207 | // Handle these last because they could be ambigious 208 | (stmt($class:ident) { $val:ident.$fn:ident($(($($var:tt)*)),*); $($remaining:tt)* }) => { 209 | $val::$fn($(java_inner!(expr($class) { $($var)* })),*); 210 | java_inner!(stmt($class) { $($remaining)* }); 211 | }; 212 | (stmt($class:ident) { $val:ident.$fn:ident($($var:expr),*); $($remaining:tt)* }) => { 213 | java_inner!(stmt($class) { $val.$fn($(($var)),*); $($remaining)* }); 214 | }; 215 | (stmt($class:ident) { $fn:ident($(($($var:tt)*)),*); $($remaining:tt)* }) => { 216 | $class::$fn($(java_inner!(expr($class) { $($var)* })),*); 217 | java_inner!(stmt($class) { $($remaining)* }); 218 | }; 219 | (stmt($class:ident) { $fn:ident($($var:expr),*); $($remaining:tt)* }) => { 220 | java_inner!(stmt($class) { $fn($(($var)),*); $($remaining)* }); 221 | }; 222 | 223 | (expr($class:ident) { $array:ident[$index:expr] }) => {{ 224 | assert!($index >= 0); 225 | &mut $array[$index as usize] 226 | }}; 227 | (expr($class:ident) { $array:ident.length }) => {{ 228 | $array.len() as i32 229 | }}; 230 | (expr($class:ident) { ($($var1:tt)*) $(+ ($($var2:tt)*))+ }) => {{ 231 | use jrust::*; 232 | java_inner!(expr($class) { $($var1)* }) 233 | $(.add(java_inner!(expr($class) { $($var2)* })))* 234 | }}; 235 | (expr($class:ident) { $var:ident++ }) => {{ 236 | let old = $var; 237 | $var += 1; 238 | old 239 | }}; 240 | (expr($class:ident) { $var1:ident $op:tt $var2:ident }) => {{ 241 | java_inner!(expr($class) { ($var1) $op ($var2) }) 242 | }}; 243 | (expr($class:ident) { ($($var1:tt)*) $op:tt ($($var2:tt)*) }) => {{ 244 | (java_inner!(expr($class) { $($var1)* }) as i64) $op (java_inner!(expr($class) { $($var2)* }) as i64) 245 | }}; 246 | (expr($_class:ident) { new $class:ident($(($($var:tt)*)),*) }) => {{ 247 | &mut $class::new($(java_inner!(expr($class) { $($var)* })),*) 248 | }}; 249 | (expr($_class:ident) { new $class:ident($($var:expr),*) }) => {{ 250 | java_inner!(expr($class) { new $class($(($var)),*) }) 251 | }}; 252 | // Handle these last because they could be ambigious 253 | (expr($class:ident) { $fn:ident($(($($var:tt)*)),*) }) => { 254 | $class::$fn($(java_inner!(expr($class) { $($var)* })),*); 255 | }; 256 | (expr($class:ident) { $fn:ident($($var:expr),*) }) => { 257 | java_inner!(expr($class) { $fn($(($var)),*) }); 258 | }; 259 | (expr($class:ident) { $expr:expr }) => {{ 260 | $expr 261 | }}; 262 | 263 | (kind byte) => { i8 }; 264 | (kind short) => { i16 }; 265 | (kind int) => { i32 }; 266 | (kind long) => { i64 }; 267 | (kind void) => { () }; 268 | (kind $name:ident) => { &mut $name }; 269 | } 270 | #[macro_export] 271 | macro_rules! java { 272 | ($($code:tt)*) => { 273 | java_inner!(toplevel { $($code)* }); 274 | } 275 | } 276 | 277 | use std::fmt::Display; 278 | 279 | pub trait JavaAdd { 280 | type Target; 281 | 282 | fn add(self, other: T) -> Self::Target; 283 | } 284 | 285 | impl JavaAdd for String { 286 | type Target = Self; 287 | 288 | fn add(mut self, other: T) -> Self::Target { 289 | use std::fmt::Write; 290 | write!(self, "{}", other).unwrap(); 291 | self 292 | } 293 | } 294 | impl<'a, T: Display> JavaAdd for &'a str { 295 | type Target = String; 296 | 297 | fn add(self, other: T) -> Self::Target { 298 | JavaAdd::::add(String::from(self), other) 299 | //String::from(self) 300 | // .add(other) 301 | } 302 | } 303 | 304 | macro_rules! impl_add { 305 | ($($primitive:ident),*) => { 306 | $(impl> JavaAdd for $primitive { 307 | type Target = i64; 308 | 309 | fn add(self, other: T) -> Self::Target { 310 | i64::from(self) + other.into() 311 | } 312 | })* 313 | } 314 | } 315 | 316 | impl_add!(i8, i16, i32, i64); 317 | --------------------------------------------------------------------------------