jrust/
lib.rs

1#[macro_export]
2macro_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<String> = 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]
271macro_rules! java {
272    ($($code:tt)*) => {
273        java_inner!(toplevel { $($code)* });
274    }
275}
276
277use std::fmt::Display;
278
279pub trait JavaAdd<T> {
280    type Target;
281
282    fn add(self, other: T) -> Self::Target;
283}
284
285impl<T: Display> JavaAdd<T> 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}
294impl<'a, T: Display> JavaAdd<T> for &'a str {
295    type Target = String;
296
297    fn add(self, other: T) -> Self::Target {
298        JavaAdd::<T>::add(String::from(self), other)
299        //String::from(self)
300        //    .add(other)
301    }
302}
303
304macro_rules! impl_add {
305    ($($primitive:ident),*) => {
306        $(impl<T: Into<i64>> JavaAdd<T> 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
316impl_add!(i8, i16, i32, i64);