Skip to main content

oxilean_codegen/scala_backend/
types.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5use crate::lcnf::*;
6
7use super::functions::*;
8use std::collections::{HashMap, HashSet, VecDeque};
9
10/// A single parameter in a Scala method.
11#[derive(Debug, Clone, PartialEq)]
12pub struct ScalaParam {
13    pub name: String,
14    pub ty: ScalaType,
15    pub default: Option<ScalaExpr>,
16}
17/// Statistics for ScalaExt passes.
18#[allow(dead_code)]
19#[derive(Debug, Clone, Default)]
20pub struct ScalaExtPassStats {
21    pub iterations: usize,
22    pub changed: bool,
23    pub nodes_visited: usize,
24    pub nodes_modified: usize,
25    pub time_ms: u64,
26    pub memory_bytes: usize,
27    pub errors: usize,
28}
29impl ScalaExtPassStats {
30    #[allow(dead_code)]
31    pub fn new() -> Self {
32        Self::default()
33    }
34    #[allow(dead_code)]
35    pub fn visit(&mut self) {
36        self.nodes_visited += 1;
37    }
38    #[allow(dead_code)]
39    pub fn modify(&mut self) {
40        self.nodes_modified += 1;
41        self.changed = true;
42    }
43    #[allow(dead_code)]
44    pub fn iterate(&mut self) {
45        self.iterations += 1;
46    }
47    #[allow(dead_code)]
48    pub fn error(&mut self) {
49        self.errors += 1;
50    }
51    #[allow(dead_code)]
52    pub fn efficiency(&self) -> f64 {
53        if self.nodes_visited == 0 {
54            0.0
55        } else {
56            self.nodes_modified as f64 / self.nodes_visited as f64
57        }
58    }
59    #[allow(dead_code)]
60    pub fn merge(&mut self, o: &ScalaExtPassStats) {
61        self.iterations += o.iterations;
62        self.changed |= o.changed;
63        self.nodes_visited += o.nodes_visited;
64        self.nodes_modified += o.nodes_modified;
65        self.time_ms += o.time_ms;
66        self.memory_bytes = self.memory_bytes.max(o.memory_bytes);
67        self.errors += o.errors;
68    }
69}
70/// Dependency graph for ScalaExt.
71#[allow(dead_code)]
72#[derive(Debug, Clone)]
73pub struct ScalaExtDepGraph {
74    pub(super) n: usize,
75    pub(super) adj: Vec<Vec<usize>>,
76    pub(super) rev: Vec<Vec<usize>>,
77    pub(super) edge_count: usize,
78}
79impl ScalaExtDepGraph {
80    #[allow(dead_code)]
81    pub fn new(n: usize) -> Self {
82        Self {
83            n,
84            adj: vec![Vec::new(); n],
85            rev: vec![Vec::new(); n],
86            edge_count: 0,
87        }
88    }
89    #[allow(dead_code)]
90    pub fn add_edge(&mut self, from: usize, to: usize) {
91        if from < self.n && to < self.n {
92            if !self.adj[from].contains(&to) {
93                self.adj[from].push(to);
94                self.rev[to].push(from);
95                self.edge_count += 1;
96            }
97        }
98    }
99    #[allow(dead_code)]
100    pub fn succs(&self, n: usize) -> &[usize] {
101        self.adj.get(n).map(|v| v.as_slice()).unwrap_or(&[])
102    }
103    #[allow(dead_code)]
104    pub fn preds(&self, n: usize) -> &[usize] {
105        self.rev.get(n).map(|v| v.as_slice()).unwrap_or(&[])
106    }
107    #[allow(dead_code)]
108    pub fn topo_sort(&self) -> Option<Vec<usize>> {
109        let mut deg: Vec<usize> = (0..self.n).map(|i| self.rev[i].len()).collect();
110        let mut q: std::collections::VecDeque<usize> =
111            (0..self.n).filter(|&i| deg[i] == 0).collect();
112        let mut out = Vec::with_capacity(self.n);
113        while let Some(u) = q.pop_front() {
114            out.push(u);
115            for &v in &self.adj[u] {
116                deg[v] -= 1;
117                if deg[v] == 0 {
118                    q.push_back(v);
119                }
120            }
121        }
122        if out.len() == self.n {
123            Some(out)
124        } else {
125            None
126        }
127    }
128    #[allow(dead_code)]
129    pub fn has_cycle(&self) -> bool {
130        self.topo_sort().is_none()
131    }
132    #[allow(dead_code)]
133    pub fn reachable(&self, start: usize) -> Vec<usize> {
134        let mut vis = vec![false; self.n];
135        let mut stk = vec![start];
136        let mut out = Vec::new();
137        while let Some(u) = stk.pop() {
138            if u < self.n && !vis[u] {
139                vis[u] = true;
140                out.push(u);
141                for &v in &self.adj[u] {
142                    if !vis[v] {
143                        stk.push(v);
144                    }
145                }
146            }
147        }
148        out
149    }
150    #[allow(dead_code)]
151    pub fn scc(&self) -> Vec<Vec<usize>> {
152        let mut visited = vec![false; self.n];
153        let mut order = Vec::new();
154        for i in 0..self.n {
155            if !visited[i] {
156                let mut stk = vec![(i, 0usize)];
157                while let Some((u, idx)) = stk.last_mut() {
158                    if !visited[*u] {
159                        visited[*u] = true;
160                    }
161                    if *idx < self.adj[*u].len() {
162                        let v = self.adj[*u][*idx];
163                        *idx += 1;
164                        if !visited[v] {
165                            stk.push((v, 0));
166                        }
167                    } else {
168                        order.push(*u);
169                        stk.pop();
170                    }
171                }
172            }
173        }
174        let mut comp = vec![usize::MAX; self.n];
175        let mut components: Vec<Vec<usize>> = Vec::new();
176        for &start in order.iter().rev() {
177            if comp[start] == usize::MAX {
178                let cid = components.len();
179                let mut component = Vec::new();
180                let mut stk = vec![start];
181                while let Some(u) = stk.pop() {
182                    if comp[u] == usize::MAX {
183                        comp[u] = cid;
184                        component.push(u);
185                        for &v in &self.rev[u] {
186                            if comp[v] == usize::MAX {
187                                stk.push(v);
188                            }
189                        }
190                    }
191                }
192                components.push(component);
193            }
194        }
195        components
196    }
197    #[allow(dead_code)]
198    pub fn node_count(&self) -> usize {
199        self.n
200    }
201    #[allow(dead_code)]
202    pub fn edge_count(&self) -> usize {
203        self.edge_count
204    }
205}
206#[allow(dead_code)]
207pub struct ScalaConstantFoldingHelper;
208impl ScalaConstantFoldingHelper {
209    #[allow(dead_code)]
210    pub fn fold_add_i64(a: i64, b: i64) -> Option<i64> {
211        a.checked_add(b)
212    }
213    #[allow(dead_code)]
214    pub fn fold_sub_i64(a: i64, b: i64) -> Option<i64> {
215        a.checked_sub(b)
216    }
217    #[allow(dead_code)]
218    pub fn fold_mul_i64(a: i64, b: i64) -> Option<i64> {
219        a.checked_mul(b)
220    }
221    #[allow(dead_code)]
222    pub fn fold_div_i64(a: i64, b: i64) -> Option<i64> {
223        if b == 0 {
224            None
225        } else {
226            a.checked_div(b)
227        }
228    }
229    #[allow(dead_code)]
230    pub fn fold_add_f64(a: f64, b: f64) -> f64 {
231        a + b
232    }
233    #[allow(dead_code)]
234    pub fn fold_mul_f64(a: f64, b: f64) -> f64 {
235        a * b
236    }
237    #[allow(dead_code)]
238    pub fn fold_neg_i64(a: i64) -> Option<i64> {
239        a.checked_neg()
240    }
241    #[allow(dead_code)]
242    pub fn fold_not_bool(a: bool) -> bool {
243        !a
244    }
245    #[allow(dead_code)]
246    pub fn fold_and_bool(a: bool, b: bool) -> bool {
247        a && b
248    }
249    #[allow(dead_code)]
250    pub fn fold_or_bool(a: bool, b: bool) -> bool {
251        a || b
252    }
253    #[allow(dead_code)]
254    pub fn fold_shl_i64(a: i64, b: u32) -> Option<i64> {
255        a.checked_shl(b)
256    }
257    #[allow(dead_code)]
258    pub fn fold_shr_i64(a: i64, b: u32) -> Option<i64> {
259        a.checked_shr(b)
260    }
261    #[allow(dead_code)]
262    pub fn fold_rem_i64(a: i64, b: i64) -> Option<i64> {
263        if b == 0 {
264            None
265        } else {
266            Some(a % b)
267        }
268    }
269    #[allow(dead_code)]
270    pub fn fold_bitand_i64(a: i64, b: i64) -> i64 {
271        a & b
272    }
273    #[allow(dead_code)]
274    pub fn fold_bitor_i64(a: i64, b: i64) -> i64 {
275        a | b
276    }
277    #[allow(dead_code)]
278    pub fn fold_bitxor_i64(a: i64, b: i64) -> i64 {
279        a ^ b
280    }
281    #[allow(dead_code)]
282    pub fn fold_bitnot_i64(a: i64) -> i64 {
283        !a
284    }
285}
286/// A `catch` clause in a Scala try expression.
287#[derive(Debug, Clone, PartialEq)]
288pub struct ScalaCatch {
289    pub pattern: ScalaPattern,
290    pub body: ScalaExpr,
291}
292/// A Scala method definition.
293#[derive(Debug, Clone, PartialEq)]
294pub struct ScalaMethod {
295    /// Method name
296    pub name: String,
297    /// Type parameters: `[A, B]`
298    pub type_params: Vec<String>,
299    /// Parameter lists (multiple for currying)
300    pub params: Vec<Vec<ScalaParam>>,
301    /// Return type
302    pub return_type: ScalaType,
303    /// Method body (None for abstract)
304    pub body: Option<ScalaExpr>,
305    /// Modifiers
306    pub modifiers: Vec<ScalaModifier>,
307}
308/// Liveness analysis for ScalaExt.
309#[allow(dead_code)]
310#[derive(Debug, Clone, Default)]
311pub struct ScalaExtLiveness {
312    pub live_in: Vec<Vec<usize>>,
313    pub live_out: Vec<Vec<usize>>,
314    pub defs: Vec<Vec<usize>>,
315    pub uses: Vec<Vec<usize>>,
316}
317impl ScalaExtLiveness {
318    #[allow(dead_code)]
319    pub fn new(n: usize) -> Self {
320        Self {
321            live_in: vec![Vec::new(); n],
322            live_out: vec![Vec::new(); n],
323            defs: vec![Vec::new(); n],
324            uses: vec![Vec::new(); n],
325        }
326    }
327    #[allow(dead_code)]
328    pub fn live_in(&self, b: usize, v: usize) -> bool {
329        self.live_in.get(b).map(|s| s.contains(&v)).unwrap_or(false)
330    }
331    #[allow(dead_code)]
332    pub fn live_out(&self, b: usize, v: usize) -> bool {
333        self.live_out
334            .get(b)
335            .map(|s| s.contains(&v))
336            .unwrap_or(false)
337    }
338    #[allow(dead_code)]
339    pub fn add_def(&mut self, b: usize, v: usize) {
340        if let Some(s) = self.defs.get_mut(b) {
341            if !s.contains(&v) {
342                s.push(v);
343            }
344        }
345    }
346    #[allow(dead_code)]
347    pub fn add_use(&mut self, b: usize, v: usize) {
348        if let Some(s) = self.uses.get_mut(b) {
349            if !s.contains(&v) {
350                s.push(v);
351            }
352        }
353    }
354    #[allow(dead_code)]
355    pub fn var_is_used_in_block(&self, b: usize, v: usize) -> bool {
356        self.uses.get(b).map(|s| s.contains(&v)).unwrap_or(false)
357    }
358    #[allow(dead_code)]
359    pub fn var_is_def_in_block(&self, b: usize, v: usize) -> bool {
360        self.defs.get(b).map(|s| s.contains(&v)).unwrap_or(false)
361    }
362}
363/// Scala expression AST.
364#[derive(Debug, Clone, PartialEq)]
365pub enum ScalaExpr {
366    /// Literal value
367    Lit(ScalaLit),
368    /// Variable reference: `foo`
369    Var(String),
370    /// Method call / application: `f(a, b)` or `obj.method(args)`
371    App(Box<ScalaExpr>, Vec<ScalaExpr>),
372    /// Infix operator: `a + b`
373    Infix(Box<ScalaExpr>, String, Box<ScalaExpr>),
374    /// Prefix operator: `!x`, `-x`
375    Prefix(String, Box<ScalaExpr>),
376    /// If-else expression
377    If(Box<ScalaExpr>, Box<ScalaExpr>, Box<ScalaExpr>),
378    /// Match expression
379    Match(Box<ScalaExpr>, Vec<ScalaCaseClause>),
380    /// For comprehension / for-yield
381    For(Vec<ScalaEnumerator>, Box<ScalaExpr>),
382    /// Try-catch-finally
383    Try(Box<ScalaExpr>, Vec<ScalaCatch>, Option<Box<ScalaExpr>>),
384    /// Lambda: `x => body` or `(x, y) => body`
385    Lambda(Vec<String>, Box<ScalaExpr>),
386    /// Block: `{ stmts; expr }`
387    Block(Vec<ScalaExpr>, Box<ScalaExpr>),
388    /// `new ClassName(args)`
389    New(String, Vec<ScalaExpr>),
390    /// `this`
391    This,
392    /// `super`
393    Super,
394    /// Assignment: `x = expr`
395    Assign(String, Box<ScalaExpr>),
396    /// Type ascription: `expr: Type`
397    TypeAnnotation(Box<ScalaExpr>, ScalaType),
398    /// Throw expression: `throw new Exception(...)`
399    Throw(Box<ScalaExpr>),
400}
401#[allow(dead_code)]
402#[derive(Debug, Clone)]
403pub struct ScalaDepGraph {
404    pub(super) nodes: Vec<u32>,
405    pub(super) edges: Vec<(u32, u32)>,
406}
407impl ScalaDepGraph {
408    #[allow(dead_code)]
409    pub fn new() -> Self {
410        ScalaDepGraph {
411            nodes: Vec::new(),
412            edges: Vec::new(),
413        }
414    }
415    #[allow(dead_code)]
416    pub fn add_node(&mut self, id: u32) {
417        if !self.nodes.contains(&id) {
418            self.nodes.push(id);
419        }
420    }
421    #[allow(dead_code)]
422    pub fn add_dep(&mut self, dep: u32, dependent: u32) {
423        self.add_node(dep);
424        self.add_node(dependent);
425        self.edges.push((dep, dependent));
426    }
427    #[allow(dead_code)]
428    pub fn dependents_of(&self, node: u32) -> Vec<u32> {
429        self.edges
430            .iter()
431            .filter(|(d, _)| *d == node)
432            .map(|(_, dep)| *dep)
433            .collect()
434    }
435    #[allow(dead_code)]
436    pub fn dependencies_of(&self, node: u32) -> Vec<u32> {
437        self.edges
438            .iter()
439            .filter(|(_, dep)| *dep == node)
440            .map(|(d, _)| *d)
441            .collect()
442    }
443    #[allow(dead_code)]
444    pub fn topological_sort(&self) -> Vec<u32> {
445        let mut in_degree: std::collections::HashMap<u32, u32> = std::collections::HashMap::new();
446        for &n in &self.nodes {
447            in_degree.insert(n, 0);
448        }
449        for (_, dep) in &self.edges {
450            *in_degree.entry(*dep).or_insert(0) += 1;
451        }
452        let mut queue: std::collections::VecDeque<u32> = self
453            .nodes
454            .iter()
455            .filter(|&&n| in_degree[&n] == 0)
456            .copied()
457            .collect();
458        let mut result = Vec::new();
459        while let Some(node) = queue.pop_front() {
460            result.push(node);
461            for dep in self.dependents_of(node) {
462                let cnt = in_degree.entry(dep).or_insert(0);
463                *cnt = cnt.saturating_sub(1);
464                if *cnt == 0 {
465                    queue.push_back(dep);
466                }
467            }
468        }
469        result
470    }
471    #[allow(dead_code)]
472    pub fn has_cycle(&self) -> bool {
473        self.topological_sort().len() < self.nodes.len()
474    }
475}
476/// Constant folding helper for ScalaExt.
477#[allow(dead_code)]
478#[derive(Debug, Clone, Default)]
479pub struct ScalaExtConstFolder {
480    pub(super) folds: usize,
481    pub(super) failures: usize,
482    pub(super) enabled: bool,
483}
484impl ScalaExtConstFolder {
485    #[allow(dead_code)]
486    pub fn new() -> Self {
487        Self {
488            folds: 0,
489            failures: 0,
490            enabled: true,
491        }
492    }
493    #[allow(dead_code)]
494    pub fn add_i64(&mut self, a: i64, b: i64) -> Option<i64> {
495        self.folds += 1;
496        a.checked_add(b)
497    }
498    #[allow(dead_code)]
499    pub fn sub_i64(&mut self, a: i64, b: i64) -> Option<i64> {
500        self.folds += 1;
501        a.checked_sub(b)
502    }
503    #[allow(dead_code)]
504    pub fn mul_i64(&mut self, a: i64, b: i64) -> Option<i64> {
505        self.folds += 1;
506        a.checked_mul(b)
507    }
508    #[allow(dead_code)]
509    pub fn div_i64(&mut self, a: i64, b: i64) -> Option<i64> {
510        if b == 0 {
511            self.failures += 1;
512            None
513        } else {
514            self.folds += 1;
515            a.checked_div(b)
516        }
517    }
518    #[allow(dead_code)]
519    pub fn rem_i64(&mut self, a: i64, b: i64) -> Option<i64> {
520        if b == 0 {
521            self.failures += 1;
522            None
523        } else {
524            self.folds += 1;
525            a.checked_rem(b)
526        }
527    }
528    #[allow(dead_code)]
529    pub fn neg_i64(&mut self, a: i64) -> Option<i64> {
530        self.folds += 1;
531        a.checked_neg()
532    }
533    #[allow(dead_code)]
534    pub fn shl_i64(&mut self, a: i64, s: u32) -> Option<i64> {
535        if s >= 64 {
536            self.failures += 1;
537            None
538        } else {
539            self.folds += 1;
540            a.checked_shl(s)
541        }
542    }
543    #[allow(dead_code)]
544    pub fn shr_i64(&mut self, a: i64, s: u32) -> Option<i64> {
545        if s >= 64 {
546            self.failures += 1;
547            None
548        } else {
549            self.folds += 1;
550            a.checked_shr(s)
551        }
552    }
553    #[allow(dead_code)]
554    pub fn and_i64(&mut self, a: i64, b: i64) -> i64 {
555        self.folds += 1;
556        a & b
557    }
558    #[allow(dead_code)]
559    pub fn or_i64(&mut self, a: i64, b: i64) -> i64 {
560        self.folds += 1;
561        a | b
562    }
563    #[allow(dead_code)]
564    pub fn xor_i64(&mut self, a: i64, b: i64) -> i64 {
565        self.folds += 1;
566        a ^ b
567    }
568    #[allow(dead_code)]
569    pub fn not_i64(&mut self, a: i64) -> i64 {
570        self.folds += 1;
571        !a
572    }
573    #[allow(dead_code)]
574    pub fn fold_count(&self) -> usize {
575        self.folds
576    }
577    #[allow(dead_code)]
578    pub fn failure_count(&self) -> usize {
579        self.failures
580    }
581    #[allow(dead_code)]
582    pub fn enable(&mut self) {
583        self.enabled = true;
584    }
585    #[allow(dead_code)]
586    pub fn disable(&mut self) {
587        self.enabled = false;
588    }
589    #[allow(dead_code)]
590    pub fn is_enabled(&self) -> bool {
591        self.enabled
592    }
593}
594/// Analysis cache for ScalaExt.
595#[allow(dead_code)]
596#[derive(Debug)]
597pub struct ScalaExtCache {
598    pub(super) entries: Vec<(u64, Vec<u8>, bool, u32)>,
599    pub(super) cap: usize,
600    pub(super) total_hits: u64,
601    pub(super) total_misses: u64,
602}
603impl ScalaExtCache {
604    #[allow(dead_code)]
605    pub fn new(cap: usize) -> Self {
606        Self {
607            entries: Vec::new(),
608            cap,
609            total_hits: 0,
610            total_misses: 0,
611        }
612    }
613    #[allow(dead_code)]
614    pub fn get(&mut self, key: u64) -> Option<&[u8]> {
615        for e in self.entries.iter_mut() {
616            if e.0 == key && e.2 {
617                e.3 += 1;
618                self.total_hits += 1;
619                return Some(&e.1);
620            }
621        }
622        self.total_misses += 1;
623        None
624    }
625    #[allow(dead_code)]
626    pub fn put(&mut self, key: u64, data: Vec<u8>) {
627        if self.entries.len() >= self.cap {
628            self.entries.retain(|e| e.2);
629            if self.entries.len() >= self.cap {
630                self.entries.remove(0);
631            }
632        }
633        self.entries.push((key, data, true, 0));
634    }
635    #[allow(dead_code)]
636    pub fn invalidate(&mut self) {
637        for e in self.entries.iter_mut() {
638            e.2 = false;
639        }
640    }
641    #[allow(dead_code)]
642    pub fn hit_rate(&self) -> f64 {
643        let t = self.total_hits + self.total_misses;
644        if t == 0 {
645            0.0
646        } else {
647            self.total_hits as f64 / t as f64
648        }
649    }
650    #[allow(dead_code)]
651    pub fn live_count(&self) -> usize {
652        self.entries.iter().filter(|e| e.2).count()
653    }
654}
655#[allow(dead_code)]
656#[derive(Debug, Clone)]
657pub struct ScalaLivenessInfo {
658    pub live_in: Vec<std::collections::HashSet<u32>>,
659    pub live_out: Vec<std::collections::HashSet<u32>>,
660    pub defs: Vec<std::collections::HashSet<u32>>,
661    pub uses: Vec<std::collections::HashSet<u32>>,
662}
663impl ScalaLivenessInfo {
664    #[allow(dead_code)]
665    pub fn new(block_count: usize) -> Self {
666        ScalaLivenessInfo {
667            live_in: vec![std::collections::HashSet::new(); block_count],
668            live_out: vec![std::collections::HashSet::new(); block_count],
669            defs: vec![std::collections::HashSet::new(); block_count],
670            uses: vec![std::collections::HashSet::new(); block_count],
671        }
672    }
673    #[allow(dead_code)]
674    pub fn add_def(&mut self, block: usize, var: u32) {
675        if block < self.defs.len() {
676            self.defs[block].insert(var);
677        }
678    }
679    #[allow(dead_code)]
680    pub fn add_use(&mut self, block: usize, var: u32) {
681        if block < self.uses.len() {
682            self.uses[block].insert(var);
683        }
684    }
685    #[allow(dead_code)]
686    pub fn is_live_in(&self, block: usize, var: u32) -> bool {
687        self.live_in
688            .get(block)
689            .map(|s| s.contains(&var))
690            .unwrap_or(false)
691    }
692    #[allow(dead_code)]
693    pub fn is_live_out(&self, block: usize, var: u32) -> bool {
694        self.live_out
695            .get(block)
696            .map(|s| s.contains(&var))
697            .unwrap_or(false)
698    }
699}
700#[allow(dead_code)]
701#[derive(Debug, Clone)]
702pub struct ScalaCacheEntry {
703    pub key: String,
704    pub data: Vec<u8>,
705    pub timestamp: u64,
706    pub valid: bool,
707}
708/// Worklist for ScalaExt.
709#[allow(dead_code)]
710#[derive(Debug, Clone)]
711pub struct ScalaExtWorklist {
712    pub(super) items: std::collections::VecDeque<usize>,
713    pub(super) present: Vec<bool>,
714}
715impl ScalaExtWorklist {
716    #[allow(dead_code)]
717    pub fn new(capacity: usize) -> Self {
718        Self {
719            items: std::collections::VecDeque::new(),
720            present: vec![false; capacity],
721        }
722    }
723    #[allow(dead_code)]
724    pub fn push(&mut self, id: usize) {
725        if id < self.present.len() && !self.present[id] {
726            self.present[id] = true;
727            self.items.push_back(id);
728        }
729    }
730    #[allow(dead_code)]
731    pub fn push_front(&mut self, id: usize) {
732        if id < self.present.len() && !self.present[id] {
733            self.present[id] = true;
734            self.items.push_front(id);
735        }
736    }
737    #[allow(dead_code)]
738    pub fn pop(&mut self) -> Option<usize> {
739        let id = self.items.pop_front()?;
740        if id < self.present.len() {
741            self.present[id] = false;
742        }
743        Some(id)
744    }
745    #[allow(dead_code)]
746    pub fn is_empty(&self) -> bool {
747        self.items.is_empty()
748    }
749    #[allow(dead_code)]
750    pub fn len(&self) -> usize {
751        self.items.len()
752    }
753    #[allow(dead_code)]
754    pub fn contains(&self, id: usize) -> bool {
755        id < self.present.len() && self.present[id]
756    }
757    #[allow(dead_code)]
758    pub fn drain_all(&mut self) -> Vec<usize> {
759        let v: Vec<usize> = self.items.drain(..).collect();
760        for &id in &v {
761            if id < self.present.len() {
762                self.present[id] = false;
763            }
764        }
765        v
766    }
767}
768/// Pass execution phase for ScalaExt.
769#[allow(dead_code)]
770#[derive(Debug, Clone, PartialEq, Eq, Hash)]
771pub enum ScalaExtPassPhase {
772    Early,
773    Middle,
774    Late,
775    Finalize,
776}
777impl ScalaExtPassPhase {
778    #[allow(dead_code)]
779    pub fn is_early(&self) -> bool {
780        matches!(self, Self::Early)
781    }
782    #[allow(dead_code)]
783    pub fn is_middle(&self) -> bool {
784        matches!(self, Self::Middle)
785    }
786    #[allow(dead_code)]
787    pub fn is_late(&self) -> bool {
788        matches!(self, Self::Late)
789    }
790    #[allow(dead_code)]
791    pub fn is_finalize(&self) -> bool {
792        matches!(self, Self::Finalize)
793    }
794    #[allow(dead_code)]
795    pub fn order(&self) -> u32 {
796        match self {
797            Self::Early => 0,
798            Self::Middle => 1,
799            Self::Late => 2,
800            Self::Finalize => 3,
801        }
802    }
803    #[allow(dead_code)]
804    pub fn from_order(n: u32) -> Option<Self> {
805        match n {
806            0 => Some(Self::Early),
807            1 => Some(Self::Middle),
808            2 => Some(Self::Late),
809            3 => Some(Self::Finalize),
810            _ => None,
811        }
812    }
813}
814#[allow(dead_code)]
815pub struct ScalaPassRegistry {
816    pub(super) configs: Vec<ScalaPassConfig>,
817    pub(super) stats: std::collections::HashMap<String, ScalaPassStats>,
818}
819impl ScalaPassRegistry {
820    #[allow(dead_code)]
821    pub fn new() -> Self {
822        ScalaPassRegistry {
823            configs: Vec::new(),
824            stats: std::collections::HashMap::new(),
825        }
826    }
827    #[allow(dead_code)]
828    pub fn register(&mut self, config: ScalaPassConfig) {
829        self.stats
830            .insert(config.pass_name.clone(), ScalaPassStats::new());
831        self.configs.push(config);
832    }
833    #[allow(dead_code)]
834    pub fn enabled_passes(&self) -> Vec<&ScalaPassConfig> {
835        self.configs.iter().filter(|c| c.enabled).collect()
836    }
837    #[allow(dead_code)]
838    pub fn get_stats(&self, name: &str) -> Option<&ScalaPassStats> {
839        self.stats.get(name)
840    }
841    #[allow(dead_code)]
842    pub fn total_passes(&self) -> usize {
843        self.configs.len()
844    }
845    #[allow(dead_code)]
846    pub fn enabled_count(&self) -> usize {
847        self.enabled_passes().len()
848    }
849    #[allow(dead_code)]
850    pub fn update_stats(&mut self, name: &str, changes: u64, time_ms: u64, iter: u32) {
851        if let Some(stats) = self.stats.get_mut(name) {
852            stats.record_run(changes, time_ms, iter);
853        }
854    }
855}
856/// A single arm in a Scala `match` expression.
857#[derive(Debug, Clone, PartialEq)]
858pub struct ScalaCaseClause {
859    pub pattern: ScalaPattern,
860    pub guard: Option<ScalaExpr>,
861    pub body: ScalaExpr,
862}
863/// A complete Scala compilation unit (file / package object).
864#[derive(Debug, Clone, PartialEq)]
865pub struct ScalaModule {
866    /// Package declaration: `com.example.mylib`
867    pub package: Option<String>,
868    /// Import declarations
869    pub imports: Vec<ScalaImport>,
870    /// Top-level declarations
871    pub declarations: Vec<ScalaDecl>,
872}
873impl ScalaModule {
874    /// Create a new empty module.
875    pub fn new(package: Option<impl Into<String>>) -> Self {
876        ScalaModule {
877            package: package.map(|p| p.into()),
878            imports: Vec::new(),
879            declarations: Vec::new(),
880        }
881    }
882    /// Add an import.
883    pub fn add_import(&mut self, imp: ScalaImport) {
884        self.imports.push(imp);
885    }
886    /// Add a top-level declaration.
887    pub fn add_decl(&mut self, decl: ScalaDecl) {
888        self.declarations.push(decl);
889    }
890    /// Emit the complete Scala 3 source for this module.
891    pub fn emit(&self) -> String {
892        let mut out = String::new();
893        if let Some(pkg) = &self.package {
894            out.push_str(&format!("package {}\n\n", pkg));
895        }
896        for imp in &self.imports {
897            out.push_str(&format!("{}\n", imp));
898        }
899        if !self.imports.is_empty() {
900            out.push('\n');
901        }
902        for decl in &self.declarations {
903            out.push_str(&format!("{}\n\n", decl));
904        }
905        out
906    }
907}
908#[derive(Debug, Clone, PartialEq)]
909pub struct ScalaEnum {
910    /// Enum name
911    pub name: String,
912    /// Type parameters
913    pub type_params: Vec<String>,
914    /// Enum cases
915    pub cases: Vec<ScalaEnumCase>,
916    /// Extends list (for ADTs)
917    pub extends_list: Vec<String>,
918}
919/// Pass registry for ScalaExt.
920#[allow(dead_code)]
921#[derive(Debug, Default)]
922pub struct ScalaExtPassRegistry {
923    pub(super) configs: Vec<ScalaExtPassConfig>,
924    pub(super) stats: Vec<ScalaExtPassStats>,
925}
926impl ScalaExtPassRegistry {
927    #[allow(dead_code)]
928    pub fn new() -> Self {
929        Self::default()
930    }
931    #[allow(dead_code)]
932    pub fn register(&mut self, c: ScalaExtPassConfig) {
933        self.stats.push(ScalaExtPassStats::new());
934        self.configs.push(c);
935    }
936    #[allow(dead_code)]
937    pub fn len(&self) -> usize {
938        self.configs.len()
939    }
940    #[allow(dead_code)]
941    pub fn is_empty(&self) -> bool {
942        self.configs.is_empty()
943    }
944    #[allow(dead_code)]
945    pub fn get(&self, i: usize) -> Option<&ScalaExtPassConfig> {
946        self.configs.get(i)
947    }
948    #[allow(dead_code)]
949    pub fn get_stats(&self, i: usize) -> Option<&ScalaExtPassStats> {
950        self.stats.get(i)
951    }
952    #[allow(dead_code)]
953    pub fn enabled_passes(&self) -> Vec<&ScalaExtPassConfig> {
954        self.configs.iter().filter(|c| c.enabled).collect()
955    }
956    #[allow(dead_code)]
957    pub fn passes_in_phase(&self, ph: &ScalaExtPassPhase) -> Vec<&ScalaExtPassConfig> {
958        self.configs
959            .iter()
960            .filter(|c| c.enabled && &c.phase == ph)
961            .collect()
962    }
963    #[allow(dead_code)]
964    pub fn total_nodes_visited(&self) -> usize {
965        self.stats.iter().map(|s| s.nodes_visited).sum()
966    }
967    #[allow(dead_code)]
968    pub fn any_changed(&self) -> bool {
969        self.stats.iter().any(|s| s.changed)
970    }
971}
972/// Dominator tree for ScalaExt.
973#[allow(dead_code)]
974#[derive(Debug, Clone)]
975pub struct ScalaExtDomTree {
976    pub(super) idom: Vec<Option<usize>>,
977    pub(super) children: Vec<Vec<usize>>,
978    pub(super) depth: Vec<usize>,
979}
980impl ScalaExtDomTree {
981    #[allow(dead_code)]
982    pub fn new(n: usize) -> Self {
983        Self {
984            idom: vec![None; n],
985            children: vec![Vec::new(); n],
986            depth: vec![0; n],
987        }
988    }
989    #[allow(dead_code)]
990    pub fn set_idom(&mut self, node: usize, dom: usize) {
991        if node < self.idom.len() {
992            self.idom[node] = Some(dom);
993            if dom < self.children.len() {
994                self.children[dom].push(node);
995            }
996            self.depth[node] = if dom < self.depth.len() {
997                self.depth[dom] + 1
998            } else {
999                1
1000            };
1001        }
1002    }
1003    #[allow(dead_code)]
1004    pub fn dominates(&self, a: usize, mut b: usize) -> bool {
1005        if a == b {
1006            return true;
1007        }
1008        let n = self.idom.len();
1009        for _ in 0..n {
1010            match self.idom.get(b).copied().flatten() {
1011                None => return false,
1012                Some(p) if p == a => return true,
1013                Some(p) if p == b => return false,
1014                Some(p) => b = p,
1015            }
1016        }
1017        false
1018    }
1019    #[allow(dead_code)]
1020    pub fn children_of(&self, n: usize) -> &[usize] {
1021        self.children.get(n).map(|v| v.as_slice()).unwrap_or(&[])
1022    }
1023    #[allow(dead_code)]
1024    pub fn depth_of(&self, n: usize) -> usize {
1025        self.depth.get(n).copied().unwrap_or(0)
1026    }
1027    #[allow(dead_code)]
1028    pub fn lca(&self, mut a: usize, mut b: usize) -> usize {
1029        let n = self.idom.len();
1030        for _ in 0..(2 * n) {
1031            if a == b {
1032                return a;
1033            }
1034            if self.depth_of(a) > self.depth_of(b) {
1035                a = self.idom.get(a).and_then(|x| *x).unwrap_or(a);
1036            } else {
1037                b = self.idom.get(b).and_then(|x| *x).unwrap_or(b);
1038            }
1039        }
1040        0
1041    }
1042}
1043/// Scala literal values.
1044#[derive(Debug, Clone, PartialEq)]
1045pub enum ScalaLit {
1046    /// Integer literal: `42`
1047    Int(i64),
1048    /// Long literal: `42L`
1049    Long(i64),
1050    /// Double literal: `3.14`
1051    Double(f64),
1052    /// Float literal: `3.14f`
1053    Float(f32),
1054    /// Boolean literal: `true` / `false`
1055    Bool(bool),
1056    /// Character literal: `'a'`
1057    Char(char),
1058    /// String literal: `"hello"`
1059    Str(String),
1060    /// `null`
1061    Null,
1062    /// `()` / unit
1063    Unit,
1064}
1065/// Scala pattern AST for `match` expressions.
1066#[derive(Debug, Clone, PartialEq)]
1067pub enum ScalaPattern {
1068    /// `_` — wildcard
1069    Wildcard,
1070    /// Variable binding: `x`
1071    Var(String),
1072    /// Literal pattern: `42`, `"hello"`, `true`
1073    Lit(ScalaLit),
1074    /// Type pattern: `x: SomeType`
1075    Typed(String, ScalaType),
1076    /// Tuple pattern: `(a, b, c)`
1077    Tuple(Vec<ScalaPattern>),
1078    /// Extractor pattern: `Some(x)`, `Cons(h, t)`
1079    Extractor(String, Vec<ScalaPattern>),
1080    /// Alternative patterns: `1 | 2 | 3`
1081    Alt(Vec<ScalaPattern>),
1082}
1083/// Modifiers for a Scala method or field.
1084#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1085pub enum ScalaModifier {
1086    Private,
1087    Protected,
1088    Override,
1089    Final,
1090    Abstract,
1091    Implicit,
1092    Inline,
1093    Lazy,
1094    Given,
1095    Extension,
1096}
1097/// A Scala `case class` declaration.
1098///
1099/// Example: `case class Person(name: String, age: Int) extends Entity`
1100#[derive(Debug, Clone, PartialEq)]
1101pub struct ScalaCaseClass {
1102    /// Class name
1103    pub name: String,
1104    /// Type parameters: `A`, `B`
1105    pub type_params: Vec<String>,
1106    /// Constructor fields
1107    pub fields: Vec<ScalaParam>,
1108    /// Extends list
1109    pub extends_list: Vec<String>,
1110}
1111/// A Scala `object` declaration (companion or standalone).
1112#[derive(Debug, Clone, PartialEq)]
1113pub struct ScalaObject {
1114    /// Object name
1115    pub name: String,
1116    /// Extends list
1117    pub extends_list: Vec<String>,
1118    /// Methods
1119    pub methods: Vec<ScalaMethod>,
1120    /// Constants / val definitions: (name, type, expr)
1121    pub constants: Vec<(String, ScalaType, ScalaExpr)>,
1122}
1123/// A general Scala `class` declaration.
1124#[derive(Debug, Clone, PartialEq)]
1125pub struct ScalaClass {
1126    /// Class name
1127    pub name: String,
1128    /// Type parameters
1129    pub type_params: Vec<String>,
1130    /// Constructor parameters
1131    pub constructor_params: Vec<ScalaParam>,
1132    /// Extends list
1133    pub extends_list: Vec<String>,
1134    /// Methods
1135    pub methods: Vec<ScalaMethod>,
1136    /// Modifiers
1137    pub modifiers: Vec<ScalaModifier>,
1138}
1139#[allow(dead_code)]
1140#[derive(Debug, Clone)]
1141pub struct ScalaWorklist {
1142    pub(super) items: std::collections::VecDeque<u32>,
1143    pub(super) in_worklist: std::collections::HashSet<u32>,
1144}
1145impl ScalaWorklist {
1146    #[allow(dead_code)]
1147    pub fn new() -> Self {
1148        ScalaWorklist {
1149            items: std::collections::VecDeque::new(),
1150            in_worklist: std::collections::HashSet::new(),
1151        }
1152    }
1153    #[allow(dead_code)]
1154    pub fn push(&mut self, item: u32) -> bool {
1155        if self.in_worklist.insert(item) {
1156            self.items.push_back(item);
1157            true
1158        } else {
1159            false
1160        }
1161    }
1162    #[allow(dead_code)]
1163    pub fn pop(&mut self) -> Option<u32> {
1164        let item = self.items.pop_front()?;
1165        self.in_worklist.remove(&item);
1166        Some(item)
1167    }
1168    #[allow(dead_code)]
1169    pub fn is_empty(&self) -> bool {
1170        self.items.is_empty()
1171    }
1172    #[allow(dead_code)]
1173    pub fn len(&self) -> usize {
1174        self.items.len()
1175    }
1176    #[allow(dead_code)]
1177    pub fn contains(&self, item: u32) -> bool {
1178        self.in_worklist.contains(&item)
1179    }
1180}
1181/// An enumerator in a Scala for-comprehension.
1182#[derive(Debug, Clone, PartialEq)]
1183pub enum ScalaEnumerator {
1184    /// Generator: `x <- xs`
1185    Generator(String, ScalaExpr),
1186    /// Guard/filter: `if x > 0`
1187    Guard(ScalaExpr),
1188    /// Definition: `y = f(x)`
1189    Definition(String, ScalaExpr),
1190}
1191/// A Scala import declaration.
1192#[derive(Debug, Clone, PartialEq)]
1193pub struct ScalaImport {
1194    /// Import path: `scala.collection.mutable`
1195    pub path: String,
1196    /// Specific names or `_` for wildcard
1197    pub items: Vec<String>,
1198}
1199#[allow(dead_code)]
1200#[derive(Debug, Clone)]
1201pub struct ScalaDominatorTree {
1202    pub idom: Vec<Option<u32>>,
1203    pub dom_children: Vec<Vec<u32>>,
1204    pub dom_depth: Vec<u32>,
1205}
1206impl ScalaDominatorTree {
1207    #[allow(dead_code)]
1208    pub fn new(size: usize) -> Self {
1209        ScalaDominatorTree {
1210            idom: vec![None; size],
1211            dom_children: vec![Vec::new(); size],
1212            dom_depth: vec![0; size],
1213        }
1214    }
1215    #[allow(dead_code)]
1216    pub fn set_idom(&mut self, node: usize, idom: u32) {
1217        self.idom[node] = Some(idom);
1218    }
1219    #[allow(dead_code)]
1220    pub fn dominates(&self, a: usize, b: usize) -> bool {
1221        if a == b {
1222            return true;
1223        }
1224        let mut cur = b;
1225        loop {
1226            match self.idom[cur] {
1227                Some(parent) if parent as usize == a => return true,
1228                Some(parent) if parent as usize == cur => return false,
1229                Some(parent) => cur = parent as usize,
1230                None => return false,
1231            }
1232        }
1233    }
1234    #[allow(dead_code)]
1235    pub fn depth(&self, node: usize) -> u32 {
1236        self.dom_depth.get(node).copied().unwrap_or(0)
1237    }
1238}
1239#[allow(dead_code)]
1240#[derive(Debug, Clone, PartialEq)]
1241pub enum ScalaPassPhase {
1242    Analysis,
1243    Transformation,
1244    Verification,
1245    Cleanup,
1246}
1247impl ScalaPassPhase {
1248    #[allow(dead_code)]
1249    pub fn name(&self) -> &str {
1250        match self {
1251            ScalaPassPhase::Analysis => "analysis",
1252            ScalaPassPhase::Transformation => "transformation",
1253            ScalaPassPhase::Verification => "verification",
1254            ScalaPassPhase::Cleanup => "cleanup",
1255        }
1256    }
1257    #[allow(dead_code)]
1258    pub fn is_modifying(&self) -> bool {
1259        matches!(
1260            self,
1261            ScalaPassPhase::Transformation | ScalaPassPhase::Cleanup
1262        )
1263    }
1264}
1265/// The Scala code generation backend.
1266pub struct ScalaBackend {
1267    pub(super) module: ScalaModule,
1268}
1269impl ScalaBackend {
1270    /// Create a new backend for the given package.
1271    pub fn new(package: Option<impl Into<String>>) -> Self {
1272        let mut module = ScalaModule::new(package);
1273        module.add_import(ScalaImport {
1274            path: "scala.annotation".to_string(),
1275            items: vec!["tailrec".to_string()],
1276        });
1277        ScalaBackend { module }
1278    }
1279    /// Compile a single LCNF function declaration and add it to the module.
1280    pub fn compile_decl(&mut self, decl: &LcnfFunDecl) {
1281        let method = self.compile_fun(decl);
1282        self.module.add_decl(ScalaDecl::Method(method));
1283    }
1284    /// Compile an LCNF function to a Scala method.
1285    pub(super) fn compile_fun(&self, decl: &LcnfFunDecl) -> ScalaMethod {
1286        let params: Vec<ScalaParam> = decl
1287            .params
1288            .iter()
1289            .map(|p| ScalaParam {
1290                name: p.name.clone(),
1291                ty: lcnf_type_to_scala(&p.ty),
1292                default: None,
1293            })
1294            .collect();
1295        let body = self.compile_expr(&decl.body);
1296        let ret_type = lcnf_type_to_scala(&decl.ret_type);
1297        ScalaMethod {
1298            name: sanitize_scala_ident(&decl.name),
1299            type_params: Vec::new(),
1300            params: if params.is_empty() {
1301                Vec::new()
1302            } else {
1303                vec![params]
1304            },
1305            return_type: ret_type,
1306            body: Some(body),
1307            modifiers: Vec::new(),
1308        }
1309    }
1310    /// Compile an LCNF expression to a Scala expression.
1311    pub(super) fn compile_expr(&self, expr: &LcnfExpr) -> ScalaExpr {
1312        match expr {
1313            LcnfExpr::Return(arg) => self.compile_arg(arg),
1314            LcnfExpr::Let {
1315                name, value, body, ..
1316            } => {
1317                let rhs_expr = self.compile_let_value(value);
1318                let cont_expr = self.compile_expr(body);
1319                ScalaExpr::Block(
1320                    vec![ScalaExpr::Assign(name.clone(), Box::new(rhs_expr))],
1321                    Box::new(cont_expr),
1322                )
1323            }
1324            LcnfExpr::Case {
1325                scrutinee,
1326                alts,
1327                default,
1328                ..
1329            } => {
1330                let scrut = ScalaExpr::Var(format!("{}", scrutinee));
1331                let mut arms: Vec<ScalaCaseClause> =
1332                    alts.iter().map(|alt| self.compile_alt(alt)).collect();
1333                if let Some(def) = default {
1334                    let def_expr = self.compile_expr(def);
1335                    arms.push(ScalaCaseClause {
1336                        pattern: ScalaPattern::Wildcard,
1337                        guard: None,
1338                        body: def_expr,
1339                    });
1340                }
1341                ScalaExpr::Match(Box::new(scrut), arms)
1342            }
1343            LcnfExpr::TailCall(func, args) => {
1344                let func_expr = self.compile_arg(func);
1345                if args.is_empty() {
1346                    func_expr
1347                } else {
1348                    let arg_exprs: Vec<ScalaExpr> =
1349                        args.iter().map(|a| self.compile_arg(a)).collect();
1350                    ScalaExpr::App(Box::new(func_expr), arg_exprs)
1351                }
1352            }
1353            LcnfExpr::Unreachable => ScalaExpr::Throw(Box::new(ScalaExpr::New(
1354                "RuntimeException".to_string(),
1355                vec![ScalaExpr::Lit(ScalaLit::Str("unreachable".to_string()))],
1356            ))),
1357        }
1358    }
1359    /// Compile an LCNF let-value to a Scala expression.
1360    pub(super) fn compile_let_value(&self, val: &LcnfLetValue) -> ScalaExpr {
1361        match val {
1362            LcnfLetValue::App(func, args) => {
1363                let func_expr = self.compile_arg(func);
1364                if args.is_empty() {
1365                    func_expr
1366                } else {
1367                    let arg_exprs: Vec<ScalaExpr> =
1368                        args.iter().map(|a| self.compile_arg(a)).collect();
1369                    ScalaExpr::App(Box::new(func_expr), arg_exprs)
1370                }
1371            }
1372            LcnfLetValue::Ctor(name, _tag, args) => {
1373                let ctor_expr = ScalaExpr::Var(name.clone());
1374                if args.is_empty() {
1375                    ctor_expr
1376                } else {
1377                    let arg_exprs: Vec<ScalaExpr> =
1378                        args.iter().map(|a| self.compile_arg(a)).collect();
1379                    ScalaExpr::App(Box::new(ctor_expr), arg_exprs)
1380                }
1381            }
1382            LcnfLetValue::Proj(_name, idx, var) => {
1383                let field = format!("_{}", idx + 1);
1384                ScalaExpr::App(
1385                    Box::new(ScalaExpr::Var(format!("{}. {}", var, field))),
1386                    Vec::new(),
1387                )
1388            }
1389            LcnfLetValue::Lit(lit) => match lit {
1390                LcnfLit::Nat(n) => ScalaExpr::Lit(ScalaLit::Long(*n as i64)),
1391                LcnfLit::Str(s) => ScalaExpr::Lit(ScalaLit::Str(s.clone())),
1392            },
1393            LcnfLetValue::Erased | LcnfLetValue::Reset(_) => ScalaExpr::Lit(ScalaLit::Unit),
1394            LcnfLetValue::FVar(v) => ScalaExpr::Var(format!("{}", v)),
1395            LcnfLetValue::Reuse(_, name, _tag, args) => {
1396                let ctor_expr = ScalaExpr::Var(name.clone());
1397                if args.is_empty() {
1398                    ctor_expr
1399                } else {
1400                    let arg_exprs: Vec<ScalaExpr> =
1401                        args.iter().map(|a| self.compile_arg(a)).collect();
1402                    ScalaExpr::App(Box::new(ctor_expr), arg_exprs)
1403                }
1404            }
1405        }
1406    }
1407    /// Compile an LCNF case alternative to a Scala case clause.
1408    pub(super) fn compile_alt(&self, alt: &LcnfAlt) -> ScalaCaseClause {
1409        let body = self.compile_expr(&alt.body);
1410        let pat = ScalaPattern::Extractor(
1411            alt.ctor_name.clone(),
1412            alt.params
1413                .iter()
1414                .map(|p| ScalaPattern::Var(p.name.clone()))
1415                .collect(),
1416        );
1417        ScalaCaseClause {
1418            pattern: pat,
1419            guard: None,
1420            body,
1421        }
1422    }
1423    /// Compile an LCNF argument to a Scala expression.
1424    pub(super) fn compile_arg(&self, arg: &LcnfArg) -> ScalaExpr {
1425        match arg {
1426            LcnfArg::Var(v) => ScalaExpr::Var(format!("{}", v)),
1427            LcnfArg::Lit(lit) => match lit {
1428                LcnfLit::Nat(n) => ScalaExpr::Lit(ScalaLit::Long(*n as i64)),
1429                LcnfLit::Str(s) => ScalaExpr::Lit(ScalaLit::Str(s.clone())),
1430            },
1431            LcnfArg::Erased | LcnfArg::Type(_) => ScalaExpr::Lit(ScalaLit::Unit),
1432        }
1433    }
1434    /// Emit the complete Scala module source.
1435    pub fn emit_module(&self) -> String {
1436        self.module.emit()
1437    }
1438}
1439/// The various top-level declarations in a Scala compilation unit.
1440#[derive(Debug, Clone, PartialEq)]
1441pub enum ScalaDecl {
1442    CaseClass(ScalaCaseClass),
1443    Trait(ScalaTrait),
1444    Enum(ScalaEnum),
1445    Object(ScalaObject),
1446    Class(ScalaClass),
1447    Method(ScalaMethod),
1448    /// `val name: Type = expr` at top level
1449    Val(String, ScalaType, ScalaExpr),
1450    /// `type Name = Type` (alias)
1451    TypeAlias(String, Vec<String>, ScalaType),
1452    /// `opaque type Name = Type`
1453    OpaqueType(String, Vec<String>, ScalaType),
1454    /// `extension (x: Type) def method...`
1455    Extension(ScalaType, Vec<ScalaMethod>),
1456    /// `given name: Type with { ... }`
1457    Given(String, ScalaType, Vec<ScalaMethod>),
1458    Comment(String),
1459    RawLine(String),
1460}
1461#[allow(dead_code)]
1462#[derive(Debug, Clone, Default)]
1463pub struct ScalaPassStats {
1464    pub total_runs: u32,
1465    pub successful_runs: u32,
1466    pub total_changes: u64,
1467    pub time_ms: u64,
1468    pub iterations_used: u32,
1469}
1470impl ScalaPassStats {
1471    #[allow(dead_code)]
1472    pub fn new() -> Self {
1473        Self::default()
1474    }
1475    #[allow(dead_code)]
1476    pub fn record_run(&mut self, changes: u64, time_ms: u64, iterations: u32) {
1477        self.total_runs += 1;
1478        self.successful_runs += 1;
1479        self.total_changes += changes;
1480        self.time_ms += time_ms;
1481        self.iterations_used = iterations;
1482    }
1483    #[allow(dead_code)]
1484    pub fn average_changes_per_run(&self) -> f64 {
1485        if self.total_runs == 0 {
1486            return 0.0;
1487        }
1488        self.total_changes as f64 / self.total_runs as f64
1489    }
1490    #[allow(dead_code)]
1491    pub fn success_rate(&self) -> f64 {
1492        if self.total_runs == 0 {
1493            return 0.0;
1494        }
1495        self.successful_runs as f64 / self.total_runs as f64
1496    }
1497    #[allow(dead_code)]
1498    pub fn format_summary(&self) -> String {
1499        format!(
1500            "Runs: {}/{}, Changes: {}, Time: {}ms",
1501            self.successful_runs, self.total_runs, self.total_changes, self.time_ms
1502        )
1503    }
1504}
1505/// A Scala `trait` declaration.
1506#[derive(Debug, Clone, PartialEq)]
1507pub struct ScalaTrait {
1508    /// Trait name
1509    pub name: String,
1510    /// Type parameters
1511    pub type_params: Vec<String>,
1512    /// Extends list
1513    pub extends_list: Vec<String>,
1514    /// Abstract method signatures
1515    pub abstract_methods: Vec<ScalaMethod>,
1516    /// Concrete method implementations
1517    pub concrete_methods: Vec<ScalaMethod>,
1518}
1519#[allow(dead_code)]
1520#[derive(Debug, Clone)]
1521pub struct ScalaAnalysisCache {
1522    pub(super) entries: std::collections::HashMap<String, ScalaCacheEntry>,
1523    pub(super) max_size: usize,
1524    pub(super) hits: u64,
1525    pub(super) misses: u64,
1526}
1527impl ScalaAnalysisCache {
1528    #[allow(dead_code)]
1529    pub fn new(max_size: usize) -> Self {
1530        ScalaAnalysisCache {
1531            entries: std::collections::HashMap::new(),
1532            max_size,
1533            hits: 0,
1534            misses: 0,
1535        }
1536    }
1537    #[allow(dead_code)]
1538    pub fn get(&mut self, key: &str) -> Option<&ScalaCacheEntry> {
1539        if self.entries.contains_key(key) {
1540            self.hits += 1;
1541            self.entries.get(key)
1542        } else {
1543            self.misses += 1;
1544            None
1545        }
1546    }
1547    #[allow(dead_code)]
1548    pub fn insert(&mut self, key: String, data: Vec<u8>) {
1549        if self.entries.len() >= self.max_size {
1550            if let Some(oldest) = self.entries.keys().next().cloned() {
1551                self.entries.remove(&oldest);
1552            }
1553        }
1554        self.entries.insert(
1555            key.clone(),
1556            ScalaCacheEntry {
1557                key,
1558                data,
1559                timestamp: 0,
1560                valid: true,
1561            },
1562        );
1563    }
1564    #[allow(dead_code)]
1565    pub fn invalidate(&mut self, key: &str) {
1566        if let Some(entry) = self.entries.get_mut(key) {
1567            entry.valid = false;
1568        }
1569    }
1570    #[allow(dead_code)]
1571    pub fn clear(&mut self) {
1572        self.entries.clear();
1573    }
1574    #[allow(dead_code)]
1575    pub fn hit_rate(&self) -> f64 {
1576        let total = self.hits + self.misses;
1577        if total == 0 {
1578            return 0.0;
1579        }
1580        self.hits as f64 / total as f64
1581    }
1582    #[allow(dead_code)]
1583    pub fn size(&self) -> usize {
1584        self.entries.len()
1585    }
1586}
1587/// A Scala 3 `enum` declaration.
1588///
1589/// Example:
1590/// ```text
1591/// enum Color:
1592///   case Red, Green, Blue
1593/// ```
1594///
1595/// Also supports parameterized cases:
1596/// ```text
1597/// enum Expr:
1598///   case Lit(n: Int)
1599///   case Add(l: Expr, r: Expr)
1600/// ```
1601#[derive(Debug, Clone, PartialEq)]
1602pub struct ScalaEnumCase {
1603    /// Case name: `Red`, `Lit`
1604    pub name: String,
1605    /// Fields (empty for simple cases)
1606    pub fields: Vec<ScalaParam>,
1607}
1608#[allow(dead_code)]
1609#[derive(Debug, Clone)]
1610pub struct ScalaPassConfig {
1611    pub phase: ScalaPassPhase,
1612    pub enabled: bool,
1613    pub max_iterations: u32,
1614    pub debug_output: bool,
1615    pub pass_name: String,
1616}
1617impl ScalaPassConfig {
1618    #[allow(dead_code)]
1619    pub fn new(name: impl Into<String>, phase: ScalaPassPhase) -> Self {
1620        ScalaPassConfig {
1621            phase,
1622            enabled: true,
1623            max_iterations: 10,
1624            debug_output: false,
1625            pass_name: name.into(),
1626        }
1627    }
1628    #[allow(dead_code)]
1629    pub fn disabled(mut self) -> Self {
1630        self.enabled = false;
1631        self
1632    }
1633    #[allow(dead_code)]
1634    pub fn with_debug(mut self) -> Self {
1635        self.debug_output = true;
1636        self
1637    }
1638    #[allow(dead_code)]
1639    pub fn max_iter(mut self, n: u32) -> Self {
1640        self.max_iterations = n;
1641        self
1642    }
1643}
1644/// Configuration for ScalaExt passes.
1645#[allow(dead_code)]
1646#[derive(Debug, Clone)]
1647pub struct ScalaExtPassConfig {
1648    pub name: String,
1649    pub phase: ScalaExtPassPhase,
1650    pub enabled: bool,
1651    pub max_iterations: usize,
1652    pub debug: u32,
1653    pub timeout_ms: Option<u64>,
1654}
1655impl ScalaExtPassConfig {
1656    #[allow(dead_code)]
1657    pub fn new(name: impl Into<String>) -> Self {
1658        Self {
1659            name: name.into(),
1660            phase: ScalaExtPassPhase::Middle,
1661            enabled: true,
1662            max_iterations: 100,
1663            debug: 0,
1664            timeout_ms: None,
1665        }
1666    }
1667    #[allow(dead_code)]
1668    pub fn with_phase(mut self, phase: ScalaExtPassPhase) -> Self {
1669        self.phase = phase;
1670        self
1671    }
1672    #[allow(dead_code)]
1673    pub fn with_max_iter(mut self, n: usize) -> Self {
1674        self.max_iterations = n;
1675        self
1676    }
1677    #[allow(dead_code)]
1678    pub fn with_debug(mut self, d: u32) -> Self {
1679        self.debug = d;
1680        self
1681    }
1682    #[allow(dead_code)]
1683    pub fn disabled(mut self) -> Self {
1684        self.enabled = false;
1685        self
1686    }
1687    #[allow(dead_code)]
1688    pub fn with_timeout(mut self, ms: u64) -> Self {
1689        self.timeout_ms = Some(ms);
1690        self
1691    }
1692    #[allow(dead_code)]
1693    pub fn is_debug_enabled(&self) -> bool {
1694        self.debug > 0
1695    }
1696}
1697/// Scala type representation for type-directed code generation.
1698#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1699pub enum ScalaType {
1700    /// `Int` — 32-bit signed integer
1701    Int,
1702    /// `Long` — 64-bit signed integer
1703    Long,
1704    /// `Double` — 64-bit IEEE floating-point
1705    Double,
1706    /// `Float` — 32-bit IEEE floating-point
1707    Float,
1708    /// `Boolean` — boolean
1709    Boolean,
1710    /// `Char` — Unicode character
1711    Char,
1712    /// `String` — UTF-16 string
1713    ScalaString,
1714    /// `Unit` — unit type
1715    Unit,
1716    /// `Null` — null type (subtype of all AnyRef)
1717    Null,
1718    /// `Nothing` — bottom type
1719    Nothing,
1720    /// `Any` — top type
1721    Any,
1722    /// `AnyRef` — reference type root
1723    AnyRef,
1724    /// `AnyVal` — value type root
1725    AnyVal,
1726    /// `List[T]`
1727    List(Box<ScalaType>),
1728    /// `Option[T]`
1729    Option(Box<ScalaType>),
1730    /// `Either[A, B]`
1731    Either(Box<ScalaType>, Box<ScalaType>),
1732    /// `(A, B, ...)` — tuple
1733    Tuple(Vec<ScalaType>),
1734    /// `(A, B) => R` — function type
1735    Function(Vec<ScalaType>, Box<ScalaType>),
1736    /// Named type: class, trait, object
1737    Custom(String),
1738    /// Generic type application: `Map[K, V]`, `Future[T]`
1739    Generic(String, Vec<ScalaType>),
1740}