Skip to main content

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}