Skip to main content

oxilean_codegen/java_backend/
types.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5use crate::lcnf::*;
6use std::collections::HashSet;
7
8use super::functions::JAVA_KEYWORDS;
9
10use super::functions::*;
11use std::collections::{HashMap, VecDeque};
12
13#[allow(dead_code)]
14#[derive(Debug, Clone)]
15pub struct JavaWorklist {
16    pub(super) items: std::collections::VecDeque<u32>,
17    pub(super) in_worklist: std::collections::HashSet<u32>,
18}
19impl JavaWorklist {
20    #[allow(dead_code)]
21    pub fn new() -> Self {
22        JavaWorklist {
23            items: std::collections::VecDeque::new(),
24            in_worklist: std::collections::HashSet::new(),
25        }
26    }
27    #[allow(dead_code)]
28    pub fn push(&mut self, item: u32) -> bool {
29        if self.in_worklist.insert(item) {
30            self.items.push_back(item);
31            true
32        } else {
33            false
34        }
35    }
36    #[allow(dead_code)]
37    pub fn pop(&mut self) -> Option<u32> {
38        let item = self.items.pop_front()?;
39        self.in_worklist.remove(&item);
40        Some(item)
41    }
42    #[allow(dead_code)]
43    pub fn is_empty(&self) -> bool {
44        self.items.is_empty()
45    }
46    #[allow(dead_code)]
47    pub fn len(&self) -> usize {
48        self.items.len()
49    }
50    #[allow(dead_code)]
51    pub fn contains(&self, item: u32) -> bool {
52        self.in_worklist.contains(&item)
53    }
54}
55#[allow(dead_code)]
56#[derive(Debug, Clone, Default)]
57pub struct JavaPassStats {
58    pub total_runs: u32,
59    pub successful_runs: u32,
60    pub total_changes: u64,
61    pub time_ms: u64,
62    pub iterations_used: u32,
63}
64impl JavaPassStats {
65    #[allow(dead_code)]
66    pub fn new() -> Self {
67        Self::default()
68    }
69    #[allow(dead_code)]
70    pub fn record_run(&mut self, changes: u64, time_ms: u64, iterations: u32) {
71        self.total_runs += 1;
72        self.successful_runs += 1;
73        self.total_changes += changes;
74        self.time_ms += time_ms;
75        self.iterations_used = iterations;
76    }
77    #[allow(dead_code)]
78    pub fn average_changes_per_run(&self) -> f64 {
79        if self.total_runs == 0 {
80            return 0.0;
81        }
82        self.total_changes as f64 / self.total_runs as f64
83    }
84    #[allow(dead_code)]
85    pub fn success_rate(&self) -> f64 {
86        if self.total_runs == 0 {
87            return 0.0;
88        }
89        self.successful_runs as f64 / self.total_runs as f64
90    }
91    #[allow(dead_code)]
92    pub fn format_summary(&self) -> String {
93        format!(
94            "Runs: {}/{}, Changes: {}, Time: {}ms",
95            self.successful_runs, self.total_runs, self.total_changes, self.time_ms
96        )
97    }
98}
99/// A Java method definition.
100#[derive(Debug, Clone)]
101pub struct JavaMethod {
102    pub name: std::string::String,
103    pub return_type: JavaType,
104    pub params: Vec<(std::string::String, JavaType)>,
105    pub body: Vec<JavaStmt>,
106    pub visibility: Visibility,
107    pub is_static: bool,
108    pub is_final: bool,
109    pub is_abstract: bool,
110    pub annotations: Vec<std::string::String>,
111    /// Checked exceptions declared in `throws`
112    pub throws: Vec<std::string::String>,
113}
114impl JavaMethod {
115    /// Create a simple public non-static method.
116    pub fn new(
117        name: &str,
118        return_type: JavaType,
119        params: Vec<(&str, JavaType)>,
120        body: Vec<JavaStmt>,
121    ) -> Self {
122        JavaMethod {
123            name: name.to_string(),
124            return_type,
125            params: params
126                .into_iter()
127                .map(|(n, t)| (n.to_string(), t))
128                .collect(),
129            body,
130            visibility: Visibility::Public,
131            is_static: false,
132            is_final: false,
133            is_abstract: false,
134            annotations: Vec::new(),
135            throws: Vec::new(),
136        }
137    }
138}
139/// A complete Java compilation unit (one `.java` file).
140#[derive(Debug, Clone)]
141pub struct JavaModule {
142    pub package: std::string::String,
143    pub imports: Vec<std::string::String>,
144    pub classes: Vec<JavaClass>,
145    pub interfaces: Vec<SealedInterface>,
146    pub records: Vec<JavaRecord>,
147    pub enums: Vec<JavaEnum>,
148}
149impl JavaModule {
150    /// Create a new empty module in the given package.
151    pub fn new(package: &str) -> Self {
152        JavaModule {
153            package: package.to_string(),
154            imports: Vec::new(),
155            classes: Vec::new(),
156            interfaces: Vec::new(),
157            records: Vec::new(),
158            enums: Vec::new(),
159        }
160    }
161    /// Emit a complete Java source file as a `String`.
162    pub fn emit(&self) -> std::string::String {
163        let mut out = std::string::String::new();
164        if !self.package.is_empty() {
165            out.push_str(&format!("package {};\n\n", self.package));
166        }
167        for imp in &self.imports {
168            out.push_str(&format!("import {};\n", imp));
169        }
170        if !self.imports.is_empty() {
171            out.push('\n');
172        }
173        for iface in &self.interfaces {
174            emit_sealed_interface(&mut out, iface, 0);
175            out.push('\n');
176        }
177        for rec in &self.records {
178            emit_record(&mut out, rec, 0);
179            out.push('\n');
180        }
181        for en in &self.enums {
182            emit_enum(&mut out, en, 0);
183            out.push('\n');
184        }
185        for cls in &self.classes {
186            emit_class(&mut out, cls, 0);
187            out.push('\n');
188        }
189        out
190    }
191}
192/// Java code generation backend.
193pub struct JavaBackend {
194    pub(super) var_counter: u64,
195}
196impl JavaBackend {
197    /// Create a new `JavaBackend`.
198    pub fn new() -> Self {
199        JavaBackend { var_counter: 0 }
200    }
201    /// Mangle a name so it does not clash with Java keywords or invalid characters.
202    pub fn mangle_name(&self, name: &str) -> std::string::String {
203        let sanitized: std::string::String = name
204            .chars()
205            .map(|c| match c {
206                'a'..='z' | 'A'..='Z' | '0'..='9' | '_' => c,
207                '.' | ':' | '\'' | '!' | '?' | '@' => '_',
208                _ => '_',
209            })
210            .collect();
211        let sanitized = if sanitized.starts_with(|c: char| c.is_ascii_digit()) {
212            format!("_{}", sanitized)
213        } else {
214            sanitized
215        };
216        if JAVA_KEYWORDS.contains(&sanitized.as_str()) {
217            format!("{}_", sanitized)
218        } else if sanitized.is_empty() {
219            "_anon".to_string()
220        } else {
221            sanitized
222        }
223    }
224    /// Generate a fresh temporary variable name.
225    pub fn fresh_var(&mut self) -> std::string::String {
226        let v = self.var_counter;
227        self.var_counter += 1;
228        format!("_t{}", v)
229    }
230    /// Compile a slice of LCNF declarations into a complete Java source string.
231    pub fn emit_module(decls: &[LcnfFunDecl]) -> Result<std::string::String, std::string::String> {
232        let mut backend = JavaBackend::new();
233        let mut methods = Vec::new();
234        let mut ctor_names: HashSet<std::string::String> = HashSet::new();
235        for decl in decls {
236            collect_ctor_names_from_expr(&decl.body, &mut ctor_names);
237        }
238        let mut fun_class = JavaClass::new("OxiLeanGenerated");
239        fun_class
240            .annotations
241            .push("@SuppressWarnings(\"all\")".to_string());
242        for decl in decls {
243            let m = backend.compile_decl(decl)?;
244            methods.push(m);
245        }
246        fun_class.methods = methods;
247        let mut records: Vec<JavaRecord> = ctor_names
248            .into_iter()
249            .collect::<Vec<_>>()
250            .into_iter()
251            .map(|name| {
252                let mangled = backend.mangle_name(&name);
253                JavaRecord {
254                    name: mangled,
255                    components: vec![("tag".to_string(), JavaType::Int)],
256                    methods: Vec::new(),
257                    is_sealed: false,
258                    implements: Vec::new(),
259                    annotations: Vec::new(),
260                }
261            })
262            .collect();
263        records.sort_by(|a, b| a.name.cmp(&b.name));
264        let mut module = JavaModule::new("oxilean.generated");
265        module.imports = vec![
266            "java.util.List".to_string(),
267            "java.util.Map".to_string(),
268            "java.util.Optional".to_string(),
269            "java.util.function.Function".to_string(),
270            "java.util.function.Supplier".to_string(),
271            "java.util.stream.Collectors".to_string(),
272        ];
273        module.records = records;
274        module.classes = vec![fun_class];
275        Ok(module.emit())
276    }
277    /// Compile a single LCNF function declaration to a `JavaMethod`.
278    pub fn compile_decl(&mut self, decl: &LcnfFunDecl) -> Result<JavaMethod, std::string::String> {
279        let name = self.mangle_name(&decl.name.to_string());
280        let params: Vec<(std::string::String, JavaType)> = decl
281            .params
282            .iter()
283            .map(|p| (self.mangle_name(&p.name), lcnf_type_to_java(&p.ty)))
284            .collect();
285        let return_type = lcnf_type_to_java(&decl.ret_type);
286        let mut body: Vec<JavaStmt> = Vec::new();
287        let result_expr = self.compile_expr(&decl.body, &mut body)?;
288        match &return_type {
289            JavaType::Void => {
290                body.push(JavaStmt::Expr(result_expr));
291            }
292            _ => {
293                body.push(JavaStmt::Return(Some(result_expr)));
294            }
295        }
296        let mut method = JavaMethod {
297            name,
298            return_type,
299            params: params.into_iter().collect(),
300            body,
301            visibility: Visibility::Public,
302            is_static: true,
303            is_final: false,
304            is_abstract: false,
305            annotations: Vec::new(),
306            throws: Vec::new(),
307        };
308        method
309            .annotations
310            .push("@SuppressWarnings(\"unchecked\")".to_string());
311        Ok(method)
312    }
313    /// Compile an LCNF expression, emitting binding statements into `stmts`.
314    pub fn compile_expr(
315        &mut self,
316        expr: &LcnfExpr,
317        stmts: &mut Vec<JavaStmt>,
318    ) -> Result<JavaExpr, std::string::String> {
319        match expr {
320            LcnfExpr::Return(arg) => Ok(self.compile_arg(arg)),
321            LcnfExpr::Unreachable => Ok(JavaExpr::MethodCall(
322                Box::new(JavaExpr::Var("OxiLeanRuntime".to_string())),
323                "unreachable".to_string(),
324                vec![],
325            )),
326            LcnfExpr::TailCall(func, args) => {
327                let callee = self.compile_arg(func);
328                let java_args: Vec<JavaExpr> = args.iter().map(|a| self.compile_arg(a)).collect();
329                Ok(JavaExpr::Call(Box::new(callee), java_args))
330            }
331            LcnfExpr::Let {
332                id: _,
333                name,
334                ty,
335                value,
336                body,
337            } => {
338                let java_val = self.compile_let_value(value)?;
339                let var_name = self.mangle_name(name);
340                let java_ty = lcnf_type_to_java(ty);
341                stmts.push(JavaStmt::LocalVar {
342                    ty: Some(java_ty),
343                    name: var_name.clone(),
344                    init: Some(java_val),
345                    is_final: true,
346                });
347                self.compile_expr(body, stmts)
348            }
349            LcnfExpr::Case {
350                scrutinee,
351                scrutinee_ty: _,
352                alts,
353                default,
354            } => {
355                let result_var = self.fresh_var();
356                let scrutinee_expr = JavaExpr::Var(format!("_x{}", scrutinee.0));
357                stmts.push(JavaStmt::LocalVar {
358                    ty: Some(JavaType::Object),
359                    name: result_var.clone(),
360                    init: Some(JavaExpr::Null),
361                    is_final: false,
362                });
363                let mut cases: Vec<(JavaExpr, Vec<JavaStmt>)> = Vec::new();
364                for alt in alts {
365                    let mut branch_stmts: Vec<JavaStmt> = Vec::new();
366                    for (idx, param) in alt.params.iter().enumerate() {
367                        let param_name = self.mangle_name(&param.name);
368                        let field_access = JavaExpr::FieldAccess(
369                            Box::new(JavaExpr::Var(format!("_x{}", scrutinee.0))),
370                            format!("field{}", idx),
371                        );
372                        branch_stmts.push(JavaStmt::LocalVar {
373                            ty: Some(lcnf_type_to_java(&param.ty)),
374                            name: param_name,
375                            init: Some(field_access),
376                            is_final: true,
377                        });
378                    }
379                    let branch_result = self.compile_expr(&alt.body, &mut branch_stmts)?;
380                    branch_stmts.push(JavaStmt::Expr(JavaExpr::BinOp(
381                        "=".to_string(),
382                        Box::new(JavaExpr::Var(result_var.clone())),
383                        Box::new(branch_result),
384                    )));
385                    branch_stmts.push(JavaStmt::Break(None));
386                    let tag_label = JavaExpr::Lit(JavaLit::Int(alt.ctor_tag as i64));
387                    cases.push((tag_label, branch_stmts));
388                }
389                let mut default_stmts: Vec<JavaStmt> = Vec::new();
390                if let Some(def) = default {
391                    let def_result = self.compile_expr(def, &mut default_stmts)?;
392                    default_stmts.push(JavaStmt::Expr(JavaExpr::BinOp(
393                        "=".to_string(),
394                        Box::new(JavaExpr::Var(result_var.clone())),
395                        Box::new(def_result),
396                    )));
397                } else {
398                    default_stmts.push(JavaStmt::Throw(JavaExpr::New(
399                        "IllegalStateException".to_string(),
400                        vec![JavaExpr::Lit(JavaLit::Str(
401                            "OxiLean: unreachable".to_string(),
402                        ))],
403                    )));
404                }
405                let discriminant =
406                    JavaExpr::FieldAccess(Box::new(scrutinee_expr), "tag".to_string());
407                stmts.push(JavaStmt::Switch {
408                    scrutinee: discriminant,
409                    cases,
410                    default: default_stmts,
411                });
412                Ok(JavaExpr::Var(result_var))
413            }
414        }
415    }
416    /// Compile an LCNF let-value to a Java expression.
417    pub(super) fn compile_let_value(
418        &mut self,
419        value: &LcnfLetValue,
420    ) -> Result<JavaExpr, std::string::String> {
421        match value {
422            LcnfLetValue::Lit(lit) => Ok(self.compile_lit(lit)),
423            LcnfLetValue::Erased => Ok(JavaExpr::Null),
424            LcnfLetValue::FVar(id) => Ok(JavaExpr::Var(format!("_x{}", id.0))),
425            LcnfLetValue::App(func, args) => {
426                let callee = self.compile_arg(func);
427                let java_args: Vec<JavaExpr> = args.iter().map(|a| self.compile_arg(a)).collect();
428                Ok(JavaExpr::Call(Box::new(callee), java_args))
429            }
430            LcnfLetValue::Proj(_name, idx, var) => {
431                let base = JavaExpr::Var(format!("_x{}", var.0));
432                Ok(JavaExpr::FieldAccess(
433                    Box::new(base),
434                    format!("field{}", idx),
435                ))
436            }
437            LcnfLetValue::Ctor(name, _tag, args) => {
438                let ctor_name = self.mangle_name(name);
439                let java_args: Vec<JavaExpr> = args.iter().map(|a| self.compile_arg(a)).collect();
440                Ok(JavaExpr::New(ctor_name, java_args))
441            }
442            LcnfLetValue::Reset(_var) => Ok(JavaExpr::Null),
443            LcnfLetValue::Reuse(_slot, name, _tag, args) => {
444                let ctor_name = self.mangle_name(name);
445                let java_args: Vec<JavaExpr> = args.iter().map(|a| self.compile_arg(a)).collect();
446                Ok(JavaExpr::New(ctor_name, java_args))
447            }
448        }
449    }
450    /// Compile an LCNF argument to a Java expression.
451    pub(super) fn compile_arg(&self, arg: &LcnfArg) -> JavaExpr {
452        match arg {
453            LcnfArg::Var(id) => JavaExpr::Var(format!("_x{}", id.0)),
454            LcnfArg::Lit(lit) => self.compile_lit(lit),
455            LcnfArg::Erased => JavaExpr::Null,
456            LcnfArg::Type(_) => JavaExpr::Null,
457        }
458    }
459    /// Compile an LCNF literal.
460    pub(super) fn compile_lit(&self, lit: &LcnfLit) -> JavaExpr {
461        match lit {
462            LcnfLit::Nat(n) => JavaExpr::Lit(JavaLit::Long(*n as i64)),
463            LcnfLit::Int(i) => JavaExpr::Lit(JavaLit::Long(*i)),
464            LcnfLit::Str(s) => JavaExpr::Lit(JavaLit::Str(s.clone())),
465        }
466    }
467}
468/// Java statement AST.
469#[derive(Debug, Clone, PartialEq)]
470pub enum JavaStmt {
471    /// Expression statement: `expr;`
472    Expr(JavaExpr),
473    /// Local variable declaration: `Type name = init;` or `var name = init;`
474    LocalVar {
475        ty: Option<JavaType>,
476        name: std::string::String,
477        init: Option<JavaExpr>,
478        is_final: bool,
479    },
480    /// If statement: `if (cond) { then } else { else_ }`
481    If(JavaExpr, Vec<JavaStmt>, Vec<JavaStmt>),
482    /// Switch expression/statement
483    Switch {
484        scrutinee: JavaExpr,
485        cases: Vec<(JavaExpr, Vec<JavaStmt>)>,
486        default: Vec<JavaStmt>,
487    },
488    /// Classic for loop: `for (init; cond; update) { body }`
489    For {
490        init: Option<Box<JavaStmt>>,
491        cond: Option<JavaExpr>,
492        update: Option<JavaExpr>,
493        body: Vec<JavaStmt>,
494    },
495    /// Enhanced for loop: `for (Type elem : iterable) { body }`
496    ForEach {
497        ty: JavaType,
498        elem: std::string::String,
499        iterable: JavaExpr,
500        body: Vec<JavaStmt>,
501    },
502    /// While loop: `while (cond) { body }`
503    While(JavaExpr, Vec<JavaStmt>),
504    /// Do-while loop: `do { body } while (cond);`
505    DoWhile(Vec<JavaStmt>, JavaExpr),
506    /// Return statement: `return expr;` or `return;`
507    Return(Option<JavaExpr>),
508    /// Throw statement: `throw expr;`
509    Throw(JavaExpr),
510    /// Try-catch-finally
511    TryCatch {
512        body: Vec<JavaStmt>,
513        catches: Vec<JavaCatchClause>,
514        finally: Vec<JavaStmt>,
515    },
516    /// Try-with-resources
517    TryWithResources {
518        resources: Vec<(std::string::String, JavaExpr)>,
519        body: Vec<JavaStmt>,
520        catches: Vec<JavaCatchClause>,
521        finally: Vec<JavaStmt>,
522    },
523    /// Synchronized block: `synchronized (lock) { body }`
524    Synchronized(JavaExpr, Vec<JavaStmt>),
525    /// Break statement
526    Break(Option<std::string::String>),
527    /// Continue statement
528    Continue(Option<std::string::String>),
529    /// Assert statement: `assert cond : msg;`
530    Assert(JavaExpr, Option<JavaExpr>),
531}
532/// Modifiers that can appear on a class.
533#[derive(Debug, Clone, PartialEq, Eq)]
534pub enum ClassModifier {
535    Sealed,
536    Abstract,
537    Final,
538    Static,
539    NonSealed,
540}
541#[allow(dead_code)]
542#[derive(Debug, Clone, PartialEq)]
543pub enum JavaPassPhase {
544    Analysis,
545    Transformation,
546    Verification,
547    Cleanup,
548}
549impl JavaPassPhase {
550    #[allow(dead_code)]
551    pub fn name(&self) -> &str {
552        match self {
553            JavaPassPhase::Analysis => "analysis",
554            JavaPassPhase::Transformation => "transformation",
555            JavaPassPhase::Verification => "verification",
556            JavaPassPhase::Cleanup => "cleanup",
557        }
558    }
559    #[allow(dead_code)]
560    pub fn is_modifying(&self) -> bool {
561        matches!(self, JavaPassPhase::Transformation | JavaPassPhase::Cleanup)
562    }
563}
564#[allow(dead_code)]
565#[derive(Debug, Clone)]
566pub struct JavaPassConfig {
567    pub phase: JavaPassPhase,
568    pub enabled: bool,
569    pub max_iterations: u32,
570    pub debug_output: bool,
571    pub pass_name: String,
572}
573impl JavaPassConfig {
574    #[allow(dead_code)]
575    pub fn new(name: impl Into<String>, phase: JavaPassPhase) -> Self {
576        JavaPassConfig {
577            phase,
578            enabled: true,
579            max_iterations: 10,
580            debug_output: false,
581            pass_name: name.into(),
582        }
583    }
584    #[allow(dead_code)]
585    pub fn disabled(mut self) -> Self {
586        self.enabled = false;
587        self
588    }
589    #[allow(dead_code)]
590    pub fn with_debug(mut self) -> Self {
591        self.debug_output = true;
592        self
593    }
594    #[allow(dead_code)]
595    pub fn max_iter(mut self, n: u32) -> Self {
596        self.max_iterations = n;
597        self
598    }
599}
600/// Java access modifiers.
601#[derive(Debug, Clone, PartialEq, Eq)]
602pub enum Visibility {
603    Public,
604    Protected,
605    Private,
606    /// Package-private (no modifier)
607    Package,
608}
609/// A Java enum constant.
610#[derive(Debug, Clone)]
611pub struct JavaEnumConstant {
612    pub name: std::string::String,
613    pub args: Vec<JavaExpr>,
614    pub annotations: Vec<std::string::String>,
615}
616#[allow(dead_code)]
617#[derive(Debug, Clone)]
618pub struct JavaDepGraph {
619    pub(super) nodes: Vec<u32>,
620    pub(super) edges: Vec<(u32, u32)>,
621}
622impl JavaDepGraph {
623    #[allow(dead_code)]
624    pub fn new() -> Self {
625        JavaDepGraph {
626            nodes: Vec::new(),
627            edges: Vec::new(),
628        }
629    }
630    #[allow(dead_code)]
631    pub fn add_node(&mut self, id: u32) {
632        if !self.nodes.contains(&id) {
633            self.nodes.push(id);
634        }
635    }
636    #[allow(dead_code)]
637    pub fn add_dep(&mut self, dep: u32, dependent: u32) {
638        self.add_node(dep);
639        self.add_node(dependent);
640        self.edges.push((dep, dependent));
641    }
642    #[allow(dead_code)]
643    pub fn dependents_of(&self, node: u32) -> Vec<u32> {
644        self.edges
645            .iter()
646            .filter(|(d, _)| *d == node)
647            .map(|(_, dep)| *dep)
648            .collect()
649    }
650    #[allow(dead_code)]
651    pub fn dependencies_of(&self, node: u32) -> Vec<u32> {
652        self.edges
653            .iter()
654            .filter(|(_, dep)| *dep == node)
655            .map(|(d, _)| *d)
656            .collect()
657    }
658    #[allow(dead_code)]
659    pub fn topological_sort(&self) -> Vec<u32> {
660        let mut in_degree: std::collections::HashMap<u32, u32> = std::collections::HashMap::new();
661        for &n in &self.nodes {
662            in_degree.insert(n, 0);
663        }
664        for (_, dep) in &self.edges {
665            *in_degree.entry(*dep).or_insert(0) += 1;
666        }
667        let mut queue: std::collections::VecDeque<u32> = self
668            .nodes
669            .iter()
670            .filter(|&&n| in_degree[&n] == 0)
671            .copied()
672            .collect();
673        let mut result = Vec::new();
674        while let Some(node) = queue.pop_front() {
675            result.push(node);
676            for dep in self.dependents_of(node) {
677                let cnt = in_degree.entry(dep).or_insert(0);
678                *cnt = cnt.saturating_sub(1);
679                if *cnt == 0 {
680                    queue.push_back(dep);
681                }
682            }
683        }
684        result
685    }
686    #[allow(dead_code)]
687    pub fn has_cycle(&self) -> bool {
688        self.topological_sort().len() < self.nodes.len()
689    }
690}
691#[allow(dead_code)]
692#[derive(Debug, Clone)]
693pub struct JavaCacheEntry {
694    pub key: String,
695    pub data: Vec<u8>,
696    pub timestamp: u64,
697    pub valid: bool,
698}
699/// A single catch clause in a try-catch.
700#[derive(Debug, Clone, PartialEq)]
701pub struct JavaCatchClause {
702    /// Exception type(s) (e.g. `"IOException"` or `"IOException | SQLException"`)
703    pub exception_types: Vec<std::string::String>,
704    /// Bound variable name
705    pub var_name: std::string::String,
706    /// Handler body
707    pub body: Vec<JavaStmt>,
708}
709/// Java expression AST.
710#[derive(Debug, Clone, PartialEq)]
711pub enum JavaExpr {
712    /// Literal value: `42`, `"hello"`, `null`
713    Lit(JavaLit),
714    /// Variable or identifier: `x`, `MyClass`
715    Var(std::string::String),
716    /// Binary operation: `a + b`
717    BinOp(std::string::String, Box<JavaExpr>, Box<JavaExpr>),
718    /// Unary operation: `!x`, `-n`
719    UnaryOp(std::string::String, Box<JavaExpr>),
720    /// Static or free function call: `f(a, b)`
721    Call(Box<JavaExpr>, Vec<JavaExpr>),
722    /// Instance method call: `obj.method(args...)`
723    MethodCall(Box<JavaExpr>, std::string::String, Vec<JavaExpr>),
724    /// Object instantiation: `new Foo(args...)`
725    New(std::string::String, Vec<JavaExpr>),
726    /// Cast: `(Type) expr`
727    Cast(JavaType, Box<JavaExpr>),
728    /// Instanceof check: `expr instanceof Type`
729    Instanceof(Box<JavaExpr>, std::string::String),
730    /// Ternary: `cond ? then : else`
731    Ternary(Box<JavaExpr>, Box<JavaExpr>, Box<JavaExpr>),
732    /// Null literal (convenience variant)
733    Null,
734    /// Lambda expression: `(x, y) -> expr`
735    Lambda(Vec<std::string::String>, Box<JavaExpr>),
736    /// Method reference: `Class::method`
737    MethodRef(std::string::String, std::string::String),
738    /// Array access: `arr[idx]`
739    ArrayAccess(Box<JavaExpr>, Box<JavaExpr>),
740    /// Field access: `obj.field`
741    FieldAccess(Box<JavaExpr>, std::string::String),
742}
743/// A field declaration in a Java class.
744#[derive(Debug, Clone)]
745pub struct JavaField {
746    pub name: std::string::String,
747    pub ty: JavaType,
748    pub init: Option<JavaExpr>,
749    pub visibility: Visibility,
750    pub is_static: bool,
751    pub is_final: bool,
752    pub annotations: Vec<std::string::String>,
753}
754/// A Java class declaration.
755#[derive(Debug, Clone)]
756pub struct JavaClass {
757    pub name: std::string::String,
758    pub superclass: Option<std::string::String>,
759    pub interfaces: Vec<std::string::String>,
760    pub fields: Vec<JavaField>,
761    pub methods: Vec<JavaMethod>,
762    pub inner_classes: Vec<JavaClass>,
763    pub modifiers: Vec<ClassModifier>,
764    pub annotations: Vec<std::string::String>,
765    pub type_params: Vec<std::string::String>,
766    pub visibility: Visibility,
767    /// Permitted subclasses (for sealed classes)
768    pub permits: Vec<std::string::String>,
769}
770impl JavaClass {
771    /// Create a simple public class.
772    pub fn new(name: &str) -> Self {
773        JavaClass {
774            name: name.to_string(),
775            superclass: None,
776            interfaces: Vec::new(),
777            fields: Vec::new(),
778            methods: Vec::new(),
779            inner_classes: Vec::new(),
780            modifiers: Vec::new(),
781            annotations: Vec::new(),
782            type_params: Vec::new(),
783            visibility: Visibility::Public,
784            permits: Vec::new(),
785        }
786    }
787}
788/// A Java enum declaration.
789#[derive(Debug, Clone)]
790pub struct JavaEnum {
791    pub name: std::string::String,
792    pub constants: Vec<JavaEnumConstant>,
793    pub fields: Vec<JavaField>,
794    pub methods: Vec<JavaMethod>,
795    pub interfaces: Vec<std::string::String>,
796    pub visibility: Visibility,
797    pub annotations: Vec<std::string::String>,
798}
799impl JavaEnum {
800    /// Create a simple public enum with named constants.
801    pub fn new(name: &str, constants: Vec<&str>) -> Self {
802        JavaEnum {
803            name: name.to_string(),
804            constants: constants
805                .into_iter()
806                .map(|c| JavaEnumConstant {
807                    name: c.to_string(),
808                    args: Vec::new(),
809                    annotations: Vec::new(),
810                })
811                .collect(),
812            fields: Vec::new(),
813            methods: Vec::new(),
814            interfaces: Vec::new(),
815            visibility: Visibility::Public,
816            annotations: Vec::new(),
817        }
818    }
819}
820#[allow(dead_code)]
821#[derive(Debug, Clone)]
822pub struct JavaDominatorTree {
823    pub idom: Vec<Option<u32>>,
824    pub dom_children: Vec<Vec<u32>>,
825    pub dom_depth: Vec<u32>,
826}
827impl JavaDominatorTree {
828    #[allow(dead_code)]
829    pub fn new(size: usize) -> Self {
830        JavaDominatorTree {
831            idom: vec![None; size],
832            dom_children: vec![Vec::new(); size],
833            dom_depth: vec![0; size],
834        }
835    }
836    #[allow(dead_code)]
837    pub fn set_idom(&mut self, node: usize, idom: u32) {
838        self.idom[node] = Some(idom);
839    }
840    #[allow(dead_code)]
841    pub fn dominates(&self, a: usize, b: usize) -> bool {
842        if a == b {
843            return true;
844        }
845        let mut cur = b;
846        loop {
847            match self.idom[cur] {
848                Some(parent) if parent as usize == a => return true,
849                Some(parent) if parent as usize == cur => return false,
850                Some(parent) => cur = parent as usize,
851                None => return false,
852            }
853        }
854    }
855    #[allow(dead_code)]
856    pub fn depth(&self, node: usize) -> u32 {
857        self.dom_depth.get(node).copied().unwrap_or(0)
858    }
859}
860#[allow(dead_code)]
861pub struct JavaPassRegistry {
862    pub(super) configs: Vec<JavaPassConfig>,
863    pub(super) stats: std::collections::HashMap<String, JavaPassStats>,
864}
865impl JavaPassRegistry {
866    #[allow(dead_code)]
867    pub fn new() -> Self {
868        JavaPassRegistry {
869            configs: Vec::new(),
870            stats: std::collections::HashMap::new(),
871        }
872    }
873    #[allow(dead_code)]
874    pub fn register(&mut self, config: JavaPassConfig) {
875        self.stats
876            .insert(config.pass_name.clone(), JavaPassStats::new());
877        self.configs.push(config);
878    }
879    #[allow(dead_code)]
880    pub fn enabled_passes(&self) -> Vec<&JavaPassConfig> {
881        self.configs.iter().filter(|c| c.enabled).collect()
882    }
883    #[allow(dead_code)]
884    pub fn get_stats(&self, name: &str) -> Option<&JavaPassStats> {
885        self.stats.get(name)
886    }
887    #[allow(dead_code)]
888    pub fn total_passes(&self) -> usize {
889        self.configs.len()
890    }
891    #[allow(dead_code)]
892    pub fn enabled_count(&self) -> usize {
893        self.enabled_passes().len()
894    }
895    #[allow(dead_code)]
896    pub fn update_stats(&mut self, name: &str, changes: u64, time_ms: u64, iter: u32) {
897        if let Some(stats) = self.stats.get_mut(name) {
898            stats.record_run(changes, time_ms, iter);
899        }
900    }
901}
902#[allow(dead_code)]
903pub struct JavaConstantFoldingHelper;
904impl JavaConstantFoldingHelper {
905    #[allow(dead_code)]
906    pub fn fold_add_i64(a: i64, b: i64) -> Option<i64> {
907        a.checked_add(b)
908    }
909    #[allow(dead_code)]
910    pub fn fold_sub_i64(a: i64, b: i64) -> Option<i64> {
911        a.checked_sub(b)
912    }
913    #[allow(dead_code)]
914    pub fn fold_mul_i64(a: i64, b: i64) -> Option<i64> {
915        a.checked_mul(b)
916    }
917    #[allow(dead_code)]
918    pub fn fold_div_i64(a: i64, b: i64) -> Option<i64> {
919        if b == 0 {
920            None
921        } else {
922            a.checked_div(b)
923        }
924    }
925    #[allow(dead_code)]
926    pub fn fold_add_f64(a: f64, b: f64) -> f64 {
927        a + b
928    }
929    #[allow(dead_code)]
930    pub fn fold_mul_f64(a: f64, b: f64) -> f64 {
931        a * b
932    }
933    #[allow(dead_code)]
934    pub fn fold_neg_i64(a: i64) -> Option<i64> {
935        a.checked_neg()
936    }
937    #[allow(dead_code)]
938    pub fn fold_not_bool(a: bool) -> bool {
939        !a
940    }
941    #[allow(dead_code)]
942    pub fn fold_and_bool(a: bool, b: bool) -> bool {
943        a && b
944    }
945    #[allow(dead_code)]
946    pub fn fold_or_bool(a: bool, b: bool) -> bool {
947        a || b
948    }
949    #[allow(dead_code)]
950    pub fn fold_shl_i64(a: i64, b: u32) -> Option<i64> {
951        a.checked_shl(b)
952    }
953    #[allow(dead_code)]
954    pub fn fold_shr_i64(a: i64, b: u32) -> Option<i64> {
955        a.checked_shr(b)
956    }
957    #[allow(dead_code)]
958    pub fn fold_rem_i64(a: i64, b: i64) -> Option<i64> {
959        if b == 0 {
960            None
961        } else {
962            Some(a % b)
963        }
964    }
965    #[allow(dead_code)]
966    pub fn fold_bitand_i64(a: i64, b: i64) -> i64 {
967        a & b
968    }
969    #[allow(dead_code)]
970    pub fn fold_bitor_i64(a: i64, b: i64) -> i64 {
971        a | b
972    }
973    #[allow(dead_code)]
974    pub fn fold_bitxor_i64(a: i64, b: i64) -> i64 {
975        a ^ b
976    }
977    #[allow(dead_code)]
978    pub fn fold_bitnot_i64(a: i64) -> i64 {
979        !a
980    }
981}
982/// A sealed interface declaration (Java 17+).
983///
984/// ```java
985/// public sealed interface Expr permits Lit, Add, Mul {}
986/// ```
987#[derive(Debug, Clone)]
988pub struct SealedInterface {
989    pub name: std::string::String,
990    /// Permitted subclasses/records
991    pub permits: Vec<std::string::String>,
992    /// Methods defined in the interface (default or abstract)
993    pub methods: Vec<JavaMethod>,
994    /// Annotations
995    pub annotations: Vec<std::string::String>,
996    /// Extended interfaces
997    pub extends: Vec<std::string::String>,
998}
999impl SealedInterface {
1000    /// Create a simple sealed interface.
1001    pub fn new(name: &str, permits: Vec<&str>) -> Self {
1002        SealedInterface {
1003            name: name.to_string(),
1004            permits: permits.into_iter().map(|s| s.to_string()).collect(),
1005            methods: Vec::new(),
1006            annotations: Vec::new(),
1007            extends: Vec::new(),
1008        }
1009    }
1010}
1011/// A Java record declaration (Java 16+).
1012///
1013/// ```java
1014/// public record Point(int x, int y) {}
1015/// ```
1016#[derive(Debug, Clone)]
1017pub struct JavaRecord {
1018    pub name: std::string::String,
1019    /// Record components (name, type)
1020    pub components: Vec<(std::string::String, JavaType)>,
1021    /// Additional methods defined inside the record
1022    pub methods: Vec<JavaMethod>,
1023    /// Whether the record is `sealed` (Java 17+)
1024    pub is_sealed: bool,
1025    /// Interfaces this record implements
1026    pub implements: Vec<std::string::String>,
1027    /// Annotations
1028    pub annotations: Vec<std::string::String>,
1029}
1030impl JavaRecord {
1031    /// Create a simple public record.
1032    pub fn new(name: &str, components: Vec<(&str, JavaType)>) -> Self {
1033        JavaRecord {
1034            name: name.to_string(),
1035            components: components
1036                .into_iter()
1037                .map(|(n, t)| (n.to_string(), t))
1038                .collect(),
1039            methods: Vec::new(),
1040            is_sealed: false,
1041            implements: Vec::new(),
1042            annotations: Vec::new(),
1043        }
1044    }
1045}
1046#[allow(dead_code)]
1047#[derive(Debug, Clone)]
1048pub struct JavaAnalysisCache {
1049    pub(super) entries: std::collections::HashMap<String, JavaCacheEntry>,
1050    pub(super) max_size: usize,
1051    pub(super) hits: u64,
1052    pub(super) misses: u64,
1053}
1054impl JavaAnalysisCache {
1055    #[allow(dead_code)]
1056    pub fn new(max_size: usize) -> Self {
1057        JavaAnalysisCache {
1058            entries: std::collections::HashMap::new(),
1059            max_size,
1060            hits: 0,
1061            misses: 0,
1062        }
1063    }
1064    #[allow(dead_code)]
1065    pub fn get(&mut self, key: &str) -> Option<&JavaCacheEntry> {
1066        if self.entries.contains_key(key) {
1067            self.hits += 1;
1068            self.entries.get(key)
1069        } else {
1070            self.misses += 1;
1071            None
1072        }
1073    }
1074    #[allow(dead_code)]
1075    pub fn insert(&mut self, key: String, data: Vec<u8>) {
1076        if self.entries.len() >= self.max_size {
1077            if let Some(oldest) = self.entries.keys().next().cloned() {
1078                self.entries.remove(&oldest);
1079            }
1080        }
1081        self.entries.insert(
1082            key.clone(),
1083            JavaCacheEntry {
1084                key,
1085                data,
1086                timestamp: 0,
1087                valid: true,
1088            },
1089        );
1090    }
1091    #[allow(dead_code)]
1092    pub fn invalidate(&mut self, key: &str) {
1093        if let Some(entry) = self.entries.get_mut(key) {
1094            entry.valid = false;
1095        }
1096    }
1097    #[allow(dead_code)]
1098    pub fn clear(&mut self) {
1099        self.entries.clear();
1100    }
1101    #[allow(dead_code)]
1102    pub fn hit_rate(&self) -> f64 {
1103        let total = self.hits + self.misses;
1104        if total == 0 {
1105            return 0.0;
1106        }
1107        self.hits as f64 / total as f64
1108    }
1109    #[allow(dead_code)]
1110    pub fn size(&self) -> usize {
1111        self.entries.len()
1112    }
1113}
1114/// Java type representation.
1115#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1116pub enum JavaType {
1117    /// `int` — 32-bit signed integer
1118    Int,
1119    /// `long` — 64-bit signed integer
1120    Long,
1121    /// `double` — 64-bit floating point
1122    Double,
1123    /// `float` — 32-bit floating point
1124    Float,
1125    /// `boolean`
1126    Boolean,
1127    /// `char`
1128    Char,
1129    /// `byte`
1130    Byte,
1131    /// `short`
1132    Short,
1133    /// `void`
1134    Void,
1135    /// `String`
1136    String,
1137    /// `Object`
1138    Object,
1139    /// `T[]` — Java array
1140    Array(Box<JavaType>),
1141    /// `List<T>`
1142    List(Box<JavaType>),
1143    /// `Map<K, V>`
1144    Map(Box<JavaType>, Box<JavaType>),
1145    /// `Optional<T>`
1146    Optional(Box<JavaType>),
1147    /// User-defined named type
1148    Custom(std::string::String),
1149    /// Generic instantiation: `MyType<A, B>`
1150    Generic(std::string::String, Vec<JavaType>),
1151}
1152/// Java literal values.
1153#[derive(Debug, Clone, PartialEq)]
1154pub enum JavaLit {
1155    /// Integer literal: `42`
1156    Int(i64),
1157    /// Long literal: `42L`
1158    Long(i64),
1159    /// Double literal: `3.14`
1160    Double(f64),
1161    /// Float literal: `3.14f`
1162    Float(f64),
1163    /// Boolean literal: `true` / `false`
1164    Bool(bool),
1165    /// Char literal: `'a'`
1166    Char(char),
1167    /// String literal: `"hello"`
1168    Str(std::string::String),
1169    /// Null literal: `null`
1170    Null,
1171}
1172#[allow(dead_code)]
1173#[derive(Debug, Clone)]
1174pub struct JavaLivenessInfo {
1175    pub live_in: Vec<std::collections::HashSet<u32>>,
1176    pub live_out: Vec<std::collections::HashSet<u32>>,
1177    pub defs: Vec<std::collections::HashSet<u32>>,
1178    pub uses: Vec<std::collections::HashSet<u32>>,
1179}
1180impl JavaLivenessInfo {
1181    #[allow(dead_code)]
1182    pub fn new(block_count: usize) -> Self {
1183        JavaLivenessInfo {
1184            live_in: vec![std::collections::HashSet::new(); block_count],
1185            live_out: vec![std::collections::HashSet::new(); block_count],
1186            defs: vec![std::collections::HashSet::new(); block_count],
1187            uses: vec![std::collections::HashSet::new(); block_count],
1188        }
1189    }
1190    #[allow(dead_code)]
1191    pub fn add_def(&mut self, block: usize, var: u32) {
1192        if block < self.defs.len() {
1193            self.defs[block].insert(var);
1194        }
1195    }
1196    #[allow(dead_code)]
1197    pub fn add_use(&mut self, block: usize, var: u32) {
1198        if block < self.uses.len() {
1199            self.uses[block].insert(var);
1200        }
1201    }
1202    #[allow(dead_code)]
1203    pub fn is_live_in(&self, block: usize, var: u32) -> bool {
1204        self.live_in
1205            .get(block)
1206            .map(|s| s.contains(&var))
1207            .unwrap_or(false)
1208    }
1209    #[allow(dead_code)]
1210    pub fn is_live_out(&self, block: usize, var: u32) -> bool {
1211        self.live_out
1212            .get(block)
1213            .map(|s| s.contains(&var))
1214            .unwrap_or(false)
1215    }
1216}