1use std::collections::{HashMap, HashSet, VecDeque};
6
7#[allow(dead_code)]
8#[derive(Debug, Clone, Default)]
9pub struct ZigPassStats {
10 pub total_runs: u32,
11 pub successful_runs: u32,
12 pub total_changes: u64,
13 pub time_ms: u64,
14 pub iterations_used: u32,
15}
16impl ZigPassStats {
17 #[allow(dead_code)]
18 pub fn new() -> Self {
19 Self::default()
20 }
21 #[allow(dead_code)]
22 pub fn record_run(&mut self, changes: u64, time_ms: u64, iterations: u32) {
23 self.total_runs += 1;
24 self.successful_runs += 1;
25 self.total_changes += changes;
26 self.time_ms += time_ms;
27 self.iterations_used = iterations;
28 }
29 #[allow(dead_code)]
30 pub fn average_changes_per_run(&self) -> f64 {
31 if self.total_runs == 0 {
32 return 0.0;
33 }
34 self.total_changes as f64 / self.total_runs as f64
35 }
36 #[allow(dead_code)]
37 pub fn success_rate(&self) -> f64 {
38 if self.total_runs == 0 {
39 return 0.0;
40 }
41 self.successful_runs as f64 / self.total_runs as f64
42 }
43 #[allow(dead_code)]
44 pub fn format_summary(&self) -> String {
45 format!(
46 "Runs: {}/{}, Changes: {}, Time: {}ms",
47 self.successful_runs, self.total_runs, self.total_changes, self.time_ms
48 )
49 }
50}
51#[allow(dead_code)]
53#[derive(Debug, Default)]
54pub struct ZigExtPassRegistry {
55 pub(super) configs: Vec<ZigExtPassConfig>,
56 pub(super) stats: Vec<ZigExtPassStats>,
57}
58impl ZigExtPassRegistry {
59 #[allow(dead_code)]
60 pub fn new() -> Self {
61 Self::default()
62 }
63 #[allow(dead_code)]
64 pub fn register(&mut self, c: ZigExtPassConfig) {
65 self.stats.push(ZigExtPassStats::new());
66 self.configs.push(c);
67 }
68 #[allow(dead_code)]
69 pub fn len(&self) -> usize {
70 self.configs.len()
71 }
72 #[allow(dead_code)]
73 pub fn is_empty(&self) -> bool {
74 self.configs.is_empty()
75 }
76 #[allow(dead_code)]
77 pub fn get(&self, i: usize) -> Option<&ZigExtPassConfig> {
78 self.configs.get(i)
79 }
80 #[allow(dead_code)]
81 pub fn get_stats(&self, i: usize) -> Option<&ZigExtPassStats> {
82 self.stats.get(i)
83 }
84 #[allow(dead_code)]
85 pub fn enabled_passes(&self) -> Vec<&ZigExtPassConfig> {
86 self.configs.iter().filter(|c| c.enabled).collect()
87 }
88 #[allow(dead_code)]
89 pub fn passes_in_phase(&self, ph: &ZigExtPassPhase) -> Vec<&ZigExtPassConfig> {
90 self.configs
91 .iter()
92 .filter(|c| c.enabled && &c.phase == ph)
93 .collect()
94 }
95 #[allow(dead_code)]
96 pub fn total_nodes_visited(&self) -> usize {
97 self.stats.iter().map(|s| s.nodes_visited).sum()
98 }
99 #[allow(dead_code)]
100 pub fn any_changed(&self) -> bool {
101 self.stats.iter().any(|s| s.changed)
102 }
103}
104#[allow(dead_code)]
105#[derive(Debug, Clone)]
106pub struct ZigErrorSet {
107 pub name: String,
108 pub errors: Vec<String>,
109}
110impl ZigErrorSet {
111 #[allow(dead_code)]
112 pub fn new(name: impl Into<String>) -> Self {
113 ZigErrorSet {
114 name: name.into(),
115 errors: Vec::new(),
116 }
117 }
118 #[allow(dead_code)]
119 pub fn add_error(&mut self, err: impl Into<String>) {
120 self.errors.push(err.into());
121 }
122 #[allow(dead_code)]
123 pub fn emit(&self) -> String {
124 format!(
125 "const {} = error{{ {} }};",
126 self.name,
127 self.errors.join(", ")
128 )
129 }
130}
131#[allow(dead_code)]
132#[derive(Debug, Clone)]
133pub struct ZigAsyncFn {
134 pub name: String,
135 pub params: Vec<(String, String)>,
136 pub return_type: String,
137 pub frame_size: Option<usize>,
138}
139impl ZigAsyncFn {
140 #[allow(dead_code)]
141 pub fn new(name: impl Into<String>) -> Self {
142 ZigAsyncFn {
143 name: name.into(),
144 params: Vec::new(),
145 return_type: "void".to_string(),
146 frame_size: None,
147 }
148 }
149 #[allow(dead_code)]
150 pub fn param(mut self, name: impl Into<String>, ty: impl Into<String>) -> Self {
151 self.params.push((name.into(), ty.into()));
152 self
153 }
154 #[allow(dead_code)]
155 pub fn emit(&self) -> String {
156 let params: Vec<String> = self
157 .params
158 .iter()
159 .map(|(n, t)| format!("{}: {}", n, t))
160 .collect();
161 format!(
162 "async fn {}({}) {} {{\n // async body\n}}",
163 self.name,
164 params.join(", "),
165 self.return_type
166 )
167 }
168 #[allow(dead_code)]
169 pub fn emit_await_call(&self, args: &[&str]) -> String {
170 format!("await async {}({})", self.name, args.join(", "))
171 }
172}
173#[allow(dead_code)]
175#[derive(Debug, Clone, PartialEq, Eq, Hash)]
176pub enum ZigExtPassPhase {
177 Early,
178 Middle,
179 Late,
180 Finalize,
181}
182impl ZigExtPassPhase {
183 #[allow(dead_code)]
184 pub fn is_early(&self) -> bool {
185 matches!(self, Self::Early)
186 }
187 #[allow(dead_code)]
188 pub fn is_middle(&self) -> bool {
189 matches!(self, Self::Middle)
190 }
191 #[allow(dead_code)]
192 pub fn is_late(&self) -> bool {
193 matches!(self, Self::Late)
194 }
195 #[allow(dead_code)]
196 pub fn is_finalize(&self) -> bool {
197 matches!(self, Self::Finalize)
198 }
199 #[allow(dead_code)]
200 pub fn order(&self) -> u32 {
201 match self {
202 Self::Early => 0,
203 Self::Middle => 1,
204 Self::Late => 2,
205 Self::Finalize => 3,
206 }
207 }
208 #[allow(dead_code)]
209 pub fn from_order(n: u32) -> Option<Self> {
210 match n {
211 0 => Some(Self::Early),
212 1 => Some(Self::Middle),
213 2 => Some(Self::Late),
214 3 => Some(Self::Finalize),
215 _ => None,
216 }
217 }
218}
219#[allow(dead_code)]
221#[derive(Debug, Clone)]
222pub struct ZigExtWorklist {
223 pub(super) items: std::collections::VecDeque<usize>,
224 pub(super) present: Vec<bool>,
225}
226impl ZigExtWorklist {
227 #[allow(dead_code)]
228 pub fn new(capacity: usize) -> Self {
229 Self {
230 items: std::collections::VecDeque::new(),
231 present: vec![false; capacity],
232 }
233 }
234 #[allow(dead_code)]
235 pub fn push(&mut self, id: usize) {
236 if id < self.present.len() && !self.present[id] {
237 self.present[id] = true;
238 self.items.push_back(id);
239 }
240 }
241 #[allow(dead_code)]
242 pub fn push_front(&mut self, id: usize) {
243 if id < self.present.len() && !self.present[id] {
244 self.present[id] = true;
245 self.items.push_front(id);
246 }
247 }
248 #[allow(dead_code)]
249 pub fn pop(&mut self) -> Option<usize> {
250 let id = self.items.pop_front()?;
251 if id < self.present.len() {
252 self.present[id] = false;
253 }
254 Some(id)
255 }
256 #[allow(dead_code)]
257 pub fn is_empty(&self) -> bool {
258 self.items.is_empty()
259 }
260 #[allow(dead_code)]
261 pub fn len(&self) -> usize {
262 self.items.len()
263 }
264 #[allow(dead_code)]
265 pub fn contains(&self, id: usize) -> bool {
266 id < self.present.len() && self.present[id]
267 }
268 #[allow(dead_code)]
269 pub fn drain_all(&mut self) -> Vec<usize> {
270 let v: Vec<usize> = self.items.drain(..).collect();
271 for &id in &v {
272 if id < self.present.len() {
273 self.present[id] = false;
274 }
275 }
276 v
277 }
278}
279#[allow(dead_code)]
280struct ZigStructField2 {
281 pub name: String,
282 pub ty_name: String,
283}
284#[allow(dead_code)]
285pub struct ZigBuildConfiguration {
286 pub target_os: String,
287 pub target_arch: String,
288 pub optimize_mode: ZigOptimizeMode,
289 pub root_source_file: String,
290 pub dependencies: Vec<String>,
291}
292impl ZigBuildConfiguration {
293 #[allow(dead_code)]
294 pub fn new(root: impl Into<String>) -> Self {
295 ZigBuildConfiguration {
296 target_os: "native".to_string(),
297 target_arch: "native".to_string(),
298 optimize_mode: ZigOptimizeMode::Debug,
299 root_source_file: root.into(),
300 dependencies: Vec::new(),
301 }
302 }
303 #[allow(dead_code)]
304 pub fn optimize(mut self, mode: ZigOptimizeMode) -> Self {
305 self.optimize_mode = mode;
306 self
307 }
308 #[allow(dead_code)]
309 pub fn dep(mut self, name: impl Into<String>) -> Self {
310 self.dependencies.push(name.into());
311 self
312 }
313 #[allow(dead_code)]
314 pub fn emit_build_zig(&self) -> String {
315 let mut out = String::from("const std = @import(\"std\");\n\n");
316 out.push_str("pub fn build(b: *std.Build) void {\n");
317 out.push_str(&format!(
318 " const target = b.standardTargetOptions(.{{}});\n"
319 ));
320 out.push_str(&format!(
321 " const optimize = b.standardOptimizeOption(.{{}});\n"
322 ));
323 out.push_str(
324 &format!(
325 " const exe = b.addExecutable(.{{\n .name = \"app\",\n .root_source_file = .{{ .path = \"{}\" }},\n .target = target,\n .optimize = optimize,\n }});\n",
326 self.root_source_file
327 ),
328 );
329 out.push_str(" b.installArtifact(exe);\n");
330 out.push('}');
331 out
332 }
333}
334pub struct ZigFn {
336 pub name: String,
337 pub params: Vec<(String, ZigType)>,
338 pub ret_ty: ZigType,
339 pub body: Vec<ZigStmt>,
340 pub is_pub: bool,
341 pub is_async: bool,
342}
343impl ZigFn {
344 pub fn new(name: &str, ret: ZigType) -> Self {
346 ZigFn {
347 name: name.to_string(),
348 params: Vec::new(),
349 ret_ty: ret,
350 body: Vec::new(),
351 is_pub: false,
352 is_async: false,
353 }
354 }
355 pub fn add_param(&mut self, name: &str, ty: ZigType) {
357 self.params.push((name.to_string(), ty));
358 }
359 pub fn add_stmt(&mut self, stmt: ZigStmt) {
361 self.body.push(stmt);
362 }
363 pub fn codegen(&self) -> String {
365 let pub_str = if self.is_pub { "pub " } else { "" };
366 let async_str = if self.is_async { "async " } else { "" };
367 let params_str: Vec<String> = self
368 .params
369 .iter()
370 .map(|(name, ty)| format!("{}: {}", name, ty.codegen()))
371 .collect();
372 let body_str: Vec<String> = self
373 .body
374 .iter()
375 .map(|s| format!(" {}", s.codegen()))
376 .collect();
377 format!(
378 "{}{}fn {}({}) {} {{\n{}\n}}",
379 pub_str,
380 async_str,
381 self.name,
382 params_str.join(", "),
383 self.ret_ty.codegen(),
384 body_str.join("\n")
385 )
386 }
387}
388#[allow(dead_code)]
389pub struct ZigConstantFoldingHelper;
390impl ZigConstantFoldingHelper {
391 #[allow(dead_code)]
392 pub fn fold_add_i64(a: i64, b: i64) -> Option<i64> {
393 a.checked_add(b)
394 }
395 #[allow(dead_code)]
396 pub fn fold_sub_i64(a: i64, b: i64) -> Option<i64> {
397 a.checked_sub(b)
398 }
399 #[allow(dead_code)]
400 pub fn fold_mul_i64(a: i64, b: i64) -> Option<i64> {
401 a.checked_mul(b)
402 }
403 #[allow(dead_code)]
404 pub fn fold_div_i64(a: i64, b: i64) -> Option<i64> {
405 if b == 0 {
406 None
407 } else {
408 a.checked_div(b)
409 }
410 }
411 #[allow(dead_code)]
412 pub fn fold_add_f64(a: f64, b: f64) -> f64 {
413 a + b
414 }
415 #[allow(dead_code)]
416 pub fn fold_mul_f64(a: f64, b: f64) -> f64 {
417 a * b
418 }
419 #[allow(dead_code)]
420 pub fn fold_neg_i64(a: i64) -> Option<i64> {
421 a.checked_neg()
422 }
423 #[allow(dead_code)]
424 pub fn fold_not_bool(a: bool) -> bool {
425 !a
426 }
427 #[allow(dead_code)]
428 pub fn fold_and_bool(a: bool, b: bool) -> bool {
429 a && b
430 }
431 #[allow(dead_code)]
432 pub fn fold_or_bool(a: bool, b: bool) -> bool {
433 a || b
434 }
435 #[allow(dead_code)]
436 pub fn fold_shl_i64(a: i64, b: u32) -> Option<i64> {
437 a.checked_shl(b)
438 }
439 #[allow(dead_code)]
440 pub fn fold_shr_i64(a: i64, b: u32) -> Option<i64> {
441 a.checked_shr(b)
442 }
443 #[allow(dead_code)]
444 pub fn fold_rem_i64(a: i64, b: i64) -> Option<i64> {
445 if b == 0 {
446 None
447 } else {
448 Some(a % b)
449 }
450 }
451 #[allow(dead_code)]
452 pub fn fold_bitand_i64(a: i64, b: i64) -> i64 {
453 a & b
454 }
455 #[allow(dead_code)]
456 pub fn fold_bitor_i64(a: i64, b: i64) -> i64 {
457 a | b
458 }
459 #[allow(dead_code)]
460 pub fn fold_bitxor_i64(a: i64, b: i64) -> i64 {
461 a ^ b
462 }
463 #[allow(dead_code)]
464 pub fn fold_bitnot_i64(a: i64) -> i64 {
465 !a
466 }
467}
468#[allow(dead_code)]
470#[derive(Debug)]
471pub struct ZigExtCache {
472 pub(super) entries: Vec<(u64, Vec<u8>, bool, u32)>,
473 pub(super) cap: usize,
474 pub(super) total_hits: u64,
475 pub(super) total_misses: u64,
476}
477impl ZigExtCache {
478 #[allow(dead_code)]
479 pub fn new(cap: usize) -> Self {
480 Self {
481 entries: Vec::new(),
482 cap,
483 total_hits: 0,
484 total_misses: 0,
485 }
486 }
487 #[allow(dead_code)]
488 pub fn get(&mut self, key: u64) -> Option<&[u8]> {
489 for e in self.entries.iter_mut() {
490 if e.0 == key && e.2 {
491 e.3 += 1;
492 self.total_hits += 1;
493 return Some(&e.1);
494 }
495 }
496 self.total_misses += 1;
497 None
498 }
499 #[allow(dead_code)]
500 pub fn put(&mut self, key: u64, data: Vec<u8>) {
501 if self.entries.len() >= self.cap {
502 self.entries.retain(|e| e.2);
503 if self.entries.len() >= self.cap {
504 self.entries.remove(0);
505 }
506 }
507 self.entries.push((key, data, true, 0));
508 }
509 #[allow(dead_code)]
510 pub fn invalidate(&mut self) {
511 for e in self.entries.iter_mut() {
512 e.2 = false;
513 }
514 }
515 #[allow(dead_code)]
516 pub fn hit_rate(&self) -> f64 {
517 let t = self.total_hits + self.total_misses;
518 if t == 0 {
519 0.0
520 } else {
521 self.total_hits as f64 / t as f64
522 }
523 }
524 #[allow(dead_code)]
525 pub fn live_count(&self) -> usize {
526 self.entries.iter().filter(|e| e.2).count()
527 }
528}
529#[allow(dead_code)]
530#[derive(Debug, Clone)]
531pub struct ZigWorklist {
532 pub(super) items: std::collections::VecDeque<u32>,
533 pub(super) in_worklist: std::collections::HashSet<u32>,
534}
535impl ZigWorklist {
536 #[allow(dead_code)]
537 pub fn new() -> Self {
538 ZigWorklist {
539 items: std::collections::VecDeque::new(),
540 in_worklist: std::collections::HashSet::new(),
541 }
542 }
543 #[allow(dead_code)]
544 pub fn push(&mut self, item: u32) -> bool {
545 if self.in_worklist.insert(item) {
546 self.items.push_back(item);
547 true
548 } else {
549 false
550 }
551 }
552 #[allow(dead_code)]
553 pub fn pop(&mut self) -> Option<u32> {
554 let item = self.items.pop_front()?;
555 self.in_worklist.remove(&item);
556 Some(item)
557 }
558 #[allow(dead_code)]
559 pub fn is_empty(&self) -> bool {
560 self.items.is_empty()
561 }
562 #[allow(dead_code)]
563 pub fn len(&self) -> usize {
564 self.items.len()
565 }
566 #[allow(dead_code)]
567 pub fn contains(&self, item: u32) -> bool {
568 self.in_worklist.contains(&item)
569 }
570}
571#[allow(dead_code)]
572#[derive(Debug, Clone)]
573pub struct ZigPassConfig {
574 pub phase: ZigPassPhase,
575 pub enabled: bool,
576 pub max_iterations: u32,
577 pub debug_output: bool,
578 pub pass_name: String,
579}
580impl ZigPassConfig {
581 #[allow(dead_code)]
582 pub fn new(name: impl Into<String>, phase: ZigPassPhase) -> Self {
583 ZigPassConfig {
584 phase,
585 enabled: true,
586 max_iterations: 10,
587 debug_output: false,
588 pass_name: name.into(),
589 }
590 }
591 #[allow(dead_code)]
592 pub fn disabled(mut self) -> Self {
593 self.enabled = false;
594 self
595 }
596 #[allow(dead_code)]
597 pub fn with_debug(mut self) -> Self {
598 self.debug_output = true;
599 self
600 }
601 #[allow(dead_code)]
602 pub fn max_iter(mut self, n: u32) -> Self {
603 self.max_iterations = n;
604 self
605 }
606}
607#[allow(dead_code)]
609#[derive(Debug, Clone)]
610pub struct ZigExtDepGraph {
611 pub(super) n: usize,
612 pub(super) adj: Vec<Vec<usize>>,
613 pub(super) rev: Vec<Vec<usize>>,
614 pub(super) edge_count: usize,
615}
616impl ZigExtDepGraph {
617 #[allow(dead_code)]
618 pub fn new(n: usize) -> Self {
619 Self {
620 n,
621 adj: vec![Vec::new(); n],
622 rev: vec![Vec::new(); n],
623 edge_count: 0,
624 }
625 }
626 #[allow(dead_code)]
627 pub fn add_edge(&mut self, from: usize, to: usize) {
628 if from < self.n && to < self.n {
629 if !self.adj[from].contains(&to) {
630 self.adj[from].push(to);
631 self.rev[to].push(from);
632 self.edge_count += 1;
633 }
634 }
635 }
636 #[allow(dead_code)]
637 pub fn succs(&self, n: usize) -> &[usize] {
638 self.adj.get(n).map(|v| v.as_slice()).unwrap_or(&[])
639 }
640 #[allow(dead_code)]
641 pub fn preds(&self, n: usize) -> &[usize] {
642 self.rev.get(n).map(|v| v.as_slice()).unwrap_or(&[])
643 }
644 #[allow(dead_code)]
645 pub fn topo_sort(&self) -> Option<Vec<usize>> {
646 let mut deg: Vec<usize> = (0..self.n).map(|i| self.rev[i].len()).collect();
647 let mut q: std::collections::VecDeque<usize> =
648 (0..self.n).filter(|&i| deg[i] == 0).collect();
649 let mut out = Vec::with_capacity(self.n);
650 while let Some(u) = q.pop_front() {
651 out.push(u);
652 for &v in &self.adj[u] {
653 deg[v] -= 1;
654 if deg[v] == 0 {
655 q.push_back(v);
656 }
657 }
658 }
659 if out.len() == self.n {
660 Some(out)
661 } else {
662 None
663 }
664 }
665 #[allow(dead_code)]
666 pub fn has_cycle(&self) -> bool {
667 self.topo_sort().is_none()
668 }
669 #[allow(dead_code)]
670 pub fn reachable(&self, start: usize) -> Vec<usize> {
671 let mut vis = vec![false; self.n];
672 let mut stk = vec![start];
673 let mut out = Vec::new();
674 while let Some(u) = stk.pop() {
675 if u < self.n && !vis[u] {
676 vis[u] = true;
677 out.push(u);
678 for &v in &self.adj[u] {
679 if !vis[v] {
680 stk.push(v);
681 }
682 }
683 }
684 }
685 out
686 }
687 #[allow(dead_code)]
688 pub fn scc(&self) -> Vec<Vec<usize>> {
689 let mut visited = vec![false; self.n];
690 let mut order = Vec::new();
691 for i in 0..self.n {
692 if !visited[i] {
693 let mut stk = vec![(i, 0usize)];
694 while let Some((u, idx)) = stk.last_mut() {
695 if !visited[*u] {
696 visited[*u] = true;
697 }
698 if *idx < self.adj[*u].len() {
699 let v = self.adj[*u][*idx];
700 *idx += 1;
701 if !visited[v] {
702 stk.push((v, 0));
703 }
704 } else {
705 order.push(*u);
706 stk.pop();
707 }
708 }
709 }
710 }
711 let mut comp = vec![usize::MAX; self.n];
712 let mut components: Vec<Vec<usize>> = Vec::new();
713 for &start in order.iter().rev() {
714 if comp[start] == usize::MAX {
715 let cid = components.len();
716 let mut component = Vec::new();
717 let mut stk = vec![start];
718 while let Some(u) = stk.pop() {
719 if comp[u] == usize::MAX {
720 comp[u] = cid;
721 component.push(u);
722 for &v in &self.rev[u] {
723 if comp[v] == usize::MAX {
724 stk.push(v);
725 }
726 }
727 }
728 }
729 components.push(component);
730 }
731 }
732 components
733 }
734 #[allow(dead_code)]
735 pub fn node_count(&self) -> usize {
736 self.n
737 }
738 #[allow(dead_code)]
739 pub fn edge_count(&self) -> usize {
740 self.edge_count
741 }
742}
743#[derive(Debug, Clone, PartialEq)]
745pub enum ZigStmt {
746 VarDecl {
747 name: String,
748 ty: Option<ZigType>,
749 value: ZigExpr,
750 },
751 ConstDecl {
752 name: String,
753 ty: Option<ZigType>,
754 value: ZigExpr,
755 },
756 Assign {
757 target: ZigExpr,
758 value: ZigExpr,
759 },
760 Return(Option<ZigExpr>),
761 Expr(ZigExpr),
762 If {
763 cond: ZigExpr,
764 body: Vec<ZigStmt>,
765 else_: Vec<ZigStmt>,
766 },
767 While {
768 cond: ZigExpr,
769 body: Vec<ZigStmt>,
770 },
771 Defer(ZigExpr),
772}
773impl ZigStmt {
774 pub fn codegen(&self) -> String {
776 match self {
777 ZigStmt::VarDecl { name, ty, value } => {
778 let ty_str = ty
779 .as_ref()
780 .map(|t| format!(": {}", t.codegen()))
781 .unwrap_or_default();
782 format!("var {}{} = {};", name, ty_str, value.codegen())
783 }
784 ZigStmt::ConstDecl { name, ty, value } => {
785 let ty_str = ty
786 .as_ref()
787 .map(|t| format!(": {}", t.codegen()))
788 .unwrap_or_default();
789 format!("const {}{} = {};", name, ty_str, value.codegen())
790 }
791 ZigStmt::Assign { target, value } => {
792 format!("{} = {};", target.codegen(), value.codegen())
793 }
794 ZigStmt::Return(None) => "return;".to_string(),
795 ZigStmt::Return(Some(expr)) => format!("return {};", expr.codegen()),
796 ZigStmt::Expr(expr) => format!("{};", expr.codegen()),
797 ZigStmt::If { cond, body, else_ } => {
798 let body_str: Vec<String> = body
799 .iter()
800 .map(|s| format!(" {}", s.codegen()))
801 .collect();
802 let else_str = if else_.is_empty() {
803 String::new()
804 } else {
805 let else_body: Vec<String> = else_
806 .iter()
807 .map(|s| format!(" {}", s.codegen()))
808 .collect();
809 format!(" else {{\n{}\n}}", else_body.join("\n"))
810 };
811 format!(
812 "if ({}) {{\n{}\n}}{}",
813 cond.codegen(),
814 body_str.join("\n"),
815 else_str
816 )
817 }
818 ZigStmt::While { cond, body } => {
819 let body_str: Vec<String> = body
820 .iter()
821 .map(|s| format!(" {}", s.codegen()))
822 .collect();
823 format!("while ({}) {{\n{}\n}}", cond.codegen(), body_str.join("\n"))
824 }
825 ZigStmt::Defer(expr) => format!("defer {};", expr.codegen()),
826 }
827 }
828}
829#[allow(dead_code)]
831#[derive(Debug, Clone, Default)]
832pub struct ZigExtConstFolder {
833 pub(super) folds: usize,
834 pub(super) failures: usize,
835 pub(super) enabled: bool,
836}
837impl ZigExtConstFolder {
838 #[allow(dead_code)]
839 pub fn new() -> Self {
840 Self {
841 folds: 0,
842 failures: 0,
843 enabled: true,
844 }
845 }
846 #[allow(dead_code)]
847 pub fn add_i64(&mut self, a: i64, b: i64) -> Option<i64> {
848 self.folds += 1;
849 a.checked_add(b)
850 }
851 #[allow(dead_code)]
852 pub fn sub_i64(&mut self, a: i64, b: i64) -> Option<i64> {
853 self.folds += 1;
854 a.checked_sub(b)
855 }
856 #[allow(dead_code)]
857 pub fn mul_i64(&mut self, a: i64, b: i64) -> Option<i64> {
858 self.folds += 1;
859 a.checked_mul(b)
860 }
861 #[allow(dead_code)]
862 pub fn div_i64(&mut self, a: i64, b: i64) -> Option<i64> {
863 if b == 0 {
864 self.failures += 1;
865 None
866 } else {
867 self.folds += 1;
868 a.checked_div(b)
869 }
870 }
871 #[allow(dead_code)]
872 pub fn rem_i64(&mut self, a: i64, b: i64) -> Option<i64> {
873 if b == 0 {
874 self.failures += 1;
875 None
876 } else {
877 self.folds += 1;
878 a.checked_rem(b)
879 }
880 }
881 #[allow(dead_code)]
882 pub fn neg_i64(&mut self, a: i64) -> Option<i64> {
883 self.folds += 1;
884 a.checked_neg()
885 }
886 #[allow(dead_code)]
887 pub fn shl_i64(&mut self, a: i64, s: u32) -> Option<i64> {
888 if s >= 64 {
889 self.failures += 1;
890 None
891 } else {
892 self.folds += 1;
893 a.checked_shl(s)
894 }
895 }
896 #[allow(dead_code)]
897 pub fn shr_i64(&mut self, a: i64, s: u32) -> Option<i64> {
898 if s >= 64 {
899 self.failures += 1;
900 None
901 } else {
902 self.folds += 1;
903 a.checked_shr(s)
904 }
905 }
906 #[allow(dead_code)]
907 pub fn and_i64(&mut self, a: i64, b: i64) -> i64 {
908 self.folds += 1;
909 a & b
910 }
911 #[allow(dead_code)]
912 pub fn or_i64(&mut self, a: i64, b: i64) -> i64 {
913 self.folds += 1;
914 a | b
915 }
916 #[allow(dead_code)]
917 pub fn xor_i64(&mut self, a: i64, b: i64) -> i64 {
918 self.folds += 1;
919 a ^ b
920 }
921 #[allow(dead_code)]
922 pub fn not_i64(&mut self, a: i64) -> i64 {
923 self.folds += 1;
924 !a
925 }
926 #[allow(dead_code)]
927 pub fn fold_count(&self) -> usize {
928 self.folds
929 }
930 #[allow(dead_code)]
931 pub fn failure_count(&self) -> usize {
932 self.failures
933 }
934 #[allow(dead_code)]
935 pub fn enable(&mut self) {
936 self.enabled = true;
937 }
938 #[allow(dead_code)]
939 pub fn disable(&mut self) {
940 self.enabled = false;
941 }
942 #[allow(dead_code)]
943 pub fn is_enabled(&self) -> bool {
944 self.enabled
945 }
946}
947#[allow(dead_code)]
948#[derive(Debug, Clone)]
949pub struct ZigLivenessInfo {
950 pub live_in: Vec<std::collections::HashSet<u32>>,
951 pub live_out: Vec<std::collections::HashSet<u32>>,
952 pub defs: Vec<std::collections::HashSet<u32>>,
953 pub uses: Vec<std::collections::HashSet<u32>>,
954}
955impl ZigLivenessInfo {
956 #[allow(dead_code)]
957 pub fn new(block_count: usize) -> Self {
958 ZigLivenessInfo {
959 live_in: vec![std::collections::HashSet::new(); block_count],
960 live_out: vec![std::collections::HashSet::new(); block_count],
961 defs: vec![std::collections::HashSet::new(); block_count],
962 uses: vec![std::collections::HashSet::new(); block_count],
963 }
964 }
965 #[allow(dead_code)]
966 pub fn add_def(&mut self, block: usize, var: u32) {
967 if block < self.defs.len() {
968 self.defs[block].insert(var);
969 }
970 }
971 #[allow(dead_code)]
972 pub fn add_use(&mut self, block: usize, var: u32) {
973 if block < self.uses.len() {
974 self.uses[block].insert(var);
975 }
976 }
977 #[allow(dead_code)]
978 pub fn is_live_in(&self, block: usize, var: u32) -> bool {
979 self.live_in
980 .get(block)
981 .map(|s| s.contains(&var))
982 .unwrap_or(false)
983 }
984 #[allow(dead_code)]
985 pub fn is_live_out(&self, block: usize, var: u32) -> bool {
986 self.live_out
987 .get(block)
988 .map(|s| s.contains(&var))
989 .unwrap_or(false)
990 }
991}
992#[allow(dead_code)]
993pub struct ZigFile {
994 pub imports: Vec<ZigImport>,
995 pub structs: Vec<ZigStruct>,
996 pub functions: Vec<ZigFn>,
997 pub tests: Vec<ZigTestBlock>,
998}
999impl ZigFile {
1000 #[allow(dead_code)]
1001 pub fn new() -> Self {
1002 ZigFile {
1003 imports: Vec::new(),
1004 structs: Vec::new(),
1005 functions: Vec::new(),
1006 tests: Vec::new(),
1007 }
1008 }
1009 #[allow(dead_code)]
1010 pub fn import(mut self, imp: ZigImport) -> Self {
1011 self.imports.push(imp);
1012 self
1013 }
1014 #[allow(dead_code)]
1015 pub fn add_struct(mut self, s: ZigStruct) -> Self {
1016 self.structs.push(s);
1017 self
1018 }
1019 #[allow(dead_code)]
1020 pub fn add_fn(mut self, f: ZigFn) -> Self {
1021 self.functions.push(f);
1022 self
1023 }
1024 #[allow(dead_code)]
1025 pub fn add_test(mut self, t: ZigTestBlock) -> Self {
1026 self.tests.push(t);
1027 self
1028 }
1029 #[allow(dead_code)]
1030 pub fn emit(&self) -> String {
1031 let mut parts = Vec::new();
1032 for imp in &self.imports {
1033 parts.push(imp.emit());
1034 }
1035 for s in &self.structs {
1036 let mut out = format!("const {} = struct {{\n", s.name);
1037 for f in &s.fields {
1038 out.push_str(&format!(" {}: {},\n", f.0, f.1.codegen()));
1039 }
1040 out.push_str("};");
1041 parts.push(out);
1042 }
1043 for t in &self.tests {
1044 parts.push(t.emit());
1045 }
1046 parts.join("\n\n")
1047 }
1048}
1049#[allow(dead_code)]
1050pub struct ZigSliceOps;
1051impl ZigSliceOps {
1052 #[allow(dead_code)]
1053 pub fn len_expr(slice: &str) -> String {
1054 format!("{}.len", slice)
1055 }
1056 #[allow(dead_code)]
1057 pub fn ptr_expr(slice: &str) -> String {
1058 format!("{}.ptr", slice)
1059 }
1060 #[allow(dead_code)]
1061 pub fn index_expr(slice: &str, idx: &str) -> String {
1062 format!("{}[{}]", slice, idx)
1063 }
1064 #[allow(dead_code)]
1065 pub fn slice_expr(slice: &str, start: &str, end: &str) -> String {
1066 format!("{}[{}..{}]", slice, start, end)
1067 }
1068 #[allow(dead_code)]
1069 pub fn concat_alloc(alloc: &str, a: &str, b: &str) -> String {
1070 format!("try std.mem.concat({}, u8, &.{{ {}, {} }})", alloc, a, b)
1071 }
1072 #[allow(dead_code)]
1073 pub fn copy(dst: &str, src: &str) -> String {
1074 format!("std.mem.copy(u8, {}, {})", dst, src)
1075 }
1076 #[allow(dead_code)]
1077 pub fn eql(a: &str, b: &str) -> String {
1078 format!("std.mem.eql(u8, {}, {})", a, b)
1079 }
1080}
1081#[allow(dead_code)]
1082#[derive(Debug, Clone)]
1083pub struct ZigPackedStruct {
1084 pub name: String,
1085 pub fields: Vec<ZigPackedField>,
1086}
1087impl ZigPackedStruct {
1088 #[allow(dead_code)]
1089 pub fn new(name: impl Into<String>) -> Self {
1090 ZigPackedStruct {
1091 name: name.into(),
1092 fields: Vec::new(),
1093 }
1094 }
1095 #[allow(dead_code)]
1096 pub fn add_field(&mut self, name: impl Into<String>, ty: ZigType, bits: Option<u32>) {
1097 self.fields.push(ZigPackedField {
1098 name: name.into(),
1099 ty,
1100 bit_width: bits,
1101 });
1102 }
1103 #[allow(dead_code)]
1104 pub fn emit(&self) -> String {
1105 let mut out = format!("const {} = packed struct {{\n", self.name);
1106 for f in &self.fields {
1107 match f.bit_width {
1108 Some(bits) => out.push_str(&format!(" {}: u{},\n", f.name, bits)),
1109 None => out.push_str(&format!(" {}: {},\n", f.name, "type")),
1110 }
1111 }
1112 out.push_str("};");
1113 out
1114 }
1115 #[allow(dead_code)]
1116 pub fn total_bits(&self) -> u32 {
1117 self.fields.iter().map(|f| f.bit_width.unwrap_or(8)).sum()
1118 }
1119}
1120#[allow(dead_code)]
1122#[derive(Debug, Clone)]
1123pub struct ZigExtDomTree {
1124 pub(super) idom: Vec<Option<usize>>,
1125 pub(super) children: Vec<Vec<usize>>,
1126 pub(super) depth: Vec<usize>,
1127}
1128impl ZigExtDomTree {
1129 #[allow(dead_code)]
1130 pub fn new(n: usize) -> Self {
1131 Self {
1132 idom: vec![None; n],
1133 children: vec![Vec::new(); n],
1134 depth: vec![0; n],
1135 }
1136 }
1137 #[allow(dead_code)]
1138 pub fn set_idom(&mut self, node: usize, dom: usize) {
1139 if node < self.idom.len() {
1140 self.idom[node] = Some(dom);
1141 if dom < self.children.len() {
1142 self.children[dom].push(node);
1143 }
1144 self.depth[node] = if dom < self.depth.len() {
1145 self.depth[dom] + 1
1146 } else {
1147 1
1148 };
1149 }
1150 }
1151 #[allow(dead_code)]
1152 pub fn dominates(&self, a: usize, mut b: usize) -> bool {
1153 if a == b {
1154 return true;
1155 }
1156 let n = self.idom.len();
1157 for _ in 0..n {
1158 match self.idom.get(b).copied().flatten() {
1159 None => return false,
1160 Some(p) if p == a => return true,
1161 Some(p) if p == b => return false,
1162 Some(p) => b = p,
1163 }
1164 }
1165 false
1166 }
1167 #[allow(dead_code)]
1168 pub fn children_of(&self, n: usize) -> &[usize] {
1169 self.children.get(n).map(|v| v.as_slice()).unwrap_or(&[])
1170 }
1171 #[allow(dead_code)]
1172 pub fn depth_of(&self, n: usize) -> usize {
1173 self.depth.get(n).copied().unwrap_or(0)
1174 }
1175 #[allow(dead_code)]
1176 pub fn lca(&self, mut a: usize, mut b: usize) -> usize {
1177 let n = self.idom.len();
1178 for _ in 0..(2 * n) {
1179 if a == b {
1180 return a;
1181 }
1182 if self.depth_of(a) > self.depth_of(b) {
1183 a = self.idom.get(a).and_then(|x| *x).unwrap_or(a);
1184 } else {
1185 b = self.idom.get(b).and_then(|x| *x).unwrap_or(b);
1186 }
1187 }
1188 0
1189 }
1190}
1191#[allow(dead_code)]
1192#[derive(Debug, Clone)]
1193pub struct ZigCacheEntry {
1194 pub key: String,
1195 pub data: Vec<u8>,
1196 pub timestamp: u64,
1197 pub valid: bool,
1198}
1199pub struct ZigModule {
1201 pub name: String,
1202 pub imports: Vec<String>,
1203 pub structs: Vec<ZigStruct>,
1204 pub fns: Vec<ZigFn>,
1205 pub consts: Vec<(String, ZigType, ZigExpr)>,
1206}
1207impl ZigModule {
1208 pub fn new(name: &str) -> Self {
1210 ZigModule {
1211 name: name.to_string(),
1212 imports: Vec::new(),
1213 structs: Vec::new(),
1214 fns: Vec::new(),
1215 consts: Vec::new(),
1216 }
1217 }
1218 pub fn add_import(&mut self, path: &str) {
1220 self.imports.push(path.to_string());
1221 }
1222 pub fn add_struct(&mut self, s: ZigStruct) {
1224 self.structs.push(s);
1225 }
1226 pub fn add_fn(&mut self, f: ZigFn) {
1228 self.fns.push(f);
1229 }
1230 pub fn codegen(&self) -> String {
1232 let mut parts: Vec<String> = Vec::new();
1233 for (i, path) in self.imports.iter().enumerate() {
1234 let binding = format!("_import_{}", i);
1235 parts.push(format!("const {} = @import(\"{}\");", binding, path));
1236 }
1237 for (name, ty, expr) in &self.consts {
1238 parts.push(format!(
1239 "const {}: {} = {};",
1240 name,
1241 ty.codegen(),
1242 expr.codegen()
1243 ));
1244 }
1245 for s in &self.structs {
1246 parts.push(s.codegen());
1247 }
1248 for f in &self.fns {
1249 parts.push(f.codegen());
1250 }
1251 parts.join("\n\n")
1252 }
1253}
1254#[allow(dead_code)]
1255#[derive(Debug, Clone)]
1256pub struct ZigPackedField {
1257 pub name: String,
1258 pub ty: ZigType,
1259 pub bit_width: Option<u32>,
1260}
1261#[allow(dead_code)]
1262#[derive(Debug, Clone)]
1263pub enum ZigAllocatorKind {
1264 GeneralPurpose,
1265 Arena,
1266 Page,
1267 FixedBuffer(usize),
1268 C,
1269 LogToFile,
1270}
1271impl ZigAllocatorKind {
1272 #[allow(dead_code)]
1273 pub fn type_name(&self) -> &str {
1274 match self {
1275 ZigAllocatorKind::GeneralPurpose => "std.heap.GeneralPurposeAllocator(.{})",
1276 ZigAllocatorKind::Arena => "std.heap.ArenaAllocator",
1277 ZigAllocatorKind::Page => "std.heap.page_allocator",
1278 ZigAllocatorKind::FixedBuffer(_) => "std.heap.FixedBufferAllocator",
1279 ZigAllocatorKind::C => "std.heap.c_allocator",
1280 ZigAllocatorKind::LogToFile => "std.heap.LoggingAllocator",
1281 }
1282 }
1283}
1284#[allow(dead_code)]
1285#[derive(Debug, Clone, PartialEq)]
1286pub enum ZigPassPhase {
1287 Analysis,
1288 Transformation,
1289 Verification,
1290 Cleanup,
1291}
1292impl ZigPassPhase {
1293 #[allow(dead_code)]
1294 pub fn name(&self) -> &str {
1295 match self {
1296 ZigPassPhase::Analysis => "analysis",
1297 ZigPassPhase::Transformation => "transformation",
1298 ZigPassPhase::Verification => "verification",
1299 ZigPassPhase::Cleanup => "cleanup",
1300 }
1301 }
1302 #[allow(dead_code)]
1303 pub fn is_modifying(&self) -> bool {
1304 matches!(self, ZigPassPhase::Transformation | ZigPassPhase::Cleanup)
1305 }
1306}
1307#[allow(dead_code)]
1308#[derive(Debug, Clone)]
1309pub struct ZigDepGraph {
1310 pub(super) nodes: Vec<u32>,
1311 pub(super) edges: Vec<(u32, u32)>,
1312}
1313impl ZigDepGraph {
1314 #[allow(dead_code)]
1315 pub fn new() -> Self {
1316 ZigDepGraph {
1317 nodes: Vec::new(),
1318 edges: Vec::new(),
1319 }
1320 }
1321 #[allow(dead_code)]
1322 pub fn add_node(&mut self, id: u32) {
1323 if !self.nodes.contains(&id) {
1324 self.nodes.push(id);
1325 }
1326 }
1327 #[allow(dead_code)]
1328 pub fn add_dep(&mut self, dep: u32, dependent: u32) {
1329 self.add_node(dep);
1330 self.add_node(dependent);
1331 self.edges.push((dep, dependent));
1332 }
1333 #[allow(dead_code)]
1334 pub fn dependents_of(&self, node: u32) -> Vec<u32> {
1335 self.edges
1336 .iter()
1337 .filter(|(d, _)| *d == node)
1338 .map(|(_, dep)| *dep)
1339 .collect()
1340 }
1341 #[allow(dead_code)]
1342 pub fn dependencies_of(&self, node: u32) -> Vec<u32> {
1343 self.edges
1344 .iter()
1345 .filter(|(_, dep)| *dep == node)
1346 .map(|(d, _)| *d)
1347 .collect()
1348 }
1349 #[allow(dead_code)]
1350 pub fn topological_sort(&self) -> Vec<u32> {
1351 let mut in_degree: std::collections::HashMap<u32, u32> = std::collections::HashMap::new();
1352 for &n in &self.nodes {
1353 in_degree.insert(n, 0);
1354 }
1355 for (_, dep) in &self.edges {
1356 *in_degree.entry(*dep).or_insert(0) += 1;
1357 }
1358 let mut queue: std::collections::VecDeque<u32> = self
1359 .nodes
1360 .iter()
1361 .filter(|&&n| in_degree[&n] == 0)
1362 .copied()
1363 .collect();
1364 let mut result = Vec::new();
1365 while let Some(node) = queue.pop_front() {
1366 result.push(node);
1367 for dep in self.dependents_of(node) {
1368 let cnt = in_degree.entry(dep).or_insert(0);
1369 *cnt = cnt.saturating_sub(1);
1370 if *cnt == 0 {
1371 queue.push_back(dep);
1372 }
1373 }
1374 }
1375 result
1376 }
1377 #[allow(dead_code)]
1378 pub fn has_cycle(&self) -> bool {
1379 self.topological_sort().len() < self.nodes.len()
1380 }
1381}
1382#[allow(dead_code)]
1384#[derive(Debug, Clone, Default)]
1385pub struct ZigExtPassStats {
1386 pub iterations: usize,
1387 pub changed: bool,
1388 pub nodes_visited: usize,
1389 pub nodes_modified: usize,
1390 pub time_ms: u64,
1391 pub memory_bytes: usize,
1392 pub errors: usize,
1393}
1394impl ZigExtPassStats {
1395 #[allow(dead_code)]
1396 pub fn new() -> Self {
1397 Self::default()
1398 }
1399 #[allow(dead_code)]
1400 pub fn visit(&mut self) {
1401 self.nodes_visited += 1;
1402 }
1403 #[allow(dead_code)]
1404 pub fn modify(&mut self) {
1405 self.nodes_modified += 1;
1406 self.changed = true;
1407 }
1408 #[allow(dead_code)]
1409 pub fn iterate(&mut self) {
1410 self.iterations += 1;
1411 }
1412 #[allow(dead_code)]
1413 pub fn error(&mut self) {
1414 self.errors += 1;
1415 }
1416 #[allow(dead_code)]
1417 pub fn efficiency(&self) -> f64 {
1418 if self.nodes_visited == 0 {
1419 0.0
1420 } else {
1421 self.nodes_modified as f64 / self.nodes_visited as f64
1422 }
1423 }
1424 #[allow(dead_code)]
1425 pub fn merge(&mut self, o: &ZigExtPassStats) {
1426 self.iterations += o.iterations;
1427 self.changed |= o.changed;
1428 self.nodes_visited += o.nodes_visited;
1429 self.nodes_modified += o.nodes_modified;
1430 self.time_ms += o.time_ms;
1431 self.memory_bytes = self.memory_bytes.max(o.memory_bytes);
1432 self.errors += o.errors;
1433 }
1434}
1435pub struct ZigStruct {
1437 pub name: String,
1438 pub fields: Vec<(String, ZigType)>,
1439 pub is_pub: bool,
1440}
1441impl ZigStruct {
1442 pub fn new(name: &str) -> Self {
1444 ZigStruct {
1445 name: name.to_string(),
1446 fields: Vec::new(),
1447 is_pub: false,
1448 }
1449 }
1450 pub fn add_field(&mut self, name: &str, ty: ZigType) {
1452 self.fields.push((name.to_string(), ty));
1453 }
1454 pub fn codegen(&self) -> String {
1456 let pub_str = if self.is_pub { "pub " } else { "" };
1457 let fields_str: Vec<String> = self
1458 .fields
1459 .iter()
1460 .map(|(name, ty)| format!(" {}: {},", name, ty.codegen()))
1461 .collect();
1462 format!(
1463 "{}const {} = struct {{\n{}\n}};",
1464 pub_str,
1465 self.name,
1466 fields_str.join("\n")
1467 )
1468 }
1469}
1470#[allow(dead_code)]
1472#[derive(Debug, Clone, Default)]
1473pub struct ZigExtLiveness {
1474 pub live_in: Vec<Vec<usize>>,
1475 pub live_out: Vec<Vec<usize>>,
1476 pub defs: Vec<Vec<usize>>,
1477 pub uses: Vec<Vec<usize>>,
1478}
1479impl ZigExtLiveness {
1480 #[allow(dead_code)]
1481 pub fn new(n: usize) -> Self {
1482 Self {
1483 live_in: vec![Vec::new(); n],
1484 live_out: vec![Vec::new(); n],
1485 defs: vec![Vec::new(); n],
1486 uses: vec![Vec::new(); n],
1487 }
1488 }
1489 #[allow(dead_code)]
1490 pub fn live_in(&self, b: usize, v: usize) -> bool {
1491 self.live_in.get(b).map(|s| s.contains(&v)).unwrap_or(false)
1492 }
1493 #[allow(dead_code)]
1494 pub fn live_out(&self, b: usize, v: usize) -> bool {
1495 self.live_out
1496 .get(b)
1497 .map(|s| s.contains(&v))
1498 .unwrap_or(false)
1499 }
1500 #[allow(dead_code)]
1501 pub fn add_def(&mut self, b: usize, v: usize) {
1502 if let Some(s) = self.defs.get_mut(b) {
1503 if !s.contains(&v) {
1504 s.push(v);
1505 }
1506 }
1507 }
1508 #[allow(dead_code)]
1509 pub fn add_use(&mut self, b: usize, v: usize) {
1510 if let Some(s) = self.uses.get_mut(b) {
1511 if !s.contains(&v) {
1512 s.push(v);
1513 }
1514 }
1515 }
1516 #[allow(dead_code)]
1517 pub fn var_is_used_in_block(&self, b: usize, v: usize) -> bool {
1518 self.uses.get(b).map(|s| s.contains(&v)).unwrap_or(false)
1519 }
1520 #[allow(dead_code)]
1521 pub fn var_is_def_in_block(&self, b: usize, v: usize) -> bool {
1522 self.defs.get(b).map(|s| s.contains(&v)).unwrap_or(false)
1523 }
1524}
1525#[derive(Debug, Clone, PartialEq)]
1527pub enum ZigType {
1528 Void,
1529 Bool,
1530 U8,
1531 U64,
1532 I64,
1533 F64,
1534 Int,
1536 Ptr(Box<ZigType>),
1537 Slice(Box<ZigType>),
1538 Struct(String),
1539 Fn(Vec<ZigType>, Box<ZigType>),
1540 Optional(Box<ZigType>),
1541 ErrorUnion(Box<ZigType>),
1542 Anyopaque,
1543}
1544impl ZigType {
1545 pub fn codegen(&self) -> String {
1547 match self {
1548 ZigType::Void => "void".to_string(),
1549 ZigType::Bool => "bool".to_string(),
1550 ZigType::U8 => "u8".to_string(),
1551 ZigType::U64 => "u64".to_string(),
1552 ZigType::I64 => "i64".to_string(),
1553 ZigType::F64 => "f64".to_string(),
1554 ZigType::Int => "i64".to_string(),
1555 ZigType::Ptr(inner) => format!("*{}", inner.codegen()),
1556 ZigType::Slice(inner) => format!("[]{}", inner.codegen()),
1557 ZigType::Struct(name) => name.clone(),
1558 ZigType::Fn(params, ret) => {
1559 let params_str: Vec<String> = params.iter().map(|p| p.codegen()).collect();
1560 format!("fn({}) {}", params_str.join(", "), ret.codegen())
1561 }
1562 ZigType::Optional(inner) => format!("?{}", inner.codegen()),
1563 ZigType::ErrorUnion(inner) => format!("!{}", inner.codegen()),
1564 ZigType::Anyopaque => "anyopaque".to_string(),
1565 }
1566 }
1567}
1568#[allow(dead_code)]
1569#[derive(Debug, Clone)]
1570pub struct ZigTestBlock {
1571 pub name: String,
1572 pub body: Vec<String>,
1573}
1574impl ZigTestBlock {
1575 #[allow(dead_code)]
1576 pub fn new(name: impl Into<String>) -> Self {
1577 ZigTestBlock {
1578 name: name.into(),
1579 body: Vec::new(),
1580 }
1581 }
1582 #[allow(dead_code)]
1583 pub fn add_line(&mut self, line: impl Into<String>) {
1584 self.body.push(line.into());
1585 }
1586 #[allow(dead_code)]
1587 pub fn add_expect(mut self, lhs: &str, rhs: &str) -> Self {
1588 self.body
1589 .push(format!("try std.testing.expectEqual({}, {});", lhs, rhs));
1590 self
1591 }
1592 #[allow(dead_code)]
1593 pub fn add_expect_equal_strings(mut self, lhs: &str, rhs: &str) -> Self {
1594 self.body.push(format!(
1595 "try std.testing.expectEqualStrings({}, {});",
1596 lhs, rhs
1597 ));
1598 self
1599 }
1600 #[allow(dead_code)]
1601 pub fn emit(&self) -> String {
1602 let mut out = format!("test \"{}\" {{\n", self.name);
1603 for line in &self.body {
1604 out.push_str(&format!(" {}\n", line));
1605 }
1606 out.push('}');
1607 out
1608 }
1609}
1610#[allow(dead_code)]
1611#[derive(Debug, Clone)]
1612pub struct ZigTaggedUnion {
1613 pub name: String,
1614 pub tag_type: Option<String>,
1615 pub fields: Vec<(String, Option<ZigType>)>,
1616}
1617impl ZigTaggedUnion {
1618 #[allow(dead_code)]
1619 pub fn new(name: impl Into<String>) -> Self {
1620 ZigTaggedUnion {
1621 name: name.into(),
1622 tag_type: None,
1623 fields: Vec::new(),
1624 }
1625 }
1626 #[allow(dead_code)]
1627 pub fn with_tag(mut self, ty: impl Into<String>) -> Self {
1628 self.tag_type = Some(ty.into());
1629 self
1630 }
1631 #[allow(dead_code)]
1632 pub fn add_field(&mut self, name: impl Into<String>, ty: Option<ZigType>) {
1633 self.fields.push((name.into(), ty));
1634 }
1635 #[allow(dead_code)]
1636 pub fn emit(&self) -> String {
1637 let tag_part = if let Some(ref t) = self.tag_type {
1638 format!("union({}) ", t)
1639 } else {
1640 "union ".to_string()
1641 };
1642 let mut out = format!("const {} = {}{{\n", self.name, tag_part);
1643 for (name, ty) in &self.fields {
1644 match ty {
1645 Some(_) => out.push_str(&format!(" {}: {},\n", name, "type")),
1646 None => out.push_str(&format!(" {},\n", name)),
1647 }
1648 }
1649 out.push_str("};");
1650 out
1651 }
1652}
1653#[allow(dead_code)]
1654#[derive(Debug, Clone)]
1655pub struct ZigAnalysisCache {
1656 pub(super) entries: std::collections::HashMap<String, ZigCacheEntry>,
1657 pub(super) max_size: usize,
1658 pub(super) hits: u64,
1659 pub(super) misses: u64,
1660}
1661impl ZigAnalysisCache {
1662 #[allow(dead_code)]
1663 pub fn new(max_size: usize) -> Self {
1664 ZigAnalysisCache {
1665 entries: std::collections::HashMap::new(),
1666 max_size,
1667 hits: 0,
1668 misses: 0,
1669 }
1670 }
1671 #[allow(dead_code)]
1672 pub fn get(&mut self, key: &str) -> Option<&ZigCacheEntry> {
1673 if self.entries.contains_key(key) {
1674 self.hits += 1;
1675 self.entries.get(key)
1676 } else {
1677 self.misses += 1;
1678 None
1679 }
1680 }
1681 #[allow(dead_code)]
1682 pub fn insert(&mut self, key: String, data: Vec<u8>) {
1683 if self.entries.len() >= self.max_size {
1684 if let Some(oldest) = self.entries.keys().next().cloned() {
1685 self.entries.remove(&oldest);
1686 }
1687 }
1688 self.entries.insert(
1689 key.clone(),
1690 ZigCacheEntry {
1691 key,
1692 data,
1693 timestamp: 0,
1694 valid: true,
1695 },
1696 );
1697 }
1698 #[allow(dead_code)]
1699 pub fn invalidate(&mut self, key: &str) {
1700 if let Some(entry) = self.entries.get_mut(key) {
1701 entry.valid = false;
1702 }
1703 }
1704 #[allow(dead_code)]
1705 pub fn clear(&mut self) {
1706 self.entries.clear();
1707 }
1708 #[allow(dead_code)]
1709 pub fn hit_rate(&self) -> f64 {
1710 let total = self.hits + self.misses;
1711 if total == 0 {
1712 return 0.0;
1713 }
1714 self.hits as f64 / total as f64
1715 }
1716 #[allow(dead_code)]
1717 pub fn size(&self) -> usize {
1718 self.entries.len()
1719 }
1720}
1721#[derive(Debug, Clone, PartialEq)]
1723pub enum ZigExpr {
1724 Ident(String),
1725 IntLit(i64),
1726 FloatLit(f64),
1727 BoolLit(bool),
1728 StringLit(String),
1729 NullLit,
1730 BinOp {
1731 op: String,
1732 lhs: Box<ZigExpr>,
1733 rhs: Box<ZigExpr>,
1734 },
1735 UnaryOp {
1736 op: String,
1737 operand: Box<ZigExpr>,
1738 },
1739 Call {
1740 callee: Box<ZigExpr>,
1741 args: Vec<ZigExpr>,
1742 },
1743 FieldAccess {
1744 base: Box<ZigExpr>,
1745 field: String,
1746 },
1747 Try(Box<ZigExpr>),
1748 Await(Box<ZigExpr>),
1749 Comptime(Box<ZigExpr>),
1750 If {
1751 cond: Box<ZigExpr>,
1752 then: Box<ZigExpr>,
1753 else_: Option<Box<ZigExpr>>,
1754 },
1755 Block(Vec<ZigStmt>),
1756}
1757impl ZigExpr {
1758 pub fn codegen(&self) -> String {
1760 match self {
1761 ZigExpr::Ident(name) => name.clone(),
1762 ZigExpr::IntLit(n) => n.to_string(),
1763 ZigExpr::FloatLit(f) => format!("{}", f),
1764 ZigExpr::BoolLit(b) => b.to_string(),
1765 ZigExpr::StringLit(s) => {
1766 format!("\"{}\"", s.replace('\\', "\\\\").replace('"', "\\\""))
1767 }
1768 ZigExpr::NullLit => "null".to_string(),
1769 ZigExpr::BinOp { op, lhs, rhs } => {
1770 format!("({} {} {})", lhs.codegen(), op, rhs.codegen())
1771 }
1772 ZigExpr::UnaryOp { op, operand } => format!("({}{})", op, operand.codegen()),
1773 ZigExpr::Call { callee, args } => {
1774 let args_str: Vec<String> = args.iter().map(|a| a.codegen()).collect();
1775 format!("{}({})", callee.codegen(), args_str.join(", "))
1776 }
1777 ZigExpr::FieldAccess { base, field } => {
1778 format!("{}.{}", base.codegen(), field)
1779 }
1780 ZigExpr::Try(inner) => format!("try {}", inner.codegen()),
1781 ZigExpr::Await(inner) => format!("await {}", inner.codegen()),
1782 ZigExpr::Comptime(inner) => format!("comptime {}", inner.codegen()),
1783 ZigExpr::If { cond, then, else_ } => {
1784 let else_str = else_
1785 .as_ref()
1786 .map(|e| format!(" else {}", e.codegen()))
1787 .unwrap_or_default();
1788 format!("if ({}) {}{}", cond.codegen(), then.codegen(), else_str)
1789 }
1790 ZigExpr::Block(stmts) => {
1791 let body: Vec<String> = stmts
1792 .iter()
1793 .map(|s| format!(" {}", s.codegen()))
1794 .collect();
1795 format!("{{\n{}\n}}", body.join("\n"))
1796 }
1797 }
1798 }
1799}
1800#[allow(dead_code)]
1801#[derive(Debug, Clone)]
1802pub enum ZigOptimizeMode {
1803 Debug,
1804 ReleaseSafe,
1805 ReleaseFast,
1806 ReleaseSmall,
1807}
1808impl ZigOptimizeMode {
1809 #[allow(dead_code)]
1810 pub fn name(&self) -> &str {
1811 match self {
1812 ZigOptimizeMode::Debug => "Debug",
1813 ZigOptimizeMode::ReleaseSafe => "ReleaseSafe",
1814 ZigOptimizeMode::ReleaseFast => "ReleaseFast",
1815 ZigOptimizeMode::ReleaseSmall => "ReleaseSmall",
1816 }
1817 }
1818}
1819#[allow(dead_code)]
1820#[derive(Debug, Clone)]
1821pub struct ZigDominatorTree {
1822 pub idom: Vec<Option<u32>>,
1823 pub dom_children: Vec<Vec<u32>>,
1824 pub dom_depth: Vec<u32>,
1825}
1826impl ZigDominatorTree {
1827 #[allow(dead_code)]
1828 pub fn new(size: usize) -> Self {
1829 ZigDominatorTree {
1830 idom: vec![None; size],
1831 dom_children: vec![Vec::new(); size],
1832 dom_depth: vec![0; size],
1833 }
1834 }
1835 #[allow(dead_code)]
1836 pub fn set_idom(&mut self, node: usize, idom: u32) {
1837 self.idom[node] = Some(idom);
1838 }
1839 #[allow(dead_code)]
1840 pub fn dominates(&self, a: usize, b: usize) -> bool {
1841 if a == b {
1842 return true;
1843 }
1844 let mut cur = b;
1845 loop {
1846 match self.idom[cur] {
1847 Some(parent) if parent as usize == a => return true,
1848 Some(parent) if parent as usize == cur => return false,
1849 Some(parent) => cur = parent as usize,
1850 None => return false,
1851 }
1852 }
1853 }
1854 #[allow(dead_code)]
1855 pub fn depth(&self, node: usize) -> u32 {
1856 self.dom_depth.get(node).copied().unwrap_or(0)
1857 }
1858}
1859#[allow(dead_code)]
1860#[derive(Debug, Clone)]
1861pub struct ZigImport {
1862 pub module: String,
1863 pub alias: Option<String>,
1864}
1865impl ZigImport {
1866 #[allow(dead_code)]
1867 pub fn std() -> Self {
1868 ZigImport {
1869 module: "std".to_string(),
1870 alias: Some("std".to_string()),
1871 }
1872 }
1873 #[allow(dead_code)]
1874 pub fn module(module: impl Into<String>) -> Self {
1875 let m = module.into();
1876 ZigImport {
1877 module: m.clone(),
1878 alias: Some(m),
1879 }
1880 }
1881 #[allow(dead_code)]
1882 pub fn with_alias(mut self, alias: impl Into<String>) -> Self {
1883 self.alias = Some(alias.into());
1884 self
1885 }
1886 #[allow(dead_code)]
1887 pub fn emit(&self) -> String {
1888 if let Some(ref alias) = self.alias {
1889 format!("const {} = @import(\"{}\");", alias, self.module)
1890 } else {
1891 format!("_ = @import(\"{}\");", self.module)
1892 }
1893 }
1894}
1895#[allow(dead_code)]
1896#[derive(Debug, Clone)]
1897pub struct ZigAllocatorUsage {
1898 pub allocator_type: ZigAllocatorKind,
1899 pub var_name: String,
1900}
1901impl ZigAllocatorUsage {
1902 #[allow(dead_code)]
1903 pub fn new(kind: ZigAllocatorKind, var_name: impl Into<String>) -> Self {
1904 ZigAllocatorUsage {
1905 allocator_type: kind,
1906 var_name: var_name.into(),
1907 }
1908 }
1909 #[allow(dead_code)]
1910 pub fn emit_init(&self) -> String {
1911 match &self.allocator_type {
1912 ZigAllocatorKind::GeneralPurpose => {
1913 format!(
1914 "var {} = std.heap.GeneralPurposeAllocator(.{{}}){{}};\ndefer _ = {}.deinit();",
1915 self.var_name, self.var_name
1916 )
1917 }
1918 ZigAllocatorKind::Arena => {
1919 format!(
1920 "var {} = std.heap.ArenaAllocator.init(std.heap.page_allocator);\ndefer {}.deinit();",
1921 self.var_name, self.var_name
1922 )
1923 }
1924 ZigAllocatorKind::FixedBuffer(size) => {
1925 format!(
1926 "var buf: [{}]u8 = undefined;\nvar {} = std.heap.FixedBufferAllocator.init(&buf);",
1927 size, self.var_name
1928 )
1929 }
1930 _ => format!("// allocator: {}", self.allocator_type.type_name()),
1931 }
1932 }
1933 #[allow(dead_code)]
1934 pub fn emit_interface_call(&self) -> String {
1935 match &self.allocator_type {
1936 ZigAllocatorKind::GeneralPurpose => format!("{}.allocator()", self.var_name),
1937 ZigAllocatorKind::Arena => format!("{}.allocator()", self.var_name),
1938 ZigAllocatorKind::FixedBuffer(_) => format!("{}.allocator()", self.var_name),
1939 ZigAllocatorKind::Page => "std.heap.page_allocator".to_string(),
1940 ZigAllocatorKind::C => "std.heap.c_allocator".to_string(),
1941 _ => format!("{}.allocator()", self.var_name),
1942 }
1943 }
1944}
1945#[allow(dead_code)]
1946#[derive(Debug, Clone)]
1947pub struct ZigComptime {
1948 pub body: Vec<ZigStmt>,
1949 pub is_block: bool,
1950}
1951impl ZigComptime {
1952 #[allow(dead_code)]
1953 pub fn new() -> Self {
1954 ZigComptime {
1955 body: Vec::new(),
1956 is_block: true,
1957 }
1958 }
1959 #[allow(dead_code)]
1960 pub fn add_stmt(&mut self, stmt: ZigStmt) {
1961 self.body.push(stmt);
1962 }
1963 #[allow(dead_code)]
1964 pub fn emit(&self) -> String {
1965 if self.is_block {
1966 format!(
1967 "comptime {{\n{}}}",
1968 self.body
1969 .iter()
1970 .map(|_| " // stmt\n")
1971 .collect::<String>()
1972 )
1973 } else {
1974 "comptime expr".to_string()
1975 }
1976 }
1977}
1978#[allow(dead_code)]
1979pub struct ZigPassRegistry {
1980 pub(super) configs: Vec<ZigPassConfig>,
1981 pub(super) stats: std::collections::HashMap<String, ZigPassStats>,
1982}
1983impl ZigPassRegistry {
1984 #[allow(dead_code)]
1985 pub fn new() -> Self {
1986 ZigPassRegistry {
1987 configs: Vec::new(),
1988 stats: std::collections::HashMap::new(),
1989 }
1990 }
1991 #[allow(dead_code)]
1992 pub fn register(&mut self, config: ZigPassConfig) {
1993 self.stats
1994 .insert(config.pass_name.clone(), ZigPassStats::new());
1995 self.configs.push(config);
1996 }
1997 #[allow(dead_code)]
1998 pub fn enabled_passes(&self) -> Vec<&ZigPassConfig> {
1999 self.configs.iter().filter(|c| c.enabled).collect()
2000 }
2001 #[allow(dead_code)]
2002 pub fn get_stats(&self, name: &str) -> Option<&ZigPassStats> {
2003 self.stats.get(name)
2004 }
2005 #[allow(dead_code)]
2006 pub fn total_passes(&self) -> usize {
2007 self.configs.len()
2008 }
2009 #[allow(dead_code)]
2010 pub fn enabled_count(&self) -> usize {
2011 self.enabled_passes().len()
2012 }
2013 #[allow(dead_code)]
2014 pub fn update_stats(&mut self, name: &str, changes: u64, time_ms: u64, iter: u32) {
2015 if let Some(stats) = self.stats.get_mut(name) {
2016 stats.record_run(changes, time_ms, iter);
2017 }
2018 }
2019}
2020#[allow(dead_code)]
2021#[derive(Debug, Clone)]
2022pub struct ZigGenericFn {
2023 pub name: String,
2024 pub type_params: Vec<String>,
2025 pub params: Vec<(String, String)>,
2026 pub return_type: String,
2027 pub body: Vec<ZigStmt>,
2028}
2029impl ZigGenericFn {
2030 #[allow(dead_code)]
2031 pub fn new(name: impl Into<String>) -> Self {
2032 ZigGenericFn {
2033 name: name.into(),
2034 type_params: Vec::new(),
2035 params: Vec::new(),
2036 return_type: "void".to_string(),
2037 body: Vec::new(),
2038 }
2039 }
2040 #[allow(dead_code)]
2041 pub fn type_param(mut self, tp: impl Into<String>) -> Self {
2042 self.type_params.push(tp.into());
2043 self
2044 }
2045 #[allow(dead_code)]
2046 pub fn param(mut self, name: impl Into<String>, ty: impl Into<String>) -> Self {
2047 self.params.push((name.into(), ty.into()));
2048 self
2049 }
2050 #[allow(dead_code)]
2051 pub fn returns(mut self, ty: impl Into<String>) -> Self {
2052 self.return_type = ty.into();
2053 self
2054 }
2055 #[allow(dead_code)]
2056 pub fn emit(&self) -> String {
2057 let tp_part = if self.type_params.is_empty() {
2058 String::new()
2059 } else {
2060 format!("comptime {}: type, ", self.type_params.join(", comptime "))
2061 };
2062 let params: Vec<String> = self
2063 .params
2064 .iter()
2065 .map(|(n, t)| format!("{}: {}", n, t))
2066 .collect();
2067 format!(
2068 "fn {}({}{}){} {{\n // body\n}}",
2069 self.name,
2070 tp_part,
2071 params.join(", "),
2072 self.return_type
2073 )
2074 }
2075}
2076pub struct ZigBackend;
2078impl ZigBackend {
2079 pub fn new() -> Self {
2081 ZigBackend
2082 }
2083 pub fn emit_module(&self, module: &ZigModule) -> String {
2085 module.codegen()
2086 }
2087 pub fn emit_fn(&self, f: &ZigFn) -> String {
2089 f.codegen()
2090 }
2091 pub fn emit_struct(&self, s: &ZigStruct) -> String {
2093 s.codegen()
2094 }
2095 pub fn compile_name(oxilean_name: &str) -> String {
2100 let sanitized: String = oxilean_name
2101 .chars()
2102 .map(|c| {
2103 if c.is_alphanumeric() || c == '_' {
2104 c
2105 } else {
2106 '_'
2107 }
2108 })
2109 .collect();
2110 let result = if sanitized.is_empty() {
2111 "ox_empty".to_string()
2112 } else if sanitized
2113 .chars()
2114 .next()
2115 .map(|c| c.is_ascii_digit())
2116 .unwrap_or(false)
2117 {
2118 format!("ox_{}", sanitized)
2119 } else {
2120 sanitized
2121 };
2122 let zig_keywords = [
2123 "align",
2124 "allowzero",
2125 "and",
2126 "anyframe",
2127 "anytype",
2128 "asm",
2129 "async",
2130 "await",
2131 "break",
2132 "callconv",
2133 "catch",
2134 "comptime",
2135 "const",
2136 "continue",
2137 "defer",
2138 "else",
2139 "enum",
2140 "errdefer",
2141 "error",
2142 "export",
2143 "extern",
2144 "fn",
2145 "for",
2146 "if",
2147 "inline",
2148 "noalias",
2149 "noinline",
2150 "nosuspend",
2151 "opaque",
2152 "or",
2153 "orelse",
2154 "packed",
2155 "pub",
2156 "resume",
2157 "return",
2158 "struct",
2159 "suspend",
2160 "switch",
2161 "test",
2162 "threadlocal",
2163 "try",
2164 "union",
2165 "unreachable",
2166 "usingnamespace",
2167 "var",
2168 "volatile",
2169 "while",
2170 ];
2171 if zig_keywords.contains(&result.as_str()) {
2172 format!("ox_{}", result)
2173 } else {
2174 result
2175 }
2176 }
2177}
2178#[allow(dead_code)]
2180#[derive(Debug, Clone)]
2181pub struct ZigExtPassConfig {
2182 pub name: String,
2183 pub phase: ZigExtPassPhase,
2184 pub enabled: bool,
2185 pub max_iterations: usize,
2186 pub debug: u32,
2187 pub timeout_ms: Option<u64>,
2188}
2189impl ZigExtPassConfig {
2190 #[allow(dead_code)]
2191 pub fn new(name: impl Into<String>) -> Self {
2192 Self {
2193 name: name.into(),
2194 phase: ZigExtPassPhase::Middle,
2195 enabled: true,
2196 max_iterations: 100,
2197 debug: 0,
2198 timeout_ms: None,
2199 }
2200 }
2201 #[allow(dead_code)]
2202 pub fn with_phase(mut self, phase: ZigExtPassPhase) -> Self {
2203 self.phase = phase;
2204 self
2205 }
2206 #[allow(dead_code)]
2207 pub fn with_max_iter(mut self, n: usize) -> Self {
2208 self.max_iterations = n;
2209 self
2210 }
2211 #[allow(dead_code)]
2212 pub fn with_debug(mut self, d: u32) -> Self {
2213 self.debug = d;
2214 self
2215 }
2216 #[allow(dead_code)]
2217 pub fn disabled(mut self) -> Self {
2218 self.enabled = false;
2219 self
2220 }
2221 #[allow(dead_code)]
2222 pub fn with_timeout(mut self, ms: u64) -> Self {
2223 self.timeout_ms = Some(ms);
2224 self
2225 }
2226 #[allow(dead_code)]
2227 pub fn is_debug_enabled(&self) -> bool {
2228 self.debug > 0
2229 }
2230}
2231#[allow(dead_code)]
2232#[derive(Debug, Clone)]
2233pub struct ZigBuiltinFn {
2234 pub name: String,
2235 pub args: Vec<String>,
2236}
2237impl ZigBuiltinFn {
2238 #[allow(dead_code)]
2239 pub fn new(name: impl Into<String>) -> Self {
2240 ZigBuiltinFn {
2241 name: name.into(),
2242 args: Vec::new(),
2243 }
2244 }
2245 #[allow(dead_code)]
2246 pub fn arg(mut self, a: impl Into<String>) -> Self {
2247 self.args.push(a.into());
2248 self
2249 }
2250 #[allow(dead_code)]
2251 pub fn emit(&self) -> String {
2252 format!("@{}({})", self.name, self.args.join(", "))
2253 }
2254}