Skip to main content

alef/docs/
type_mapping.rs

1use crate::core::config::Language;
2use crate::core::ir::{PrimitiveType, TypeRef};
3use crate::docs::naming::type_name;
4
5pub fn doc_type(ty: &TypeRef, lang: Language, ffi_prefix: &str) -> String {
6    match ty {
7        TypeRef::String | TypeRef::Char => match lang {
8            Language::Python => "str".to_string(),
9            Language::Node | Language::Wasm => "string".to_string(),
10            Language::Go => "string".to_string(),
11            Language::Java => "String".to_string(),
12            Language::Csharp => "string".to_string(),
13            Language::Ruby => "String".to_string(),
14            Language::Php => "string".to_string(),
15            Language::Elixir => "String.t()".to_string(),
16            Language::R => "character".to_string(),
17            Language::Rust => "String".to_string(),
18            Language::Ffi | Language::C | Language::Jni => "const char*".to_string(),
19            Language::Kotlin | Language::KotlinAndroid | Language::Swift | Language::Dart => "String".to_string(),
20            Language::Gleam => "String".to_string(),
21            Language::Zig => "[:0]const u8".to_string(),
22        },
23        TypeRef::Bytes => match lang {
24            Language::Python => "bytes".to_string(),
25            Language::Node | Language::Wasm => "Buffer".to_string(),
26            Language::Go => "[]byte".to_string(),
27            Language::Java => "byte[]".to_string(),
28            Language::Csharp => "byte[]".to_string(),
29            Language::Ruby => "String".to_string(),
30            Language::Php => "string".to_string(),
31            Language::Elixir => "binary()".to_string(),
32            Language::R => "raw".to_string(),
33            Language::Rust => "Vec<u8>".to_string(),
34            Language::Ffi | Language::C | Language::Jni => "const uint8_t*".to_string(),
35            Language::Kotlin | Language::KotlinAndroid => "ByteArray".to_string(),
36            Language::Swift => "Data".to_string(),
37            Language::Dart => "Uint8List".to_string(),
38            Language::Gleam => "BitArray".to_string(),
39            Language::Zig => "[]const u8".to_string(),
40        },
41        TypeRef::Primitive(p) => doc_primitive(p, lang),
42        TypeRef::Optional(inner) => {
43            let inner_ty = doc_type(inner, lang, ffi_prefix);
44            match lang {
45                Language::Python => format!("{inner_ty} | None"),
46                Language::Node | Language::Wasm => format!("{inner_ty} | null"),
47                Language::Go => format!("*{inner_ty}"),
48                Language::Java => {
49                    let boxed = java_boxed_type(inner);
50                    format!("Optional<{boxed}>")
51                }
52                Language::Csharp => format!("{inner_ty}?"),
53                Language::Ruby => format!("{inner_ty}?"),
54                Language::Php => format!("?{inner_ty}"),
55                Language::Elixir => format!("{inner_ty} | nil"),
56                Language::R => format!("{inner_ty} or NULL"),
57                Language::Rust => format!("Option<{inner_ty}>"),
58                Language::Ffi | Language::C | Language::Jni => format!("{inner_ty}*"),
59                Language::Kotlin | Language::KotlinAndroid | Language::Swift | Language::Dart => format!("{inner_ty}?"),
60                Language::Gleam => format!("Option({inner_ty})"),
61                Language::Zig => format!("?{inner_ty}"),
62            }
63        }
64        TypeRef::Vec(inner) => {
65            match lang {
66                Language::Java => {
67                    // Java generics can't use primitives — box them
68                    let inner_ty = java_boxed_type(inner);
69                    format!("List<{inner_ty}>")
70                }
71                Language::Csharp => {
72                    let inner_ty = doc_type(inner, lang, ffi_prefix);
73                    format!("List<{inner_ty}>")
74                }
75                _ => {
76                    let inner_ty = doc_type(inner, lang, ffi_prefix);
77                    match lang {
78                        Language::Python => format!("list[{inner_ty}]"),
79                        Language::Node | Language::Wasm => format!("Array<{inner_ty}>"),
80                        Language::Go => format!("[]{inner_ty}"),
81                        Language::Ruby => format!("Array<{inner_ty}>"),
82                        Language::Php => format!("array<{inner_ty}>"),
83                        Language::Elixir => format!("list({inner_ty})"),
84                        Language::R => "list".to_string(),
85                        Language::Rust => format!("Vec<{inner_ty}>"),
86                        Language::Ffi | Language::C | Language::Jni => format!("{inner_ty}*"),
87                        Language::Java | Language::Csharp => unreachable!(),
88                        Language::Kotlin | Language::KotlinAndroid | Language::Dart => format!("List<{inner_ty}>"),
89                        Language::Swift => format!("[{inner_ty}]"),
90                        Language::Gleam => format!("List({inner_ty})"),
91                        Language::Zig => format!("[]const {inner_ty}"),
92                    }
93                }
94            }
95        }
96        TypeRef::Map(k, v) => {
97            if lang == Language::Java {
98                // Java generics require boxed types
99                let kty = java_boxed_type(k);
100                let vty = java_boxed_type(v);
101                return format!("Map<{kty}, {vty}>");
102            }
103            let kty = doc_type(k, lang, ffi_prefix);
104            let vty = doc_type(v, lang, ffi_prefix);
105            match lang {
106                Language::Python => format!("dict[{kty}, {vty}]"),
107                Language::Node | Language::Wasm => format!("Record<{kty}, {vty}>"),
108                Language::Go => format!("map[{kty}]{vty}"),
109                Language::Java => format!("Map<{kty}, {vty}>"),
110                Language::Csharp => format!("Dictionary<{kty}, {vty}>"),
111                Language::Ruby => format!("Hash{{{kty}=>{vty}}}"),
112                Language::Php => format!("array<{kty}, {vty}>"),
113                Language::Elixir => "map()".to_string(),
114                Language::R => "list".to_string(),
115                Language::Rust => format!("HashMap<{kty}, {vty}>"),
116                Language::Ffi | Language::C | Language::Jni => "void*".to_string(),
117                Language::Kotlin | Language::KotlinAndroid => format!("Map<{kty}, {vty}>"),
118                Language::Swift => format!("[{kty}: {vty}]"),
119                Language::Dart => format!("Map<{kty}, {vty}>"),
120                Language::Gleam => format!("Dict({kty}, {vty})"),
121                Language::Zig => format!("std.StringHashMap({vty})"),
122            }
123        }
124        TypeRef::Named(name) if name.starts_with('(') && name.ends_with(')') => {
125            // Tuple type encoded as Named("(A, B)") — render idiomatically per language
126            let inner = &name[1..name.len() - 1];
127            let rendered: Vec<String> = inner
128                .split(',')
129                .map(|part| {
130                    let trimmed = part.trim();
131                    match trimmed {
132                        "usize" | "u64" | "u32" | "u16" | "u8" | "i64" | "i32" | "i16" | "i8" | "isize" => {
133                            // Swift preserves the signed/unsigned distinction; other
134                            // languages collapse to a single integer type per their
135                            // primitive convention.
136                            let swift_name = match trimmed {
137                                "u64" | "usize" => "UInt64",
138                                "u32" => "UInt32",
139                                "u16" => "UInt16",
140                                "u8" => "UInt8",
141                                "i64" | "isize" => "Int64",
142                                "i32" => "Int32",
143                                "i16" => "Int16",
144                                "i8" => "Int8",
145                                _ => "Int64",
146                            };
147                            match lang {
148                                Language::Python => "int".to_string(),
149                                Language::Node | Language::Wasm => "number".to_string(),
150                                Language::Go => "int".to_string(),
151                                Language::Java => "long".to_string(),
152                                Language::Csharp => "long".to_string(),
153                                Language::Ruby => "Integer".to_string(),
154                                Language::Php => "int".to_string(),
155                                Language::Elixir => "integer()".to_string(),
156                                Language::R => "integer".to_string(),
157                                Language::Rust => trimmed.to_string(),
158                                Language::Ffi | Language::C | Language::Jni => "uint64_t".to_string(),
159                                Language::Kotlin | Language::KotlinAndroid => "Long".to_string(),
160                                Language::Swift => swift_name.to_string(),
161                                Language::Dart => "int".to_string(),
162                                Language::Gleam => "Int".to_string(),
163                                Language::Zig => "i64".to_string(),
164                            }
165                        }
166                        s @ ("str" | "&str" | "String" | "&'static str" | "&'staticstr") => match lang {
167                            Language::Python => "str".to_string(),
168                            Language::Node | Language::Wasm => "string".to_string(),
169                            Language::Go => "string".to_string(),
170                            Language::Java => "String".to_string(),
171                            Language::Csharp => "string".to_string(),
172                            Language::Ruby => "String".to_string(),
173                            Language::Php => "string".to_string(),
174                            Language::Elixir => "String.t()".to_string(),
175                            Language::R => "character".to_string(),
176                            Language::Rust => s.to_string(),
177                            Language::Ffi | Language::C | Language::Jni => "const char*".to_string(),
178                            Language::Kotlin | Language::KotlinAndroid | Language::Swift | Language::Dart => {
179                                "String".to_string()
180                            }
181                            Language::Gleam => "String".to_string(),
182                            Language::Zig => "[]const u8".to_string(),
183                        },
184                        // Slice of strings — &[&str], &'static [&'static str], Vec<String>, etc.
185                        // Also covers compacted IR forms like &'static[&'staticstr]
186                        s if s.contains("[&")
187                            || s.contains("[String")
188                            || s.contains("Vec<&")
189                            || s.contains("Vec<String")
190                            || s.contains("staticstr") =>
191                        {
192                            match lang {
193                                Language::Python => "list[str]".to_string(),
194                                Language::Node | Language::Wasm => "string[]".to_string(),
195                                Language::Go => "[]string".to_string(),
196                                Language::Java => "List<String>".to_string(),
197                                Language::Csharp => "List<string>".to_string(),
198                                Language::Ruby => "Array<String>".to_string(),
199                                Language::Php => "array<string>".to_string(),
200                                Language::Elixir => "list(String.t())".to_string(),
201                                Language::R => "list".to_string(),
202                                Language::Rust => s.to_string(),
203                                Language::Ffi | Language::C | Language::Jni => "const char**".to_string(),
204                                Language::Kotlin | Language::KotlinAndroid | Language::Swift | Language::Dart => {
205                                    "List<String>".to_string()
206                                }
207                                Language::Gleam => "List(String)".to_string(),
208                                Language::Zig => "[]const []const u8".to_string(),
209                            }
210                        }
211                        other => {
212                            // For Rust, preserve the raw type token rather than
213                            // PascalCasing it — Rust type names are already correct.
214                            if lang == Language::Rust {
215                                other.to_string()
216                            } else {
217                                type_name(other, lang, ffi_prefix)
218                            }
219                        }
220                    }
221                })
222                .collect();
223            match lang {
224                Language::Python => format!("tuple[{}]", rendered.join(", ")),
225                Language::Node | Language::Wasm => format!("[{}]", rendered.join(", ")),
226                Language::Go => format!("({})", rendered.join(", ")),
227                Language::Java => format!("Tuple<{}>", rendered.join(", ")),
228                Language::Csharp => format!("({})", rendered.join(", ")),
229                Language::Ruby => format!("[{}]", rendered.join(", ")),
230                Language::Php => format!("array{{{}}}", rendered.join(", ")),
231                Language::Elixir => format!("{{{}}}", rendered.join(", ")),
232                Language::R => "list".to_string(),
233                Language::Rust => format!("({})", rendered.join(", ")),
234                Language::Ffi | Language::C | Language::Jni => "void*".to_string(),
235                Language::Kotlin | Language::KotlinAndroid => format!("Pair<{}>", rendered.join(", ")),
236                Language::Swift => format!("({})", rendered.join(", ")),
237                Language::Dart => format!("({})", rendered.join(", ")),
238                Language::Gleam => format!("#({})", rendered.join(", ")),
239                Language::Zig => format!("struct {{ {} }}", rendered.join(", ")),
240            }
241        }
242        TypeRef::Named(name) => type_name(name, lang, ffi_prefix),
243        TypeRef::Path => match lang {
244            Language::Python => "str".to_string(),
245            Language::Node | Language::Wasm => "string".to_string(),
246            Language::Go => "string".to_string(),
247            Language::Java => "String".to_string(),
248            Language::Csharp => "string".to_string(),
249            Language::Ruby => "String".to_string(),
250            Language::Php => "string".to_string(),
251            Language::Elixir => "String.t()".to_string(),
252            Language::R => "character".to_string(),
253            Language::Rust => "PathBuf".to_string(),
254            Language::Ffi | Language::C | Language::Jni => "const char*".to_string(),
255            Language::Kotlin | Language::KotlinAndroid => "Path".to_string(),
256            Language::Swift => "URL".to_string(),
257            Language::Dart => "String".to_string(),
258            Language::Gleam => "String".to_string(),
259            Language::Zig => "[:0]const u8".to_string(),
260        },
261        TypeRef::Unit => match lang {
262            Language::Python => "None".to_string(),
263            Language::Node | Language::Wasm => "void".to_string(),
264            Language::Go => "".to_string(),
265            Language::Java => "void".to_string(),
266            Language::Csharp => "void".to_string(),
267            Language::Ruby => "nil".to_string(),
268            Language::Php => "void".to_string(),
269            Language::Elixir => ":ok".to_string(),
270            Language::R => "NULL".to_string(),
271            Language::Rust => "()".to_string(),
272            Language::Ffi | Language::C | Language::Jni => "void".to_string(),
273            Language::Kotlin | Language::KotlinAndroid => "Unit".to_string(),
274            Language::Swift => "Void".to_string(),
275            Language::Dart => "void".to_string(),
276            Language::Gleam => "Nil".to_string(),
277            Language::Zig => "void".to_string(),
278        },
279        TypeRef::Json => match lang {
280            Language::Python => "dict[str, Any]".to_string(),
281            Language::Node | Language::Wasm => "unknown".to_string(),
282            Language::Go => "interface{}".to_string(),
283            Language::Java => "Object".to_string(),
284            Language::Csharp => "object".to_string(),
285            Language::Ruby => "Object".to_string(),
286            Language::Php => "mixed".to_string(),
287            Language::Elixir => "term()".to_string(),
288            Language::R => "list".to_string(),
289            Language::Rust => "serde_json::Value".to_string(),
290            Language::Ffi | Language::C | Language::Jni => "void*".to_string(),
291            Language::Kotlin | Language::KotlinAndroid => "Any".to_string(),
292            // Swift and Dart mappers return "String" — JSON is passed serialized.
293            Language::Swift => "String".to_string(),
294            Language::Dart => "String".to_string(),
295            // Gleam and Zig backends serialize JSON as a string (the Mappers
296            // return "String" / "[:0]const u8"); doc names must match.
297            Language::Gleam => "String".to_string(),
298            // Zig backend serializes JSON as a string (the Mapper
299            // returns "[:0]const u8"); doc name must match.
300            Language::Zig => "[:0]const u8".to_string(),
301        },
302        TypeRef::Duration => match lang {
303            Language::Python => "float".to_string(),
304            Language::Node | Language::Wasm => "number".to_string(),
305            Language::Go => "time.Duration".to_string(),
306            Language::Java => "Duration".to_string(),
307            Language::Csharp => "TimeSpan".to_string(),
308            Language::Ruby => "Float".to_string(),
309            Language::Php => "float".to_string(),
310            Language::Elixir => "integer()".to_string(),
311            Language::R => "numeric".to_string(),
312            Language::Rust => "std::time::Duration".to_string(),
313            Language::Ffi | Language::C | Language::Jni => "uint64_t".to_string(),
314            Language::Kotlin | Language::KotlinAndroid => "Duration".to_string(),
315            Language::Swift => "Duration".to_string(),
316            Language::Dart => "Duration".to_string(),
317            Language::Gleam => "Int".to_string(),
318            Language::Zig => "i64".to_string(),
319        },
320    }
321}
322
323pub(crate) fn doc_primitive(p: &PrimitiveType, lang: Language) -> String {
324    match lang {
325        Language::Python => match p {
326            PrimitiveType::Bool => "bool".to_string(),
327            PrimitiveType::F32 | PrimitiveType::F64 => "float".to_string(),
328            _ => "int".to_string(),
329        },
330        Language::Node | Language::Wasm => match p {
331            PrimitiveType::Bool => "boolean".to_string(),
332            _ => "number".to_string(),
333        },
334        Language::Go => match p {
335            PrimitiveType::Bool => "bool".to_string(),
336            PrimitiveType::U8 => "uint8".to_string(),
337            PrimitiveType::U16 => "uint16".to_string(),
338            PrimitiveType::U32 => "uint32".to_string(),
339            PrimitiveType::U64 => "uint64".to_string(),
340            PrimitiveType::I8 => "int8".to_string(),
341            PrimitiveType::I16 => "int16".to_string(),
342            PrimitiveType::I32 => "int32".to_string(),
343            PrimitiveType::I64 => "int64".to_string(),
344            PrimitiveType::F32 => "float32".to_string(),
345            PrimitiveType::F64 => "float64".to_string(),
346            PrimitiveType::Usize | PrimitiveType::Isize => "int".to_string(),
347        },
348        Language::Java => match p {
349            PrimitiveType::Bool => "boolean".to_string(),
350            PrimitiveType::U8 | PrimitiveType::I8 => "byte".to_string(),
351            PrimitiveType::U16 | PrimitiveType::I16 => "short".to_string(),
352            PrimitiveType::U32 | PrimitiveType::I32 => "int".to_string(),
353            PrimitiveType::U64 | PrimitiveType::I64 | PrimitiveType::Usize | PrimitiveType::Isize => "long".to_string(),
354            PrimitiveType::F32 => "float".to_string(),
355            PrimitiveType::F64 => "double".to_string(),
356        },
357        Language::Csharp => match p {
358            PrimitiveType::Bool => "bool".to_string(),
359            PrimitiveType::U8 => "byte".to_string(),
360            PrimitiveType::U16 => "ushort".to_string(),
361            PrimitiveType::U32 => "uint".to_string(),
362            PrimitiveType::U64 => "ulong".to_string(),
363            PrimitiveType::I8 => "sbyte".to_string(),
364            PrimitiveType::I16 => "short".to_string(),
365            PrimitiveType::I32 => "int".to_string(),
366            PrimitiveType::I64 => "long".to_string(),
367            PrimitiveType::Usize => "nuint".to_string(),
368            PrimitiveType::Isize => "nint".to_string(),
369            PrimitiveType::F32 => "float".to_string(),
370            PrimitiveType::F64 => "double".to_string(),
371        },
372        Language::Ruby => match p {
373            PrimitiveType::Bool => "Boolean".to_string(),
374            PrimitiveType::F32 | PrimitiveType::F64 => "Float".to_string(),
375            _ => "Integer".to_string(),
376        },
377        Language::Php => match p {
378            PrimitiveType::Bool => "bool".to_string(),
379            PrimitiveType::F32 | PrimitiveType::F64 => "float".to_string(),
380            _ => "int".to_string(),
381        },
382        Language::Elixir => match p {
383            PrimitiveType::Bool => "boolean()".to_string(),
384            PrimitiveType::F32 | PrimitiveType::F64 => "float()".to_string(),
385            _ => "integer()".to_string(),
386        },
387        Language::R => match p {
388            PrimitiveType::Bool => "logical".to_string(),
389            PrimitiveType::F32 | PrimitiveType::F64 => "numeric".to_string(),
390            _ => "integer".to_string(),
391        },
392        Language::Ffi | Language::C | Language::Jni => match p {
393            PrimitiveType::Bool => "bool".to_string(),
394            PrimitiveType::U8 => "uint8_t".to_string(),
395            PrimitiveType::U16 => "uint16_t".to_string(),
396            PrimitiveType::U32 => "uint32_t".to_string(),
397            PrimitiveType::U64 => "uint64_t".to_string(),
398            PrimitiveType::I8 => "int8_t".to_string(),
399            PrimitiveType::I16 => "int16_t".to_string(),
400            PrimitiveType::I32 => "int32_t".to_string(),
401            PrimitiveType::I64 => "int64_t".to_string(),
402            PrimitiveType::Usize => "uintptr_t".to_string(),
403            PrimitiveType::Isize => "intptr_t".to_string(),
404            PrimitiveType::F32 => "float".to_string(),
405            PrimitiveType::F64 => "double".to_string(),
406        },
407        Language::Rust => match p {
408            PrimitiveType::Bool => "bool".to_string(),
409            PrimitiveType::U8 => "u8".to_string(),
410            PrimitiveType::U16 => "u16".to_string(),
411            PrimitiveType::U32 => "u32".to_string(),
412            PrimitiveType::U64 => "u64".to_string(),
413            PrimitiveType::I8 => "i8".to_string(),
414            PrimitiveType::I16 => "i16".to_string(),
415            PrimitiveType::I32 => "i32".to_string(),
416            PrimitiveType::I64 => "i64".to_string(),
417            PrimitiveType::Usize => "usize".to_string(),
418            PrimitiveType::Isize => "isize".to_string(),
419            PrimitiveType::F32 => "f32".to_string(),
420            PrimitiveType::F64 => "f64".to_string(),
421        },
422        Language::Kotlin | Language::KotlinAndroid => match p {
423            PrimitiveType::Bool => "Boolean".to_string(),
424            PrimitiveType::U8 | PrimitiveType::I8 => "Byte".to_string(),
425            PrimitiveType::U16 | PrimitiveType::I16 => "Short".to_string(),
426            PrimitiveType::U32 | PrimitiveType::I32 => "Int".to_string(),
427            PrimitiveType::U64 | PrimitiveType::I64 | PrimitiveType::Usize | PrimitiveType::Isize => "Long".to_string(),
428            PrimitiveType::F32 => "Float".to_string(),
429            PrimitiveType::F64 => "Double".to_string(),
430        },
431        Language::Swift => match p {
432            PrimitiveType::Bool => "Bool".to_string(),
433            PrimitiveType::U8 => "UInt8".to_string(),
434            PrimitiveType::U16 => "UInt16".to_string(),
435            PrimitiveType::U32 => "UInt32".to_string(),
436            PrimitiveType::U64 | PrimitiveType::Usize => "UInt64".to_string(),
437            PrimitiveType::I8 => "Int8".to_string(),
438            PrimitiveType::I16 => "Int16".to_string(),
439            PrimitiveType::I32 => "Int32".to_string(),
440            PrimitiveType::I64 | PrimitiveType::Isize => "Int64".to_string(),
441            PrimitiveType::F32 => "Float".to_string(),
442            PrimitiveType::F64 => "Double".to_string(),
443        },
444        Language::Dart => match p {
445            PrimitiveType::Bool => "bool".to_string(),
446            PrimitiveType::F32 | PrimitiveType::F64 => "double".to_string(),
447            _ => "int".to_string(),
448        },
449        Language::Gleam => match p {
450            PrimitiveType::Bool => "Bool".to_string(),
451            PrimitiveType::F32 | PrimitiveType::F64 => "Float".to_string(),
452            _ => "Int".to_string(),
453        },
454        Language::Zig => match p {
455            PrimitiveType::Bool => "bool".to_string(),
456            PrimitiveType::U8 => "u8".to_string(),
457            PrimitiveType::U16 => "u16".to_string(),
458            PrimitiveType::U32 => "u32".to_string(),
459            PrimitiveType::U64 => "u64".to_string(),
460            PrimitiveType::I8 => "i8".to_string(),
461            PrimitiveType::I16 => "i16".to_string(),
462            PrimitiveType::I32 => "i32".to_string(),
463            PrimitiveType::I64 => "i64".to_string(),
464            // ZigMapper deliberately uses fixed-width types for FFI stability.
465            PrimitiveType::Usize => "u64".to_string(),
466            PrimitiveType::Isize => "i64".to_string(),
467            PrimitiveType::F32 => "f32".to_string(),
468            PrimitiveType::F64 => "f64".to_string(),
469        },
470    }
471}
472
473/// Return the boxed (object) type for Java generics.
474///
475/// Java generics cannot use primitive types (`int`, `long`, etc.); they require
476/// the corresponding wrapper classes (`Integer`, `Long`, etc.).
477pub(crate) fn java_boxed_type(ty: &TypeRef) -> String {
478    match ty {
479        TypeRef::Primitive(p) => match p {
480            PrimitiveType::Bool => "Boolean".to_string(),
481            PrimitiveType::U8 | PrimitiveType::I8 => "Byte".to_string(),
482            PrimitiveType::U16 | PrimitiveType::I16 => "Short".to_string(),
483            PrimitiveType::U32 | PrimitiveType::I32 => "Integer".to_string(),
484            PrimitiveType::U64 | PrimitiveType::I64 | PrimitiveType::Usize | PrimitiveType::Isize => "Long".to_string(),
485            PrimitiveType::F32 => "Float".to_string(),
486            PrimitiveType::F64 => "Double".to_string(),
487        },
488        // Non-primitive types are already reference types in Java
489        _ => doc_type(ty, Language::Java, ""),
490    }
491}
492
493#[cfg(test)]
494mod tests;