1use 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
15pub(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}
24pub(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}
149const 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];
240pub fn is_swift_keyword(name: &str) -> bool {
242 SWIFT_KEYWORDS.contains(&name)
243}
244pub 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}