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::Int => GoType::GoInt,
633 LcnfType::LcnfString => GoType::GoString,
634 LcnfType::Erased | LcnfType::Irrelevant | LcnfType::Unit => GoType::GoUnit,
635 LcnfType::Object => GoType::GoInterface,
636 LcnfType::Var(_) => GoType::GoInterface,
637 LcnfType::Ctor(_, _) => {
638 GoType::GoPtr(Box::new(GoType::GoStruct("OxiCtor".to_string())))
639 }
640 LcnfType::Fun(params, ret) => {
641 let go_params: Vec<GoType> = params.iter().map(|p| self.compile_type(p)).collect();
642 let go_ret = self.compile_type(ret);
643 GoType::GoFunc(go_params, vec![go_ret])
644 }
645 }
646 }
647 pub fn compile_expr(&mut self, expr: &LcnfExpr) -> Vec<GoStmt> {
651 match expr {
652 LcnfExpr::Return(arg) => {
653 let go_expr = self.compile_arg(arg);
654 vec![GoStmt::Return(vec![go_expr])]
655 }
656 LcnfExpr::Unreachable => {
657 vec![GoStmt::Panic(GoExpr::Lit(GoLit::Str(
658 "unreachable".to_string(),
659 )))]
660 }
661 LcnfExpr::TailCall(func, args) => {
662 let go_func = self.compile_arg(func);
663 let go_args: Vec<GoExpr> = args.iter().map(|a| self.compile_arg(a)).collect();
664 let call = GoExpr::Call(Box::new(go_func), go_args);
665 vec![GoStmt::Return(vec![call])]
666 }
667 LcnfExpr::Let {
668 id,
669 name,
670 ty: _,
671 value,
672 body,
673 } => {
674 let go_name = Self::mangle_name(name);
675 let go_name = format!("{}_{}", go_name, id.0);
676 self.var_map.insert(*id, go_name.clone());
677 let mut stmts = Vec::new();
678 let val_expr = self.compile_let_value(value);
679 stmts.push(GoStmt::ShortDecl(go_name, val_expr));
680 let cont = self.compile_expr(body);
681 stmts.extend(cont);
682 stmts
683 }
684 LcnfExpr::Case {
685 scrutinee,
686 scrutinee_ty: _,
687 alts,
688 default,
689 } => self.compile_case(*scrutinee, alts, default.as_deref()),
690 }
691 }
692 pub(super) fn compile_let_value(&mut self, value: &LcnfLetValue) -> GoExpr {
694 match value {
695 LcnfLetValue::Lit(lit) => self.compile_lit(lit),
696 LcnfLetValue::Erased | LcnfLetValue::Reset(_) => GoExpr::Lit(GoLit::Nil),
697 LcnfLetValue::FVar(id) => {
698 let name = self
699 .var_map
700 .get(id)
701 .cloned()
702 .unwrap_or_else(|| format!("_x{}", id.0));
703 GoExpr::Var(name)
704 }
705 LcnfLetValue::App(func, args) => {
706 let go_func = self.compile_arg(func);
707 let go_args: Vec<GoExpr> = args.iter().map(|a| self.compile_arg(a)).collect();
708 GoExpr::Call(Box::new(go_func), go_args)
709 }
710 LcnfLetValue::Proj(_, idx, var) => {
711 let var_name = self
712 .var_map
713 .get(var)
714 .cloned()
715 .unwrap_or_else(|| format!("_x{}", var.0));
716 GoExpr::Index(
717 Box::new(GoExpr::Field(
718 Box::new(GoExpr::Var(var_name)),
719 "Fields".to_string(),
720 )),
721 Box::new(GoExpr::Lit(GoLit::Int(*idx as i64))),
722 )
723 }
724 LcnfLetValue::Ctor(name, tag, args) => {
725 let go_name = Self::mangle_name(name);
726 let mut fields = vec![
727 ("Tag".to_string(), GoExpr::Lit(GoLit::Int(*tag as i64))),
728 ("_ctorName".to_string(), GoExpr::Lit(GoLit::Str(go_name))),
729 ];
730 if !args.is_empty() {
731 let go_args: Vec<GoExpr> = args.iter().map(|a| self.compile_arg(a)).collect();
732 fields.push((
733 "Fields".to_string(),
734 GoExpr::SliceLit(GoType::GoInterface, go_args),
735 ));
736 } else {
737 fields.push((
738 "Fields".to_string(),
739 GoExpr::SliceLit(GoType::GoInterface, vec![]),
740 ));
741 }
742 GoExpr::AddressOf(Box::new(GoExpr::Composite(
743 GoType::GoStruct("OxiCtor".to_string()),
744 fields,
745 )))
746 }
747 LcnfLetValue::Reuse(_slot, name, tag, args) => {
748 self.compile_let_value(&LcnfLetValue::Ctor(name.clone(), *tag, args.clone()))
749 }
750 }
751 }
752 pub fn compile_arg(&self, arg: &LcnfArg) -> GoExpr {
754 match arg {
755 LcnfArg::Var(id) => {
756 let name = self
757 .var_map
758 .get(id)
759 .cloned()
760 .unwrap_or_else(|| format!("_x{}", id.0));
761 GoExpr::Var(name)
762 }
763 LcnfArg::Lit(lit) => self.compile_lit(lit),
764 LcnfArg::Erased | LcnfArg::Type(_) => GoExpr::Lit(GoLit::Nil),
765 }
766 }
767 pub(super) fn compile_lit(&self, lit: &LcnfLit) -> GoExpr {
769 match lit {
770 LcnfLit::Nat(n) => GoExpr::Lit(GoLit::Int(*n as i64)),
771 LcnfLit::Int(i) => GoExpr::Lit(GoLit::Int(*i)),
772 LcnfLit::Str(s) => GoExpr::Lit(GoLit::Str(s.clone())),
773 }
774 }
775 pub(super) fn compile_case(
777 &mut self,
778 scrutinee: LcnfVarId,
779 alts: &[LcnfAlt],
780 default: Option<&LcnfExpr>,
781 ) -> Vec<GoStmt> {
782 let scr_name = self
783 .var_map
784 .get(&scrutinee)
785 .cloned()
786 .unwrap_or_else(|| format!("_x{}", scrutinee.0));
787 let tag_expr = GoExpr::Field(Box::new(GoExpr::Var(scr_name.clone())), "Tag".to_string());
788 let mut cases: Vec<GoCase> = Vec::new();
789 for alt in alts {
790 let mut alt_body: Vec<GoStmt> = Vec::new();
791 for (idx, param) in alt.params.iter().enumerate() {
792 if !param.erased {
793 let go_param = Self::mangle_name(¶m.name);
794 let go_param = format!("{}_{}", go_param, param.id.0);
795 self.var_map.insert(param.id, go_param.clone());
796 let field_expr = GoExpr::Index(
797 Box::new(GoExpr::Field(
798 Box::new(GoExpr::Var(scr_name.clone())),
799 "Fields".to_string(),
800 )),
801 Box::new(GoExpr::Lit(GoLit::Int(idx as i64))),
802 );
803 alt_body.push(GoStmt::ShortDecl(go_param, field_expr));
804 }
805 }
806 let cont = self.compile_expr(&alt.body);
807 alt_body.extend(cont);
808 cases.push(GoCase {
809 pattern: Some(vec![GoExpr::Lit(GoLit::Int(alt.ctor_tag as i64))]),
810 body: alt_body,
811 });
812 }
813 if let Some(def_expr) = default {
814 let def_stmts = self.compile_expr(def_expr);
815 cases.push(GoCase {
816 pattern: None,
817 body: def_stmts,
818 });
819 }
820 vec![GoStmt::Switch(Some(tag_expr), cases)]
821 }
822 pub(super) fn build_runtime(&self) -> Vec<GoFunc> {
826 let mut funcs = Vec::new();
827 funcs.push(self.simple_binop_func("natAdd", "+"));
828 {
829 let mut f = GoFunc::new("natSub");
830 f.add_param("a", GoType::GoInt);
831 f.add_param("b", GoType::GoInt);
832 f.add_return(GoType::GoInt);
833 f.body = vec![GoStmt::If(
834 GoExpr::BinOp(
835 ">=".to_string(),
836 Box::new(GoExpr::Var("a".to_string())),
837 Box::new(GoExpr::Var("b".to_string())),
838 ),
839 vec![GoStmt::Return(vec![GoExpr::BinOp(
840 "-".to_string(),
841 Box::new(GoExpr::Var("a".to_string())),
842 Box::new(GoExpr::Var("b".to_string())),
843 )])],
844 vec![GoStmt::Return(vec![GoExpr::Lit(GoLit::Int(0))])],
845 )];
846 funcs.push(f);
847 }
848 funcs.push(self.simple_binop_func("natMul", "*"));
849 {
850 let mut f = GoFunc::new("natDiv");
851 f.add_param("a", GoType::GoInt);
852 f.add_param("b", GoType::GoInt);
853 f.add_return(GoType::GoInt);
854 f.body = vec![GoStmt::If(
855 GoExpr::BinOp(
856 "==".to_string(),
857 Box::new(GoExpr::Var("b".to_string())),
858 Box::new(GoExpr::Lit(GoLit::Int(0))),
859 ),
860 vec![GoStmt::Return(vec![GoExpr::Lit(GoLit::Int(0))])],
861 vec![GoStmt::Return(vec![GoExpr::BinOp(
862 "/".to_string(),
863 Box::new(GoExpr::Var("a".to_string())),
864 Box::new(GoExpr::Var("b".to_string())),
865 )])],
866 )];
867 funcs.push(f);
868 }
869 {
870 let mut f = GoFunc::new("natMod");
871 f.add_param("a", GoType::GoInt);
872 f.add_param("b", GoType::GoInt);
873 f.add_return(GoType::GoInt);
874 f.body = vec![GoStmt::If(
875 GoExpr::BinOp(
876 "==".to_string(),
877 Box::new(GoExpr::Var("b".to_string())),
878 Box::new(GoExpr::Lit(GoLit::Int(0))),
879 ),
880 vec![GoStmt::Return(vec![GoExpr::Lit(GoLit::Int(0))])],
881 vec![GoStmt::Return(vec![GoExpr::BinOp(
882 "%".to_string(),
883 Box::new(GoExpr::Var("a".to_string())),
884 Box::new(GoExpr::Var("b".to_string())),
885 )])],
886 )];
887 funcs.push(f);
888 }
889 funcs.push(self.simple_cmp_func("natEq", "=="));
890 funcs.push(self.simple_cmp_func("natLt", "<"));
891 funcs.push(self.simple_cmp_func("natLe", "<="));
892 funcs.push(self.simple_cmp_func("natGt", ">"));
893 funcs.push(self.simple_cmp_func("natGe", ">="));
894 funcs.push(self.simple_bool_func("boolAnd", "&&"));
895 funcs.push(self.simple_bool_func("boolOr", "||"));
896 {
897 let mut f = GoFunc::new("boolNot");
898 f.add_param("a", GoType::GoBool);
899 f.add_return(GoType::GoBool);
900 f.body = vec![GoStmt::Return(vec![GoExpr::Unary(
901 "!".to_string(),
902 Box::new(GoExpr::Var("a".to_string())),
903 )])];
904 funcs.push(f);
905 }
906 {
907 let mut f = GoFunc::new("strAppend");
908 f.add_param("a", GoType::GoString);
909 f.add_param("b", GoType::GoString);
910 f.add_return(GoType::GoString);
911 f.body = vec![GoStmt::Return(vec![GoExpr::BinOp(
912 "+".to_string(),
913 Box::new(GoExpr::Var("a".to_string())),
914 Box::new(GoExpr::Var("b".to_string())),
915 )])];
916 funcs.push(f);
917 }
918 {
919 let mut f = GoFunc::new("strEq");
920 f.add_param("a", GoType::GoString);
921 f.add_param("b", GoType::GoString);
922 f.add_return(GoType::GoBool);
923 f.body = vec![GoStmt::Return(vec![GoExpr::BinOp(
924 "==".to_string(),
925 Box::new(GoExpr::Var("a".to_string())),
926 Box::new(GoExpr::Var("b".to_string())),
927 )])];
928 funcs.push(f);
929 }
930 {
931 let mut f = GoFunc::new("strLen");
932 f.add_param("s", GoType::GoString);
933 f.add_return(GoType::GoInt);
934 f.body = vec![GoStmt::Return(vec![GoExpr::Call(
935 Box::new(GoExpr::Var("int64".to_string())),
936 vec![GoExpr::Call(
937 Box::new(GoExpr::Var("len".to_string())),
938 vec![GoExpr::Var("s".to_string())],
939 )],
940 )])];
941 funcs.push(f);
942 }
943 {
944 let mut f = GoFunc::new("oxiPrint");
945 f.add_param("s", GoType::GoString);
946 f.body = vec![GoStmt::Expr(GoExpr::Call(
947 Box::new(GoExpr::Field(
948 Box::new(GoExpr::Var("fmt".to_string())),
949 "Println".to_string(),
950 )),
951 vec![GoExpr::Var("s".to_string())],
952 ))];
953 funcs.push(f);
954 }
955 {
956 let mut f = GoFunc::new("oxiPanic");
957 f.add_param("msg", GoType::GoString);
958 f.body = vec![GoStmt::Panic(GoExpr::Var("msg".to_string()))];
959 funcs.push(f);
960 }
961 funcs
962 }
963 pub(super) fn simple_binop_func(&self, name: &str, op: &str) -> GoFunc {
965 let mut f = GoFunc::new(name);
966 f.add_param("a", GoType::GoInt);
967 f.add_param("b", GoType::GoInt);
968 f.add_return(GoType::GoInt);
969 f.body = vec![GoStmt::Return(vec![GoExpr::BinOp(
970 op.to_string(),
971 Box::new(GoExpr::Var("a".to_string())),
972 Box::new(GoExpr::Var("b".to_string())),
973 )])];
974 f
975 }
976 pub(super) fn simple_cmp_func(&self, name: &str, op: &str) -> GoFunc {
978 let mut f = GoFunc::new(name);
979 f.add_param("a", GoType::GoInt);
980 f.add_param("b", GoType::GoInt);
981 f.add_return(GoType::GoBool);
982 f.body = vec![GoStmt::Return(vec![GoExpr::BinOp(
983 op.to_string(),
984 Box::new(GoExpr::Var("a".to_string())),
985 Box::new(GoExpr::Var("b".to_string())),
986 )])];
987 f
988 }
989 pub(super) fn simple_bool_func(&self, name: &str, op: &str) -> GoFunc {
991 let mut f = GoFunc::new(name);
992 f.add_param("a", GoType::GoBool);
993 f.add_param("b", GoType::GoBool);
994 f.add_return(GoType::GoBool);
995 f.body = vec![GoStmt::Return(vec![GoExpr::BinOp(
996 op.to_string(),
997 Box::new(GoExpr::Var("a".to_string())),
998 Box::new(GoExpr::Var("b".to_string())),
999 )])];
1000 f
1001 }
1002 pub fn emit_func(&self, func: &GoFunc) -> String {
1004 func.codegen()
1005 }
1006 pub fn emit_type_decl(&self, decl: &GoTypeDecl) -> String {
1008 decl.codegen()
1009 }
1010 pub fn emit_module(&self, module: &GoModule) -> String {
1012 module.codegen()
1013 }
1014}
1015#[derive(Debug, Clone, PartialEq)]
1017pub struct GoCase {
1018 pub pattern: Option<Vec<GoExpr>>,
1020 pub body: Vec<GoStmt>,
1021}
1022#[derive(Debug, Clone)]
1024pub struct GoTypeDecl {
1025 pub name: String,
1027 pub fields: Vec<(String, GoType)>,
1029 pub exported: bool,
1031}
1032impl GoTypeDecl {
1033 pub fn new(name: impl Into<String>) -> Self {
1035 GoTypeDecl {
1036 name: name.into(),
1037 fields: Vec::new(),
1038 exported: false,
1039 }
1040 }
1041 pub fn add_field(&mut self, name: impl Into<String>, ty: GoType) {
1043 self.fields.push((name.into(), ty));
1044 }
1045 pub fn codegen(&self) -> String {
1047 let mut out = format!("type {} struct {{\n", self.name);
1048 for (name, ty) in &self.fields {
1049 out.push_str(&format!(" {} {}\n", name, ty));
1050 }
1051 out.push('}');
1052 out
1053 }
1054}
1055#[allow(dead_code)]
1056#[derive(Debug, Clone, Default)]
1057pub struct GoPassStats {
1058 pub total_runs: u32,
1059 pub successful_runs: u32,
1060 pub total_changes: u64,
1061 pub time_ms: u64,
1062 pub iterations_used: u32,
1063}
1064impl GoPassStats {
1065 #[allow(dead_code)]
1066 pub fn new() -> Self {
1067 Self::default()
1068 }
1069 #[allow(dead_code)]
1070 pub fn record_run(&mut self, changes: u64, time_ms: u64, iterations: u32) {
1071 self.total_runs += 1;
1072 self.successful_runs += 1;
1073 self.total_changes += changes;
1074 self.time_ms += time_ms;
1075 self.iterations_used = iterations;
1076 }
1077 #[allow(dead_code)]
1078 pub fn average_changes_per_run(&self) -> f64 {
1079 if self.total_runs == 0 {
1080 return 0.0;
1081 }
1082 self.total_changes as f64 / self.total_runs as f64
1083 }
1084 #[allow(dead_code)]
1085 pub fn success_rate(&self) -> f64 {
1086 if self.total_runs == 0 {
1087 return 0.0;
1088 }
1089 self.successful_runs as f64 / self.total_runs as f64
1090 }
1091 #[allow(dead_code)]
1092 pub fn format_summary(&self) -> String {
1093 format!(
1094 "Runs: {}/{}, Changes: {}, Time: {}ms",
1095 self.successful_runs, self.total_runs, self.total_changes, self.time_ms
1096 )
1097 }
1098}
1099#[derive(Debug, Clone, PartialEq)]
1101pub enum GoLit {
1102 Int(i64),
1104 Float(f64),
1106 Bool(bool),
1108 Str(String),
1110 Nil,
1112}
1113#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1115pub enum GoType {
1116 GoBool,
1118 GoInt,
1120 GoFloat,
1122 GoString,
1124 GoSlice(Box<GoType>),
1126 GoMap(Box<GoType>, Box<GoType>),
1128 GoFunc(Vec<GoType>, Vec<GoType>),
1130 GoInterface,
1132 GoStruct(String),
1134 GoPtr(Box<GoType>),
1136 GoChan(Box<GoType>),
1138 GoError,
1140 GoUnit,
1142}
1143#[derive(Debug, Clone, PartialEq)]
1145pub enum GoStmt {
1146 Const(String, Option<GoType>, GoExpr),
1148 Var(String, GoType, Option<GoExpr>),
1150 ShortDecl(String, GoExpr),
1152 Assign(GoExpr, GoExpr),
1154 Return(Vec<GoExpr>),
1156 If(GoExpr, Vec<GoStmt>, Vec<GoStmt>),
1158 Switch(Option<GoExpr>, Vec<GoCase>),
1160 For(
1162 Option<Box<GoStmt>>,
1163 Option<GoExpr>,
1164 Option<Box<GoStmt>>,
1165 Vec<GoStmt>,
1166 ),
1167 ForRange(Option<String>, Option<String>, GoExpr, Vec<GoStmt>),
1169 Block(Vec<GoStmt>),
1171 Expr(GoExpr),
1173 Break,
1175 Continue,
1177 Goto(String),
1179 Label(String, Box<GoStmt>),
1181 Defer(GoExpr),
1183 GoRoutine(GoExpr),
1185 Panic(GoExpr),
1187}
1188#[allow(dead_code)]
1189#[derive(Debug, Clone, PartialEq)]
1190pub enum GoPassPhase {
1191 Analysis,
1192 Transformation,
1193 Verification,
1194 Cleanup,
1195}
1196impl GoPassPhase {
1197 #[allow(dead_code)]
1198 pub fn name(&self) -> &str {
1199 match self {
1200 GoPassPhase::Analysis => "analysis",
1201 GoPassPhase::Transformation => "transformation",
1202 GoPassPhase::Verification => "verification",
1203 GoPassPhase::Cleanup => "cleanup",
1204 }
1205 }
1206 #[allow(dead_code)]
1207 pub fn is_modifying(&self) -> bool {
1208 matches!(self, GoPassPhase::Transformation | GoPassPhase::Cleanup)
1209 }
1210}
1211#[allow(dead_code)]
1212pub struct GoPassRegistry {
1213 pub(super) configs: Vec<GoPassConfig>,
1214 pub(super) stats: std::collections::HashMap<String, GoPassStats>,
1215}
1216impl GoPassRegistry {
1217 #[allow(dead_code)]
1218 pub fn new() -> Self {
1219 GoPassRegistry {
1220 configs: Vec::new(),
1221 stats: std::collections::HashMap::new(),
1222 }
1223 }
1224 #[allow(dead_code)]
1225 pub fn register(&mut self, config: GoPassConfig) {
1226 self.stats
1227 .insert(config.pass_name.clone(), GoPassStats::new());
1228 self.configs.push(config);
1229 }
1230 #[allow(dead_code)]
1231 pub fn enabled_passes(&self) -> Vec<&GoPassConfig> {
1232 self.configs.iter().filter(|c| c.enabled).collect()
1233 }
1234 #[allow(dead_code)]
1235 pub fn get_stats(&self, name: &str) -> Option<&GoPassStats> {
1236 self.stats.get(name)
1237 }
1238 #[allow(dead_code)]
1239 pub fn total_passes(&self) -> usize {
1240 self.configs.len()
1241 }
1242 #[allow(dead_code)]
1243 pub fn enabled_count(&self) -> usize {
1244 self.enabled_passes().len()
1245 }
1246 #[allow(dead_code)]
1247 pub fn update_stats(&mut self, name: &str, changes: u64, time_ms: u64, iter: u32) {
1248 if let Some(stats) = self.stats.get_mut(name) {
1249 stats.record_run(changes, time_ms, iter);
1250 }
1251 }
1252}
1253#[allow(dead_code)]
1254#[derive(Debug, Clone)]
1255pub struct GoCacheEntry {
1256 pub key: String,
1257 pub data: Vec<u8>,
1258 pub timestamp: u64,
1259 pub valid: bool,
1260}
1261#[allow(dead_code)]
1262#[derive(Debug, Clone)]
1263pub struct GoLivenessInfo {
1264 pub live_in: Vec<std::collections::HashSet<u32>>,
1265 pub live_out: Vec<std::collections::HashSet<u32>>,
1266 pub defs: Vec<std::collections::HashSet<u32>>,
1267 pub uses: Vec<std::collections::HashSet<u32>>,
1268}
1269impl GoLivenessInfo {
1270 #[allow(dead_code)]
1271 pub fn new(block_count: usize) -> Self {
1272 GoLivenessInfo {
1273 live_in: vec![std::collections::HashSet::new(); block_count],
1274 live_out: vec![std::collections::HashSet::new(); block_count],
1275 defs: vec![std::collections::HashSet::new(); block_count],
1276 uses: vec![std::collections::HashSet::new(); block_count],
1277 }
1278 }
1279 #[allow(dead_code)]
1280 pub fn add_def(&mut self, block: usize, var: u32) {
1281 if block < self.defs.len() {
1282 self.defs[block].insert(var);
1283 }
1284 }
1285 #[allow(dead_code)]
1286 pub fn add_use(&mut self, block: usize, var: u32) {
1287 if block < self.uses.len() {
1288 self.uses[block].insert(var);
1289 }
1290 }
1291 #[allow(dead_code)]
1292 pub fn is_live_in(&self, block: usize, var: u32) -> bool {
1293 self.live_in
1294 .get(block)
1295 .map(|s| s.contains(&var))
1296 .unwrap_or(false)
1297 }
1298 #[allow(dead_code)]
1299 pub fn is_live_out(&self, block: usize, var: u32) -> bool {
1300 self.live_out
1301 .get(block)
1302 .map(|s| s.contains(&var))
1303 .unwrap_or(false)
1304 }
1305}