Skip to main content

oxilean_codegen/swift_backend/
functions.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5use crate::lcnf::*;
6
7use super::types::{
8    SwiftAnalysisCache, SwiftBackend, SwiftClassDecl, SwiftConformance, SwiftConstantFoldingHelper,
9    SwiftDepGraph, SwiftDominatorTree, SwiftEnumCase, SwiftEnumDecl, SwiftExpr, SwiftExtension,
10    SwiftField, SwiftFunc, SwiftLit, SwiftLivenessInfo, SwiftModule, SwiftParam, SwiftPassConfig,
11    SwiftPassPhase, SwiftPassRegistry, SwiftPassStats, SwiftStmt, SwiftStructDecl, SwiftType,
12    SwiftTypeDecl, SwiftWorklist,
13};
14
15/// Emit a block of statements indented by `indent` spaces.
16pub(super) fn emit_block(stmts: &[SwiftStmt], indent: usize) -> String {
17    let pad = " ".repeat(indent);
18    stmts
19        .iter()
20        .map(|s| format!("{}{}", pad, emit_stmt(s, indent)))
21        .collect::<Vec<_>>()
22        .join("\n")
23}
24/// Emit a single statement at the given indent level.
25pub(super) fn emit_stmt(stmt: &SwiftStmt, indent: usize) -> String {
26    let pad = " ".repeat(indent);
27    let pad2 = " ".repeat(indent + 4);
28    match stmt {
29        SwiftStmt::Let { name, ty, value } => {
30            if let Some(t) = ty {
31                format!("let {}: {} = {}", name, t, value)
32            } else {
33                format!("let {} = {}", name, value)
34            }
35        }
36        SwiftStmt::Var { name, ty, value } => match (ty, value) {
37            (Some(t), Some(v)) => format!("var {}: {} = {}", name, t, v),
38            (Some(t), None) => format!("var {}: {}", name, t),
39            (None, Some(v)) => format!("var {} = {}", name, v),
40            (None, None) => format!("var {}", name),
41        },
42        SwiftStmt::Assign { target, value } => format!("{} = {}", target, value),
43        SwiftStmt::Return(None) => "return".to_string(),
44        SwiftStmt::Return(Some(expr)) => format!("return {}", expr),
45        SwiftStmt::If {
46            cond,
47            then_body,
48            else_body,
49        } => {
50            let mut out = format!("if {} {{\n", cond);
51            out += &emit_block(then_body, indent + 4);
52            if !then_body.is_empty() {
53                out += "\n";
54            }
55            if else_body.is_empty() {
56                out += &format!("{}}}", pad);
57            } else {
58                out += &format!("{}}} else {{\n", pad);
59                out += &emit_block(else_body, indent + 4);
60                if !else_body.is_empty() {
61                    out += "\n";
62                }
63                out += &format!("{}}}", pad);
64            }
65            out
66        }
67        SwiftStmt::IfLet {
68            name,
69            value,
70            then_body,
71            else_body,
72        } => {
73            let mut out = format!("if let {} = {} {{\n", name, value);
74            out += &emit_block(then_body, indent + 4);
75            if !then_body.is_empty() {
76                out += "\n";
77            }
78            if else_body.is_empty() {
79                out += &format!("{}}}", pad);
80            } else {
81                out += &format!("{}}} else {{\n", pad);
82                out += &emit_block(else_body, indent + 4);
83                if !else_body.is_empty() {
84                    out += "\n";
85                }
86                out += &format!("{}}}", pad);
87            }
88            out
89        }
90        SwiftStmt::Guard { cond, else_body } => {
91            let mut out = format!("guard {} else {{\n", cond);
92            out += &emit_block(else_body, indent + 4);
93            if !else_body.is_empty() {
94                out += "\n";
95            }
96            out += &format!("{}}}", pad);
97            out
98        }
99        SwiftStmt::Switch { subject, cases } => {
100            let mut out = format!("switch {} {{\n", subject);
101            for case in cases {
102                out += &format!("{}case {}:\n", pad2, case.pattern);
103                out += &emit_block(&case.body, indent + 8);
104                if !case.body.is_empty() {
105                    out += "\n";
106                }
107            }
108            out += &format!("{}}}", pad);
109            out
110        }
111        SwiftStmt::For {
112            name,
113            collection,
114            body,
115        } => {
116            let mut out = format!("for {} in {} {{\n", name, collection);
117            out += &emit_block(body, indent + 4);
118            if !body.is_empty() {
119                out += "\n";
120            }
121            out += &format!("{}}}", pad);
122            out
123        }
124        SwiftStmt::While { cond, body } => {
125            let mut out = format!("while {} {{\n", cond);
126            out += &emit_block(body, indent + 4);
127            if !body.is_empty() {
128                out += "\n";
129            }
130            out += &format!("{}}}", pad);
131            out
132        }
133        SwiftStmt::Throw(expr) => format!("throw {}", expr),
134        SwiftStmt::Break => "break".to_string(),
135        SwiftStmt::Continue => "continue".to_string(),
136        SwiftStmt::ExprStmt(e) => format!("{}", e),
137        SwiftStmt::Raw(s) => s.clone(),
138        SwiftStmt::Block(stmts) => {
139            let mut out = "{\n".to_string();
140            out += &emit_block(stmts, indent + 4);
141            if !stmts.is_empty() {
142                out += "\n";
143            }
144            out += &format!("{}}}", pad);
145            out
146        }
147    }
148}
149/// All Swift reserved keywords that cannot be used as bare identifiers.
150const SWIFT_KEYWORDS: &[&str] = &[
151    "associatedtype",
152    "class",
153    "deinit",
154    "enum",
155    "extension",
156    "fileprivate",
157    "func",
158    "import",
159    "init",
160    "inout",
161    "internal",
162    "let",
163    "open",
164    "operator",
165    "private",
166    "precedencegroup",
167    "protocol",
168    "public",
169    "rethrows",
170    "static",
171    "struct",
172    "subscript",
173    "typealias",
174    "var",
175    "break",
176    "case",
177    "catch",
178    "continue",
179    "default",
180    "defer",
181    "do",
182    "else",
183    "fallthrough",
184    "for",
185    "guard",
186    "if",
187    "in",
188    "repeat",
189    "return",
190    "throw",
191    "switch",
192    "where",
193    "while",
194    "any",
195    "as",
196    "await",
197    "false",
198    "is",
199    "nil",
200    "self",
201    "Self",
202    "super",
203    "throws",
204    "true",
205    "try",
206    "async",
207    "convenience",
208    "didSet",
209    "dynamic",
210    "final",
211    "get",
212    "indirect",
213    "lazy",
214    "mutating",
215    "none",
216    "nonisolated",
217    "nonmutating",
218    "optional",
219    "override",
220    "postfix",
221    "prefix",
222    "required",
223    "set",
224    "some",
225    "Type",
226    "unowned",
227    "weak",
228    "willSet",
229    "associativity",
230    "consume",
231    "copy",
232    "discard",
233    "distributed",
234    "each",
235    "isolated",
236    "macro",
237    "package",
238    "then",
239];
240/// Return `true` if `name` is a Swift reserved keyword.
241pub fn is_swift_keyword(name: &str) -> bool {
242    SWIFT_KEYWORDS.contains(&name)
243}
244/// A minimal Swift runtime preamble embedded in every generated module.
245///
246/// Provides:
247/// - `OxValue` — the universal boxed value type
248/// - `OxNat`   — arbitrary-precision natural numbers (wraps `UInt`)
249/// - `OxError` — runtime error type conforming to `Swift.Error`
250/// - Helper utilities: `ox_panic`, `ox_unreachable`
251pub const OXILEAN_SWIFT_RUNTIME: &str = r#"
252// ── OxiLean Swift Runtime ────────────────────────────────────────────────────
253
254/// Universal boxed value for OxiLean-compiled terms.
255public indirect enum OxValue {
256    case int(Int)
257    case bool(Bool)
258    case string(String)
259    case float(Double)
260    case ctor(tag: Int, fields: [OxValue])
261    case closure(([OxValue]) -> OxValue)
262    case unit
263    case erased
264}
265
266/// Natural number wrapper (Lean `Nat` maps to `UInt` on 64-bit platforms).
267public struct OxNat: Equatable, Comparable, CustomStringConvertible {
268    public let value: UInt
269    public init(_ value: UInt) { self.value = value }
270    public var description: String { "\(value)" }
271    public static func < (lhs: OxNat, rhs: OxNat) -> Bool { lhs.value < rhs.value }
272    public static func + (lhs: OxNat, rhs: OxNat) -> OxNat { OxNat(lhs.value + rhs.value) }
273    public static func * (lhs: OxNat, rhs: OxNat) -> OxNat { OxNat(lhs.value * rhs.value) }
274    public func pred() -> OxNat { OxNat(value > 0 ? value - 1 : 0) }
275}
276
277/// Runtime error thrown by compiled OxiLean programs.
278public struct OxError: Error, CustomStringConvertible {
279    public let message: String
280    public init(_ message: String) { self.message = message }
281    public var description: String { "OxError: \(message)" }
282}
283
284/// Panic unconditionally — never returns.
285@inline(never)
286public func ox_panic(_ message: String = "unreachable") -> Never {
287    fatalError("[OxiLean] \(message)")
288}
289
290/// Abort on unreachable code path.
291@inline(never)
292public func ox_unreachable() -> Never {
293    ox_panic("unreachable code executed")
294}
295
296// ── End OxiLean Swift Runtime ─────────────────────────────────────────────────
297"#;
298#[cfg(test)]
299mod tests {
300    use super::*;
301    #[test]
302    pub(super) fn test_swift_type_display_primitives() {
303        assert_eq!(SwiftType::SwiftInt.to_string(), "Int");
304        assert_eq!(SwiftType::SwiftBool.to_string(), "Bool");
305        assert_eq!(SwiftType::SwiftString.to_string(), "String");
306        assert_eq!(SwiftType::SwiftDouble.to_string(), "Double");
307        assert_eq!(SwiftType::SwiftVoid.to_string(), "Void");
308        assert_eq!(SwiftType::SwiftAny.to_string(), "Any");
309        assert_eq!(SwiftType::SwiftNever.to_string(), "Never");
310    }
311    #[test]
312    pub(super) fn test_swift_type_display_compound() {
313        let arr = SwiftType::SwiftArray(Box::new(SwiftType::SwiftInt));
314        assert_eq!(arr.to_string(), "[Int]");
315        let opt = SwiftType::SwiftOptional(Box::new(SwiftType::SwiftString));
316        assert_eq!(opt.to_string(), "String?");
317        let dict = SwiftType::SwiftDict(
318            Box::new(SwiftType::SwiftString),
319            Box::new(SwiftType::SwiftInt),
320        );
321        assert_eq!(dict.to_string(), "[String: Int]");
322        let tuple = SwiftType::SwiftTuple(vec![SwiftType::SwiftInt, SwiftType::SwiftBool]);
323        assert_eq!(tuple.to_string(), "(Int, Bool)");
324        let func = SwiftType::SwiftFunc(
325            vec![SwiftType::SwiftInt, SwiftType::SwiftString],
326            Box::new(SwiftType::SwiftBool),
327        );
328        assert_eq!(func.to_string(), "(Int, String) -> Bool");
329    }
330    #[test]
331    pub(super) fn test_swift_type_display_generic() {
332        let g = SwiftType::SwiftGeneric(
333            "Result".to_string(),
334            vec![
335                SwiftType::SwiftString,
336                SwiftType::SwiftNamed("Error".to_string()),
337            ],
338        );
339        assert_eq!(g.to_string(), "Result<String, Error>");
340    }
341    #[test]
342    pub(super) fn test_swift_lit_int() {
343        assert_eq!(SwiftLit::Int(42).to_string(), "42");
344        assert_eq!(SwiftLit::Int(-7).to_string(), "-7");
345    }
346    #[test]
347    pub(super) fn test_swift_lit_bool() {
348        assert_eq!(SwiftLit::Bool(true).to_string(), "true");
349        assert_eq!(SwiftLit::Bool(false).to_string(), "false");
350    }
351    #[test]
352    pub(super) fn test_swift_lit_nil() {
353        assert_eq!(SwiftLit::Nil.to_string(), "nil");
354    }
355    #[test]
356    pub(super) fn test_swift_lit_float() {
357        assert_eq!(SwiftLit::Float(1.0).to_string(), "1.0");
358        assert_eq!(SwiftLit::Float(3.14).to_string(), "3.14");
359    }
360    #[test]
361    pub(super) fn test_swift_lit_str_escaping() {
362        let s = SwiftLit::Str("say \"hi\"\nbye".to_string());
363        assert_eq!(s.to_string(), r#""say \"hi\"\nbye""#);
364    }
365    #[test]
366    pub(super) fn test_swift_expr_var() {
367        assert_eq!(
368            SwiftExpr::SwiftVar("myVar".to_string()).to_string(),
369            "myVar"
370        );
371    }
372    #[test]
373    pub(super) fn test_swift_expr_call_unlabeled() {
374        let call = SwiftExpr::SwiftCall {
375            callee: Box::new(SwiftExpr::SwiftVar("foo".to_string())),
376            args: vec![
377                ("".to_string(), SwiftExpr::SwiftLitExpr(SwiftLit::Int(1))),
378                ("".to_string(), SwiftExpr::SwiftLitExpr(SwiftLit::Int(2))),
379            ],
380        };
381        assert_eq!(call.to_string(), "foo(1, 2)");
382    }
383    #[test]
384    pub(super) fn test_swift_expr_call_labeled() {
385        let call = SwiftExpr::SwiftCall {
386            callee: Box::new(SwiftExpr::SwiftVar("foo".to_string())),
387            args: vec![
388                ("x".to_string(), SwiftExpr::SwiftLitExpr(SwiftLit::Int(1))),
389                ("y".to_string(), SwiftExpr::SwiftLitExpr(SwiftLit::Int(2))),
390            ],
391        };
392        assert_eq!(call.to_string(), "foo(x: 1, y: 2)");
393    }
394    #[test]
395    pub(super) fn test_swift_expr_binop() {
396        let e = SwiftExpr::SwiftBinOp {
397            op: "+".to_string(),
398            lhs: Box::new(SwiftExpr::SwiftLitExpr(SwiftLit::Int(1))),
399            rhs: Box::new(SwiftExpr::SwiftLitExpr(SwiftLit::Int(2))),
400        };
401        assert_eq!(e.to_string(), "(1 + 2)");
402    }
403    #[test]
404    pub(super) fn test_swift_expr_member() {
405        let e = SwiftExpr::SwiftMember(
406            Box::new(SwiftExpr::SwiftVar("obj".to_string())),
407            "field".to_string(),
408        );
409        assert_eq!(e.to_string(), "obj.field");
410    }
411    #[test]
412    pub(super) fn test_swift_expr_optional_chain() {
413        let e = SwiftExpr::SwiftOptionalChain(
414            Box::new(SwiftExpr::SwiftVar("obj".to_string())),
415            "name".to_string(),
416        );
417        assert_eq!(e.to_string(), "obj?.name");
418    }
419    #[test]
420    pub(super) fn test_swift_expr_array_lit() {
421        let e = SwiftExpr::SwiftArrayLit(vec![
422            SwiftExpr::SwiftLitExpr(SwiftLit::Int(1)),
423            SwiftExpr::SwiftLitExpr(SwiftLit::Int(2)),
424        ]);
425        assert_eq!(e.to_string(), "[1, 2]");
426    }
427    #[test]
428    pub(super) fn test_swift_expr_dict_lit_empty() {
429        let e = SwiftExpr::SwiftDictLit(vec![]);
430        assert_eq!(e.to_string(), "[:]");
431    }
432    #[test]
433    pub(super) fn test_swift_expr_ternary() {
434        let e = SwiftExpr::SwiftTernary(
435            Box::new(SwiftExpr::SwiftVar("c".to_string())),
436            Box::new(SwiftExpr::SwiftLitExpr(SwiftLit::Int(1))),
437            Box::new(SwiftExpr::SwiftLitExpr(SwiftLit::Int(0))),
438        );
439        assert_eq!(e.to_string(), "(c ? 1 : 0)");
440    }
441    #[test]
442    pub(super) fn test_swift_stmt_let() {
443        let s = SwiftStmt::Let {
444            name: "x".to_string(),
445            ty: Some(SwiftType::SwiftInt),
446            value: SwiftExpr::SwiftLitExpr(SwiftLit::Int(42)),
447        };
448        assert_eq!(s.to_string(), "let x: Int = 42");
449    }
450    #[test]
451    pub(super) fn test_swift_stmt_var_no_value() {
452        let s = SwiftStmt::Var {
453            name: "count".to_string(),
454            ty: Some(SwiftType::SwiftInt),
455            value: None,
456        };
457        assert_eq!(s.to_string(), "var count: Int");
458    }
459    #[test]
460    pub(super) fn test_swift_stmt_return_none() {
461        assert_eq!(SwiftStmt::Return(None).to_string(), "return");
462    }
463    #[test]
464    pub(super) fn test_swift_stmt_return_expr() {
465        let s = SwiftStmt::Return(Some(SwiftExpr::SwiftLitExpr(SwiftLit::Bool(true))));
466        assert_eq!(s.to_string(), "return true");
467    }
468    #[test]
469    pub(super) fn test_swift_stmt_throw() {
470        let s = SwiftStmt::Throw(SwiftExpr::SwiftCall {
471            callee: Box::new(SwiftExpr::SwiftVar("OxError".to_string())),
472            args: vec![(
473                "".to_string(),
474                SwiftExpr::SwiftLitExpr(SwiftLit::Str("oops".to_string())),
475            )],
476        });
477        assert_eq!(s.to_string(), "throw OxError(\"oops\")");
478    }
479    #[test]
480    pub(super) fn test_swift_stmt_if_no_else() {
481        let s = SwiftStmt::If {
482            cond: SwiftExpr::SwiftVar("cond".to_string()),
483            then_body: vec![SwiftStmt::Return(Some(SwiftExpr::SwiftLitExpr(
484                SwiftLit::Int(1),
485            )))],
486            else_body: vec![],
487        };
488        let out = s.to_string();
489        assert!(out.contains("if cond {"));
490        assert!(out.contains("return 1"));
491        assert!(!out.contains("else"));
492    }
493    #[test]
494    pub(super) fn test_swift_stmt_if_with_else() {
495        let s = SwiftStmt::If {
496            cond: SwiftExpr::SwiftVar("cond".to_string()),
497            then_body: vec![SwiftStmt::Return(Some(SwiftExpr::SwiftLitExpr(
498                SwiftLit::Int(1),
499            )))],
500            else_body: vec![SwiftStmt::Return(Some(SwiftExpr::SwiftLitExpr(
501                SwiftLit::Int(0),
502            )))],
503        };
504        let out = s.to_string();
505        assert!(out.contains("} else {"));
506    }
507    #[test]
508    pub(super) fn test_swift_stmt_guard() {
509        let s = SwiftStmt::Guard {
510            cond: SwiftExpr::SwiftVar("ok".to_string()),
511            else_body: vec![SwiftStmt::Return(None)],
512        };
513        let out = s.to_string();
514        assert!(out.contains("guard ok else {"));
515        assert!(out.contains("return"));
516    }
517    #[test]
518    pub(super) fn test_swift_stmt_for() {
519        let s = SwiftStmt::For {
520            name: "item".to_string(),
521            collection: SwiftExpr::SwiftVar("items".to_string()),
522            body: vec![SwiftStmt::Break],
523        };
524        let out = s.to_string();
525        assert!(out.contains("for item in items {"));
526        assert!(out.contains("break"));
527    }
528    #[test]
529    pub(super) fn test_swift_stmt_while() {
530        let s = SwiftStmt::While {
531            cond: SwiftExpr::SwiftLitExpr(SwiftLit::Bool(true)),
532            body: vec![SwiftStmt::Break],
533        };
534        let out = s.to_string();
535        assert!(out.contains("while true {"));
536    }
537    #[test]
538    pub(super) fn test_swift_param_simple() {
539        let p = SwiftParam::new("x", SwiftType::SwiftInt);
540        assert_eq!(p.to_string(), "x: Int");
541    }
542    #[test]
543    pub(super) fn test_swift_param_labeled() {
544        let p = SwiftParam::labeled("from", "start", SwiftType::SwiftInt);
545        assert_eq!(p.to_string(), "from start: Int");
546    }
547    #[test]
548    pub(super) fn test_swift_param_variadic() {
549        let mut p = SwiftParam::new("args", SwiftType::SwiftInt);
550        p.variadic = true;
551        assert_eq!(p.to_string(), "args: Int...");
552    }
553    #[test]
554    pub(super) fn test_swift_func_simple() {
555        let mut f = SwiftFunc::new("greet", SwiftType::SwiftVoid);
556        f.body = vec![SwiftStmt::ExprStmt(SwiftExpr::SwiftCall {
557            callee: Box::new(SwiftExpr::SwiftVar("print".to_string())),
558            args: vec![(
559                "".to_string(),
560                SwiftExpr::SwiftLitExpr(SwiftLit::Str("hi".to_string())),
561            )],
562        })];
563        let out = f.codegen();
564        assert!(out.contains("func greet()"));
565        assert!(out.contains("print(\"hi\")"));
566    }
567    #[test]
568    pub(super) fn test_swift_func_public_throws_async() {
569        let mut f = SwiftFunc::new("fetchData", SwiftType::SwiftString);
570        f.is_public = true;
571        f.throws = true;
572        f.is_async = true;
573        let out = f.codegen();
574        assert!(out.contains("public func fetchData()"));
575        assert!(out.contains("async throws"));
576        assert!(out.contains("-> String"));
577    }
578    #[test]
579    pub(super) fn test_swift_func_with_generic() {
580        let mut f = SwiftFunc::new("identity", SwiftType::SwiftNamed("T".to_string()));
581        f.generic_params = vec!["T".to_string()];
582        f.params = vec![SwiftParam::new(
583            "value",
584            SwiftType::SwiftNamed("T".to_string()),
585        )];
586        let out = f.codegen();
587        assert!(out.contains("func identity<T>"));
588        assert!(out.contains("-> T"));
589    }
590    #[test]
591    pub(super) fn test_swift_enum_bare_cases() {
592        let mut e = SwiftEnumDecl::new("Direction");
593        e.cases.push(SwiftEnumCase::bare("north"));
594        e.cases.push(SwiftEnumCase::bare("south"));
595        let out = e.codegen();
596        assert!(out.contains("enum Direction {"));
597        assert!(out.contains("case north"));
598        assert!(out.contains("case south"));
599    }
600    #[test]
601    pub(super) fn test_swift_enum_associated_values() {
602        let mut e = SwiftEnumDecl::new("Result");
603        e.cases
604            .push(SwiftEnumCase::with_values("ok", vec![SwiftType::SwiftInt]));
605        e.cases.push(SwiftEnumCase::with_values(
606            "err",
607            vec![SwiftType::SwiftString],
608        ));
609        let out = e.codegen();
610        assert!(out.contains("case ok(Int)"));
611        assert!(out.contains("case err(String)"));
612    }
613    #[test]
614    pub(super) fn test_swift_enum_public_generic() {
615        let mut e = SwiftEnumDecl::new("Option");
616        e.is_public = true;
617        e.generic_params = vec!["T".to_string()];
618        e.cases.push(SwiftEnumCase::bare("none"));
619        e.cases.push(SwiftEnumCase::with_values(
620            "some",
621            vec![SwiftType::SwiftNamed("T".to_string())],
622        ));
623        let out = e.codegen();
624        assert!(out.contains("public enum Option<T> {"));
625    }
626    #[test]
627    pub(super) fn test_swift_struct_fields() {
628        let mut s = SwiftStructDecl::new("Point");
629        s.fields
630            .push(SwiftField::new_let("x", SwiftType::SwiftDouble));
631        s.fields
632            .push(SwiftField::new_let("y", SwiftType::SwiftDouble));
633        let out = s.codegen();
634        assert!(out.contains("struct Point {"));
635        assert!(out.contains("let x: Double"));
636        assert!(out.contains("let y: Double"));
637    }
638    #[test]
639    pub(super) fn test_swift_struct_conformance() {
640        let mut s = SwiftStructDecl::new("Foo");
641        s.conformances
642            .push(SwiftConformance("Equatable".to_string()));
643        s.conformances
644            .push(SwiftConformance("Hashable".to_string()));
645        let out = s.codegen();
646        assert!(out.contains("struct Foo: Equatable, Hashable {"));
647    }
648    #[test]
649    pub(super) fn test_swift_class_basic() {
650        let mut c = SwiftClassDecl::new("Animal");
651        c.fields
652            .push(SwiftField::new_var("name", SwiftType::SwiftString));
653        let out = c.codegen();
654        assert!(out.contains("class Animal {"));
655        assert!(out.contains("var name: String"));
656    }
657    #[test]
658    pub(super) fn test_swift_class_final_public() {
659        let mut c = SwiftClassDecl::new("Dog");
660        c.is_final = true;
661        c.is_public = true;
662        c.superclass = Some("Animal".to_string());
663        let out = c.codegen();
664        assert!(out.contains("public final class Dog: Animal {"));
665    }
666    #[test]
667    pub(super) fn test_swift_extension_basic() {
668        let mut ext = SwiftExtension::new("Int");
669        let mut f = SwiftFunc::new("doubled", SwiftType::SwiftInt);
670        f.body = vec![SwiftStmt::Return(Some(SwiftExpr::SwiftBinOp {
671            op: "*".to_string(),
672            lhs: Box::new(SwiftExpr::SwiftSelf),
673            rhs: Box::new(SwiftExpr::SwiftLitExpr(SwiftLit::Int(2))),
674        }))];
675        ext.methods.push(f);
676        let out = ext.codegen();
677        assert!(out.contains("extension Int {"));
678        assert!(out.contains("func doubled()"));
679    }
680    #[test]
681    pub(super) fn test_swift_module_imports_deduped() {
682        let mut m = SwiftModule::new("Test");
683        m.add_import("Foundation");
684        m.add_import("Foundation");
685        m.add_import("Swift");
686        let out = m.codegen();
687        assert_eq!(out.matches("import Foundation").count(), 1);
688        assert!(out.contains("import Swift"));
689    }
690    #[test]
691    pub(super) fn test_swift_module_contains_runtime() {
692        let m = SwiftModule::new("Runtime");
693        let out = m.codegen();
694        assert!(out.contains("OxiLean Swift Runtime"));
695        assert!(out.contains("enum OxValue"));
696        assert!(out.contains("struct OxNat"));
697        assert!(out.contains("struct OxError"));
698    }
699    #[test]
700    pub(super) fn test_swift_module_func_and_type() {
701        let mut m = SwiftModule::new("MyMod");
702        let mut e = SwiftEnumDecl::new("Color");
703        e.cases.push(SwiftEnumCase::bare("red"));
704        m.types.push(SwiftTypeDecl::Enum(e));
705        let f = SwiftFunc::new("noop", SwiftType::SwiftVoid);
706        m.funcs.push(f);
707        let out = m.codegen();
708        assert!(out.contains("enum Color {"));
709        assert!(out.contains("func noop()"));
710    }
711    #[test]
712    pub(super) fn test_mangle_name_keywords() {
713        for kw in SWIFT_KEYWORDS {
714            let result = SwiftBackend::mangle_name(kw);
715            assert!(
716                result.starts_with("ox_"),
717                "keyword '{}' should be prefixed, got '{}'",
718                kw,
719                result
720            );
721        }
722    }
723    #[test]
724    pub(super) fn test_mangle_name_digit_prefix() {
725        assert_eq!(SwiftBackend::mangle_name("0abc"), "ox_0abc");
726        assert_eq!(SwiftBackend::mangle_name("9"), "ox_9");
727    }
728    #[test]
729    pub(super) fn test_mangle_name_empty() {
730        assert_eq!(SwiftBackend::mangle_name(""), "ox_empty");
731    }
732    #[test]
733    pub(super) fn test_mangle_name_special_chars() {
734        assert_eq!(SwiftBackend::mangle_name("foo-bar"), "foo_bar");
735        assert_eq!(SwiftBackend::mangle_name("a.b.c"), "a_b_c");
736        assert_eq!(SwiftBackend::mangle_name("hello world"), "hello_world");
737    }
738    #[test]
739    pub(super) fn test_mangle_name_valid_identifier() {
740        assert_eq!(SwiftBackend::mangle_name("myFunc"), "myFunc");
741        assert_eq!(SwiftBackend::mangle_name("_private"), "_private");
742        assert_eq!(SwiftBackend::mangle_name("camelCase"), "camelCase");
743    }
744    #[test]
745    pub(super) fn test_is_swift_keyword_true() {
746        assert!(is_swift_keyword("func"));
747        assert!(is_swift_keyword("let"));
748        assert!(is_swift_keyword("var"));
749        assert!(is_swift_keyword("class"));
750        assert!(is_swift_keyword("return"));
751        assert!(is_swift_keyword("throws"));
752        assert!(is_swift_keyword("async"));
753        assert!(is_swift_keyword("await"));
754    }
755    #[test]
756    pub(super) fn test_is_swift_keyword_false() {
757        assert!(!is_swift_keyword("myFunc"));
758        assert!(!is_swift_keyword("data"));
759        assert!(!is_swift_keyword("oxilean"));
760    }
761    #[test]
762    pub(super) fn test_compile_decl_simple() {
763        use crate::lcnf::{LcnfFunDecl, LcnfParam as LParam, LcnfVarId};
764        let decl = LcnfFunDecl {
765            name: "myFn".to_string(),
766            original_name: None,
767            params: vec![LParam {
768                id: LcnfVarId(0),
769                name: "x".to_string(),
770                ty: LcnfType::Nat,
771                erased: false,
772                borrowed: false,
773            }],
774            body: LcnfExpr::Return(LcnfArg::Var(LcnfVarId(0))),
775            ret_type: LcnfType::Nat,
776            is_recursive: false,
777            is_lifted: false,
778            inline_cost: 0,
779        };
780        let backend = SwiftBackend::new();
781        let func = backend.compile_decl(&decl);
782        assert_eq!(func.name, "myFn");
783        assert_eq!(func.params.len(), 1);
784        let out = func.codegen();
785        assert!(out.contains("func myFn("));
786        assert!(out.contains("return _x0"));
787    }
788    #[test]
789    pub(super) fn test_compile_module_empty() {
790        let backend = SwiftBackend::new();
791        let module = backend.compile_module("EmptyMod", &[]);
792        let out = module.codegen();
793        assert!(out.contains("OxiLean-generated Swift module: EmptyMod"));
794        assert!(out.contains("import Foundation"));
795    }
796    #[test]
797    pub(super) fn test_fresh_var() {
798        let mut backend = SwiftBackend::new();
799        assert_eq!(backend.fresh_var(), "_ox0");
800        assert_eq!(backend.fresh_var(), "_ox1");
801        assert_eq!(backend.fresh_var(), "_ox2");
802    }
803    #[test]
804    pub(super) fn test_backend_default() {
805        let b = SwiftBackend::default();
806        assert!(b.emit_public);
807        assert!(b.emit_comments);
808    }
809    #[test]
810    pub(super) fn test_runtime_contains_ox_panic() {
811        assert!(OXILEAN_SWIFT_RUNTIME.contains("func ox_panic"));
812    }
813    #[test]
814    pub(super) fn test_runtime_contains_ox_unreachable() {
815        assert!(OXILEAN_SWIFT_RUNTIME.contains("func ox_unreachable"));
816    }
817}
818#[cfg(test)]
819mod Swift_infra_tests {
820    use super::*;
821    #[test]
822    pub(super) fn test_pass_config() {
823        let config = SwiftPassConfig::new("test_pass", SwiftPassPhase::Transformation);
824        assert!(config.enabled);
825        assert!(config.phase.is_modifying());
826        assert_eq!(config.phase.name(), "transformation");
827    }
828    #[test]
829    pub(super) fn test_pass_stats() {
830        let mut stats = SwiftPassStats::new();
831        stats.record_run(10, 100, 3);
832        stats.record_run(20, 200, 5);
833        assert_eq!(stats.total_runs, 2);
834        assert!((stats.average_changes_per_run() - 15.0).abs() < 0.01);
835        assert!((stats.success_rate() - 1.0).abs() < 0.01);
836        let s = stats.format_summary();
837        assert!(s.contains("Runs: 2/2"));
838    }
839    #[test]
840    pub(super) fn test_pass_registry() {
841        let mut reg = SwiftPassRegistry::new();
842        reg.register(SwiftPassConfig::new("pass_a", SwiftPassPhase::Analysis));
843        reg.register(SwiftPassConfig::new("pass_b", SwiftPassPhase::Transformation).disabled());
844        assert_eq!(reg.total_passes(), 2);
845        assert_eq!(reg.enabled_count(), 1);
846        reg.update_stats("pass_a", 5, 50, 2);
847        let stats = reg.get_stats("pass_a").expect("stats should exist");
848        assert_eq!(stats.total_changes, 5);
849    }
850    #[test]
851    pub(super) fn test_analysis_cache() {
852        let mut cache = SwiftAnalysisCache::new(10);
853        cache.insert("key1".to_string(), vec![1, 2, 3]);
854        assert!(cache.get("key1").is_some());
855        assert!(cache.get("key2").is_none());
856        assert!((cache.hit_rate() - 0.5).abs() < 0.01);
857        cache.invalidate("key1");
858        assert!(!cache.entries["key1"].valid);
859        assert_eq!(cache.size(), 1);
860    }
861    #[test]
862    pub(super) fn test_worklist() {
863        let mut wl = SwiftWorklist::new();
864        assert!(wl.push(1));
865        assert!(wl.push(2));
866        assert!(!wl.push(1));
867        assert_eq!(wl.len(), 2);
868        assert_eq!(wl.pop(), Some(1));
869        assert!(!wl.contains(1));
870        assert!(wl.contains(2));
871    }
872    #[test]
873    pub(super) fn test_dominator_tree() {
874        let mut dt = SwiftDominatorTree::new(5);
875        dt.set_idom(1, 0);
876        dt.set_idom(2, 0);
877        dt.set_idom(3, 1);
878        assert!(dt.dominates(0, 3));
879        assert!(dt.dominates(1, 3));
880        assert!(!dt.dominates(2, 3));
881        assert!(dt.dominates(3, 3));
882    }
883    #[test]
884    pub(super) fn test_liveness() {
885        let mut liveness = SwiftLivenessInfo::new(3);
886        liveness.add_def(0, 1);
887        liveness.add_use(1, 1);
888        assert!(liveness.defs[0].contains(&1));
889        assert!(liveness.uses[1].contains(&1));
890    }
891    #[test]
892    pub(super) fn test_constant_folding() {
893        assert_eq!(SwiftConstantFoldingHelper::fold_add_i64(3, 4), Some(7));
894        assert_eq!(SwiftConstantFoldingHelper::fold_div_i64(10, 0), None);
895        assert_eq!(SwiftConstantFoldingHelper::fold_div_i64(10, 2), Some(5));
896        assert_eq!(
897            SwiftConstantFoldingHelper::fold_bitand_i64(0b1100, 0b1010),
898            0b1000
899        );
900        assert_eq!(SwiftConstantFoldingHelper::fold_bitnot_i64(0), -1);
901    }
902    #[test]
903    pub(super) fn test_dep_graph() {
904        let mut g = SwiftDepGraph::new();
905        g.add_dep(1, 2);
906        g.add_dep(2, 3);
907        g.add_dep(1, 3);
908        assert_eq!(g.dependencies_of(2), vec![1]);
909        let topo = g.topological_sort();
910        assert_eq!(topo.len(), 3);
911        assert!(!g.has_cycle());
912        let pos: std::collections::HashMap<u32, usize> =
913            topo.iter().enumerate().map(|(i, &n)| (n, i)).collect();
914        assert!(pos[&1] < pos[&2]);
915        assert!(pos[&1] < pos[&3]);
916        assert!(pos[&2] < pos[&3]);
917    }
918}