1use crate::lcnf::*;
6
7use super::functions::*;
8use std::collections::{HashMap, HashSet, VecDeque};
9
10#[derive(Debug, Clone, PartialEq)]
12pub struct ScalaParam {
13 pub name: String,
14 pub ty: ScalaType,
15 pub default: Option<ScalaExpr>,
16}
17#[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#[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#[derive(Debug, Clone, PartialEq)]
288pub struct ScalaCatch {
289 pub pattern: ScalaPattern,
290 pub body: ScalaExpr,
291}
292#[derive(Debug, Clone, PartialEq)]
294pub struct ScalaMethod {
295 pub name: String,
297 pub type_params: Vec<String>,
299 pub params: Vec<Vec<ScalaParam>>,
301 pub return_type: ScalaType,
303 pub body: Option<ScalaExpr>,
305 pub modifiers: Vec<ScalaModifier>,
307}
308#[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#[derive(Debug, Clone, PartialEq)]
365pub enum ScalaExpr {
366 Lit(ScalaLit),
368 Var(String),
370 App(Box<ScalaExpr>, Vec<ScalaExpr>),
372 Infix(Box<ScalaExpr>, String, Box<ScalaExpr>),
374 Prefix(String, Box<ScalaExpr>),
376 If(Box<ScalaExpr>, Box<ScalaExpr>, Box<ScalaExpr>),
378 Match(Box<ScalaExpr>, Vec<ScalaCaseClause>),
380 For(Vec<ScalaEnumerator>, Box<ScalaExpr>),
382 Try(Box<ScalaExpr>, Vec<ScalaCatch>, Option<Box<ScalaExpr>>),
384 Lambda(Vec<String>, Box<ScalaExpr>),
386 Block(Vec<ScalaExpr>, Box<ScalaExpr>),
388 New(String, Vec<ScalaExpr>),
390 This,
392 Super,
394 Assign(String, Box<ScalaExpr>),
396 TypeAnnotation(Box<ScalaExpr>, ScalaType),
398 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#[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#[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#[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#[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#[derive(Debug, Clone, PartialEq)]
858pub struct ScalaCaseClause {
859 pub pattern: ScalaPattern,
860 pub guard: Option<ScalaExpr>,
861 pub body: ScalaExpr,
862}
863#[derive(Debug, Clone, PartialEq)]
865pub struct ScalaModule {
866 pub package: Option<String>,
868 pub imports: Vec<ScalaImport>,
870 pub declarations: Vec<ScalaDecl>,
872}
873impl ScalaModule {
874 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 pub fn add_import(&mut self, imp: ScalaImport) {
884 self.imports.push(imp);
885 }
886 pub fn add_decl(&mut self, decl: ScalaDecl) {
888 self.declarations.push(decl);
889 }
890 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 pub name: String,
912 pub type_params: Vec<String>,
914 pub cases: Vec<ScalaEnumCase>,
916 pub extends_list: Vec<String>,
918}
919#[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#[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#[derive(Debug, Clone, PartialEq)]
1045pub enum ScalaLit {
1046 Int(i64),
1048 Long(i64),
1050 Double(f64),
1052 Float(f32),
1054 Bool(bool),
1056 Char(char),
1058 Str(String),
1060 Null,
1062 Unit,
1064}
1065#[derive(Debug, Clone, PartialEq)]
1067pub enum ScalaPattern {
1068 Wildcard,
1070 Var(String),
1072 Lit(ScalaLit),
1074 Typed(String, ScalaType),
1076 Tuple(Vec<ScalaPattern>),
1078 Extractor(String, Vec<ScalaPattern>),
1080 Alt(Vec<ScalaPattern>),
1082}
1083#[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#[derive(Debug, Clone, PartialEq)]
1101pub struct ScalaCaseClass {
1102 pub name: String,
1104 pub type_params: Vec<String>,
1106 pub fields: Vec<ScalaParam>,
1108 pub extends_list: Vec<String>,
1110}
1111#[derive(Debug, Clone, PartialEq)]
1113pub struct ScalaObject {
1114 pub name: String,
1116 pub extends_list: Vec<String>,
1118 pub methods: Vec<ScalaMethod>,
1120 pub constants: Vec<(String, ScalaType, ScalaExpr)>,
1122}
1123#[derive(Debug, Clone, PartialEq)]
1125pub struct ScalaClass {
1126 pub name: String,
1128 pub type_params: Vec<String>,
1130 pub constructor_params: Vec<ScalaParam>,
1132 pub extends_list: Vec<String>,
1134 pub methods: Vec<ScalaMethod>,
1136 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#[derive(Debug, Clone, PartialEq)]
1183pub enum ScalaEnumerator {
1184 Generator(String, ScalaExpr),
1186 Guard(ScalaExpr),
1188 Definition(String, ScalaExpr),
1190}
1191#[derive(Debug, Clone, PartialEq)]
1193pub struct ScalaImport {
1194 pub path: String,
1196 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}
1265pub struct ScalaBackend {
1267 pub(super) module: ScalaModule,
1268}
1269impl ScalaBackend {
1270 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 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 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 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 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 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 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 pub fn emit_module(&self) -> String {
1436 self.module.emit()
1437 }
1438}
1439#[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(String, ScalaType, ScalaExpr),
1450 TypeAlias(String, Vec<String>, ScalaType),
1452 OpaqueType(String, Vec<String>, ScalaType),
1454 Extension(ScalaType, Vec<ScalaMethod>),
1456 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#[derive(Debug, Clone, PartialEq)]
1507pub struct ScalaTrait {
1508 pub name: String,
1510 pub type_params: Vec<String>,
1512 pub extends_list: Vec<String>,
1514 pub abstract_methods: Vec<ScalaMethod>,
1516 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#[derive(Debug, Clone, PartialEq)]
1602pub struct ScalaEnumCase {
1603 pub name: String,
1605 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#[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#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1699pub enum ScalaType {
1700 Int,
1702 Long,
1704 Double,
1706 Float,
1708 Boolean,
1710 Char,
1712 ScalaString,
1714 Unit,
1716 Null,
1718 Nothing,
1720 Any,
1722 AnyRef,
1724 AnyVal,
1726 List(Box<ScalaType>),
1728 Option(Box<ScalaType>),
1730 Either(Box<ScalaType>, Box<ScalaType>),
1732 Tuple(Vec<ScalaType>),
1734 Function(Vec<ScalaType>, Box<ScalaType>),
1736 Custom(String),
1738 Generic(String, Vec<ScalaType>),
1740}