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::Str(s) => JavaExpr::Lit(JavaLit::Str(s.clone())),
464        }
465    }
466}
467/// Java statement AST.
468#[derive(Debug, Clone, PartialEq)]
469pub enum JavaStmt {
470    /// Expression statement: `expr;`
471    Expr(JavaExpr),
472    /// Local variable declaration: `Type name = init;` or `var name = init;`
473    LocalVar {
474        ty: Option<JavaType>,
475        name: std::string::String,
476        init: Option<JavaExpr>,
477        is_final: bool,
478    },
479    /// If statement: `if (cond) { then } else { else_ }`
480    If(JavaExpr, Vec<JavaStmt>, Vec<JavaStmt>),
481    /// Switch expression/statement
482    Switch {
483        scrutinee: JavaExpr,
484        cases: Vec<(JavaExpr, Vec<JavaStmt>)>,
485        default: Vec<JavaStmt>,
486    },
487    /// Classic for loop: `for (init; cond; update) { body }`
488    For {
489        init: Option<Box<JavaStmt>>,
490        cond: Option<JavaExpr>,
491        update: Option<JavaExpr>,
492        body: Vec<JavaStmt>,
493    },
494    /// Enhanced for loop: `for (Type elem : iterable) { body }`
495    ForEach {
496        ty: JavaType,
497        elem: std::string::String,
498        iterable: JavaExpr,
499        body: Vec<JavaStmt>,
500    },
501    /// While loop: `while (cond) { body }`
502    While(JavaExpr, Vec<JavaStmt>),
503    /// Do-while loop: `do { body } while (cond);`
504    DoWhile(Vec<JavaStmt>, JavaExpr),
505    /// Return statement: `return expr;` or `return;`
506    Return(Option<JavaExpr>),
507    /// Throw statement: `throw expr;`
508    Throw(JavaExpr),
509    /// Try-catch-finally
510    TryCatch {
511        body: Vec<JavaStmt>,
512        catches: Vec<JavaCatchClause>,
513        finally: Vec<JavaStmt>,
514    },
515    /// Try-with-resources
516    TryWithResources {
517        resources: Vec<(std::string::String, JavaExpr)>,
518        body: Vec<JavaStmt>,
519        catches: Vec<JavaCatchClause>,
520        finally: Vec<JavaStmt>,
521    },
522    /// Synchronized block: `synchronized (lock) { body }`
523    Synchronized(JavaExpr, Vec<JavaStmt>),
524    /// Break statement
525    Break(Option<std::string::String>),
526    /// Continue statement
527    Continue(Option<std::string::String>),
528    /// Assert statement: `assert cond : msg;`
529    Assert(JavaExpr, Option<JavaExpr>),
530}
531/// Modifiers that can appear on a class.
532#[derive(Debug, Clone, PartialEq, Eq)]
533pub enum ClassModifier {
534    Sealed,
535    Abstract,
536    Final,
537    Static,
538    NonSealed,
539}
540#[allow(dead_code)]
541#[derive(Debug, Clone, PartialEq)]
542pub enum JavaPassPhase {
543    Analysis,
544    Transformation,
545    Verification,
546    Cleanup,
547}
548impl JavaPassPhase {
549    #[allow(dead_code)]
550    pub fn name(&self) -> &str {
551        match self {
552            JavaPassPhase::Analysis => "analysis",
553            JavaPassPhase::Transformation => "transformation",
554            JavaPassPhase::Verification => "verification",
555            JavaPassPhase::Cleanup => "cleanup",
556        }
557    }
558    #[allow(dead_code)]
559    pub fn is_modifying(&self) -> bool {
560        matches!(self, JavaPassPhase::Transformation | JavaPassPhase::Cleanup)
561    }
562}
563#[allow(dead_code)]
564#[derive(Debug, Clone)]
565pub struct JavaPassConfig {
566    pub phase: JavaPassPhase,
567    pub enabled: bool,
568    pub max_iterations: u32,
569    pub debug_output: bool,
570    pub pass_name: String,
571}
572impl JavaPassConfig {
573    #[allow(dead_code)]
574    pub fn new(name: impl Into<String>, phase: JavaPassPhase) -> Self {
575        JavaPassConfig {
576            phase,
577            enabled: true,
578            max_iterations: 10,
579            debug_output: false,
580            pass_name: name.into(),
581        }
582    }
583    #[allow(dead_code)]
584    pub fn disabled(mut self) -> Self {
585        self.enabled = false;
586        self
587    }
588    #[allow(dead_code)]
589    pub fn with_debug(mut self) -> Self {
590        self.debug_output = true;
591        self
592    }
593    #[allow(dead_code)]
594    pub fn max_iter(mut self, n: u32) -> Self {
595        self.max_iterations = n;
596        self
597    }
598}
599/// Java access modifiers.
600#[derive(Debug, Clone, PartialEq, Eq)]
601pub enum Visibility {
602    Public,
603    Protected,
604    Private,
605    /// Package-private (no modifier)
606    Package,
607}
608/// A Java enum constant.
609#[derive(Debug, Clone)]
610pub struct JavaEnumConstant {
611    pub name: std::string::String,
612    pub args: Vec<JavaExpr>,
613    pub annotations: Vec<std::string::String>,
614}
615#[allow(dead_code)]
616#[derive(Debug, Clone)]
617pub struct JavaDepGraph {
618    pub(super) nodes: Vec<u32>,
619    pub(super) edges: Vec<(u32, u32)>,
620}
621impl JavaDepGraph {
622    #[allow(dead_code)]
623    pub fn new() -> Self {
624        JavaDepGraph {
625            nodes: Vec::new(),
626            edges: Vec::new(),
627        }
628    }
629    #[allow(dead_code)]
630    pub fn add_node(&mut self, id: u32) {
631        if !self.nodes.contains(&id) {
632            self.nodes.push(id);
633        }
634    }
635    #[allow(dead_code)]
636    pub fn add_dep(&mut self, dep: u32, dependent: u32) {
637        self.add_node(dep);
638        self.add_node(dependent);
639        self.edges.push((dep, dependent));
640    }
641    #[allow(dead_code)]
642    pub fn dependents_of(&self, node: u32) -> Vec<u32> {
643        self.edges
644            .iter()
645            .filter(|(d, _)| *d == node)
646            .map(|(_, dep)| *dep)
647            .collect()
648    }
649    #[allow(dead_code)]
650    pub fn dependencies_of(&self, node: u32) -> Vec<u32> {
651        self.edges
652            .iter()
653            .filter(|(_, dep)| *dep == node)
654            .map(|(d, _)| *d)
655            .collect()
656    }
657    #[allow(dead_code)]
658    pub fn topological_sort(&self) -> Vec<u32> {
659        let mut in_degree: std::collections::HashMap<u32, u32> = std::collections::HashMap::new();
660        for &n in &self.nodes {
661            in_degree.insert(n, 0);
662        }
663        for (_, dep) in &self.edges {
664            *in_degree.entry(*dep).or_insert(0) += 1;
665        }
666        let mut queue: std::collections::VecDeque<u32> = self
667            .nodes
668            .iter()
669            .filter(|&&n| in_degree[&n] == 0)
670            .copied()
671            .collect();
672        let mut result = Vec::new();
673        while let Some(node) = queue.pop_front() {
674            result.push(node);
675            for dep in self.dependents_of(node) {
676                let cnt = in_degree.entry(dep).or_insert(0);
677                *cnt = cnt.saturating_sub(1);
678                if *cnt == 0 {
679                    queue.push_back(dep);
680                }
681            }
682        }
683        result
684    }
685    #[allow(dead_code)]
686    pub fn has_cycle(&self) -> bool {
687        self.topological_sort().len() < self.nodes.len()
688    }
689}
690#[allow(dead_code)]
691#[derive(Debug, Clone)]
692pub struct JavaCacheEntry {
693    pub key: String,
694    pub data: Vec<u8>,
695    pub timestamp: u64,
696    pub valid: bool,
697}
698/// A single catch clause in a try-catch.
699#[derive(Debug, Clone, PartialEq)]
700pub struct JavaCatchClause {
701    /// Exception type(s) (e.g. `"IOException"` or `"IOException | SQLException"`)
702    pub exception_types: Vec<std::string::String>,
703    /// Bound variable name
704    pub var_name: std::string::String,
705    /// Handler body
706    pub body: Vec<JavaStmt>,
707}
708/// Java expression AST.
709#[derive(Debug, Clone, PartialEq)]
710pub enum JavaExpr {
711    /// Literal value: `42`, `"hello"`, `null`
712    Lit(JavaLit),
713    /// Variable or identifier: `x`, `MyClass`
714    Var(std::string::String),
715    /// Binary operation: `a + b`
716    BinOp(std::string::String, Box<JavaExpr>, Box<JavaExpr>),
717    /// Unary operation: `!x`, `-n`
718    UnaryOp(std::string::String, Box<JavaExpr>),
719    /// Static or free function call: `f(a, b)`
720    Call(Box<JavaExpr>, Vec<JavaExpr>),
721    /// Instance method call: `obj.method(args...)`
722    MethodCall(Box<JavaExpr>, std::string::String, Vec<JavaExpr>),
723    /// Object instantiation: `new Foo(args...)`
724    New(std::string::String, Vec<JavaExpr>),
725    /// Cast: `(Type) expr`
726    Cast(JavaType, Box<JavaExpr>),
727    /// Instanceof check: `expr instanceof Type`
728    Instanceof(Box<JavaExpr>, std::string::String),
729    /// Ternary: `cond ? then : else`
730    Ternary(Box<JavaExpr>, Box<JavaExpr>, Box<JavaExpr>),
731    /// Null literal (convenience variant)
732    Null,
733    /// Lambda expression: `(x, y) -> expr`
734    Lambda(Vec<std::string::String>, Box<JavaExpr>),
735    /// Method reference: `Class::method`
736    MethodRef(std::string::String, std::string::String),
737    /// Array access: `arr[idx]`
738    ArrayAccess(Box<JavaExpr>, Box<JavaExpr>),
739    /// Field access: `obj.field`
740    FieldAccess(Box<JavaExpr>, std::string::String),
741}
742/// A field declaration in a Java class.
743#[derive(Debug, Clone)]
744pub struct JavaField {
745    pub name: std::string::String,
746    pub ty: JavaType,
747    pub init: Option<JavaExpr>,
748    pub visibility: Visibility,
749    pub is_static: bool,
750    pub is_final: bool,
751    pub annotations: Vec<std::string::String>,
752}
753/// A Java class declaration.
754#[derive(Debug, Clone)]
755pub struct JavaClass {
756    pub name: std::string::String,
757    pub superclass: Option<std::string::String>,
758    pub interfaces: Vec<std::string::String>,
759    pub fields: Vec<JavaField>,
760    pub methods: Vec<JavaMethod>,
761    pub inner_classes: Vec<JavaClass>,
762    pub modifiers: Vec<ClassModifier>,
763    pub annotations: Vec<std::string::String>,
764    pub type_params: Vec<std::string::String>,
765    pub visibility: Visibility,
766    /// Permitted subclasses (for sealed classes)
767    pub permits: Vec<std::string::String>,
768}
769impl JavaClass {
770    /// Create a simple public class.
771    pub fn new(name: &str) -> Self {
772        JavaClass {
773            name: name.to_string(),
774            superclass: None,
775            interfaces: Vec::new(),
776            fields: Vec::new(),
777            methods: Vec::new(),
778            inner_classes: Vec::new(),
779            modifiers: Vec::new(),
780            annotations: Vec::new(),
781            type_params: Vec::new(),
782            visibility: Visibility::Public,
783            permits: Vec::new(),
784        }
785    }
786}
787/// A Java enum declaration.
788#[derive(Debug, Clone)]
789pub struct JavaEnum {
790    pub name: std::string::String,
791    pub constants: Vec<JavaEnumConstant>,
792    pub fields: Vec<JavaField>,
793    pub methods: Vec<JavaMethod>,
794    pub interfaces: Vec<std::string::String>,
795    pub visibility: Visibility,
796    pub annotations: Vec<std::string::String>,
797}
798impl JavaEnum {
799    /// Create a simple public enum with named constants.
800    pub fn new(name: &str, constants: Vec<&str>) -> Self {
801        JavaEnum {
802            name: name.to_string(),
803            constants: constants
804                .into_iter()
805                .map(|c| JavaEnumConstant {
806                    name: c.to_string(),
807                    args: Vec::new(),
808                    annotations: Vec::new(),
809                })
810                .collect(),
811            fields: Vec::new(),
812            methods: Vec::new(),
813            interfaces: Vec::new(),
814            visibility: Visibility::Public,
815            annotations: Vec::new(),
816        }
817    }
818}
819#[allow(dead_code)]
820#[derive(Debug, Clone)]
821pub struct JavaDominatorTree {
822    pub idom: Vec<Option<u32>>,
823    pub dom_children: Vec<Vec<u32>>,
824    pub dom_depth: Vec<u32>,
825}
826impl JavaDominatorTree {
827    #[allow(dead_code)]
828    pub fn new(size: usize) -> Self {
829        JavaDominatorTree {
830            idom: vec![None; size],
831            dom_children: vec![Vec::new(); size],
832            dom_depth: vec![0; size],
833        }
834    }
835    #[allow(dead_code)]
836    pub fn set_idom(&mut self, node: usize, idom: u32) {
837        self.idom[node] = Some(idom);
838    }
839    #[allow(dead_code)]
840    pub fn dominates(&self, a: usize, b: usize) -> bool {
841        if a == b {
842            return true;
843        }
844        let mut cur = b;
845        loop {
846            match self.idom[cur] {
847                Some(parent) if parent as usize == a => return true,
848                Some(parent) if parent as usize == cur => return false,
849                Some(parent) => cur = parent as usize,
850                None => return false,
851            }
852        }
853    }
854    #[allow(dead_code)]
855    pub fn depth(&self, node: usize) -> u32 {
856        self.dom_depth.get(node).copied().unwrap_or(0)
857    }
858}
859#[allow(dead_code)]
860pub struct JavaPassRegistry {
861    pub(super) configs: Vec<JavaPassConfig>,
862    pub(super) stats: std::collections::HashMap<String, JavaPassStats>,
863}
864impl JavaPassRegistry {
865    #[allow(dead_code)]
866    pub fn new() -> Self {
867        JavaPassRegistry {
868            configs: Vec::new(),
869            stats: std::collections::HashMap::new(),
870        }
871    }
872    #[allow(dead_code)]
873    pub fn register(&mut self, config: JavaPassConfig) {
874        self.stats
875            .insert(config.pass_name.clone(), JavaPassStats::new());
876        self.configs.push(config);
877    }
878    #[allow(dead_code)]
879    pub fn enabled_passes(&self) -> Vec<&JavaPassConfig> {
880        self.configs.iter().filter(|c| c.enabled).collect()
881    }
882    #[allow(dead_code)]
883    pub fn get_stats(&self, name: &str) -> Option<&JavaPassStats> {
884        self.stats.get(name)
885    }
886    #[allow(dead_code)]
887    pub fn total_passes(&self) -> usize {
888        self.configs.len()
889    }
890    #[allow(dead_code)]
891    pub fn enabled_count(&self) -> usize {
892        self.enabled_passes().len()
893    }
894    #[allow(dead_code)]
895    pub fn update_stats(&mut self, name: &str, changes: u64, time_ms: u64, iter: u32) {
896        if let Some(stats) = self.stats.get_mut(name) {
897            stats.record_run(changes, time_ms, iter);
898        }
899    }
900}
901#[allow(dead_code)]
902pub struct JavaConstantFoldingHelper;
903impl JavaConstantFoldingHelper {
904    #[allow(dead_code)]
905    pub fn fold_add_i64(a: i64, b: i64) -> Option<i64> {
906        a.checked_add(b)
907    }
908    #[allow(dead_code)]
909    pub fn fold_sub_i64(a: i64, b: i64) -> Option<i64> {
910        a.checked_sub(b)
911    }
912    #[allow(dead_code)]
913    pub fn fold_mul_i64(a: i64, b: i64) -> Option<i64> {
914        a.checked_mul(b)
915    }
916    #[allow(dead_code)]
917    pub fn fold_div_i64(a: i64, b: i64) -> Option<i64> {
918        if b == 0 {
919            None
920        } else {
921            a.checked_div(b)
922        }
923    }
924    #[allow(dead_code)]
925    pub fn fold_add_f64(a: f64, b: f64) -> f64 {
926        a + b
927    }
928    #[allow(dead_code)]
929    pub fn fold_mul_f64(a: f64, b: f64) -> f64 {
930        a * b
931    }
932    #[allow(dead_code)]
933    pub fn fold_neg_i64(a: i64) -> Option<i64> {
934        a.checked_neg()
935    }
936    #[allow(dead_code)]
937    pub fn fold_not_bool(a: bool) -> bool {
938        !a
939    }
940    #[allow(dead_code)]
941    pub fn fold_and_bool(a: bool, b: bool) -> bool {
942        a && b
943    }
944    #[allow(dead_code)]
945    pub fn fold_or_bool(a: bool, b: bool) -> bool {
946        a || b
947    }
948    #[allow(dead_code)]
949    pub fn fold_shl_i64(a: i64, b: u32) -> Option<i64> {
950        a.checked_shl(b)
951    }
952    #[allow(dead_code)]
953    pub fn fold_shr_i64(a: i64, b: u32) -> Option<i64> {
954        a.checked_shr(b)
955    }
956    #[allow(dead_code)]
957    pub fn fold_rem_i64(a: i64, b: i64) -> Option<i64> {
958        if b == 0 {
959            None
960        } else {
961            Some(a % b)
962        }
963    }
964    #[allow(dead_code)]
965    pub fn fold_bitand_i64(a: i64, b: i64) -> i64 {
966        a & b
967    }
968    #[allow(dead_code)]
969    pub fn fold_bitor_i64(a: i64, b: i64) -> i64 {
970        a | b
971    }
972    #[allow(dead_code)]
973    pub fn fold_bitxor_i64(a: i64, b: i64) -> i64 {
974        a ^ b
975    }
976    #[allow(dead_code)]
977    pub fn fold_bitnot_i64(a: i64) -> i64 {
978        !a
979    }
980}
981/// A sealed interface declaration (Java 17+).
982///
983/// ```java
984/// public sealed interface Expr permits Lit, Add, Mul {}
985/// ```
986#[derive(Debug, Clone)]
987pub struct SealedInterface {
988    pub name: std::string::String,
989    /// Permitted subclasses/records
990    pub permits: Vec<std::string::String>,
991    /// Methods defined in the interface (default or abstract)
992    pub methods: Vec<JavaMethod>,
993    /// Annotations
994    pub annotations: Vec<std::string::String>,
995    /// Extended interfaces
996    pub extends: Vec<std::string::String>,
997}
998impl SealedInterface {
999    /// Create a simple sealed interface.
1000    pub fn new(name: &str, permits: Vec<&str>) -> Self {
1001        SealedInterface {
1002            name: name.to_string(),
1003            permits: permits.into_iter().map(|s| s.to_string()).collect(),
1004            methods: Vec::new(),
1005            annotations: Vec::new(),
1006            extends: Vec::new(),
1007        }
1008    }
1009}
1010/// A Java record declaration (Java 16+).
1011///
1012/// ```java
1013/// public record Point(int x, int y) {}
1014/// ```
1015#[derive(Debug, Clone)]
1016pub struct JavaRecord {
1017    pub name: std::string::String,
1018    /// Record components (name, type)
1019    pub components: Vec<(std::string::String, JavaType)>,
1020    /// Additional methods defined inside the record
1021    pub methods: Vec<JavaMethod>,
1022    /// Whether the record is `sealed` (Java 17+)
1023    pub is_sealed: bool,
1024    /// Interfaces this record implements
1025    pub implements: Vec<std::string::String>,
1026    /// Annotations
1027    pub annotations: Vec<std::string::String>,
1028}
1029impl JavaRecord {
1030    /// Create a simple public record.
1031    pub fn new(name: &str, components: Vec<(&str, JavaType)>) -> Self {
1032        JavaRecord {
1033            name: name.to_string(),
1034            components: components
1035                .into_iter()
1036                .map(|(n, t)| (n.to_string(), t))
1037                .collect(),
1038            methods: Vec::new(),
1039            is_sealed: false,
1040            implements: Vec::new(),
1041            annotations: Vec::new(),
1042        }
1043    }
1044}
1045#[allow(dead_code)]
1046#[derive(Debug, Clone)]
1047pub struct JavaAnalysisCache {
1048    pub(super) entries: std::collections::HashMap<String, JavaCacheEntry>,
1049    pub(super) max_size: usize,
1050    pub(super) hits: u64,
1051    pub(super) misses: u64,
1052}
1053impl JavaAnalysisCache {
1054    #[allow(dead_code)]
1055    pub fn new(max_size: usize) -> Self {
1056        JavaAnalysisCache {
1057            entries: std::collections::HashMap::new(),
1058            max_size,
1059            hits: 0,
1060            misses: 0,
1061        }
1062    }
1063    #[allow(dead_code)]
1064    pub fn get(&mut self, key: &str) -> Option<&JavaCacheEntry> {
1065        if self.entries.contains_key(key) {
1066            self.hits += 1;
1067            self.entries.get(key)
1068        } else {
1069            self.misses += 1;
1070            None
1071        }
1072    }
1073    #[allow(dead_code)]
1074    pub fn insert(&mut self, key: String, data: Vec<u8>) {
1075        if self.entries.len() >= self.max_size {
1076            if let Some(oldest) = self.entries.keys().next().cloned() {
1077                self.entries.remove(&oldest);
1078            }
1079        }
1080        self.entries.insert(
1081            key.clone(),
1082            JavaCacheEntry {
1083                key,
1084                data,
1085                timestamp: 0,
1086                valid: true,
1087            },
1088        );
1089    }
1090    #[allow(dead_code)]
1091    pub fn invalidate(&mut self, key: &str) {
1092        if let Some(entry) = self.entries.get_mut(key) {
1093            entry.valid = false;
1094        }
1095    }
1096    #[allow(dead_code)]
1097    pub fn clear(&mut self) {
1098        self.entries.clear();
1099    }
1100    #[allow(dead_code)]
1101    pub fn hit_rate(&self) -> f64 {
1102        let total = self.hits + self.misses;
1103        if total == 0 {
1104            return 0.0;
1105        }
1106        self.hits as f64 / total as f64
1107    }
1108    #[allow(dead_code)]
1109    pub fn size(&self) -> usize {
1110        self.entries.len()
1111    }
1112}
1113/// Java type representation.
1114#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1115pub enum JavaType {
1116    /// `int` — 32-bit signed integer
1117    Int,
1118    /// `long` — 64-bit signed integer
1119    Long,
1120    /// `double` — 64-bit floating point
1121    Double,
1122    /// `float` — 32-bit floating point
1123    Float,
1124    /// `boolean`
1125    Boolean,
1126    /// `char`
1127    Char,
1128    /// `byte`
1129    Byte,
1130    /// `short`
1131    Short,
1132    /// `void`
1133    Void,
1134    /// `String`
1135    String,
1136    /// `Object`
1137    Object,
1138    /// `T[]` — Java array
1139    Array(Box<JavaType>),
1140    /// `List<T>`
1141    List(Box<JavaType>),
1142    /// `Map<K, V>`
1143    Map(Box<JavaType>, Box<JavaType>),
1144    /// `Optional<T>`
1145    Optional(Box<JavaType>),
1146    /// User-defined named type
1147    Custom(std::string::String),
1148    /// Generic instantiation: `MyType<A, B>`
1149    Generic(std::string::String, Vec<JavaType>),
1150}
1151/// Java literal values.
1152#[derive(Debug, Clone, PartialEq)]
1153pub enum JavaLit {
1154    /// Integer literal: `42`
1155    Int(i64),
1156    /// Long literal: `42L`
1157    Long(i64),
1158    /// Double literal: `3.14`
1159    Double(f64),
1160    /// Float literal: `3.14f`
1161    Float(f64),
1162    /// Boolean literal: `true` / `false`
1163    Bool(bool),
1164    /// Char literal: `'a'`
1165    Char(char),
1166    /// String literal: `"hello"`
1167    Str(std::string::String),
1168    /// Null literal: `null`
1169    Null,
1170}
1171#[allow(dead_code)]
1172#[derive(Debug, Clone)]
1173pub struct JavaLivenessInfo {
1174    pub live_in: Vec<std::collections::HashSet<u32>>,
1175    pub live_out: Vec<std::collections::HashSet<u32>>,
1176    pub defs: Vec<std::collections::HashSet<u32>>,
1177    pub uses: Vec<std::collections::HashSet<u32>>,
1178}
1179impl JavaLivenessInfo {
1180    #[allow(dead_code)]
1181    pub fn new(block_count: usize) -> Self {
1182        JavaLivenessInfo {
1183            live_in: vec![std::collections::HashSet::new(); block_count],
1184            live_out: vec![std::collections::HashSet::new(); block_count],
1185            defs: vec![std::collections::HashSet::new(); block_count],
1186            uses: vec![std::collections::HashSet::new(); block_count],
1187        }
1188    }
1189    #[allow(dead_code)]
1190    pub fn add_def(&mut self, block: usize, var: u32) {
1191        if block < self.defs.len() {
1192            self.defs[block].insert(var);
1193        }
1194    }
1195    #[allow(dead_code)]
1196    pub fn add_use(&mut self, block: usize, var: u32) {
1197        if block < self.uses.len() {
1198            self.uses[block].insert(var);
1199        }
1200    }
1201    #[allow(dead_code)]
1202    pub fn is_live_in(&self, block: usize, var: u32) -> bool {
1203        self.live_in
1204            .get(block)
1205            .map(|s| s.contains(&var))
1206            .unwrap_or(false)
1207    }
1208    #[allow(dead_code)]
1209    pub fn is_live_out(&self, block: usize, var: u32) -> bool {
1210        self.live_out
1211            .get(block)
1212            .map(|s| s.contains(&var))
1213            .unwrap_or(false)
1214    }
1215}