1use std::fmt::Display;
2
3use proc_macro2::{Delimiter, TokenStream};
4use quote::quote;
5use syn::punctuated::Punctuated;
6use syn::{Ident, LitStr, Token, parse_macro_input};
7
8pub(crate) mod parse;
9pub(crate) mod process;
10pub(crate) mod output;
11
12pub(crate) mod kw {
13 use syn::custom_keyword;
14
15 custom_keyword!(void);
16 custom_keyword!(boolean);
17 custom_keyword!(byte);
18 custom_keyword!(char);
19 custom_keyword!(short);
20 custom_keyword!(int);
21 custom_keyword!(long);
22 custom_keyword!(float);
23 custom_keyword!(double);
24 custom_keyword!(native);
25 custom_keyword!(throw);
26 custom_keyword!(new);
27 custom_keyword!(import);
28 custom_keyword!(package);
29 custom_keyword!(class);
30
31 custom_keyword!(alloc);
32}
33
34#[derive(PartialEq)]
35pub(crate) enum JavaType {
36 Void,
37 Boolean,
38 Byte,
39 Char,
40 Short,
41 Int,
42 Long,
43 Float,
44 Double,
45 String,
46 Object(DottedName),
47 Array(Box<Self>),
48}
49
50#[derive(Clone)]
51pub(crate) struct DottedName(Punctuated<Ident, Token![.]>);
52
53impl PartialEq for DottedName {
54 fn eq(&self, other: &Self) -> bool {
55 self.0.len() == other.0.len() && (
56 self.0
57 .iter()
58 .zip(other.0.iter())
59 .all(|(a, b)| a == b)
60 )
61 }
62}
63
64impl Display for DottedName {
65 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
66 let n = self.0
67 .iter()
68 .map(|t| t.to_string())
69 .collect::<Vec<_>>()
70 .join(".");
71 write!(f, "{}", n)
72 }
73}
74
75pub(crate) struct JavaClassDef {
76 pub(crate) package: DottedName,
77 pub(crate) imports: Vec<JavaImport>,
78 pub(crate) uses: Vec<JavaUse>,
79 pub(crate) class: JavaClass,
80 pub(crate) errors: Vec<TokenStream>,
81}
82
83pub(crate) struct JavaImport {
84 pub(crate) item: DottedName,
85}
86
87pub(crate) struct JavaUse {
88 pub(crate) rust_path: PathSepName,
89 pub(crate) java_path: DottedName,
90}
91
92#[derive(Default, Clone, Copy)]
93pub(crate) enum PathSepPrefix {
94 #[default]
95 None,
96 This,
97 Super,
98 Crate,
99}
100
101#[derive(Clone)]
102pub(crate) struct PathSepName {
103 pub(crate) prefix: PathSepPrefix,
104 pub(crate) parts: Vec<Ident>,
105}
106
107pub(crate) struct JavaClass {
108 pub(crate) name: Ident,
109 pub(crate) body: ClassBody,
110}
111
112pub(crate) struct ClassBody {
113 pub(crate) fields: Vec<JavaField>,
114 pub(crate) bindings: Vec<JavaBinding>,
115 pub(crate) natives: Vec<NativeFunction>,
116 pub(crate) errors: Vec<TokenStream>,
117}
118
119pub(crate) struct JavaField {
120 pub(crate) static_tk: Option<Token![static]>,
121 pub(crate) name: Ident,
122 pub(crate) typ: JavaType,
123}
124
125pub(crate) struct JavaBinding {
126 pub(crate) static_tk: Option<Token![static]>,
127 pub(crate) signature: JavaFnSignature,
128}
129
130pub(crate) struct NativeFunction {
131 pub(crate) static_tk: Option<Token![static]>,
132 pub(crate) signature: JavaFnSignature,
133 pub(crate) body: JavaCodeBlock,
134}
135
136pub(crate) struct JavaFnSignature {
137 pub(crate) fn_tk: Token![fn],
138 pub(crate) name: Ident,
139 pub(crate) params: Punctuated<JavaParam, Token![,]>,
140 pub(crate) arrow: Option<Token![->]>,
141 pub(crate) returns: JavaType,
142}
143
144pub(crate) struct JavaParam {
145 pub(crate) name: Ident,
146 pub(crate) typ: JavaType,
147}
148
149pub(crate) struct JavaCodeBlock {
150 pub(crate) delimiter: Delimiter,
151 pub(crate) sections: Vec<CodeSection>,
152}
153
154pub(crate) enum CodeSection {
155 Tokens(TokenStream),
156 Block(JavaCodeBlock),
157 Java(JavaExpression),
158}
159
160pub(crate) enum JavaExpression {
168 Expr(JavaExpr),
169 StaticFieldWrite(JavaStaticFieldWrite),
170 FieldWrite(JavaFieldWrite),
171 ArrayWrite(JavaArrayWrite),
172 ThrowNew(JavaThrowNew),
173 ThrowObj(JavaThrowObj),
174}
175
176pub(crate) enum JavaExpr {
186 Error(TokenStream),
187 StaticCall(JavaStaticCall),
188 MethodCall(JavaMethodCall),
189 StaticFieldRead(JavaStaticFieldRead),
190 FieldRead(JavaFieldRead),
191 ArrayRead(Box<JavaArrayRead>),
192 New(JavaNew),
193 Alloc(JavaAlloc),
194}
195
196pub(crate) enum JavaValueExpr {
203 Expr(JavaExpr),
204 Block(JavaCodeBlock),
205}
206
207pub(crate) struct JavaSignatureTag(LitStr);
211
212pub(crate) struct JavaStaticCall {
214 pub(crate) class: DottedName,
215 pub(crate) func: Ident,
216 pub(crate) args: Punctuated<JavaValueExpr, Token![,]>,
217 pub(crate) signature: Option<JavaSignatureTag>,
219}
220
221pub(crate) struct JavaMethodCall {
223 pub(crate) obj: Ident,
224 pub(crate) func: Ident,
225 pub(crate) args: Punctuated<JavaValueExpr, Token![,]>,
226 pub(crate) signature: Option<JavaSignatureTag>,
228}
229
230pub(crate) struct JavaStaticFieldRead {
232 pub(crate) class: DottedName,
233 pub(crate) field: Ident,
234 pub(crate) signature: Option<JavaSignatureTag>,
236}
237
238pub(crate) struct JavaStaticFieldWrite {
240 pub(crate) class: DottedName,
241 pub(crate) field: Ident,
242 pub(crate) signature: Option<JavaSignatureTag>,
244 pub(crate) value: JavaValueExpr,
245}
246
247pub(crate) struct JavaFieldWrite {
249 pub(crate) obj: Ident,
250 pub(crate) field: Ident,
251 pub(crate) signature: Option<JavaSignatureTag>,
253 pub(crate) value: JavaValueExpr,
254}
255
256pub(crate) struct JavaFieldRead {
258 pub(crate) obj: Ident,
259 pub(crate) field: Ident,
260 pub(crate) signature: Option<JavaSignatureTag>,
262}
263
264pub(crate) struct JavaArrayWrite {
266 pub(crate) array: Ident,
267 pub(crate) index: JavaValueExpr,
268 pub(crate) signature: Option<JavaSignatureTag>,
270 pub(crate) value: JavaValueExpr,
271}
272
273pub(crate) struct JavaArrayRead {
275 pub(crate) array: Ident,
276 pub(crate) index: JavaValueExpr,
277 pub(crate) signature: Option<JavaSignatureTag>,
279}
280
281pub(crate) struct JavaThrowNew {
283 pub(crate) class: DottedName,
284 pub(crate) message: JavaValueExpr,
285}
286
287pub(crate) struct JavaThrowObj {
289 pub(crate) value: JavaValueExpr,
290}
291
292pub(crate) struct JavaNew {
294 pub(crate) class: DottedName,
295 pub(crate) args: Punctuated<JavaValueExpr, Token![,]>,
296 pub(crate) signature: Option<JavaSignatureTag>,
298}
299
300pub(crate) struct JavaAlloc {
302 pub(crate) class: DottedName,
303}
304
305#[proc_macro]
398pub fn java_class(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
399 let class: JavaClassDef = parse_macro_input!(input);
400 let class = class.resolve();
401 quote! {
402 #class
403 }.into()
404}
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421