1use verilization_compiler::{model, lang, util, for_sep};
2
3use model::Named;
4use crate::lang::{GeneratorError, Language, OutputHandler};
5use std::ffi::OsString;
6use std::collections::HashMap;
7use std::io::Write;
8use std::path::PathBuf;
9use num_bigint::BigUint;
10use lang::generator::*;
11use util::{capitalize_identifier, uncapitalize_identifier};
12use num_traits::ToPrimitive;
13
14type PackageMap = HashMap<model::PackageName, model::PackageName>;
15type ExternMap = HashMap<model::QualifiedName, model::QualifiedName>;
16const RUNTIME_PACKAGE: &str = "dev.argon.verilization.runtime";
17
18
19pub struct JavaOptionsBuilder {
20 output_dir: Option<OsString>,
21 package_mapping: PackageMap,
22 library_mapping: PackageMap,
23 extern_mapping: ExternMap,
24}
25
26pub struct JavaOptions {
27 pub output_dir: OsString,
28 pub package_mapping: PackageMap,
29 pub library_mapping: PackageMap,
30 pub extern_mapping: ExternMap,
31}
32
33fn make_type_name(name: &str) -> String {
34 let mut name = String::from(name);
35 capitalize_identifier(&mut name);
36 name
37}
38
39fn make_field_name(field_name: &str) -> String {
40 let mut name = String::from(field_name);
41 uncapitalize_identifier(&mut name);
42 name
43}
44
45
46fn java_package_impl<'opt>(options: &'opt JavaOptions, package: &model::PackageName) -> Result<&'opt model::PackageName, GeneratorError> {
47 options.package_mapping.get(&package)
48 .or_else(|| options.library_mapping.get(&package))
49 .ok_or_else(|| GeneratorError::UnmappedPackage(package.clone()))
50}
51
52fn open_java_file<'output, Output: OutputHandler<'output>>(options: &JavaOptions, output: &'output mut Output, name: &model::QualifiedName) -> Result<Output::FileHandle, GeneratorError> {
53 let java_pkg = java_package_impl(options, &name.package)?;
54 let mut path = PathBuf::from(&options.output_dir);
55 for part in &java_pkg.package {
56 path.push(part);
57 }
58
59 path.push(make_type_name(&name.name) + ".java");
60 Ok(output.create_file(path)?)
61}
62
63pub trait JavaGenerator<'model, 'opt> : Generator<'model> + GeneratorWithFile {
64 fn options(&self) -> &'opt JavaOptions;
65 fn referenced_types(&self) -> model::ReferencedTypeIterator<'model>;
66
67 fn java_package(&self, package: &model::PackageName) -> Result<&'opt model::PackageName, GeneratorError> {
68 java_package_impl(self.options(), package)
69 }
70
71 fn write_package(&mut self, package: &model::PackageName) -> Result<(), GeneratorError> {
72
73 let pkg = self.java_package(package)?;
74
75 let mut pkg_iter = pkg.package.iter();
76
77 if let Some(part) = pkg_iter.next() {
78 write!(self.file(), "package {}", part)?;
79 while let Some(part) = pkg_iter.next() {
80 write!(self.file(), ".{}", part)?;
81 }
82 writeln!(self.file(), ";")?;
83 }
84
85 Ok(())
86 }
87
88 fn write_qual_name(&mut self, name: &model::QualifiedName) -> Result<(), GeneratorError> {
89 let pkg = self.java_package(&name.package)?;
90 for part in &pkg.package {
91 write!(self.file(), "{}.", part)?;
92 }
93
94 write!(self.file(), "{}", make_type_name(&name.name))?;
95
96 Ok(())
97 }
98
99 fn write_type_args(&mut self, args: &Vec<LangType<'model>>) -> Result<(), GeneratorError> {
100 if !args.is_empty() {
101 write!(self.file(), "<")?;
102 for_sep!(arg, args, { write!(self.file(), ", ")?; }, {
103 self.write_type(arg, true)?;
104 });
105 write!(self.file(), ">")?;
106
107 }
108
109 Ok(())
110 }
111
112 fn extern_type_name(&self, name: &model::QualifiedName, erased: bool) -> Result<model::QualifiedName, GeneratorError> {
113 Ok(if let Some(mapped_name) = self.options().extern_mapping.get(name) {
114 if erased {
115 match (&mapped_name.package.package[..], mapped_name.name.as_ref()) {
116 ([], "byte") => model::QualifiedName::from_parts(&["java", "lang"], "Byte"),
117 ([], "short") => model::QualifiedName::from_parts(&["java", "lang"], "Short"),
118 ([], "int") => model::QualifiedName::from_parts(&["java", "lang"], "Integer"),
119 ([], "long") => model::QualifiedName::from_parts(&["java", "lang"], "Long"),
120 ([], "float") => model::QualifiedName::from_parts(&["java", "lang"], "Float"),
121 ([], "double") => model::QualifiedName::from_parts(&["java", "lang"], "Double"),
122 ([], "boolean") => model::QualifiedName::from_parts(&["java", "lang"], "Boolean"),
123 ([], "char") => model::QualifiedName::from_parts(&["java", "lang"], "Character"),
124 _ => mapped_name.clone(),
125 }
126 }
127 else {
128 mapped_name.clone()
129 }
130 }
131 else {
132 model::QualifiedName {
133 package: self.java_package(&name.package)?.clone(),
134 name: make_type_name(&name.name),
135 }
136 })
137 }
138
139 fn write_type(&mut self, t: &LangType<'model>, erased: bool) -> Result<(), GeneratorError> {
140 Ok(match t {
141 LangType::Versioned(_, name, version, args, _) => {
142 self.write_qual_name(name)?;
143 write!(self.file(), ".V{}", version)?;
144 self.write_type_args(args)?;
145 },
146
147 LangType::Extern(name, args, _) => {
148 let mapped_name = self.extern_type_name(name, erased)?;
149
150 for part in &mapped_name.package.package {
151 write!(self.file(), "{}.", part)?;
152 }
153
154 write!(self.file(), "{}", mapped_name.name)?;
155
156
157 self.write_type_args(args)?;
158 },
159
160 LangType::TypeParameter(name) => {
161 write!(self.file(), "{}", name)?;
162 },
163
164 LangType::Converter(from, to) => {
165 write!(self.file(), "{}.Converter<", RUNTIME_PACKAGE)?;
166 self.write_type(&*from, true)?;
167 write!(self.file(), ", ")?;
168 self.write_type(&*to, true)?;
169 write!(self.file(), ">")?;
170 },
171
172 LangType::Codec(t) => {
173 write!(self.file(), "{}.Codec<", RUNTIME_PACKAGE)?;
174 self.write_type(&*t, true)?;
175 write!(self.file(), ">")?;
176 },
177 })
178 }
179
180 fn write_args(&mut self, args: &Vec<LangExpr<'model>>) -> Result<(), GeneratorError> {
181 if !args.is_empty() {
182 write!(self.file(), "(")?;
183 for_sep!(arg, args, { write!(self.file(), ", ")?; }, {
184 self.write_expr(&arg)?;
185 });
186 write!(self.file(), ")")?;
187 }
188
189 Ok(())
190 }
191
192 fn write_operation_name(&mut self, op: &Operation) -> Result<(), GeneratorError> {
193 match op {
194 Operation::FromPreviousVersion(prev_ver) => write!(self.file(), "fromV{}", prev_ver)?,
195 Operation::FinalTypeConverter => write!(self.file(), "converter")?,
196 Operation::TypeCodec => write!(self.file(), "codec")?,
197 Operation::FromInteger => write!(self.file(), "fromInteger")?,
198 Operation::FromString => write!(self.file(), "fromString")?,
199 Operation::FromSequence => write!(self.file(), "fromSequence")?,
200 Operation::FromRecord(_) => write!(self.file(), "fromRecord")?,
201 Operation::FromCase(name) => write!(self.file(), "fromCase{}", make_type_name(name))?,
202 }
203
204 Ok(())
205 }
206
207 fn write_expr(&mut self, expr: &LangExpr<'model>) -> Result<(), GeneratorError> {
208 match expr {
209 LangExpr::Identifier(name) => write!(self.file(), "{}", name)?,
210 LangExpr::IntegerLiteral(n) => {
211 if let Some(n) = n.to_i32() {
212 write!(self.file(), "{}", n)?;
213 }
214 else if let Some(n) = n.to_i64() {
215 write!(self.file(), "{}L", n)?;
216 }
217 else {
218 write!(self.file(), "java.math.BigInteger.valueOf(\"{}\")", n)?;
219 }
220 },
221 LangExpr::StringLiteral(s) => {
222 write!(self.file(), "\"")?;
223 for codepoint in s.chars() {
224 match codepoint {
225 '"' => write!(self.file(), "\\\"")?,
226 '\\' => write!(self.file(), "\\\\")?,
227 '\n' => write!(self.file(), "\\n")?,
228 '\r' => write!(self.file(), "\\r")?,
229 _ => write!(self.file(), "{}", codepoint)?,
230 }
231 }
232 write!(self.file(), "\"")?;
233 },
234 LangExpr::InvokeConverter { converter, value } => {
235 self.write_expr(&*converter)?;
236 write!(self.file(), ".convert(")?;
237 self.write_expr(&*value)?;
238 write!(self.file(), ")")?;
239 },
240 LangExpr::IdentityConverter(t) => {
241 write!(self.file(), "{}.Converter.<", RUNTIME_PACKAGE)?;
242 self.write_type(t, true)?;
243 write!(self.file(), ">identity()")?;
244 },
245 LangExpr::ReadDiscriminator => write!(self.file(), "{}.Nat.codec.read(reader)", RUNTIME_PACKAGE)?,
246 LangExpr::WriteDiscriminator(value) => write!(self.file(), "{}.Nat.codec.write(writer, java.math.BigInteger.valueOf({}))", RUNTIME_PACKAGE, value)?,
247 LangExpr::CodecRead { codec } => {
248 self.write_expr(&*codec)?;
249 write!(self.file(), ".read(reader)")?;
250 },
251 LangExpr::CodecWrite { codec, value } => {
252 self.write_expr(&*codec)?;
253 write!(self.file(), ".write(writer, ")?;
254 self.write_expr(value)?;
255 write!(self.file(), ")")?;
256 },
257 LangExpr::InvokeOperation(op, target, type_args, args) => {
258 match target {
259 OperationTarget::VersionedType(name, version) => {
260 self.write_qual_name(name)?;
261 write!(self.file(), ".V{}.", version)?;
262 },
263 OperationTarget::ExternType(name) => {
264 self.write_qual_name(name)?;
265 write!(self.file(), ".")?;
266 },
267 }
268 self.write_type_args(type_args)?;
269 self.write_operation_name(op)?;
270 self.write_args(args)?;
271 },
272 LangExpr::InvokeUserConverter { name, prev_ver, version, type_args, args } => {
273 self.write_qual_name(name)?;
274 write!(self.file(), "_Conversions.")?;
275 self.write_type_args(type_args)?;
276 write!(self.file(), "v{}ToV{}", prev_ver, version)?;
277 self.write_args(args)?;
278 },
279 LangExpr::ConstantValue(name, version) => {
280 self.write_qual_name(name)?;
281 write!(self.file(), ".{}", JavaLanguage::constant_version_name(version))?;
282 },
283 LangExpr::CreateStruct(name, version, type_args, fields) => {
284 write!(self.file(), "new ")?;
285 self.write_qual_name(name)?;
286 write!(self.file(), ".V{}", version)?;
287 self.write_type_args(type_args)?;
288 write!(self.file(), "(")?;
289 for_sep!((_, value), fields, { write!(self.file(), ", ")?; }, {
290 self.write_expr(value)?;
291 });
292 write!(self.file(), ")")?;
293 },
294 LangExpr::CreateEnum(name, version, type_args, field_name, value) => {
295 write!(self.file(), "new ")?;
296 self.write_qual_name(name)?;
297 write!(self.file(), ".V{}.{}", version, make_type_name(field_name))?;
298 self.write_type_args(type_args)?;
299 write!(self.file(), "(")?;
300 self.write_expr(value)?;
301 write!(self.file(), ")")?;
302 },
303 LangExpr::StructField(_, _, field_name, value) => {
304 self.write_expr(value)?;
305 write!(self.file(), ".{}", make_field_name(field_name))?;
306 },
307 }
308
309 Ok(())
310 }
311}
312
313impl GeneratorNameMapping for JavaLanguage {
314 fn convert_prev_type_param(param: &str) -> String {
315 format!("{}_1", param)
316 }
317
318 fn convert_current_type_param(param: &str) -> String {
319 format!("{}_2", param)
320 }
321
322 fn convert_conv_param_name(param: &str) -> String {
323 format!("{}_conv", param)
324 }
325
326 fn convert_prev_param_name() -> &'static str {
327 "prev"
328 }
329
330 fn codec_write_value_name() -> &'static str {
331 "value"
332 }
333
334 fn codec_codec_param_name(param: &str) -> String {
335 format!("{}_codec", param)
336 }
337
338 fn constant_version_name(version: &BigUint) -> String {
339 format!("v{}", version)
340 }
341}
342
343
344struct JavaConstGenerator<'model, 'opt, 'output, Output: OutputHandler<'output>> {
345 file: Output::FileHandle,
346 model: &'model model::Verilization,
347 options: &'opt JavaOptions,
348 constant: Named<'model, model::Constant>,
349 scope: model::Scope<'model>,
350}
351
352impl <'model, 'opt, 'output, Output: OutputHandler<'output>> Generator<'model> for JavaConstGenerator<'model, 'opt, 'output, Output> {
353 type Lang = JavaLanguage;
354
355 fn model(&self) -> &'model model::Verilization {
356 self.model
357 }
358
359 fn scope(&self) -> &model::Scope<'model> {
360 &self.scope
361 }
362}
363
364impl <'model, 'opt, 'output, Output: OutputHandler<'output>> GeneratorWithFile for JavaConstGenerator<'model, 'opt, 'output, Output> {
365 type GeneratorFile = Output::FileHandle;
366 fn file(&mut self) -> &mut Self::GeneratorFile {
367 &mut self.file
368 }
369}
370
371impl <'model, 'opt, 'output, Output: OutputHandler<'output>> JavaGenerator<'model, 'opt> for JavaConstGenerator<'model, 'opt, 'output, Output> {
372 fn options(&self) -> &'opt JavaOptions {
373 self.options
374 }
375
376 fn referenced_types(&self) -> model::ReferencedTypeIterator<'model> {
377 self.constant.referenced_types()
378 }
379}
380
381impl <'model, 'opt, 'output, Output: OutputHandler<'output>> ConstGenerator<'model> for JavaConstGenerator<'model, 'opt, 'output, Output> {
382 fn constant(&self) -> Named<'model, model::Constant> {
383 self.constant
384 }
385
386 fn write_header(&mut self) -> Result<(), GeneratorError> {
387 self.write_package(&self.constant.name().package)?;
388
389 writeln!(self.file, "public final class {} {{", make_type_name(&self.constant.name().name))?;
390 writeln!(self.file, "\tprivate {}() {{}}", make_type_name(&self.constant.name().name))?;
391
392 Ok(())
393 }
394
395 fn write_constant(&mut self, version_name: String, t: LangType<'model>, value: LangExpr<'model>) -> Result<(), GeneratorError> {
396 write!(self.file, "\tpublic static final ")?;
397 self.write_type(&t, false)?;
398 write!(self.file, " {} = ", version_name)?;
399 self.write_expr(&value)?;
400 writeln!(self.file, ";")?;
401
402 Ok(())
403 }
404
405 fn write_footer(&mut self) -> Result<(), GeneratorError> {
406 writeln!(self.file, "}}")?;
407 Ok(())
408 }
409}
410
411impl <'model, 'opt, 'output, Output: OutputHandler<'output>> JavaConstGenerator<'model, 'opt, 'output, Output> {
412
413 fn open(model: &'model model::Verilization, options: &'opt JavaOptions, output: &'output mut Output, constant: Named<'model, model::Constant>) -> Result<Self, GeneratorError> {
414 let file = open_java_file(options, output, constant.name())?;
415 Ok(JavaConstGenerator {
416 file: file,
417 model: model,
418 options: options,
419 constant: constant,
420 scope: constant.scope(),
421 })
422 }
423}
424
425struct JavaTypeGenerator<'model, 'opt, 'output, Output: OutputHandler<'output>> {
426 file: Output::FileHandle,
427 model: &'model model::Verilization,
428 options: &'opt JavaOptions,
429 type_def: Named<'model, model::VersionedTypeDefinitionData>,
430 scope: model::Scope<'model>,
431 indentation_level: u32,
432}
433
434impl <'model, 'opt, 'output, Output: OutputHandler<'output>> Generator<'model> for JavaTypeGenerator<'model, 'opt, 'output, Output> {
435 type Lang = JavaLanguage;
436
437 fn model(&self) -> &'model model::Verilization {
438 self.model
439 }
440
441 fn scope(&self) -> &model::Scope<'model> {
442 &self.scope
443 }
444}
445
446impl <'model, 'opt, 'output, Output: OutputHandler<'output>> GeneratorWithFile for JavaTypeGenerator<'model, 'opt, 'output, Output> {
447 type GeneratorFile = Output::FileHandle;
448 fn file(&mut self) -> &mut Self::GeneratorFile {
449 &mut self.file
450 }
451}
452
453impl <'model, 'opt, 'output, Output: OutputHandler<'output>> Indentation for JavaTypeGenerator<'model, 'opt, 'output, Output> {
454 fn indentation_size(&mut self) -> &mut u32 {
455 &mut self.indentation_level
456 }
457}
458
459impl <'model, 'opt, 'output, Output: OutputHandler<'output>> JavaGenerator<'model, 'opt> for JavaTypeGenerator<'model, 'opt, 'output, Output> {
460 fn options(&self) -> &'opt JavaOptions {
461 self.options
462 }
463
464 fn referenced_types(&self) -> model::ReferencedTypeIterator<'model> {
465 self.type_def.referenced_types()
466 }
467}
468
469impl <'model, 'opt, 'output, Output: OutputHandler<'output>> VersionedTypeGenerator<'model> for JavaTypeGenerator<'model, 'opt, 'output, Output> {
470 fn type_def(&self) -> Named<'model, model::VersionedTypeDefinitionData> {
471 self.type_def
472 }
473
474 fn write_header(&mut self) -> Result<(), GeneratorError> {
475 self.write_package(&self.type_def.name().package)?;
476 writeln!(self.file, "public abstract class {} {{", make_type_name(&self.type_def.name().name))?;
477 self.indent_increase();
478 self.write_indent()?;
479 writeln!(self.file, "private {}() {{}}", make_type_name(&self.type_def.name().name))?;
480
481 Ok(())
482 }
483
484 fn write_version_header(&mut self, t: LangType<'model>) -> Result<(), GeneratorError> {
485 self.write_indent()?;
486
487
488 match &t {
489 LangType::Versioned(VersionedTypeKind::Struct, _, version, _, _) => write!(self.file, "public static final class V{}", version)?,
490 LangType::Versioned(VersionedTypeKind::Enum, _, version, _, _) => write!(self.file, "public static abstract class V{}", version)?,
491 _ => return Err(GeneratorError::CouldNotGenerateType)
492 }
493
494 self.write_type_params(self.type_def().type_params())?;
495 writeln!(self.file, " extends {} {{", self.type_def.name().name)?;
496 self.indent_increase();
497
498 match t {
499 LangType::Versioned(VersionedTypeKind::Struct, _, version, _, fields) => {
500 self.write_indent()?;
501 write!(self.file, "public V{}(", version)?;
502
503 let fields = fields.build()?;
504
505 for_sep!(field, &fields, { write!(self.file, ",")?; }, {
506 self.write_type(&field.field_type, false)?;
507 write!(self.file, " {}", make_field_name(field.name))?;
508 });
509
510 writeln!(self.file, ") {{")?;
511 self.indent_increase();
512
513 for field in &fields {
514 self.write_indent()?;
515 writeln!(self.file, "this.{} = {};", make_field_name(field.name), make_field_name(field.name))?;
516 }
517
518 self.indent_decrease();
519 self.write_indent()?;
520 writeln!(self.file, "}}")?;
521
522 for field in &fields {
523 self.write_indent()?;
524 write!(self.file, "public final ")?;
525 self.write_type(&field.field_type, false)?;
526 writeln!(self.file, " {};", make_field_name(field.name))?;
527 }
528
529 self.write_indent()?;
530 writeln!(self.file, "@Override")?;
531
532 self.write_indent()?;
533 writeln!(self.file, "public int hashCode() {{")?;
534 self.indent_increase();
535
536 self.write_indent()?;
537 write!(self.file, "return java.util.Objects.hash(")?;
538 for_sep!(field, &fields, { write!(self.file, ", ")?; }, {
539 write!(self.file, "{}", make_field_name(field.name))?;
540 });
541 writeln!(self.file, ");")?;
542 self.indent_decrease();
543 self.write_indent()?;
544 writeln!(self.file, "}}")?;
545
546 self.write_indent()?;
547 writeln!(self.file, "@Override")?;
548 self.write_indent()?;
549 writeln!(self.file, "public boolean equals(Object obj) {{")?;
550 self.indent_increase();
551 self.write_indent()?;
552 writeln!(self.file, "if(!(obj instanceof V{})) return false;", version)?;
553 self.write_indent()?;
554 writeln!(self.file, "V{} other = (V{})obj;", version, version)?;
555 for field in &fields {
556 self.write_indent()?;
557 writeln!(self.file, "if(!java.util.Objects.deepEquals(this.{}, other.{})) return false;", make_field_name(field.name), make_field_name(field.name))?;
558 }
559 self.write_indent()?;
560 writeln!(self.file, "return true;")?;
561 self.indent_decrease();
562 self.write_indent()?;
563 writeln!(self.file, "}}")?;
564 },
565 LangType::Versioned(VersionedTypeKind::Enum, _, version, _, fields) => {
566 self.write_indent()?;
567 writeln!(self.file, "private V{}() {{}}", version)?;
568
569 let fields = fields.build()?;
570
571 for (index, field) in fields.iter().enumerate() {
572 self.write_indent()?;
573 write!(self.file, "public static final class {}", make_type_name(field.name))?;
574 self.write_type_params(self.type_def().type_params())?;
575 write!(self.file, " extends V{}", version)?;
576 self.write_type_params(self.type_def().type_params())?;
577 writeln!(self.file, " {{")?;
578
579 self.indent_increase();
580 self.write_indent()?;
581 write!(self.file, "public {}(", make_type_name(field.name))?;
582 self.write_type(&field.field_type, false)?;
583 writeln!(self.file, " {}) {{", make_field_name(field.name))?;
584 self.indent_increase();
585 self.write_indent()?;
586 writeln!(self.file, "this.{} = {};", make_field_name(field.name), make_field_name(field.name))?;
587 self.indent_decrease();
588 self.write_indent()?;
589 writeln!(self.file, "}}")?;
590 self.write_indent()?;
591 write!(self.file, "public final ")?;
592 self.write_type(&field.field_type, false)?;
593 writeln!(self.file, " {};", make_field_name(field.name))?;
594
595 self.write_indent()?;
596 writeln!(self.file, "@Override")?;
597 self.write_indent()?;
598 writeln!(self.file, "public int hashCode() {{")?;
599 self.indent_increase();
600 self.write_indent()?;
601 writeln!(self.file, "return java.util.Objects.hash({}, this.{});", index, make_field_name(field.name))?;
602 self.indent_decrease();
603 self.write_indent()?;
604 writeln!(self.file, "}}")?;
605
606 self.write_indent()?;
607 writeln!(self.file, "@Override")?;
608 self.write_indent()?;
609 writeln!(self.file, "public boolean equals(Object obj) {{")?;
610 self.indent_increase();
611 self.write_indent()?;
612 writeln!(self.file, "if(!(obj instanceof {})) return false;", make_type_name(field.name))?;
613 self.write_indent()?;
614 writeln!(self.file, "{} other = ({})obj;", make_type_name(field.name), make_type_name(field.name))?;
615 self.write_indent()?;
616 writeln!(self.file, "return java.util.Objects.deepEquals(this.{}, other.{});", make_field_name(field.name), make_field_name(field.name))?;
617 self.indent_decrease();
618 self.write_indent()?;
619 writeln!(self.file, "}}")?;
620
621 self.indent_decrease();
622 self.write_indent()?;
623 writeln!(self.file, "}}")?;
624 }
625 },
626 _ => return Err(GeneratorError::CouldNotGenerateType)
627 }
628
629 Ok(())
630 }
631
632 fn write_operation(&mut self, operation: OperationInfo<'model>) -> Result<(), GeneratorError> {
633 let is_func = !operation.type_params.is_empty() || !operation.params.is_empty();
634
635 self.write_indent()?;
636 write!(self.file, "public static ")?;
637 if !is_func {
638 write!(self.file, "final ")?;
639 }
640 self.write_type_params(&operation.type_params)?;
641 if !operation.type_params.is_empty() {
642 write!(self.file, " ")?;
643 }
644
645 self.write_type(&operation.result, false)?;
646 write!(self.file, " ")?;
647
648 self.write_operation_name(&operation.operation)?;
649
650 if is_func {
651 write!(self.file, "(")?;
652 for_sep!((param_name, param), operation.params, { write!(self.file, ", ")?; }, {
653 self.write_type(¶m, true)?;
654 write!(self.file, " {}", param_name)?;
655 });
656 writeln!(self.file, ") {{")?;
657 self.indent_increase();
658 }
659 else {
660 write!(self.file, " = ")?;
661 }
662
663 self.write_expr_statement(&operation.implementation, !is_func)?;
664
665 if is_func {
666 self.indent_decrease();
667 self.write_indent()?;
668 writeln!(self.file, "}}")?;
669 }
670
671 Ok(())
672 }
673
674 fn write_version_footer(&mut self) -> Result<(), GeneratorError> {
675 self.indent_decrease();
676 writeln!(self.file, "}}")?;
677
678 Ok(())
679 }
680
681 fn write_footer(&mut self) -> Result<(), GeneratorError> {
682 self.indent_decrease();
683 writeln!(self.file, "}}")?;
684
685 Ok(())
686 }
687
688}
689
690
691fn write_enum_case_type<'model, 'opt, Gen>(gen: &mut Gen, value_type: &LangType<'model>, case_name: &str, wildcard: bool) -> Result<(), GeneratorError> where
692 Gen : JavaGenerator<'model, 'opt> + GeneratorWithFile
693{
694 match value_type {
695 LangType::Versioned(VersionedTypeKind::Enum, name, version, args, _) => {
696 gen.write_qual_name(name)?;
697 write!(gen.file(), ".V{}.{}", version, make_type_name(case_name))?;
698 if !args.is_empty() {
699 write!(gen.file(), "<")?;
700 for_sep!(arg, args, { write!(gen.file(), ", ")?; }, {
701 if wildcard {
702 write!(gen.file(), "?")?;
703 }
704 else {
705 gen.write_type(arg, true)?;
706 }
707 });
708 write!(gen.file(), ">")?;
709 }
710 },
711 _ => panic!("Invalid enum type."),
712 }
713
714 Ok(())
715}
716
717impl <'model, 'opt, 'output, Output: OutputHandler<'output>> JavaTypeGenerator<'model, 'opt, 'output, Output> {
718
719
720 fn open(model: &'model model::Verilization, options: &'opt JavaOptions, output: &'output mut Output, type_def: Named<'model, model::VersionedTypeDefinitionData>) -> Result<Self, GeneratorError> {
721 let file = open_java_file(options, output, type_def.name())?;
722 Ok(JavaTypeGenerator {
723 file: file,
724 model: model,
725 options: options,
726 type_def: type_def,
727 scope: type_def.scope(),
728 indentation_level: 0,
729 })
730 }
731
732 fn write_expr_statement(&mut self, stmt: &LangExprStmt<'model>, is_expr: bool) -> Result<(), GeneratorError> {
733 if !is_expr {
734 self.write_indent()?;
735 write!(self.file, "return ")?;
736 }
737
738 match stmt {
739 LangExprStmt::Expr(expr) => {
740 self.write_expr(expr)?;
741 writeln!(self.file, ";")?;
742 },
743
744 LangExprStmt::CreateCodec { t, read, write } => {
745 write!(self.file, "new {}.Codec<", RUNTIME_PACKAGE)?;
746 self.write_type(t, true)?;
747 writeln!(self.file, ">() {{")?;
748 self.indent_increase();
749
750
751 self.write_indent()?;
752 writeln!(self.file, "@Override")?;
753
754 self.write_indent()?;
755 write!(self.file, "public ")?;
756 self.write_type(t, true)?;
757 writeln!(self.file, " read({}.FormatReader reader) throws java.io.IOException {{", RUNTIME_PACKAGE)?;
758 self.indent_increase();
759
760 self.write_statement(read)?;
761
762 self.indent_decrease();
763 self.write_indent()?;
764 writeln!(self.file, "}}")?;
765
766 self.write_indent()?;
767 writeln!(self.file, "@Override")?;
768
769 self.write_indent()?;
770 write!(self.file, "public void write({}.FormatWriter writer, ", RUNTIME_PACKAGE)?;
771 self.write_type(t, true)?;
772 writeln!(self.file, " value) throws java.io.IOException {{")?;
773 self.indent_increase();
774
775 self.write_statement(write)?;
776
777 self.indent_decrease();
778 self.write_indent()?;
779 writeln!(self.file, "}}")?;
780
781 self.indent_decrease();
782 self.write_indent()?;
783 writeln!(self.file, "}};")?;
784 },
785
786 LangExprStmt::CreateConverter { from_type, to_type, body } => {
787 write!(self.file, "new {}.Converter<", RUNTIME_PACKAGE)?;
788 self.write_type(from_type, true)?;
789 write!(self.file, ", ")?;
790 self.write_type(to_type, true)?;
791 writeln!(self.file, ">() {{")?;
792 self.indent_increase();
793
794
795 self.write_indent()?;
796 writeln!(self.file, "@Override")?;
797
798 self.write_indent()?;
799 write!(self.file, "public ")?;
800 self.write_type(to_type, true)?;
801 write!(self.file, " convert(")?;
802 self.write_type(from_type, true)?;
803 writeln!(self.file, " {}) {{", JavaLanguage::convert_prev_param_name())?;
804 self.indent_increase();
805
806 self.write_statement(body)?;
807
808 self.indent_decrease();
809 self.write_indent()?;
810 writeln!(self.file, "}}")?;
811
812 self.indent_decrease();
813 self.write_indent()?;
814 writeln!(self.file, "}};")?;
815 },
816
817 }
818
819 Ok(())
820 }
821
822 fn write_statement(&mut self, stmt: &LangStmt<'model>) -> Result<(), GeneratorError> {
823 match stmt {
824 LangStmt::Expr(exprs, result_expr) => {
825 for expr in exprs {
826 self.write_indent()?;
827 self.write_expr(expr)?;
828 writeln!(self.file, ";")?;
829 }
830
831 if let Some(result_expr) = result_expr {
832 self.write_indent()?;
833 write!(self.file, "return ")?;
834 self.write_expr(result_expr)?;
835 writeln!(self.file, ";")?;
836 }
837 },
838
839 LangStmt::MatchEnum { value, value_type, cases } => {
840 self.write_indent()?;
841 for MatchCase { binding_name, case_name, body } in cases {
842 write!(self.file, "if(")?;
843 self.write_expr(value)?;
844 write!(self.file, " instanceof ")?;
845 write_enum_case_type(self, value_type, case_name, true)?;
846 writeln!(self.file, ") {{")?;
847 self.indent_increase();
848
849 self.write_indent()?;
850 write!(self.file, "var {} = ((", binding_name)?;
851 write_enum_case_type(self, value_type, case_name, false)?;
852 write!(self.file, ")")?;
853 self.write_expr(value)?;
854 writeln!(self.file, ").{};", make_field_name(case_name))?;
855
856 self.write_statement(body)?;
857
858 self.indent_decrease();
859 self.write_indent()?;
860 writeln!(self.file, "}}")?;
861
862 self.write_indent()?;
863 write!(self.file, "else ")?;
864 }
865 if !cases.is_empty() {
866 writeln!(self.file, "{{")?;
867 self.indent_increase();
868 self.write_indent()?;
869 }
870
871 writeln!(self.file, "throw new IllegalArgumentException();")?;
872
873 if !cases.is_empty() {
874 self.indent_decrease();
875 self.write_indent()?;
876 writeln!(self.file, "}}")?;
877 }
878 },
879
880 LangStmt::MatchDiscriminator { value, cases } => {
881 self.write_indent()?;
882 write!(self.file, "switch(")?;
883 self.write_expr(value)?;
884 writeln!(self.file, ".intValueExact()) {{")?;
885 self.indent_increase();
886
887 for (n, body) in cases {
888 self.write_indent()?;
889 writeln!(self.file, "case {}:", n)?;
890 self.write_indent()?;
891 writeln!(self.file, "{{")?;
892 self.indent_increase();
893
894 self.write_statement(body)?;
895
896
897 if !body.has_value() {
898 self.write_indent()?;
899 writeln!(self.file, "break;")?;
900 }
901 self.indent_decrease();
902
903 self.write_indent()?;
904 writeln!(self.file, "}}")?;
905 }
906
907 self.write_indent()?;
908 writeln!(self.file, "default: throw new java.io.IOException(\"Invalid tag number.\");")?;
909
910 self.indent_decrease();
911
912 self.write_indent()?;
913 writeln!(self.file, "}}")?;
914 },
915
916
917 }
918
919 Ok(())
920 }
921
922 fn write_type_params(&mut self, params: &Vec<String>) -> Result<(), GeneratorError> {
923 if !params.is_empty() {
924 write!(self.file, "<")?;
925 for_sep!(param, params, { write!(self.file, ", ")?; }, {
926 write!(self.file, "{}", param)?;
927 });
928 write!(self.file, ">")?;
929 }
930
931 Ok(())
932 }
933
934}
935
936
937pub struct JavaLanguage {}
938
939impl Language for JavaLanguage {
940 type OptionsBuilder = JavaOptionsBuilder;
941 type Options = JavaOptions;
942
943 fn name() -> &'static str {
944 "java"
945 }
946
947 fn empty_options() -> JavaOptionsBuilder {
948 JavaOptionsBuilder {
949 output_dir: None,
950 package_mapping: HashMap::new(),
951 library_mapping: HashMap::new(),
952 extern_mapping: HashMap::new(),
953 }
954 }
955
956 fn add_option(builder: &mut JavaOptionsBuilder, name: &str, value: OsString) -> Result<(), GeneratorError> {
957 if name == "out_dir" {
958 if builder.output_dir.is_some() {
959 return Err(GeneratorError::InvalidOptions(String::from("Output directory already specified")))
960 }
961
962 builder.output_dir = Some(value);
963 Ok(())
964 }
965 else if let Some(pkg) = name.strip_prefix("pkg:") {
966 let package = model::PackageName::from_str(pkg);
967
968 let java_package = model::PackageName::from_str(value.to_str().unwrap());
969
970 if builder.library_mapping.contains_key(&package) || builder.package_mapping.insert(package, java_package).is_some() {
971 return Err(GeneratorError::InvalidOptions(format!("Package already mapped: {}", pkg)))
972 }
973 Ok(())
974 }
975 else if let Some(pkg) = name.strip_prefix("lib:") {
976 let package = model::PackageName::from_str(pkg);
977
978 let java_package = model::PackageName::from_str(value.to_str().unwrap());
979
980 if builder.package_mapping.contains_key(&package) || builder.library_mapping.insert(package, java_package).is_some() {
981 return Err(GeneratorError::InvalidOptions(format!("Package already mapped: {}", pkg)))
982 }
983 Ok(())
984 }
985 else if let Some(extern_name) = name.strip_prefix("extern:") {
986 let qual_name = model::QualifiedName::from_str(extern_name).ok_or_else(|| GeneratorError::InvalidOptions(format!("Invalid extern type name: {}", extern_name)))?;
987
988 let java_name = model::QualifiedName::from_str(value.to_str().unwrap()).ok_or_else(|| GeneratorError::InvalidOptions(format!("Invalid Java type name: {}", value.to_str().unwrap())))?;
989
990 if builder.extern_mapping.insert(qual_name, java_name).is_some() {
991 return Err(GeneratorError::InvalidOptions(format!("Extern type already mapped: {}", extern_name)))
992 }
993
994 Ok(())
995 }
996 else {
997 Err(GeneratorError::InvalidOptions(format!("Unknown option: {}", name)))
998 }
999 }
1000
1001 fn finalize_options(builder: Self::OptionsBuilder) -> Result<Self::Options, GeneratorError> {
1002 Ok(JavaOptions {
1003 output_dir: builder.output_dir.ok_or_else(|| GeneratorError::InvalidOptions(String::from("Output directory not specified")))?,
1004 package_mapping: builder.package_mapping,
1005 library_mapping: builder.library_mapping,
1006 extern_mapping: builder.extern_mapping,
1007 })
1008 }
1009
1010 fn generate<Output : for<'output> OutputHandler<'output>>(model: &model::Verilization, options: Self::Options, output: &mut Output) -> Result<(), GeneratorError> {
1011 for constant in model.constants() {
1012 let mut const_gen = JavaConstGenerator::open(model, &options, output, constant)?;
1013 const_gen.generate()?;
1014 }
1015
1016 for t in model.types() {
1017 match t {
1018 model::NamedTypeDefinition::StructType(t) | model::NamedTypeDefinition::EnumType(t) => {
1019 let mut type_gen = JavaTypeGenerator::open(model, &options, output, t)?;
1020 type_gen.generate()?;
1021 },
1022 model::NamedTypeDefinition::ExternType(_) => (),
1023 }
1024 }
1025
1026 Ok(())
1027 }
1028
1029}