Skip to main content

oxilean_codegen/zig_backend/
functions.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5use super::types::{
6    ZigAllocatorKind, ZigAllocatorUsage, ZigAnalysisCache, ZigAsyncFn, ZigBackend,
7    ZigBuildConfiguration, ZigComptime, ZigConstantFoldingHelper, ZigDepGraph, ZigDominatorTree,
8    ZigErrorSet, ZigExpr, ZigExtCache, ZigExtConstFolder, ZigExtDepGraph, ZigExtDomTree,
9    ZigExtLiveness, ZigExtPassConfig, ZigExtPassPhase, ZigExtPassRegistry, ZigExtPassStats,
10    ZigExtWorklist, ZigFn, ZigGenericFn, ZigImport, ZigLivenessInfo, ZigModule, ZigOptimizeMode,
11    ZigPackedStruct, ZigPassConfig, ZigPassPhase, ZigPassRegistry, ZigPassStats, ZigSliceOps,
12    ZigStmt, ZigStruct, ZigTaggedUnion, ZigTestBlock, ZigType, ZigWorklist,
13};
14
15#[cfg(test)]
16mod tests {
17    use super::*;
18    #[test]
19    pub(super) fn test_zig_type_codegen_primitives() {
20        assert_eq!(ZigType::Void.codegen(), "void");
21        assert_eq!(ZigType::Bool.codegen(), "bool");
22        assert_eq!(ZigType::U8.codegen(), "u8");
23        assert_eq!(ZigType::U64.codegen(), "u64");
24        assert_eq!(ZigType::I64.codegen(), "i64");
25        assert_eq!(ZigType::F64.codegen(), "f64");
26        assert_eq!(ZigType::Anyopaque.codegen(), "anyopaque");
27    }
28    #[test]
29    pub(super) fn test_zig_type_codegen_composite() {
30        let ptr = ZigType::Ptr(Box::new(ZigType::U8));
31        assert_eq!(ptr.codegen(), "*u8");
32        let slice = ZigType::Slice(Box::new(ZigType::I64));
33        assert_eq!(slice.codegen(), "[]i64");
34        let opt = ZigType::Optional(Box::new(ZigType::Bool));
35        assert_eq!(opt.codegen(), "?bool");
36        let eu = ZigType::ErrorUnion(Box::new(ZigType::Void));
37        assert_eq!(eu.codegen(), "!void");
38    }
39    #[test]
40    pub(super) fn test_zig_type_fn() {
41        let fn_ty = ZigType::Fn(vec![ZigType::U64, ZigType::Bool], Box::new(ZigType::I64));
42        let out = fn_ty.codegen();
43        assert!(out.contains("fn("));
44        assert!(out.contains("u64"));
45        assert!(out.contains("bool"));
46        assert!(out.contains("i64"));
47    }
48    #[test]
49    pub(super) fn test_zig_expr_literals() {
50        assert_eq!(ZigExpr::IntLit(42).codegen(), "42");
51        assert_eq!(ZigExpr::BoolLit(true).codegen(), "true");
52        assert_eq!(ZigExpr::BoolLit(false).codegen(), "false");
53        assert_eq!(ZigExpr::NullLit.codegen(), "null");
54        assert_eq!(
55            ZigExpr::StringLit("hello".to_string()).codegen(),
56            "\"hello\""
57        );
58        assert_eq!(ZigExpr::Ident("foo".to_string()).codegen(), "foo");
59    }
60    #[test]
61    pub(super) fn test_zig_expr_binop() {
62        let expr = ZigExpr::BinOp {
63            op: "+".to_string(),
64            lhs: Box::new(ZigExpr::IntLit(1)),
65            rhs: Box::new(ZigExpr::IntLit(2)),
66        };
67        assert_eq!(expr.codegen(), "(1 + 2)");
68    }
69    #[test]
70    pub(super) fn test_zig_expr_call() {
71        let expr = ZigExpr::Call {
72            callee: Box::new(ZigExpr::Ident("foo".to_string())),
73            args: vec![ZigExpr::IntLit(1), ZigExpr::IntLit(2)],
74        };
75        assert_eq!(expr.codegen(), "foo(1, 2)");
76    }
77    #[test]
78    pub(super) fn test_zig_fn_codegen() {
79        let mut f = ZigFn::new("add", ZigType::U64);
80        f.add_param("a", ZigType::U64);
81        f.add_param("b", ZigType::U64);
82        f.add_stmt(ZigStmt::Return(Some(ZigExpr::BinOp {
83            op: "+".to_string(),
84            lhs: Box::new(ZigExpr::Ident("a".to_string())),
85            rhs: Box::new(ZigExpr::Ident("b".to_string())),
86        })));
87        let out = f.codegen();
88        assert!(out.contains("fn add("));
89        assert!(out.contains("a: u64"));
90        assert!(out.contains("b: u64"));
91        assert!(out.contains("u64"));
92        assert!(out.contains("return"));
93    }
94    #[test]
95    pub(super) fn test_zig_struct_codegen() {
96        let mut s = ZigStruct::new("Point");
97        s.add_field("x", ZigType::F64);
98        s.add_field("y", ZigType::F64);
99        let out = s.codegen();
100        assert!(out.contains("const Point = struct"));
101        assert!(out.contains("x: f64"));
102        assert!(out.contains("y: f64"));
103    }
104    #[test]
105    pub(super) fn test_zig_module_codegen() {
106        let mut m = ZigModule::new("mymod");
107        m.add_import("std");
108        let mut s = ZigStruct::new("Foo");
109        s.add_field("val", ZigType::U64);
110        m.add_struct(s);
111        let mut f = ZigFn::new("bar", ZigType::Void);
112        f.add_stmt(ZigStmt::Return(None));
113        m.add_fn(f);
114        let out = m.codegen();
115        assert!(out.contains("@import(\"std\")"));
116        assert!(out.contains("const Foo = struct"));
117        assert!(out.contains("fn bar()"));
118    }
119    #[test]
120    pub(super) fn test_compile_name_sanitize() {
121        assert_eq!(ZigBackend::compile_name("Foo.bar"), "Foo_bar");
122        assert_eq!(ZigBackend::compile_name("123abc"), "ox_123abc");
123        assert_eq!(ZigBackend::compile_name(""), "ox_empty");
124        assert_eq!(ZigBackend::compile_name("fn"), "ox_fn");
125        assert_eq!(ZigBackend::compile_name("const"), "ox_const");
126        assert_eq!(ZigBackend::compile_name("my_var"), "my_var");
127    }
128}
129#[allow(dead_code)]
130pub fn zig_builtin_type_of(expr: &str) -> String {
131    format!("@TypeOf({})", expr)
132}
133#[allow(dead_code)]
134pub fn zig_builtin_int_cast(ty: &str, val: &str) -> String {
135    format!("@intCast({}, {})", ty, val)
136}
137#[allow(dead_code)]
138pub fn zig_builtin_float_cast(ty: &str, val: &str) -> String {
139    format!("@floatCast({}, {})", ty, val)
140}
141#[allow(dead_code)]
142pub fn zig_builtin_ptrcast(ty: &str, val: &str) -> String {
143    format!("@ptrCast({}, {})", ty, val)
144}
145#[allow(dead_code)]
146pub fn zig_builtin_size_of(ty: &str) -> String {
147    format!("@sizeOf({})", ty)
148}
149#[allow(dead_code)]
150pub fn zig_builtin_align_of(ty: &str) -> String {
151    format!("@alignOf({})", ty)
152}
153#[allow(dead_code)]
154pub fn zig_builtin_has_decl(ty: &str, name: &str) -> String {
155    format!("@hasDecl({}, \"{}\")", ty, name)
156}
157#[allow(dead_code)]
158pub fn zig_builtin_field(val: &str, field: &str) -> String {
159    format!("@field({}, \"{}\")", val, field)
160}
161#[cfg(test)]
162mod zig_extended_tests {
163    use super::*;
164    #[test]
165    pub(super) fn test_error_set() {
166        let mut es = ZigErrorSet::new("FileError");
167        es.add_error("NotFound");
168        es.add_error("AccessDenied");
169        let s = es.emit();
170        assert!(s.contains("const FileError = error{"));
171        assert!(s.contains("NotFound"));
172        assert!(s.contains("AccessDenied"));
173    }
174    #[test]
175    pub(super) fn test_tagged_union() {
176        let mut u = ZigTaggedUnion::new("Shape");
177        u.add_field("circle", None);
178        u.add_field("rectangle", None);
179        let s = u.emit();
180        assert!(s.contains("const Shape = union"));
181        assert!(s.contains("circle"));
182    }
183    #[test]
184    pub(super) fn test_packed_struct() {
185        let mut ps = ZigPackedStruct::new("Flags");
186        ps.add_field("enabled", ZigType::Bool, Some(1));
187        ps.add_field("value", ZigType::Int, Some(7));
188        assert_eq!(ps.total_bits(), 8);
189        let s = ps.emit();
190        assert!(s.contains("const Flags = packed struct"));
191        assert!(s.contains("u1"));
192        assert!(s.contains("u7"));
193    }
194    #[test]
195    pub(super) fn test_generic_fn() {
196        let f = ZigGenericFn::new("max")
197            .type_param("T")
198            .param("a", "T")
199            .param("b", "T")
200            .returns("T");
201        let s = f.emit();
202        assert!(s.contains("fn max("));
203        assert!(s.contains("comptime T: type"));
204    }
205    #[test]
206    pub(super) fn test_builtins() {
207        assert_eq!(zig_builtin_size_of("u32"), "@sizeOf(u32)");
208        assert_eq!(zig_builtin_type_of("x"), "@TypeOf(x)");
209        assert_eq!(zig_builtin_int_cast("u8", "val"), "@intCast(u8, val)");
210    }
211    #[test]
212    pub(super) fn test_test_block() {
213        let t = ZigTestBlock::new("basic add").add_expect("1 + 1", "2");
214        let s = t.emit();
215        assert!(s.contains("test \"basic add\""));
216        assert!(s.contains("expectEqual"));
217    }
218    #[test]
219    pub(super) fn test_allocator() {
220        let alloc = ZigAllocatorUsage::new(ZigAllocatorKind::GeneralPurpose, "gpa");
221        let init = alloc.emit_init();
222        assert!(init.contains("GeneralPurposeAllocator"));
223        assert!(init.contains("gpa"));
224        let iface = alloc.emit_interface_call();
225        assert!(iface.contains("allocator()"));
226    }
227    #[test]
228    pub(super) fn test_slice_ops() {
229        assert_eq!(ZigSliceOps::len_expr("items"), "items.len");
230        assert_eq!(ZigSliceOps::index_expr("arr", "i"), "arr[i]");
231        assert_eq!(ZigSliceOps::slice_expr("buf", "0", "n"), "buf[0..n]");
232        assert_eq!(ZigSliceOps::eql("a", "b"), "std.mem.eql(u8, a, b)");
233    }
234    #[test]
235    pub(super) fn test_import() {
236        let imp = ZigImport::std();
237        assert_eq!(imp.emit(), "const std = @import(\"std\");");
238    }
239    #[test]
240    pub(super) fn test_build_configuration() {
241        let cfg = ZigBuildConfiguration::new("src/main.zig").optimize(ZigOptimizeMode::ReleaseFast);
242        let build_zig = cfg.emit_build_zig();
243        assert!(build_zig.contains("pub fn build"));
244        assert!(build_zig.contains("src/main.zig"));
245    }
246    #[test]
247    pub(super) fn test_async_fn() {
248        let f = ZigAsyncFn::new("fetchData").param("url", "[]const u8");
249        let s = f.emit();
250        assert!(s.contains("async fn fetchData"));
251        assert!(s.contains("url: []const u8"));
252        let await_call = f.emit_await_call(&["\"https://example.com\""]);
253        assert!(await_call.contains("await async fetchData"));
254    }
255    #[test]
256    pub(super) fn test_comptime_block() {
257        let ct = ZigComptime::new();
258        let s = ct.emit();
259        assert!(s.starts_with("comptime {"));
260    }
261}
262#[cfg(test)]
263mod Zig_infra_tests {
264    use super::*;
265    #[test]
266    pub(super) fn test_pass_config() {
267        let config = ZigPassConfig::new("test_pass", ZigPassPhase::Transformation);
268        assert!(config.enabled);
269        assert!(config.phase.is_modifying());
270        assert_eq!(config.phase.name(), "transformation");
271    }
272    #[test]
273    pub(super) fn test_pass_stats() {
274        let mut stats = ZigPassStats::new();
275        stats.record_run(10, 100, 3);
276        stats.record_run(20, 200, 5);
277        assert_eq!(stats.total_runs, 2);
278        assert!((stats.average_changes_per_run() - 15.0).abs() < 0.01);
279        assert!((stats.success_rate() - 1.0).abs() < 0.01);
280        let s = stats.format_summary();
281        assert!(s.contains("Runs: 2/2"));
282    }
283    #[test]
284    pub(super) fn test_pass_registry() {
285        let mut reg = ZigPassRegistry::new();
286        reg.register(ZigPassConfig::new("pass_a", ZigPassPhase::Analysis));
287        reg.register(ZigPassConfig::new("pass_b", ZigPassPhase::Transformation).disabled());
288        assert_eq!(reg.total_passes(), 2);
289        assert_eq!(reg.enabled_count(), 1);
290        reg.update_stats("pass_a", 5, 50, 2);
291        let stats = reg.get_stats("pass_a").expect("stats should exist");
292        assert_eq!(stats.total_changes, 5);
293    }
294    #[test]
295    pub(super) fn test_analysis_cache() {
296        let mut cache = ZigAnalysisCache::new(10);
297        cache.insert("key1".to_string(), vec![1, 2, 3]);
298        assert!(cache.get("key1").is_some());
299        assert!(cache.get("key2").is_none());
300        assert!((cache.hit_rate() - 0.5).abs() < 0.01);
301        cache.invalidate("key1");
302        assert!(!cache.entries["key1"].valid);
303        assert_eq!(cache.size(), 1);
304    }
305    #[test]
306    pub(super) fn test_worklist() {
307        let mut wl = ZigWorklist::new();
308        assert!(wl.push(1));
309        assert!(wl.push(2));
310        assert!(!wl.push(1));
311        assert_eq!(wl.len(), 2);
312        assert_eq!(wl.pop(), Some(1));
313        assert!(!wl.contains(1));
314        assert!(wl.contains(2));
315    }
316    #[test]
317    pub(super) fn test_dominator_tree() {
318        let mut dt = ZigDominatorTree::new(5);
319        dt.set_idom(1, 0);
320        dt.set_idom(2, 0);
321        dt.set_idom(3, 1);
322        assert!(dt.dominates(0, 3));
323        assert!(dt.dominates(1, 3));
324        assert!(!dt.dominates(2, 3));
325        assert!(dt.dominates(3, 3));
326    }
327    #[test]
328    pub(super) fn test_liveness() {
329        let mut liveness = ZigLivenessInfo::new(3);
330        liveness.add_def(0, 1);
331        liveness.add_use(1, 1);
332        assert!(liveness.defs[0].contains(&1));
333        assert!(liveness.uses[1].contains(&1));
334    }
335    #[test]
336    pub(super) fn test_constant_folding() {
337        assert_eq!(ZigConstantFoldingHelper::fold_add_i64(3, 4), Some(7));
338        assert_eq!(ZigConstantFoldingHelper::fold_div_i64(10, 0), None);
339        assert_eq!(ZigConstantFoldingHelper::fold_div_i64(10, 2), Some(5));
340        assert_eq!(
341            ZigConstantFoldingHelper::fold_bitand_i64(0b1100, 0b1010),
342            0b1000
343        );
344        assert_eq!(ZigConstantFoldingHelper::fold_bitnot_i64(0), -1);
345    }
346    #[test]
347    pub(super) fn test_dep_graph() {
348        let mut g = ZigDepGraph::new();
349        g.add_dep(1, 2);
350        g.add_dep(2, 3);
351        g.add_dep(1, 3);
352        assert_eq!(g.dependencies_of(2), vec![1]);
353        let topo = g.topological_sort();
354        assert_eq!(topo.len(), 3);
355        assert!(!g.has_cycle());
356        let pos: std::collections::HashMap<u32, usize> =
357            topo.iter().enumerate().map(|(i, &n)| (n, i)).collect();
358        assert!(pos[&1] < pos[&2]);
359        assert!(pos[&1] < pos[&3]);
360        assert!(pos[&2] < pos[&3]);
361    }
362}
363#[cfg(test)]
364mod zigext_pass_tests {
365    use super::*;
366    #[test]
367    pub(super) fn test_zigext_phase_order() {
368        assert_eq!(ZigExtPassPhase::Early.order(), 0);
369        assert_eq!(ZigExtPassPhase::Middle.order(), 1);
370        assert_eq!(ZigExtPassPhase::Late.order(), 2);
371        assert_eq!(ZigExtPassPhase::Finalize.order(), 3);
372        assert!(ZigExtPassPhase::Early.is_early());
373        assert!(!ZigExtPassPhase::Early.is_late());
374    }
375    #[test]
376    pub(super) fn test_zigext_config_builder() {
377        let c = ZigExtPassConfig::new("p")
378            .with_phase(ZigExtPassPhase::Late)
379            .with_max_iter(50)
380            .with_debug(1);
381        assert_eq!(c.name, "p");
382        assert_eq!(c.max_iterations, 50);
383        assert!(c.is_debug_enabled());
384        assert!(c.enabled);
385        let c2 = c.disabled();
386        assert!(!c2.enabled);
387    }
388    #[test]
389    pub(super) fn test_zigext_stats() {
390        let mut s = ZigExtPassStats::new();
391        s.visit();
392        s.visit();
393        s.modify();
394        s.iterate();
395        assert_eq!(s.nodes_visited, 2);
396        assert_eq!(s.nodes_modified, 1);
397        assert!(s.changed);
398        assert_eq!(s.iterations, 1);
399        let e = s.efficiency();
400        assert!((e - 0.5).abs() < 1e-9);
401    }
402    #[test]
403    pub(super) fn test_zigext_registry() {
404        let mut r = ZigExtPassRegistry::new();
405        r.register(ZigExtPassConfig::new("a").with_phase(ZigExtPassPhase::Early));
406        r.register(ZigExtPassConfig::new("b").disabled());
407        assert_eq!(r.len(), 2);
408        assert_eq!(r.enabled_passes().len(), 1);
409        assert_eq!(r.passes_in_phase(&ZigExtPassPhase::Early).len(), 1);
410    }
411    #[test]
412    pub(super) fn test_zigext_cache() {
413        let mut c = ZigExtCache::new(4);
414        assert!(c.get(99).is_none());
415        c.put(99, vec![1, 2, 3]);
416        let v = c.get(99).expect("v should be present in map");
417        assert_eq!(v, &[1u8, 2, 3]);
418        assert!(c.hit_rate() > 0.0);
419        assert_eq!(c.live_count(), 1);
420    }
421    #[test]
422    pub(super) fn test_zigext_worklist() {
423        let mut w = ZigExtWorklist::new(10);
424        w.push(5);
425        w.push(3);
426        w.push(5);
427        assert_eq!(w.len(), 2);
428        assert!(w.contains(5));
429        let first = w.pop().expect("first should be available to pop");
430        assert!(!w.contains(first));
431    }
432    #[test]
433    pub(super) fn test_zigext_dom_tree() {
434        let mut dt = ZigExtDomTree::new(5);
435        dt.set_idom(1, 0);
436        dt.set_idom(2, 0);
437        dt.set_idom(3, 1);
438        dt.set_idom(4, 1);
439        assert!(dt.dominates(0, 3));
440        assert!(dt.dominates(1, 4));
441        assert!(!dt.dominates(2, 3));
442        assert_eq!(dt.depth_of(3), 2);
443    }
444    #[test]
445    pub(super) fn test_zigext_liveness() {
446        let mut lv = ZigExtLiveness::new(3);
447        lv.add_def(0, 1);
448        lv.add_use(1, 1);
449        assert!(lv.var_is_def_in_block(0, 1));
450        assert!(lv.var_is_used_in_block(1, 1));
451        assert!(!lv.var_is_def_in_block(1, 1));
452    }
453    #[test]
454    pub(super) fn test_zigext_const_folder() {
455        let mut cf = ZigExtConstFolder::new();
456        assert_eq!(cf.add_i64(3, 4), Some(7));
457        assert_eq!(cf.div_i64(10, 0), None);
458        assert_eq!(cf.mul_i64(6, 7), Some(42));
459        assert_eq!(cf.and_i64(0b1100, 0b1010), 0b1000);
460        assert_eq!(cf.fold_count(), 3);
461        assert_eq!(cf.failure_count(), 1);
462    }
463    #[test]
464    pub(super) fn test_zigext_dep_graph() {
465        let mut g = ZigExtDepGraph::new(4);
466        g.add_edge(0, 1);
467        g.add_edge(1, 2);
468        g.add_edge(2, 3);
469        assert!(!g.has_cycle());
470        assert_eq!(g.topo_sort(), Some(vec![0, 1, 2, 3]));
471        assert_eq!(g.reachable(0).len(), 4);
472        let sccs = g.scc();
473        assert_eq!(sccs.len(), 4);
474    }
475}