1use crate::lcnf::*;
6use std::collections::{HashMap, HashSet};
7
8use super::functions::*;
9use std::collections::VecDeque;
10
11#[allow(dead_code)]
12#[derive(Debug, Clone)]
13pub struct GoDominatorTree {
14 pub idom: Vec<Option<u32>>,
15 pub dom_children: Vec<Vec<u32>>,
16 pub dom_depth: Vec<u32>,
17}
18impl GoDominatorTree {
19 #[allow(dead_code)]
20 pub fn new(size: usize) -> Self {
21 GoDominatorTree {
22 idom: vec![None; size],
23 dom_children: vec![Vec::new(); size],
24 dom_depth: vec![0; size],
25 }
26 }
27 #[allow(dead_code)]
28 pub fn set_idom(&mut self, node: usize, idom: u32) {
29 self.idom[node] = Some(idom);
30 }
31 #[allow(dead_code)]
32 pub fn dominates(&self, a: usize, b: usize) -> bool {
33 if a == b {
34 return true;
35 }
36 let mut cur = b;
37 loop {
38 match self.idom[cur] {
39 Some(parent) if parent as usize == a => return true,
40 Some(parent) if parent as usize == cur => return false,
41 Some(parent) => cur = parent as usize,
42 None => return false,
43 }
44 }
45 }
46 #[allow(dead_code)]
47 pub fn depth(&self, node: usize) -> u32 {
48 self.dom_depth.get(node).copied().unwrap_or(0)
49 }
50}
51#[derive(Debug, Clone)]
53pub struct GoFunc {
54 pub name: String,
56 pub receiver: Option<(String, GoType)>,
58 pub params: Vec<(String, GoType)>,
60 pub return_types: Vec<GoType>,
62 pub body: Vec<GoStmt>,
64 pub exported: bool,
66}
67impl GoFunc {
68 pub fn new(name: impl Into<String>) -> Self {
70 GoFunc {
71 name: name.into(),
72 receiver: None,
73 params: Vec::new(),
74 return_types: Vec::new(),
75 body: Vec::new(),
76 exported: false,
77 }
78 }
79 pub fn add_param(&mut self, name: impl Into<String>, ty: GoType) {
81 self.params.push((name.into(), ty));
82 }
83 pub fn add_return(&mut self, ty: GoType) {
85 self.return_types.push(ty);
86 }
87 pub fn codegen(&self) -> String {
89 let mut out = String::new();
90 let recv_str = self
91 .receiver
92 .as_ref()
93 .map(|(n, t)| format!("({} {}) ", n, t))
94 .unwrap_or_default();
95 let params_str = self
96 .params
97 .iter()
98 .map(|(n, t)| format!("{} {}", n, t))
99 .collect::<Vec<_>>()
100 .join(", ");
101 let ret_str = match self.return_types.len() {
102 0 => String::new(),
103 1 => format!(" {}", self.return_types[0]),
104 _ => {
105 let rs: Vec<String> = self.return_types.iter().map(|t| t.to_string()).collect();
106 format!(" ({})", rs.join(", "))
107 }
108 };
109 out.push_str(&format!(
110 "func {}{}({}){} {{\n",
111 recv_str, self.name, params_str, ret_str
112 ));
113 let body_str = format_stmts(&self.body, 1);
114 if !body_str.is_empty() {
115 out.push_str(&body_str);
116 out.push('\n');
117 }
118 out.push('}');
119 out
120 }
121}
122#[allow(dead_code)]
123#[derive(Debug, Clone)]
124pub struct GoDepGraph {
125 pub(super) nodes: Vec<u32>,
126 pub(super) edges: Vec<(u32, u32)>,
127}
128impl GoDepGraph {
129 #[allow(dead_code)]
130 pub fn new() -> Self {
131 GoDepGraph {
132 nodes: Vec::new(),
133 edges: Vec::new(),
134 }
135 }
136 #[allow(dead_code)]
137 pub fn add_node(&mut self, id: u32) {
138 if !self.nodes.contains(&id) {
139 self.nodes.push(id);
140 }
141 }
142 #[allow(dead_code)]
143 pub fn add_dep(&mut self, dep: u32, dependent: u32) {
144 self.add_node(dep);
145 self.add_node(dependent);
146 self.edges.push((dep, dependent));
147 }
148 #[allow(dead_code)]
149 pub fn dependents_of(&self, node: u32) -> Vec<u32> {
150 self.edges
151 .iter()
152 .filter(|(d, _)| *d == node)
153 .map(|(_, dep)| *dep)
154 .collect()
155 }
156 #[allow(dead_code)]
157 pub fn dependencies_of(&self, node: u32) -> Vec<u32> {
158 self.edges
159 .iter()
160 .filter(|(_, dep)| *dep == node)
161 .map(|(d, _)| *d)
162 .collect()
163 }
164 #[allow(dead_code)]
165 pub fn topological_sort(&self) -> Vec<u32> {
166 let mut in_degree: std::collections::HashMap<u32, u32> = std::collections::HashMap::new();
167 for &n in &self.nodes {
168 in_degree.insert(n, 0);
169 }
170 for (_, dep) in &self.edges {
171 *in_degree.entry(*dep).or_insert(0) += 1;
172 }
173 let mut queue: std::collections::VecDeque<u32> = self
174 .nodes
175 .iter()
176 .filter(|&&n| in_degree[&n] == 0)
177 .copied()
178 .collect();
179 let mut result = Vec::new();
180 while let Some(node) = queue.pop_front() {
181 result.push(node);
182 for dep in self.dependents_of(node) {
183 let cnt = in_degree.entry(dep).or_insert(0);
184 *cnt = cnt.saturating_sub(1);
185 if *cnt == 0 {
186 queue.push_back(dep);
187 }
188 }
189 }
190 result
191 }
192 #[allow(dead_code)]
193 pub fn has_cycle(&self) -> bool {
194 self.topological_sort().len() < self.nodes.len()
195 }
196}
197#[derive(Debug, Clone)]
199pub struct GoModule {
200 pub package: String,
202 pub imports: Vec<String>,
204 pub types: Vec<GoTypeDecl>,
206 pub funcs: Vec<GoFunc>,
208 pub vars: Vec<GoStmt>,
210 pub consts: Vec<(String, GoType, GoExpr)>,
212}
213impl GoModule {
214 pub fn new(package: impl Into<String>) -> Self {
216 GoModule {
217 package: package.into(),
218 imports: Vec::new(),
219 types: Vec::new(),
220 funcs: Vec::new(),
221 vars: Vec::new(),
222 consts: Vec::new(),
223 }
224 }
225 pub fn add_import(&mut self, path: impl Into<String>) {
227 let p = path.into();
228 if !self.imports.contains(&p) {
229 self.imports.push(p);
230 }
231 }
232 pub fn codegen(&self) -> String {
234 let mut out = format!("package {}\n\n", self.package);
235 if !self.imports.is_empty() {
236 if self.imports.len() == 1 {
237 out.push_str(&format!("import \"{}\"\n\n", self.imports[0]));
238 } else {
239 out.push_str("import (\n");
240 for imp in &self.imports {
241 out.push_str(&format!(" \"{}\"\n", imp));
242 }
243 out.push_str(")\n\n");
244 }
245 }
246 if !self.consts.is_empty() {
247 out.push_str("const (\n");
248 for (name, ty, val) in &self.consts {
249 out.push_str(&format!(" {} {} = {}\n", name, ty, val));
250 }
251 out.push_str(")\n\n");
252 }
253 for ty_decl in &self.types {
254 out.push_str(&ty_decl.codegen());
255 out.push_str("\n\n");
256 }
257 if !self.vars.is_empty() {
258 out.push_str("var (\n");
259 for v in &self.vars {
260 out.push_str(&format!(" {}\n", v));
261 }
262 out.push_str(")\n\n");
263 }
264 for func in &self.funcs {
265 out.push_str(&func.codegen());
266 out.push_str("\n\n");
267 }
268 out
269 }
270}
271#[allow(dead_code)]
272#[derive(Debug, Clone)]
273pub struct GoWorklist {
274 pub(super) items: std::collections::VecDeque<u32>,
275 pub(super) in_worklist: std::collections::HashSet<u32>,
276}
277impl GoWorklist {
278 #[allow(dead_code)]
279 pub fn new() -> Self {
280 GoWorklist {
281 items: std::collections::VecDeque::new(),
282 in_worklist: std::collections::HashSet::new(),
283 }
284 }
285 #[allow(dead_code)]
286 pub fn push(&mut self, item: u32) -> bool {
287 if self.in_worklist.insert(item) {
288 self.items.push_back(item);
289 true
290 } else {
291 false
292 }
293 }
294 #[allow(dead_code)]
295 pub fn pop(&mut self) -> Option<u32> {
296 let item = self.items.pop_front()?;
297 self.in_worklist.remove(&item);
298 Some(item)
299 }
300 #[allow(dead_code)]
301 pub fn is_empty(&self) -> bool {
302 self.items.is_empty()
303 }
304 #[allow(dead_code)]
305 pub fn len(&self) -> usize {
306 self.items.len()
307 }
308 #[allow(dead_code)]
309 pub fn contains(&self, item: u32) -> bool {
310 self.in_worklist.contains(&item)
311 }
312}
313#[allow(dead_code)]
314#[derive(Debug, Clone)]
315pub struct GoAnalysisCache {
316 pub(super) entries: std::collections::HashMap<String, GoCacheEntry>,
317 pub(super) max_size: usize,
318 pub(super) hits: u64,
319 pub(super) misses: u64,
320}
321impl GoAnalysisCache {
322 #[allow(dead_code)]
323 pub fn new(max_size: usize) -> Self {
324 GoAnalysisCache {
325 entries: std::collections::HashMap::new(),
326 max_size,
327 hits: 0,
328 misses: 0,
329 }
330 }
331 #[allow(dead_code)]
332 pub fn get(&mut self, key: &str) -> Option<&GoCacheEntry> {
333 if self.entries.contains_key(key) {
334 self.hits += 1;
335 self.entries.get(key)
336 } else {
337 self.misses += 1;
338 None
339 }
340 }
341 #[allow(dead_code)]
342 pub fn insert(&mut self, key: String, data: Vec<u8>) {
343 if self.entries.len() >= self.max_size {
344 if let Some(oldest) = self.entries.keys().next().cloned() {
345 self.entries.remove(&oldest);
346 }
347 }
348 self.entries.insert(
349 key.clone(),
350 GoCacheEntry {
351 key,
352 data,
353 timestamp: 0,
354 valid: true,
355 },
356 );
357 }
358 #[allow(dead_code)]
359 pub fn invalidate(&mut self, key: &str) {
360 if let Some(entry) = self.entries.get_mut(key) {
361 entry.valid = false;
362 }
363 }
364 #[allow(dead_code)]
365 pub fn clear(&mut self) {
366 self.entries.clear();
367 }
368 #[allow(dead_code)]
369 pub fn hit_rate(&self) -> f64 {
370 let total = self.hits + self.misses;
371 if total == 0 {
372 return 0.0;
373 }
374 self.hits as f64 / total as f64
375 }
376 #[allow(dead_code)]
377 pub fn size(&self) -> usize {
378 self.entries.len()
379 }
380}
381#[allow(dead_code)]
382pub struct GoConstantFoldingHelper;
383impl GoConstantFoldingHelper {
384 #[allow(dead_code)]
385 pub fn fold_add_i64(a: i64, b: i64) -> Option<i64> {
386 a.checked_add(b)
387 }
388 #[allow(dead_code)]
389 pub fn fold_sub_i64(a: i64, b: i64) -> Option<i64> {
390 a.checked_sub(b)
391 }
392 #[allow(dead_code)]
393 pub fn fold_mul_i64(a: i64, b: i64) -> Option<i64> {
394 a.checked_mul(b)
395 }
396 #[allow(dead_code)]
397 pub fn fold_div_i64(a: i64, b: i64) -> Option<i64> {
398 if b == 0 {
399 None
400 } else {
401 a.checked_div(b)
402 }
403 }
404 #[allow(dead_code)]
405 pub fn fold_add_f64(a: f64, b: f64) -> f64 {
406 a + b
407 }
408 #[allow(dead_code)]
409 pub fn fold_mul_f64(a: f64, b: f64) -> f64 {
410 a * b
411 }
412 #[allow(dead_code)]
413 pub fn fold_neg_i64(a: i64) -> Option<i64> {
414 a.checked_neg()
415 }
416 #[allow(dead_code)]
417 pub fn fold_not_bool(a: bool) -> bool {
418 !a
419 }
420 #[allow(dead_code)]
421 pub fn fold_and_bool(a: bool, b: bool) -> bool {
422 a && b
423 }
424 #[allow(dead_code)]
425 pub fn fold_or_bool(a: bool, b: bool) -> bool {
426 a || b
427 }
428 #[allow(dead_code)]
429 pub fn fold_shl_i64(a: i64, b: u32) -> Option<i64> {
430 a.checked_shl(b)
431 }
432 #[allow(dead_code)]
433 pub fn fold_shr_i64(a: i64, b: u32) -> Option<i64> {
434 a.checked_shr(b)
435 }
436 #[allow(dead_code)]
437 pub fn fold_rem_i64(a: i64, b: i64) -> Option<i64> {
438 if b == 0 {
439 None
440 } else {
441 Some(a % b)
442 }
443 }
444 #[allow(dead_code)]
445 pub fn fold_bitand_i64(a: i64, b: i64) -> i64 {
446 a & b
447 }
448 #[allow(dead_code)]
449 pub fn fold_bitor_i64(a: i64, b: i64) -> i64 {
450 a | b
451 }
452 #[allow(dead_code)]
453 pub fn fold_bitxor_i64(a: i64, b: i64) -> i64 {
454 a ^ b
455 }
456 #[allow(dead_code)]
457 pub fn fold_bitnot_i64(a: i64) -> i64 {
458 !a
459 }
460}
461#[derive(Debug, Clone, PartialEq)]
463pub enum GoExpr {
464 Lit(GoLit),
466 Var(String),
468 Call(Box<GoExpr>, Vec<GoExpr>),
470 BinOp(String, Box<GoExpr>, Box<GoExpr>),
472 Unary(String, Box<GoExpr>),
474 Field(Box<GoExpr>, String),
476 Index(Box<GoExpr>, Box<GoExpr>),
478 TypeAssert(Box<GoExpr>, GoType),
480 Composite(GoType, Vec<(String, GoExpr)>),
482 SliceLit(GoType, Vec<GoExpr>),
484 AddressOf(Box<GoExpr>),
486 Deref(Box<GoExpr>),
488 FuncLit(Vec<(String, GoType)>, Vec<GoType>, Vec<GoStmt>),
490 Make(GoType, Vec<GoExpr>),
492 New(GoType),
494}
495#[allow(dead_code)]
496#[derive(Debug, Clone)]
497pub struct GoPassConfig {
498 pub phase: GoPassPhase,
499 pub enabled: bool,
500 pub max_iterations: u32,
501 pub debug_output: bool,
502 pub pass_name: String,
503}
504impl GoPassConfig {
505 #[allow(dead_code)]
506 pub fn new(name: impl Into<String>, phase: GoPassPhase) -> Self {
507 GoPassConfig {
508 phase,
509 enabled: true,
510 max_iterations: 10,
511 debug_output: false,
512 pass_name: name.into(),
513 }
514 }
515 #[allow(dead_code)]
516 pub fn disabled(mut self) -> Self {
517 self.enabled = false;
518 self
519 }
520 #[allow(dead_code)]
521 pub fn with_debug(mut self) -> Self {
522 self.debug_output = true;
523 self
524 }
525 #[allow(dead_code)]
526 pub fn max_iter(mut self, n: u32) -> Self {
527 self.max_iterations = n;
528 self
529 }
530}
531pub struct GoBackend {
535 pub(super) var_counter: u64,
537 pub(super) var_map: HashMap<LcnfVarId, String>,
539 pub(super) keywords: HashSet<&'static str>,
541 pub(super) builtins: HashSet<&'static str>,
543}
544impl GoBackend {
545 pub fn new() -> Self {
547 GoBackend {
548 var_counter: 0,
549 var_map: HashMap::new(),
550 keywords: go_keywords(),
551 builtins: go_builtins(),
552 }
553 }
554 pub(super) fn fresh_var(&mut self) -> String {
556 let n = self.var_counter;
557 self.var_counter += 1;
558 format!("_t{}", n)
559 }
560 pub fn mangle_name(name: &str) -> String {
568 let sanitised: String = name
569 .chars()
570 .map(|c| {
571 if c.is_alphanumeric() || c == '_' {
572 c
573 } else {
574 '_'
575 }
576 })
577 .collect();
578 if sanitised.is_empty() {
579 return "ox_empty".to_string();
580 }
581 if sanitised.starts_with(|c: char| c.is_ascii_digit()) {
582 return format!("ox_{}", sanitised);
583 }
584 let kw = go_keywords();
585 let builtins = go_builtins();
586 if kw.contains(sanitised.as_str()) || builtins.contains(sanitised.as_str()) {
587 return format!("ox_{}", sanitised);
588 }
589 sanitised
590 }
591 pub fn compile_module(&mut self, decls: &[LcnfFunDecl]) -> GoModule {
593 let mut module = GoModule::new("main");
594 module.add_import("fmt");
595 let runtime_funcs = self.build_runtime();
596 for f in runtime_funcs {
597 module.funcs.push(f);
598 }
599 let mut ctor_decl = GoTypeDecl::new("OxiCtor");
600 ctor_decl.add_field("Tag", GoType::GoInt);
601 ctor_decl.add_field("Fields", GoType::GoSlice(Box::new(GoType::GoInterface)));
602 module.types.push(ctor_decl);
603 for decl in decls {
604 if let Some(func) = self.compile_decl(decl) {
605 module.funcs.push(func);
606 }
607 }
608 module
609 }
610 pub fn compile_decl(&mut self, decl: &LcnfFunDecl) -> Option<GoFunc> {
612 let go_name = Self::mangle_name(&decl.name.to_string());
613 let mut func = GoFunc::new(go_name);
614 for param in &decl.params {
615 if !param.erased {
616 let go_param_name = Self::mangle_name(¶m.name);
617 let go_ty = self.compile_type(¶m.ty);
618 func.add_param(go_param_name.clone(), go_ty.clone());
619 self.var_map.insert(param.id, go_param_name);
620 }
621 }
622 let go_ret = self.compile_type(&decl.ret_type);
623 func.add_return(go_ret);
624 let body_stmts = self.compile_expr(&decl.body);
625 func.body = body_stmts;
626 Some(func)
627 }
628 pub fn compile_type(&self, ty: &LcnfType) -> GoType {
630 match ty {
631 LcnfType::Nat => GoType::GoInt,
632 LcnfType::LcnfString => GoType::GoString,
633 LcnfType::Erased | LcnfType::Irrelevant | LcnfType::Unit => GoType::GoUnit,
634 LcnfType::Object => GoType::GoInterface,
635 LcnfType::Var(_) => GoType::GoInterface,
636 LcnfType::Ctor(_, _) => {
637 GoType::GoPtr(Box::new(GoType::GoStruct("OxiCtor".to_string())))
638 }
639 LcnfType::Fun(params, ret) => {
640 let go_params: Vec<GoType> = params.iter().map(|p| self.compile_type(p)).collect();
641 let go_ret = self.compile_type(ret);
642 GoType::GoFunc(go_params, vec![go_ret])
643 }
644 }
645 }
646 pub fn compile_expr(&mut self, expr: &LcnfExpr) -> Vec<GoStmt> {
650 match expr {
651 LcnfExpr::Return(arg) => {
652 let go_expr = self.compile_arg(arg);
653 vec![GoStmt::Return(vec![go_expr])]
654 }
655 LcnfExpr::Unreachable => {
656 vec![GoStmt::Panic(GoExpr::Lit(GoLit::Str(
657 "unreachable".to_string(),
658 )))]
659 }
660 LcnfExpr::TailCall(func, args) => {
661 let go_func = self.compile_arg(func);
662 let go_args: Vec<GoExpr> = args.iter().map(|a| self.compile_arg(a)).collect();
663 let call = GoExpr::Call(Box::new(go_func), go_args);
664 vec![GoStmt::Return(vec![call])]
665 }
666 LcnfExpr::Let {
667 id,
668 name,
669 ty: _,
670 value,
671 body,
672 } => {
673 let go_name = Self::mangle_name(name);
674 let go_name = format!("{}_{}", go_name, id.0);
675 self.var_map.insert(*id, go_name.clone());
676 let mut stmts = Vec::new();
677 let val_expr = self.compile_let_value(value);
678 stmts.push(GoStmt::ShortDecl(go_name, val_expr));
679 let cont = self.compile_expr(body);
680 stmts.extend(cont);
681 stmts
682 }
683 LcnfExpr::Case {
684 scrutinee,
685 scrutinee_ty: _,
686 alts,
687 default,
688 } => self.compile_case(*scrutinee, alts, default.as_deref()),
689 }
690 }
691 pub(super) fn compile_let_value(&mut self, value: &LcnfLetValue) -> GoExpr {
693 match value {
694 LcnfLetValue::Lit(lit) => self.compile_lit(lit),
695 LcnfLetValue::Erased | LcnfLetValue::Reset(_) => GoExpr::Lit(GoLit::Nil),
696 LcnfLetValue::FVar(id) => {
697 let name = self
698 .var_map
699 .get(id)
700 .cloned()
701 .unwrap_or_else(|| format!("_x{}", id.0));
702 GoExpr::Var(name)
703 }
704 LcnfLetValue::App(func, args) => {
705 let go_func = self.compile_arg(func);
706 let go_args: Vec<GoExpr> = args.iter().map(|a| self.compile_arg(a)).collect();
707 GoExpr::Call(Box::new(go_func), go_args)
708 }
709 LcnfLetValue::Proj(_, idx, var) => {
710 let var_name = self
711 .var_map
712 .get(var)
713 .cloned()
714 .unwrap_or_else(|| format!("_x{}", var.0));
715 GoExpr::Index(
716 Box::new(GoExpr::Field(
717 Box::new(GoExpr::Var(var_name)),
718 "Fields".to_string(),
719 )),
720 Box::new(GoExpr::Lit(GoLit::Int(*idx as i64))),
721 )
722 }
723 LcnfLetValue::Ctor(name, tag, args) => {
724 let go_name = Self::mangle_name(name);
725 let mut fields = vec![
726 ("Tag".to_string(), GoExpr::Lit(GoLit::Int(*tag as i64))),
727 ("_ctorName".to_string(), GoExpr::Lit(GoLit::Str(go_name))),
728 ];
729 if !args.is_empty() {
730 let go_args: Vec<GoExpr> = args.iter().map(|a| self.compile_arg(a)).collect();
731 fields.push((
732 "Fields".to_string(),
733 GoExpr::SliceLit(GoType::GoInterface, go_args),
734 ));
735 } else {
736 fields.push((
737 "Fields".to_string(),
738 GoExpr::SliceLit(GoType::GoInterface, vec![]),
739 ));
740 }
741 GoExpr::AddressOf(Box::new(GoExpr::Composite(
742 GoType::GoStruct("OxiCtor".to_string()),
743 fields,
744 )))
745 }
746 LcnfLetValue::Reuse(_slot, name, tag, args) => {
747 self.compile_let_value(&LcnfLetValue::Ctor(name.clone(), *tag, args.clone()))
748 }
749 }
750 }
751 pub fn compile_arg(&self, arg: &LcnfArg) -> GoExpr {
753 match arg {
754 LcnfArg::Var(id) => {
755 let name = self
756 .var_map
757 .get(id)
758 .cloned()
759 .unwrap_or_else(|| format!("_x{}", id.0));
760 GoExpr::Var(name)
761 }
762 LcnfArg::Lit(lit) => self.compile_lit(lit),
763 LcnfArg::Erased | LcnfArg::Type(_) => GoExpr::Lit(GoLit::Nil),
764 }
765 }
766 pub(super) fn compile_lit(&self, lit: &LcnfLit) -> GoExpr {
768 match lit {
769 LcnfLit::Nat(n) => GoExpr::Lit(GoLit::Int(*n as i64)),
770 LcnfLit::Str(s) => GoExpr::Lit(GoLit::Str(s.clone())),
771 }
772 }
773 pub(super) fn compile_case(
775 &mut self,
776 scrutinee: LcnfVarId,
777 alts: &[LcnfAlt],
778 default: Option<&LcnfExpr>,
779 ) -> Vec<GoStmt> {
780 let scr_name = self
781 .var_map
782 .get(&scrutinee)
783 .cloned()
784 .unwrap_or_else(|| format!("_x{}", scrutinee.0));
785 let tag_expr = GoExpr::Field(Box::new(GoExpr::Var(scr_name.clone())), "Tag".to_string());
786 let mut cases: Vec<GoCase> = Vec::new();
787 for alt in alts {
788 let mut alt_body: Vec<GoStmt> = Vec::new();
789 for (idx, param) in alt.params.iter().enumerate() {
790 if !param.erased {
791 let go_param = Self::mangle_name(¶m.name);
792 let go_param = format!("{}_{}", go_param, param.id.0);
793 self.var_map.insert(param.id, go_param.clone());
794 let field_expr = GoExpr::Index(
795 Box::new(GoExpr::Field(
796 Box::new(GoExpr::Var(scr_name.clone())),
797 "Fields".to_string(),
798 )),
799 Box::new(GoExpr::Lit(GoLit::Int(idx as i64))),
800 );
801 alt_body.push(GoStmt::ShortDecl(go_param, field_expr));
802 }
803 }
804 let cont = self.compile_expr(&alt.body);
805 alt_body.extend(cont);
806 cases.push(GoCase {
807 pattern: Some(vec![GoExpr::Lit(GoLit::Int(alt.ctor_tag as i64))]),
808 body: alt_body,
809 });
810 }
811 if let Some(def_expr) = default {
812 let def_stmts = self.compile_expr(def_expr);
813 cases.push(GoCase {
814 pattern: None,
815 body: def_stmts,
816 });
817 }
818 vec![GoStmt::Switch(Some(tag_expr), cases)]
819 }
820 pub(super) fn build_runtime(&self) -> Vec<GoFunc> {
824 let mut funcs = Vec::new();
825 funcs.push(self.simple_binop_func("natAdd", "+"));
826 {
827 let mut f = GoFunc::new("natSub");
828 f.add_param("a", GoType::GoInt);
829 f.add_param("b", GoType::GoInt);
830 f.add_return(GoType::GoInt);
831 f.body = vec![GoStmt::If(
832 GoExpr::BinOp(
833 ">=".to_string(),
834 Box::new(GoExpr::Var("a".to_string())),
835 Box::new(GoExpr::Var("b".to_string())),
836 ),
837 vec![GoStmt::Return(vec![GoExpr::BinOp(
838 "-".to_string(),
839 Box::new(GoExpr::Var("a".to_string())),
840 Box::new(GoExpr::Var("b".to_string())),
841 )])],
842 vec![GoStmt::Return(vec![GoExpr::Lit(GoLit::Int(0))])],
843 )];
844 funcs.push(f);
845 }
846 funcs.push(self.simple_binop_func("natMul", "*"));
847 {
848 let mut f = GoFunc::new("natDiv");
849 f.add_param("a", GoType::GoInt);
850 f.add_param("b", GoType::GoInt);
851 f.add_return(GoType::GoInt);
852 f.body = vec![GoStmt::If(
853 GoExpr::BinOp(
854 "==".to_string(),
855 Box::new(GoExpr::Var("b".to_string())),
856 Box::new(GoExpr::Lit(GoLit::Int(0))),
857 ),
858 vec![GoStmt::Return(vec![GoExpr::Lit(GoLit::Int(0))])],
859 vec![GoStmt::Return(vec![GoExpr::BinOp(
860 "/".to_string(),
861 Box::new(GoExpr::Var("a".to_string())),
862 Box::new(GoExpr::Var("b".to_string())),
863 )])],
864 )];
865 funcs.push(f);
866 }
867 {
868 let mut f = GoFunc::new("natMod");
869 f.add_param("a", GoType::GoInt);
870 f.add_param("b", GoType::GoInt);
871 f.add_return(GoType::GoInt);
872 f.body = vec![GoStmt::If(
873 GoExpr::BinOp(
874 "==".to_string(),
875 Box::new(GoExpr::Var("b".to_string())),
876 Box::new(GoExpr::Lit(GoLit::Int(0))),
877 ),
878 vec![GoStmt::Return(vec![GoExpr::Lit(GoLit::Int(0))])],
879 vec![GoStmt::Return(vec![GoExpr::BinOp(
880 "%".to_string(),
881 Box::new(GoExpr::Var("a".to_string())),
882 Box::new(GoExpr::Var("b".to_string())),
883 )])],
884 )];
885 funcs.push(f);
886 }
887 funcs.push(self.simple_cmp_func("natEq", "=="));
888 funcs.push(self.simple_cmp_func("natLt", "<"));
889 funcs.push(self.simple_cmp_func("natLe", "<="));
890 funcs.push(self.simple_cmp_func("natGt", ">"));
891 funcs.push(self.simple_cmp_func("natGe", ">="));
892 funcs.push(self.simple_bool_func("boolAnd", "&&"));
893 funcs.push(self.simple_bool_func("boolOr", "||"));
894 {
895 let mut f = GoFunc::new("boolNot");
896 f.add_param("a", GoType::GoBool);
897 f.add_return(GoType::GoBool);
898 f.body = vec![GoStmt::Return(vec![GoExpr::Unary(
899 "!".to_string(),
900 Box::new(GoExpr::Var("a".to_string())),
901 )])];
902 funcs.push(f);
903 }
904 {
905 let mut f = GoFunc::new("strAppend");
906 f.add_param("a", GoType::GoString);
907 f.add_param("b", GoType::GoString);
908 f.add_return(GoType::GoString);
909 f.body = vec![GoStmt::Return(vec![GoExpr::BinOp(
910 "+".to_string(),
911 Box::new(GoExpr::Var("a".to_string())),
912 Box::new(GoExpr::Var("b".to_string())),
913 )])];
914 funcs.push(f);
915 }
916 {
917 let mut f = GoFunc::new("strEq");
918 f.add_param("a", GoType::GoString);
919 f.add_param("b", GoType::GoString);
920 f.add_return(GoType::GoBool);
921 f.body = vec![GoStmt::Return(vec![GoExpr::BinOp(
922 "==".to_string(),
923 Box::new(GoExpr::Var("a".to_string())),
924 Box::new(GoExpr::Var("b".to_string())),
925 )])];
926 funcs.push(f);
927 }
928 {
929 let mut f = GoFunc::new("strLen");
930 f.add_param("s", GoType::GoString);
931 f.add_return(GoType::GoInt);
932 f.body = vec![GoStmt::Return(vec![GoExpr::Call(
933 Box::new(GoExpr::Var("int64".to_string())),
934 vec![GoExpr::Call(
935 Box::new(GoExpr::Var("len".to_string())),
936 vec![GoExpr::Var("s".to_string())],
937 )],
938 )])];
939 funcs.push(f);
940 }
941 {
942 let mut f = GoFunc::new("oxiPrint");
943 f.add_param("s", GoType::GoString);
944 f.body = vec![GoStmt::Expr(GoExpr::Call(
945 Box::new(GoExpr::Field(
946 Box::new(GoExpr::Var("fmt".to_string())),
947 "Println".to_string(),
948 )),
949 vec![GoExpr::Var("s".to_string())],
950 ))];
951 funcs.push(f);
952 }
953 {
954 let mut f = GoFunc::new("oxiPanic");
955 f.add_param("msg", GoType::GoString);
956 f.body = vec![GoStmt::Panic(GoExpr::Var("msg".to_string()))];
957 funcs.push(f);
958 }
959 funcs
960 }
961 pub(super) fn simple_binop_func(&self, name: &str, op: &str) -> GoFunc {
963 let mut f = GoFunc::new(name);
964 f.add_param("a", GoType::GoInt);
965 f.add_param("b", GoType::GoInt);
966 f.add_return(GoType::GoInt);
967 f.body = vec![GoStmt::Return(vec![GoExpr::BinOp(
968 op.to_string(),
969 Box::new(GoExpr::Var("a".to_string())),
970 Box::new(GoExpr::Var("b".to_string())),
971 )])];
972 f
973 }
974 pub(super) fn simple_cmp_func(&self, name: &str, op: &str) -> GoFunc {
976 let mut f = GoFunc::new(name);
977 f.add_param("a", GoType::GoInt);
978 f.add_param("b", GoType::GoInt);
979 f.add_return(GoType::GoBool);
980 f.body = vec![GoStmt::Return(vec![GoExpr::BinOp(
981 op.to_string(),
982 Box::new(GoExpr::Var("a".to_string())),
983 Box::new(GoExpr::Var("b".to_string())),
984 )])];
985 f
986 }
987 pub(super) fn simple_bool_func(&self, name: &str, op: &str) -> GoFunc {
989 let mut f = GoFunc::new(name);
990 f.add_param("a", GoType::GoBool);
991 f.add_param("b", GoType::GoBool);
992 f.add_return(GoType::GoBool);
993 f.body = vec![GoStmt::Return(vec![GoExpr::BinOp(
994 op.to_string(),
995 Box::new(GoExpr::Var("a".to_string())),
996 Box::new(GoExpr::Var("b".to_string())),
997 )])];
998 f
999 }
1000 pub fn emit_func(&self, func: &GoFunc) -> String {
1002 func.codegen()
1003 }
1004 pub fn emit_type_decl(&self, decl: &GoTypeDecl) -> String {
1006 decl.codegen()
1007 }
1008 pub fn emit_module(&self, module: &GoModule) -> String {
1010 module.codegen()
1011 }
1012}
1013#[derive(Debug, Clone, PartialEq)]
1015pub struct GoCase {
1016 pub pattern: Option<Vec<GoExpr>>,
1018 pub body: Vec<GoStmt>,
1019}
1020#[derive(Debug, Clone)]
1022pub struct GoTypeDecl {
1023 pub name: String,
1025 pub fields: Vec<(String, GoType)>,
1027 pub exported: bool,
1029}
1030impl GoTypeDecl {
1031 pub fn new(name: impl Into<String>) -> Self {
1033 GoTypeDecl {
1034 name: name.into(),
1035 fields: Vec::new(),
1036 exported: false,
1037 }
1038 }
1039 pub fn add_field(&mut self, name: impl Into<String>, ty: GoType) {
1041 self.fields.push((name.into(), ty));
1042 }
1043 pub fn codegen(&self) -> String {
1045 let mut out = format!("type {} struct {{\n", self.name);
1046 for (name, ty) in &self.fields {
1047 out.push_str(&format!(" {} {}\n", name, ty));
1048 }
1049 out.push('}');
1050 out
1051 }
1052}
1053#[allow(dead_code)]
1054#[derive(Debug, Clone, Default)]
1055pub struct GoPassStats {
1056 pub total_runs: u32,
1057 pub successful_runs: u32,
1058 pub total_changes: u64,
1059 pub time_ms: u64,
1060 pub iterations_used: u32,
1061}
1062impl GoPassStats {
1063 #[allow(dead_code)]
1064 pub fn new() -> Self {
1065 Self::default()
1066 }
1067 #[allow(dead_code)]
1068 pub fn record_run(&mut self, changes: u64, time_ms: u64, iterations: u32) {
1069 self.total_runs += 1;
1070 self.successful_runs += 1;
1071 self.total_changes += changes;
1072 self.time_ms += time_ms;
1073 self.iterations_used = iterations;
1074 }
1075 #[allow(dead_code)]
1076 pub fn average_changes_per_run(&self) -> f64 {
1077 if self.total_runs == 0 {
1078 return 0.0;
1079 }
1080 self.total_changes as f64 / self.total_runs as f64
1081 }
1082 #[allow(dead_code)]
1083 pub fn success_rate(&self) -> f64 {
1084 if self.total_runs == 0 {
1085 return 0.0;
1086 }
1087 self.successful_runs as f64 / self.total_runs as f64
1088 }
1089 #[allow(dead_code)]
1090 pub fn format_summary(&self) -> String {
1091 format!(
1092 "Runs: {}/{}, Changes: {}, Time: {}ms",
1093 self.successful_runs, self.total_runs, self.total_changes, self.time_ms
1094 )
1095 }
1096}
1097#[derive(Debug, Clone, PartialEq)]
1099pub enum GoLit {
1100 Int(i64),
1102 Float(f64),
1104 Bool(bool),
1106 Str(String),
1108 Nil,
1110}
1111#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1113pub enum GoType {
1114 GoBool,
1116 GoInt,
1118 GoFloat,
1120 GoString,
1122 GoSlice(Box<GoType>),
1124 GoMap(Box<GoType>, Box<GoType>),
1126 GoFunc(Vec<GoType>, Vec<GoType>),
1128 GoInterface,
1130 GoStruct(String),
1132 GoPtr(Box<GoType>),
1134 GoChan(Box<GoType>),
1136 GoError,
1138 GoUnit,
1140}
1141#[derive(Debug, Clone, PartialEq)]
1143pub enum GoStmt {
1144 Const(String, Option<GoType>, GoExpr),
1146 Var(String, GoType, Option<GoExpr>),
1148 ShortDecl(String, GoExpr),
1150 Assign(GoExpr, GoExpr),
1152 Return(Vec<GoExpr>),
1154 If(GoExpr, Vec<GoStmt>, Vec<GoStmt>),
1156 Switch(Option<GoExpr>, Vec<GoCase>),
1158 For(
1160 Option<Box<GoStmt>>,
1161 Option<GoExpr>,
1162 Option<Box<GoStmt>>,
1163 Vec<GoStmt>,
1164 ),
1165 ForRange(Option<String>, Option<String>, GoExpr, Vec<GoStmt>),
1167 Block(Vec<GoStmt>),
1169 Expr(GoExpr),
1171 Break,
1173 Continue,
1175 Goto(String),
1177 Label(String, Box<GoStmt>),
1179 Defer(GoExpr),
1181 GoRoutine(GoExpr),
1183 Panic(GoExpr),
1185}
1186#[allow(dead_code)]
1187#[derive(Debug, Clone, PartialEq)]
1188pub enum GoPassPhase {
1189 Analysis,
1190 Transformation,
1191 Verification,
1192 Cleanup,
1193}
1194impl GoPassPhase {
1195 #[allow(dead_code)]
1196 pub fn name(&self) -> &str {
1197 match self {
1198 GoPassPhase::Analysis => "analysis",
1199 GoPassPhase::Transformation => "transformation",
1200 GoPassPhase::Verification => "verification",
1201 GoPassPhase::Cleanup => "cleanup",
1202 }
1203 }
1204 #[allow(dead_code)]
1205 pub fn is_modifying(&self) -> bool {
1206 matches!(self, GoPassPhase::Transformation | GoPassPhase::Cleanup)
1207 }
1208}
1209#[allow(dead_code)]
1210pub struct GoPassRegistry {
1211 pub(super) configs: Vec<GoPassConfig>,
1212 pub(super) stats: std::collections::HashMap<String, GoPassStats>,
1213}
1214impl GoPassRegistry {
1215 #[allow(dead_code)]
1216 pub fn new() -> Self {
1217 GoPassRegistry {
1218 configs: Vec::new(),
1219 stats: std::collections::HashMap::new(),
1220 }
1221 }
1222 #[allow(dead_code)]
1223 pub fn register(&mut self, config: GoPassConfig) {
1224 self.stats
1225 .insert(config.pass_name.clone(), GoPassStats::new());
1226 self.configs.push(config);
1227 }
1228 #[allow(dead_code)]
1229 pub fn enabled_passes(&self) -> Vec<&GoPassConfig> {
1230 self.configs.iter().filter(|c| c.enabled).collect()
1231 }
1232 #[allow(dead_code)]
1233 pub fn get_stats(&self, name: &str) -> Option<&GoPassStats> {
1234 self.stats.get(name)
1235 }
1236 #[allow(dead_code)]
1237 pub fn total_passes(&self) -> usize {
1238 self.configs.len()
1239 }
1240 #[allow(dead_code)]
1241 pub fn enabled_count(&self) -> usize {
1242 self.enabled_passes().len()
1243 }
1244 #[allow(dead_code)]
1245 pub fn update_stats(&mut self, name: &str, changes: u64, time_ms: u64, iter: u32) {
1246 if let Some(stats) = self.stats.get_mut(name) {
1247 stats.record_run(changes, time_ms, iter);
1248 }
1249 }
1250}
1251#[allow(dead_code)]
1252#[derive(Debug, Clone)]
1253pub struct GoCacheEntry {
1254 pub key: String,
1255 pub data: Vec<u8>,
1256 pub timestamp: u64,
1257 pub valid: bool,
1258}
1259#[allow(dead_code)]
1260#[derive(Debug, Clone)]
1261pub struct GoLivenessInfo {
1262 pub live_in: Vec<std::collections::HashSet<u32>>,
1263 pub live_out: Vec<std::collections::HashSet<u32>>,
1264 pub defs: Vec<std::collections::HashSet<u32>>,
1265 pub uses: Vec<std::collections::HashSet<u32>>,
1266}
1267impl GoLivenessInfo {
1268 #[allow(dead_code)]
1269 pub fn new(block_count: usize) -> Self {
1270 GoLivenessInfo {
1271 live_in: vec![std::collections::HashSet::new(); block_count],
1272 live_out: vec![std::collections::HashSet::new(); block_count],
1273 defs: vec![std::collections::HashSet::new(); block_count],
1274 uses: vec![std::collections::HashSet::new(); block_count],
1275 }
1276 }
1277 #[allow(dead_code)]
1278 pub fn add_def(&mut self, block: usize, var: u32) {
1279 if block < self.defs.len() {
1280 self.defs[block].insert(var);
1281 }
1282 }
1283 #[allow(dead_code)]
1284 pub fn add_use(&mut self, block: usize, var: u32) {
1285 if block < self.uses.len() {
1286 self.uses[block].insert(var);
1287 }
1288 }
1289 #[allow(dead_code)]
1290 pub fn is_live_in(&self, block: usize, var: u32) -> bool {
1291 self.live_in
1292 .get(block)
1293 .map(|s| s.contains(&var))
1294 .unwrap_or(false)
1295 }
1296 #[allow(dead_code)]
1297 pub fn is_live_out(&self, block: usize, var: u32) -> bool {
1298 self.live_out
1299 .get(block)
1300 .map(|s| s.contains(&var))
1301 .unwrap_or(false)
1302 }
1303}