zerodds_lang_cst/java/mod.rs
1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2026 ZeroDDS Contributors
3//! The Java concrete syntax tree. Spec §1.
4//!
5//! Java has annotations, type parameters and a package per file. It has
6//! no free functions and no header/source split, so the tree has neither.
7
8use crate::common::{Doc, Ident, Literal, Path};
9use alloc::boxed::Box;
10use alloc::string::{String, ToString};
11use alloc::vec::Vec;
12
13/// A Java source file, which holds one public type.
14#[derive(Debug, Clone, Default, PartialEq, Eq)]
15pub struct File {
16 /// The leading comment.
17 pub doc: Doc,
18 /// The package, absent for the default package.
19 pub package: Option<Path>,
20 /// `import` lines, in written order.
21 pub imports: Vec<Import>,
22 /// Type declarations; the first is the file's public type.
23 pub types: Vec<TypeDecl>,
24}
25
26/// One `import`.
27#[derive(Debug, Clone, PartialEq, Eq)]
28pub struct Import {
29 /// What is imported.
30 pub path: Path,
31 /// Whether it is `import static`.
32 pub static_: bool,
33 /// Whether it ends in `.*`.
34 pub wildcard: bool,
35}
36
37/// One type declaration.
38#[derive(Debug, Clone, PartialEq, Eq)]
39pub enum TypeDecl {
40 /// `class Name { ... }`
41 Class(Class),
42 /// `interface Name { ... }`
43 Interface(Interface),
44 /// `enum Name { ... }`
45 Enum(Enum),
46 /// `record Name(..) { ... }`
47 Record(Record),
48 /// `@interface Name { ... }` — an annotation type.
49 AnnotationType(AnnotationType),
50 /// `@verbatim` text at file level, copied into the output unchanged.
51 ///
52 /// OMG IDL 4.2 §8.3.5.1: the annotation's `text` "shall be copied
53 /// verbatim" into the generated artifact — raw lines, never a
54 /// comment. One node per directive, lines split on `\n`.
55 Verbatim(String),
56}
57
58/// `class Name<T> extends B implements I { ... }`
59#[derive(Debug, Clone, PartialEq, Eq)]
60pub struct Class {
61 /// Documentation.
62 pub doc: Doc,
63 /// Annotations, in written order.
64 pub annotations: Vec<Annotation>,
65 /// Modifiers, in written order.
66 pub modifiers: Vec<Modifier>,
67 /// Name.
68 pub name: Ident,
69 /// Type parameters.
70 pub generics: Vec<TypeParam>,
71 /// The superclass.
72 pub extends: Option<Type>,
73 /// Interfaces implemented.
74 pub implements: Vec<Type>,
75 /// Members, in written order.
76 pub members: Vec<Member>,
77}
78
79/// `interface Name { ... }`
80#[derive(Debug, Clone, PartialEq, Eq)]
81pub struct Interface {
82 /// Documentation.
83 pub doc: Doc,
84 /// Annotations.
85 pub annotations: Vec<Annotation>,
86 /// Modifiers.
87 pub modifiers: Vec<Modifier>,
88 /// Name.
89 pub name: Ident,
90 /// Type parameters.
91 pub generics: Vec<TypeParam>,
92 /// Interfaces extended.
93 pub extends: Vec<Type>,
94 /// Members.
95 pub members: Vec<Member>,
96}
97
98/// `enum Name { A, B; ... }`
99#[derive(Debug, Clone, PartialEq, Eq)]
100pub struct Enum {
101 /// Documentation.
102 pub doc: Doc,
103 /// Annotations.
104 pub annotations: Vec<Annotation>,
105 /// Modifiers.
106 pub modifiers: Vec<Modifier>,
107 /// Name.
108 pub name: Ident,
109 /// Interfaces implemented.
110 pub implements: Vec<Type>,
111 /// The constants, in written order.
112 pub constants: Vec<EnumConstant>,
113 /// Members after the constants.
114 pub members: Vec<Member>,
115}
116
117/// One enum constant.
118#[derive(Debug, Clone, PartialEq, Eq)]
119pub struct EnumConstant {
120 /// Documentation.
121 pub doc: Doc,
122 /// Annotations.
123 pub annotations: Vec<Annotation>,
124 /// Name.
125 pub name: Ident,
126 /// Constructor arguments.
127 pub args: Vec<Expr>,
128 /// A class body, for a constant that overrides something.
129 pub body: Vec<Member>,
130}
131
132/// `record Name(components) { ... }`
133#[derive(Debug, Clone, PartialEq, Eq)]
134pub struct Record {
135 /// Documentation.
136 pub doc: Doc,
137 /// Annotations.
138 pub annotations: Vec<Annotation>,
139 /// Modifiers.
140 pub modifiers: Vec<Modifier>,
141 /// Name.
142 pub name: Ident,
143 /// Type parameters.
144 pub generics: Vec<TypeParam>,
145 /// Components, in written order.
146 pub components: Vec<Param>,
147 /// Interfaces implemented.
148 pub implements: Vec<Type>,
149 /// Members.
150 pub members: Vec<Member>,
151}
152
153/// `@interface Name { ... }`
154#[derive(Debug, Clone, PartialEq, Eq)]
155pub struct AnnotationType {
156 /// Documentation.
157 pub doc: Doc,
158 /// Annotations on it, such as `@Retention`.
159 pub annotations: Vec<Annotation>,
160 /// Modifiers.
161 pub modifiers: Vec<Modifier>,
162 /// Name.
163 pub name: Ident,
164 /// Its elements.
165 pub elements: Vec<AnnotationElement>,
166}
167
168/// One element of an annotation type.
169#[derive(Debug, Clone, PartialEq, Eq)]
170pub struct AnnotationElement {
171 /// Documentation.
172 pub doc: Doc,
173 /// Type.
174 pub type_: Type,
175 /// Name.
176 pub name: Ident,
177 /// `default value`, when written.
178 pub default: Option<Expr>,
179}
180
181/// One member of a type.
182#[derive(Debug, Clone, PartialEq, Eq)]
183pub enum Member {
184 /// A field.
185 Field(Field),
186 /// A method.
187 Method(Method),
188 /// A constructor.
189 Constructor(Constructor),
190 /// A nested type.
191 Nested(Box<TypeDecl>),
192 /// A static or instance initialiser block.
193 Initialiser {
194 /// Whether it is `static`.
195 static_: bool,
196 /// The block.
197 body: Block,
198 },
199 /// A comment on its own line.
200 Comment(Doc),
201 /// `@verbatim` text inside the class body, copied unchanged.
202 ///
203 /// OMG IDL 4.2 §8.3.5.1 `begin-declaration` / `end-declaration`:
204 /// the text lands inside the annotated declaration's scope.
205 Verbatim(String),
206}
207
208/// A field.
209#[derive(Debug, Clone, PartialEq, Eq)]
210pub struct Field {
211 /// Documentation.
212 pub doc: Doc,
213 /// Annotations.
214 pub annotations: Vec<Annotation>,
215 /// Modifiers.
216 pub modifiers: Vec<Modifier>,
217 /// Type.
218 pub type_: Type,
219 /// Name.
220 pub name: Ident,
221 /// Initialiser.
222 pub value: Option<Expr>,
223}
224
225/// A method.
226#[derive(Debug, Clone, PartialEq, Eq)]
227pub struct Method {
228 /// Documentation.
229 pub doc: Doc,
230 /// Annotations.
231 pub annotations: Vec<Annotation>,
232 /// Modifiers.
233 pub modifiers: Vec<Modifier>,
234 /// Type parameters.
235 pub generics: Vec<TypeParam>,
236 /// Return type.
237 pub returns: Type,
238 /// Name.
239 pub name: Ident,
240 /// Parameters.
241 pub params: Vec<Param>,
242 /// `throws`, in written order.
243 pub throws: Vec<Type>,
244 /// The body, absent for an abstract or interface method.
245 pub body: Option<Block>,
246}
247
248/// A constructor.
249#[derive(Debug, Clone, PartialEq, Eq)]
250pub struct Constructor {
251 /// Documentation.
252 pub doc: Doc,
253 /// Annotations.
254 pub annotations: Vec<Annotation>,
255 /// Modifiers.
256 pub modifiers: Vec<Modifier>,
257 /// The class's name.
258 pub name: Ident,
259 /// Parameters.
260 pub params: Vec<Param>,
261 /// `throws`.
262 pub throws: Vec<Type>,
263 /// The body.
264 pub body: Block,
265}
266
267/// One parameter.
268#[derive(Debug, Clone, PartialEq, Eq)]
269pub struct Param {
270 /// Annotations.
271 pub annotations: Vec<Annotation>,
272 /// Whether it is `final`.
273 pub final_: bool,
274 /// Type.
275 pub type_: Type,
276 /// Name.
277 pub name: Ident,
278 /// Whether it is a varargs parameter.
279 pub varargs: bool,
280}
281
282/// A modifier.
283#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
284pub enum Modifier {
285 /// `public`
286 Public,
287 /// `protected`
288 Protected,
289 /// `private`
290 Private,
291 /// `static`
292 Static,
293 /// `final`
294 Final,
295 /// `abstract`
296 Abstract,
297 /// `synchronized`
298 Synchronized,
299 /// `transient`
300 Transient,
301 /// `volatile`
302 Volatile,
303 /// `native`
304 Native,
305 /// `strictfp`
306 Strictfp,
307 /// `default`, on an interface method.
308 Default,
309 /// `sealed`
310 Sealed,
311}
312
313impl Modifier {
314 /// Every modifier the tree can hold.
315 pub const ALL: [Self; 13] = [
316 Self::Public,
317 Self::Protected,
318 Self::Private,
319 Self::Static,
320 Self::Final,
321 Self::Abstract,
322 Self::Synchronized,
323 Self::Transient,
324 Self::Volatile,
325 Self::Native,
326 Self::Strictfp,
327 Self::Default,
328 Self::Sealed,
329 ];
330
331 /// How it is written.
332 #[must_use]
333 pub const fn as_str(self) -> &'static str {
334 match self {
335 Self::Public => "public",
336 Self::Protected => "protected",
337 Self::Private => "private",
338 Self::Static => "static",
339 Self::Final => "final",
340 Self::Abstract => "abstract",
341 Self::Synchronized => "synchronized",
342 Self::Transient => "transient",
343 Self::Volatile => "volatile",
344 Self::Native => "native",
345 Self::Strictfp => "strictfp",
346 Self::Default => "default",
347 Self::Sealed => "sealed",
348 }
349 }
350}
351
352/// One annotation use.
353#[derive(Debug, Clone, PartialEq, Eq)]
354pub struct Annotation {
355 /// Its name.
356 pub path: Path,
357 /// Its arguments, in written order.
358 pub args: Vec<AnnotationArg>,
359}
360
361/// One argument of an annotation use.
362#[derive(Debug, Clone, PartialEq, Eq)]
363pub enum AnnotationArg {
364 /// The single unnamed argument: `@Ann(value)`.
365 Value(Expr),
366 /// `name = value`
367 Pair {
368 /// The name.
369 name: Ident,
370 /// The value.
371 value: Expr,
372 },
373}
374
375/// One type parameter.
376#[derive(Debug, Clone, PartialEq, Eq)]
377pub struct TypeParam {
378 /// Name.
379 pub name: Ident,
380 /// Bounds, in written order.
381 pub bounds: Vec<Type>,
382}
383
384/// A Java type as it will be written.
385#[derive(Debug, Clone, PartialEq, Eq)]
386pub enum Type {
387 /// A built-in.
388 Primitive(Primitive),
389 /// A named type with any type arguments.
390 Named {
391 /// Its path.
392 path: Path,
393 /// Its type arguments, in written order.
394 args: Vec<Type>,
395 },
396 /// `T[]`
397 Array(Box<Type>),
398 /// `?`, `? extends T`, `? super T`.
399 Wildcard {
400 /// An upper bound.
401 extends: Option<Box<Type>>,
402 /// A lower bound.
403 super_: Option<Box<Type>>,
404 },
405 /// `void`
406 Void,
407 /// `var`, in a local declaration.
408 Var,
409}
410
411impl Type {
412 /// A named type with no type arguments.
413 #[must_use]
414 pub fn named(path: Path) -> Self {
415 Self::Named {
416 path,
417 args: Vec::new(),
418 }
419 }
420
421 /// A named type with type arguments.
422 #[must_use]
423 pub fn generic(path: Path, args: Vec<Self>) -> Self {
424 Self::Named { path, args }
425 }
426}
427
428/// A Java primitive type.
429#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
430pub enum Primitive {
431 /// `boolean`
432 Boolean,
433 /// `byte`
434 Byte,
435 /// `char`
436 Char,
437 /// `short`
438 Short,
439 /// `int`
440 Int,
441 /// `long`
442 Long,
443 /// `float`
444 Float,
445 /// `double`
446 Double,
447}
448
449impl Primitive {
450 /// Every primitive Java has.
451 pub const ALL: [Self; 8] = [
452 Self::Boolean,
453 Self::Byte,
454 Self::Char,
455 Self::Short,
456 Self::Int,
457 Self::Long,
458 Self::Float,
459 Self::Double,
460 ];
461
462 /// How it is written.
463 #[must_use]
464 pub const fn as_str(self) -> &'static str {
465 match self {
466 Self::Boolean => "boolean",
467 Self::Byte => "byte",
468 Self::Char => "char",
469 Self::Short => "short",
470 Self::Int => "int",
471 Self::Long => "long",
472 Self::Float => "float",
473 Self::Double => "double",
474 }
475 }
476
477 /// The wrapper class, for a type argument that cannot be primitive.
478 #[must_use]
479 pub const fn boxed(self) -> &'static str {
480 match self {
481 Self::Boolean => "Boolean",
482 Self::Byte => "Byte",
483 Self::Char => "Character",
484 Self::Short => "Short",
485 Self::Int => "Integer",
486 Self::Long => "Long",
487 Self::Float => "Float",
488 Self::Double => "Double",
489 }
490 }
491}
492
493/// A block of statements.
494#[derive(Debug, Clone, Default, PartialEq, Eq)]
495pub struct Block {
496 /// The statements, in order.
497 pub statements: Vec<Statement>,
498}
499
500/// One statement.
501#[derive(Debug, Clone, PartialEq, Eq)]
502pub enum Statement {
503 /// A local declaration.
504 Declare {
505 /// Whether it is `final`.
506 final_: bool,
507 /// Type.
508 type_: Type,
509 /// Name.
510 name: Ident,
511 /// Initialiser.
512 value: Option<Expr>,
513 },
514 /// An expression followed by `;`.
515 Expr(Expr),
516 /// `return expr;`
517 Return(Option<Expr>),
518 /// `if (cond) { .. } else { .. }`
519 If {
520 /// Condition.
521 condition: Expr,
522 /// Then-block.
523 then: Block,
524 /// Else-block.
525 otherwise: Option<Block>,
526 },
527 /// `for (T name : range) { .. }`
528 ForEach {
529 /// The binding's type.
530 type_: Type,
531 /// The binding.
532 binding: Ident,
533 /// What is iterated.
534 range: Expr,
535 /// The body.
536 body: Block,
537 },
538 /// `for (init; cond; step) { .. }`
539 ///
540 /// Not [`Statement::ForEach`]. A generated codec walks a collection
541 /// by index because the index is what the wire needs — an element's
542 /// position decides its alignment and, in a `map` written in
543 /// ascending key order, which entry is written at all. A `for-each`
544 /// hands the element and hides the position.
545 For {
546 /// Initialiser.
547 init: Box<Statement>,
548 /// Condition.
549 condition: Expr,
550 /// Step.
551 step: Expr,
552 /// Body.
553 body: Block,
554 },
555 /// `while (cond) { .. }`
556 ///
557 /// Not a `for` with the two clauses left empty. A decoder walks a
558 /// `@mutable` aggregate's headers until the delimiter is used up and
559 /// a PL_CDR1 list until its sentinel; neither has a counter, and
560 /// writing one as `for (; cond;)` says there was an induction
561 /// variable somebody forgot.
562 While {
563 /// Condition.
564 condition: Expr,
565 /// Body.
566 body: Block,
567 },
568 /// `break;`
569 ///
570 /// A PL_CDR1 parameter list ends at `PID_LIST_END` and not at a
571 /// count, so the loop leaves from the middle.
572 Break,
573 /// `switch (value) { case ..: }`
574 Switch {
575 /// What is switched on.
576 value: Expr,
577 /// The cases.
578 cases: Vec<SwitchCase>,
579 },
580 /// `throw expr;`
581 Throw(Expr),
582 /// A comment on its own line.
583 Comment(Doc),
584}
585
586/// One case of a switch.
587#[derive(Debug, Clone, PartialEq, Eq)]
588pub struct SwitchCase {
589 /// The labels; empty means `default:`.
590 pub labels: Vec<Expr>,
591 /// The body.
592 pub body: Block,
593 /// Whether it ends in `break;`.
594 pub breaks: bool,
595}
596
597/// An expression.
598#[derive(Debug, Clone, PartialEq, Eq)]
599pub enum Expr {
600 /// A literal.
601 Literal(Literal),
602 /// A name or qualified name.
603 Path(Path),
604 /// `receiver.name(args)`
605 MethodCall {
606 /// The receiver, absent for an unqualified call.
607 receiver: Option<Box<Expr>>,
608 /// The method.
609 name: Ident,
610 /// Arguments.
611 args: Vec<Expr>,
612 },
613 /// `value.name`
614 Field {
615 /// The value.
616 value: Box<Expr>,
617 /// The field.
618 name: Ident,
619 },
620 /// `a[i]`
621 Index {
622 /// The array.
623 value: Box<Expr>,
624 /// The index.
625 index: Box<Expr>,
626 },
627 /// `new T(args)`
628 New {
629 /// The type.
630 type_: Box<Type>,
631 /// Arguments.
632 args: Vec<Expr>,
633 },
634 /// `new T[]{ a, b }`, `new T[n]`, `new T[n][m]`, `new T[n][]`.
635 NewArray {
636 /// The element type, which may itself be an array.
637 ///
638 /// Its own `[]`s are written *after* the sized dimensions:
639 /// `new int[n][]` allocates `n` rows of `int[]`, and
640 /// `new int[][n]` is not a form Java has. A sequence of a
641 /// fixed-size array reaches exactly that shape.
642 element: Box<Type>,
643 /// One per sized dimension, outermost first. Empty asks for the
644 /// initialiser form.
645 lengths: Vec<Expr>,
646 /// The elements, for the initialiser form.
647 elements: Vec<Expr>,
648 },
649 /// `a op b`
650 Binary {
651 /// The operator, as written.
652 op: &'static str,
653 /// Left.
654 lhs: Box<Expr>,
655 /// Right.
656 rhs: Box<Expr>,
657 },
658 /// `(value)`, written because the writer meant it.
659 ///
660 /// The tree carries no precedence and the renderer adds no
661 /// brackets, so a caller that needs one says so. Java's `&` binds
662 /// *looser* than `!=`, which makes `bits & mask != 0` a type error
663 /// where C reads it as a comparison — and looser than `^`, which
664 /// makes `bits & a ^ b` a different number with nothing to say so.
665 Paren(Box<Expr>),
666 /// `(T) value`
667 Cast {
668 /// The target type.
669 type_: Box<Type>,
670 /// The value.
671 value: Box<Expr>,
672 },
673 /// `value instanceof T`
674 InstanceOf {
675 /// The value.
676 value: Box<Expr>,
677 /// The type.
678 type_: Box<Type>,
679 },
680 /// `cond ? a : b`
681 Ternary {
682 /// The condition.
683 condition: Box<Expr>,
684 /// The then-value.
685 then: Box<Expr>,
686 /// The else-value.
687 otherwise: Box<Expr>,
688 },
689 /// `this`
690 This,
691 /// A lambda: `(a, b) -> body`.
692 Lambda {
693 /// Parameter names.
694 params: Vec<Ident>,
695 /// The body as an expression.
696 body: Box<Expr>,
697 },
698 /// An annotation used as a value: an element of an annotation type
699 /// that is itself an annotation, or of an array of them.
700 Annotation(Annotation),
701 /// `{ a, b }`, the array initialiser of an annotation element.
702 ArrayInit(Vec<Expr>),
703}
704
705/// The name a Java keyword collision escapes to.
706#[must_use]
707pub fn escape_keyword(name: &str) -> String {
708 if RESERVED.contains(&name) {
709 let mut out = name.to_string();
710 out.push('_');
711 return out;
712 }
713 name.to_string()
714}
715
716/// The Java keywords a generated identifier may collide with.
717/// JLS 17 §3.9, plus the three literals that are not identifiers.
718const RESERVED: &[&str] = &[
719 "abstract",
720 "assert",
721 "boolean",
722 "break",
723 "byte",
724 "case",
725 "catch",
726 "char",
727 "class",
728 "const",
729 "continue",
730 "default",
731 "do",
732 "double",
733 "else",
734 "enum",
735 "extends",
736 "final",
737 "finally",
738 "float",
739 "for",
740 "goto",
741 "if",
742 "implements",
743 "import",
744 "instanceof",
745 "int",
746 "interface",
747 "long",
748 "native",
749 "new",
750 "package",
751 "private",
752 "protected",
753 "public",
754 "return",
755 "short",
756 "static",
757 "strictfp",
758 "super",
759 "switch",
760 "synchronized",
761 "this",
762 "throw",
763 "throws",
764 "transient",
765 "try",
766 "void",
767 "volatile",
768 "while",
769 "true",
770 "false",
771 "null",
772];
773
774#[cfg(test)]
775mod tests {
776 #![allow(clippy::expect_used, clippy::panic, clippy::unwrap_used)]
777 use super::*;
778
779 #[test]
780 fn every_primitive_writes_its_own_spelling_and_has_a_wrapper() {
781 let mut seen = Vec::new();
782 let mut boxed = Vec::new();
783 for primitive in Primitive::ALL {
784 assert!(!seen.contains(&primitive.as_str()));
785 seen.push(primitive.as_str());
786 assert!(!boxed.contains(&primitive.boxed()));
787 boxed.push(primitive.boxed());
788 }
789 }
790
791 #[test]
792 fn char_boxes_to_character_not_char() {
793 // The one wrapper whose name is not the primitive capitalised;
794 // getting it wrong produces a type that does not exist.
795 assert_eq!(Primitive::Char.boxed(), "Character");
796 assert_eq!(Primitive::Int.boxed(), "Integer");
797 }
798
799 #[test]
800 fn a_keyword_escapes_with_a_trailing_underscore() {
801 assert_eq!(escape_keyword("class"), "class_");
802 assert_eq!(escape_keyword("null"), "null_");
803 assert_eq!(escape_keyword("value"), "value");
804 }
805
806 #[test]
807 fn modifiers_keep_the_order_they_were_written_in() {
808 // `public static final` is the conventional order and the one
809 // the output has; the tree records it rather than sorting.
810 let field = Field {
811 doc: Doc::none(),
812 annotations: Vec::new(),
813 modifiers: alloc::vec![Modifier::Public, Modifier::Static, Modifier::Final],
814 type_: Type::Primitive(Primitive::Int),
815 name: Ident::new("MAX"),
816 value: None,
817 };
818 let written: Vec<&str> = field.modifiers.iter().map(|m| m.as_str()).collect();
819 assert_eq!(written, alloc::vec!["public", "static", "final"]);
820 }
821}