1use crate::lcnf::*;
6use std::collections::HashMap;
7
8use super::types::{
9 RustAnalysisCache, RustConstantFoldingHelper, RustDepGraph, RustDominatorTree, RustEnum,
10 RustExpr, RustFn, RustImpl, RustItem, RustLit, RustLivenessInfo, RustModule, RustPassConfig,
11 RustPassPhase, RustPassRegistry, RustPassStats, RustPattern, RustStmt, RustStruct,
12 RustStructFields, RustTargetBackend, RustType, RustVariant, RustVisibility, RustWorklist,
13};
14
15pub(super) fn emit_expr(expr: &RustExpr, indent: usize) -> std::string::String {
16 match expr {
17 RustExpr::Lit(lit) => lit.to_string(),
18 RustExpr::Var(name) => name.clone(),
19 RustExpr::BinOp { op, lhs, rhs } => {
20 format!(
21 "({} {} {})",
22 emit_expr(lhs, indent),
23 op,
24 emit_expr(rhs, indent)
25 )
26 }
27 RustExpr::UnaryOp { op, operand } => {
28 format!("({}{})", op, emit_expr(operand, indent))
29 }
30 RustExpr::Block(stmts, tail) => {
31 let pad = " ".repeat(indent);
32 let inner_pad = " ".repeat(indent + 1);
33 let mut out = "{\n".to_string();
34 for s in stmts {
35 out.push_str(&format!("{}{}\n", inner_pad, emit_stmt(s, indent + 1)));
36 }
37 if let Some(te) = tail {
38 out.push_str(&format!("{}{}\n", inner_pad, emit_expr(te, indent + 1)));
39 }
40 out.push_str(&format!("{}}}", pad));
41 out
42 }
43 RustExpr::If {
44 cond,
45 then_block,
46 else_block,
47 } => {
48 let pad = " ".repeat(indent);
49 let inner_pad = " ".repeat(indent + 1);
50 let mut out = format!("if {} {{\n", emit_expr(cond, indent));
51 for s in then_block {
52 out.push_str(&format!("{}{}\n", inner_pad, emit_stmt(s, indent + 1)));
53 }
54 out.push_str(&format!("{}}}", pad));
55 if let Some(eb) = else_block {
56 out.push_str(" else {\n");
57 for s in eb {
58 out.push_str(&format!("{}{}\n", inner_pad, emit_stmt(s, indent + 1)));
59 }
60 out.push_str(&format!("{}}}", pad));
61 }
62 out
63 }
64 RustExpr::Match { scrutinee, arms } => {
65 let pad = " ".repeat(indent);
66 let inner_pad = " ".repeat(indent + 1);
67 let mut out = format!("match {} {{\n", emit_expr(scrutinee, indent));
68 for (pat, body) in arms {
69 out.push_str(&format!(
70 "{}{} => {},\n",
71 inner_pad,
72 pat,
73 emit_expr(body, indent + 1)
74 ));
75 }
76 out.push_str(&format!("{}}}", pad));
77 out
78 }
79 RustExpr::Loop(body) => {
80 let pad = " ".repeat(indent);
81 let inner_pad = " ".repeat(indent + 1);
82 let mut out = "loop {\n".to_string();
83 for s in body {
84 out.push_str(&format!("{}{}\n", inner_pad, emit_stmt(s, indent + 1)));
85 }
86 out.push_str(&format!("{}}}", pad));
87 out
88 }
89 RustExpr::For { pat, iter, body } => {
90 let pad = " ".repeat(indent);
91 let inner_pad = " ".repeat(indent + 1);
92 let mut out = format!("for {} in {} {{\n", pat, emit_expr(iter, indent));
93 for s in body {
94 out.push_str(&format!("{}{}\n", inner_pad, emit_stmt(s, indent + 1)));
95 }
96 out.push_str(&format!("{}}}", pad));
97 out
98 }
99 RustExpr::While { cond, body } => {
100 let pad = " ".repeat(indent);
101 let inner_pad = " ".repeat(indent + 1);
102 let mut out = format!("while {} {{\n", emit_expr(cond, indent));
103 for s in body {
104 out.push_str(&format!("{}{}\n", inner_pad, emit_stmt(s, indent + 1)));
105 }
106 out.push_str(&format!("{}}}", pad));
107 out
108 }
109 RustExpr::Return(expr) => match expr {
110 Some(e) => format!("return {}", emit_expr(e, indent)),
111 None => "return".to_string(),
112 },
113 RustExpr::Break(expr) => match expr {
114 Some(e) => format!("break {}", emit_expr(e, indent)),
115 None => "break".to_string(),
116 },
117 RustExpr::Continue => "continue".to_string(),
118 RustExpr::Closure {
119 params,
120 ret_ty,
121 body,
122 is_move,
123 } => {
124 let move_kw = if *is_move { "move " } else { "" };
125 let params_str = params
126 .iter()
127 .map(|(n, ty)| {
128 if let Some(t) = ty {
129 format!("{}: {}", n, t)
130 } else {
131 n.clone()
132 }
133 })
134 .collect::<Vec<_>>()
135 .join(", ");
136 let ret_str = ret_ty
137 .as_ref()
138 .map(|t| format!(" -> {} ", t))
139 .unwrap_or_default();
140 format!(
141 "{}|{}|{}{}",
142 move_kw,
143 params_str,
144 ret_str,
145 emit_expr(body, indent)
146 )
147 }
148 RustExpr::Call(func, args) => {
149 let args_str = args
150 .iter()
151 .map(|a| emit_expr(a, indent))
152 .collect::<Vec<_>>()
153 .join(", ");
154 format!("{}({})", emit_expr(func, indent), args_str)
155 }
156 RustExpr::MethodCall {
157 receiver,
158 method,
159 args,
160 } => {
161 let args_str = args
162 .iter()
163 .map(|a| emit_expr(a, indent))
164 .collect::<Vec<_>>()
165 .join(", ");
166 format!("{}.{}({})", emit_expr(receiver, indent), method, args_str)
167 }
168 RustExpr::Field(obj, field) => format!("{}.{}", emit_expr(obj, indent), field),
169 RustExpr::Index(obj, idx) => {
170 format!("{}[{}]", emit_expr(obj, indent), emit_expr(idx, indent))
171 }
172 RustExpr::Ref(mutable, inner) => {
173 if *mutable {
174 format!("&mut {}", emit_expr(inner, indent))
175 } else {
176 format!("&{}", emit_expr(inner, indent))
177 }
178 }
179 RustExpr::Deref(inner) => format!("*{}", emit_expr(inner, indent)),
180 RustExpr::Struct(name, fields) => {
181 if fields.is_empty() {
182 name.clone()
183 } else {
184 let fstr = fields
185 .iter()
186 .map(|(n, e)| format!("{}: {}", n, emit_expr(e, indent)))
187 .collect::<Vec<_>>()
188 .join(", ");
189 format!("{} {{ {} }}", name, fstr)
190 }
191 }
192 RustExpr::Tuple(elems) => {
193 let es = elems
194 .iter()
195 .map(|e| emit_expr(e, indent))
196 .collect::<Vec<_>>()
197 .join(", ");
198 if elems.len() == 1 {
199 format!("({},)", es)
200 } else {
201 format!("({})", es)
202 }
203 }
204 RustExpr::Array(elems) => {
205 let es = elems
206 .iter()
207 .map(|e| emit_expr(e, indent))
208 .collect::<Vec<_>>()
209 .join(", ");
210 format!("[{}]", es)
211 }
212 RustExpr::Range(lo, hi, inclusive) => {
213 let lo_str = lo
214 .as_ref()
215 .map(|e| emit_expr(e, indent))
216 .unwrap_or_default();
217 let hi_str = hi
218 .as_ref()
219 .map(|e| emit_expr(e, indent))
220 .unwrap_or_default();
221 let sep = if *inclusive { "..=" } else { ".." };
222 format!("{}{}{}", lo_str, sep, hi_str)
223 }
224 RustExpr::Try(inner) => format!("{}?", emit_expr(inner, indent)),
225 RustExpr::Await(inner) => format!("{}.await", emit_expr(inner, indent)),
226 RustExpr::Path(segments) => segments.join("::"),
227 RustExpr::MacroCall(name, args) => format!("{}!({})", name, args),
228 }
229}
230pub(super) fn emit_stmt(stmt: &RustStmt, indent: usize) -> std::string::String {
231 match stmt {
232 RustStmt::Let { pat, ty, value } => {
233 let ty_str = ty.as_ref().map(|t| format!(": {}", t)).unwrap_or_default();
234 let val_str = value
235 .as_ref()
236 .map(|v| format!(" = {}", emit_expr(v, indent)))
237 .unwrap_or_default();
238 format!("let {}{}{};", pat, ty_str, val_str)
239 }
240 RustStmt::Expr(e) => format!("{};", emit_expr(e, indent)),
241 RustStmt::ExprNoSemi(e) => emit_expr(e, indent),
242 RustStmt::Return(e) => match e {
243 Some(expr) => format!("return {};", emit_expr(expr, indent)),
244 None => "return;".to_string(),
245 },
246 RustStmt::Break(e) => match e {
247 Some(expr) => format!("break {};", emit_expr(expr, indent)),
248 None => "break;".to_string(),
249 },
250 RustStmt::Continue => "continue;".to_string(),
251 }
252}
253pub const RUST_KEYWORDS: &[&str] = &[
255 "as", "async", "await", "break", "const", "continue", "crate", "dyn", "else", "enum", "extern",
256 "false", "fn", "for", "if", "impl", "in", "let", "loop", "match", "mod", "move", "mut", "pub",
257 "ref", "return", "self", "Self", "static", "struct", "super", "trait", "true", "type", "union",
258 "unsafe", "use", "where", "while",
259];
260#[cfg(test)]
261mod tests {
262 use super::*;
263 #[test]
264 pub(super) fn test_rust_type_primitives() {
265 assert_eq!(RustType::I32.to_string(), "i32");
266 assert_eq!(RustType::U64.to_string(), "u64");
267 assert_eq!(RustType::F64.to_string(), "f64");
268 assert_eq!(RustType::Bool.to_string(), "bool");
269 assert_eq!(RustType::Unit.to_string(), "()");
270 assert_eq!(RustType::Never.to_string(), "!");
271 }
272 #[test]
273 pub(super) fn test_rust_type_string() {
274 assert_eq!(RustType::RustString.to_string(), "String");
275 }
276 #[test]
277 pub(super) fn test_rust_type_vec() {
278 assert_eq!(
279 RustType::Vec(Box::new(RustType::I32)).to_string(),
280 "Vec<i32>"
281 );
282 }
283 #[test]
284 pub(super) fn test_rust_type_option() {
285 assert_eq!(
286 RustType::Option(Box::new(RustType::U64)).to_string(),
287 "Option<u64>"
288 );
289 }
290 #[test]
291 pub(super) fn test_rust_type_result() {
292 let r = RustType::Result(Box::new(RustType::I32), Box::new(RustType::RustString));
293 assert_eq!(r.to_string(), "Result<i32, String>");
294 }
295 #[test]
296 pub(super) fn test_rust_type_tuple() {
297 let t = RustType::Tuple(vec![RustType::I32, RustType::Bool]);
298 assert_eq!(t.to_string(), "(i32, bool)");
299 }
300 #[test]
301 pub(super) fn test_rust_type_tuple_single() {
302 let t = RustType::Tuple(vec![RustType::I32]);
303 assert_eq!(t.to_string(), "(i32,)");
304 }
305 #[test]
306 pub(super) fn test_rust_type_ref() {
307 assert_eq!(
308 RustType::Ref(false, Box::new(RustType::I32)).to_string(),
309 "&i32"
310 );
311 assert_eq!(
312 RustType::Ref(true, Box::new(RustType::I32)).to_string(),
313 "&mut i32"
314 );
315 }
316 #[test]
317 pub(super) fn test_rust_type_generic() {
318 let t = RustType::Generic(
319 "HashMap".to_string(),
320 vec![RustType::RustString, RustType::I32],
321 );
322 assert_eq!(t.to_string(), "HashMap<String, i32>");
323 }
324 #[test]
325 pub(super) fn test_rust_type_fn() {
326 let t = RustType::Fn(vec![RustType::I32, RustType::I32], Box::new(RustType::I32));
327 assert_eq!(t.to_string(), "impl Fn(i32, i32) -> i32");
328 }
329 #[test]
330 pub(super) fn test_rust_type_lifetime() {
331 assert_eq!(RustType::Lifetime("a".to_string()).to_string(), "'a");
332 }
333 #[test]
334 pub(super) fn test_rust_lit_int() {
335 assert_eq!(RustLit::Int(42).to_string(), "42");
336 assert_eq!(RustLit::Int(-7).to_string(), "-7");
337 }
338 #[test]
339 pub(super) fn test_rust_lit_uint() {
340 assert_eq!(RustLit::UInt(100).to_string(), "100");
341 }
342 #[test]
343 pub(super) fn test_rust_lit_float() {
344 assert_eq!(RustLit::Float(3.14).to_string(), "3.14");
345 assert_eq!(RustLit::Float(1.0).to_string(), "1.0");
346 }
347 #[test]
348 pub(super) fn test_rust_lit_bool() {
349 assert_eq!(RustLit::Bool(true).to_string(), "true");
350 assert_eq!(RustLit::Bool(false).to_string(), "false");
351 }
352 #[test]
353 pub(super) fn test_rust_lit_str_escape() {
354 let s = RustLit::Str("hello\nworld".to_string());
355 assert_eq!(s.to_string(), "\"hello\\nworld\"");
356 }
357 #[test]
358 pub(super) fn test_rust_lit_unit() {
359 assert_eq!(RustLit::Unit.to_string(), "()");
360 }
361 #[test]
362 pub(super) fn test_rust_pattern_wildcard() {
363 assert_eq!(RustPattern::Wildcard.to_string(), "_");
364 }
365 #[test]
366 pub(super) fn test_rust_pattern_var() {
367 assert_eq!(RustPattern::Var("x".to_string(), false).to_string(), "x");
368 assert_eq!(RustPattern::Var("x".to_string(), true).to_string(), "mut x");
369 }
370 #[test]
371 pub(super) fn test_rust_pattern_enum() {
372 let p = RustPattern::Enum(
373 "Some".to_string(),
374 vec![RustPattern::Var("v".to_string(), false)],
375 );
376 assert_eq!(p.to_string(), "Some(v)");
377 }
378 #[test]
379 pub(super) fn test_rust_pattern_tuple() {
380 let p = RustPattern::Tuple(vec![
381 RustPattern::Var("a".to_string(), false),
382 RustPattern::Var("b".to_string(), false),
383 ]);
384 assert_eq!(p.to_string(), "(a, b)");
385 }
386 #[test]
387 pub(super) fn test_rust_pattern_or() {
388 let p = RustPattern::Or(vec![
389 RustPattern::Lit(RustLit::Int(1)),
390 RustPattern::Lit(RustLit::Int(2)),
391 ]);
392 assert_eq!(p.to_string(), "1 | 2");
393 }
394 #[test]
395 pub(super) fn test_rust_expr_lit() {
396 assert_eq!(RustExpr::Lit(RustLit::Int(42)).to_string(), "42");
397 }
398 #[test]
399 pub(super) fn test_rust_expr_var() {
400 assert_eq!(RustExpr::Var("x".to_string()).to_string(), "x");
401 }
402 #[test]
403 pub(super) fn test_rust_expr_binop() {
404 let e = RustExpr::BinOp {
405 op: "+".to_string(),
406 lhs: Box::new(RustExpr::Var("a".to_string())),
407 rhs: Box::new(RustExpr::Lit(RustLit::Int(1))),
408 };
409 assert_eq!(e.to_string(), "(a + 1)");
410 }
411 #[test]
412 pub(super) fn test_rust_expr_unary() {
413 let e = RustExpr::UnaryOp {
414 op: "!".to_string(),
415 operand: Box::new(RustExpr::Var("x".to_string())),
416 };
417 assert_eq!(e.to_string(), "(!x)");
418 }
419 #[test]
420 pub(super) fn test_rust_expr_call() {
421 let e = RustExpr::Call(
422 Box::new(RustExpr::Var("foo".to_string())),
423 vec![
424 RustExpr::Lit(RustLit::Int(1)),
425 RustExpr::Lit(RustLit::Int(2)),
426 ],
427 );
428 assert_eq!(e.to_string(), "foo(1, 2)");
429 }
430 #[test]
431 pub(super) fn test_rust_expr_method_call() {
432 let e = RustExpr::MethodCall {
433 receiver: Box::new(RustExpr::Var("v".to_string())),
434 method: "push".to_string(),
435 args: vec![RustExpr::Lit(RustLit::Int(42))],
436 };
437 assert_eq!(e.to_string(), "v.push(42)");
438 }
439 #[test]
440 pub(super) fn test_rust_expr_field() {
441 let e = RustExpr::Field(Box::new(RustExpr::Var("s".to_string())), "name".to_string());
442 assert_eq!(e.to_string(), "s.name");
443 }
444 #[test]
445 pub(super) fn test_rust_expr_closure() {
446 let e = RustExpr::Closure {
447 params: vec![("x".to_string(), Some(RustType::I32))],
448 ret_ty: Some(RustType::I32),
449 body: Box::new(RustExpr::Var("x".to_string())),
450 is_move: false,
451 };
452 let s = e.to_string();
453 assert!(s.contains("|x: i32|"), "Got: {}", s);
454 assert!(s.contains("-> i32"), "Got: {}", s);
455 }
456 #[test]
457 pub(super) fn test_rust_expr_macro_call() {
458 let e = RustExpr::MacroCall("println".to_string(), "\"hello\"".to_string());
459 assert_eq!(e.to_string(), "println!(\"hello\")");
460 }
461 #[test]
462 pub(super) fn test_rust_expr_range() {
463 let e = RustExpr::Range(
464 Some(Box::new(RustExpr::Lit(RustLit::Int(0)))),
465 Some(Box::new(RustExpr::Lit(RustLit::Int(10)))),
466 false,
467 );
468 assert_eq!(e.to_string(), "0..10");
469 }
470 #[test]
471 pub(super) fn test_rust_expr_range_inclusive() {
472 let e = RustExpr::Range(
473 Some(Box::new(RustExpr::Lit(RustLit::Int(1)))),
474 Some(Box::new(RustExpr::Lit(RustLit::Int(5)))),
475 true,
476 );
477 assert_eq!(e.to_string(), "1..=5");
478 }
479 #[test]
480 pub(super) fn test_rust_expr_try() {
481 let e = RustExpr::Try(Box::new(RustExpr::Call(
482 Box::new(RustExpr::Var("do_thing".to_string())),
483 vec![],
484 )));
485 assert_eq!(e.to_string(), "do_thing()?");
486 }
487 #[test]
488 pub(super) fn test_rust_expr_path() {
489 let e = RustExpr::Path(vec![
490 "std".to_string(),
491 "collections".to_string(),
492 "HashMap".to_string(),
493 ]);
494 assert_eq!(e.to_string(), "std::collections::HashMap");
495 }
496 #[test]
497 pub(super) fn test_rust_stmt_let() {
498 let s = RustStmt::Let {
499 pat: RustPattern::Var("x".to_string(), false),
500 ty: Some(RustType::I32),
501 value: Some(RustExpr::Lit(RustLit::Int(5))),
502 };
503 assert_eq!(s.to_string(), "let x: i32 = 5;");
504 }
505 #[test]
506 pub(super) fn test_rust_stmt_expr() {
507 let s = RustStmt::Expr(RustExpr::MacroCall(
508 "println".to_string(),
509 "\"hi\"".to_string(),
510 ));
511 assert_eq!(s.to_string(), "println!(\"hi\");");
512 }
513 #[test]
514 pub(super) fn test_rust_fn_emit_simple() {
515 let func = RustFn::new(
516 "add",
517 vec![
518 ("a".to_string(), RustType::I32, false),
519 ("b".to_string(), RustType::I32, false),
520 ],
521 Some(RustType::I32),
522 vec![RustStmt::ExprNoSemi(RustExpr::BinOp {
523 op: "+".to_string(),
524 lhs: Box::new(RustExpr::Var("a".to_string())),
525 rhs: Box::new(RustExpr::Var("b".to_string())),
526 })],
527 );
528 let s = func.emit();
529 assert!(s.contains("fn add(a: i32, b: i32) -> i32"), "Got: {}", s);
530 assert!(s.contains("(a + b)"), "Got: {}", s);
531 }
532 #[test]
533 pub(super) fn test_rust_fn_async_unsafe() {
534 let func = RustFn {
535 name: "dangerous".to_string(),
536 generics: vec![],
537 params: vec![],
538 return_type: Some(RustType::Unit),
539 body: vec![],
540 attrs: vec![],
541 visibility: RustVisibility::Pub,
542 is_async: true,
543 is_unsafe: true,
544 };
545 let s = func.emit();
546 assert!(s.contains("async unsafe fn dangerous()"), "Got: {}", s);
547 }
548 #[test]
549 pub(super) fn test_rust_fn_with_generics() {
550 let func = RustFn {
551 name: "identity".to_string(),
552 generics: vec![("T".to_string(), vec!["Clone".to_string()])],
553 params: vec![("x".to_string(), RustType::Custom("T".to_string()), false)],
554 return_type: Some(RustType::Custom("T".to_string())),
555 body: vec![RustStmt::ExprNoSemi(RustExpr::Var("x".to_string()))],
556 attrs: vec![],
557 visibility: RustVisibility::Pub,
558 is_async: false,
559 is_unsafe: false,
560 };
561 let s = func.emit();
562 assert!(s.contains("fn identity<T: Clone>(x: T) -> T"), "Got: {}", s);
563 }
564 #[test]
565 pub(super) fn test_rust_struct_named_fields() {
566 let s = RustStruct {
567 name: "Point".to_string(),
568 generics: vec![],
569 fields: RustStructFields::Named(vec![
570 ("x".to_string(), RustType::F64, RustVisibility::Pub),
571 ("y".to_string(), RustType::F64, RustVisibility::Pub),
572 ]),
573 attrs: vec![],
574 derives: vec!["Debug".to_string(), "Clone".to_string()],
575 visibility: RustVisibility::Pub,
576 };
577 let out = s.emit();
578 assert!(out.contains("#[derive(Debug, Clone)]"), "Got: {}", out);
579 assert!(out.contains("pub struct Point {"), "Got: {}", out);
580 assert!(out.contains("x:f64"), "Got: {}", out);
581 }
582 #[test]
583 pub(super) fn test_rust_struct_unit() {
584 let s = RustStruct {
585 name: "Sentinel".to_string(),
586 generics: vec![],
587 fields: RustStructFields::Unit,
588 attrs: vec![],
589 derives: vec![],
590 visibility: RustVisibility::Pub,
591 };
592 let out = s.emit();
593 assert_eq!(out, "pub struct Sentinel;");
594 }
595 #[test]
596 pub(super) fn test_rust_enum_emit() {
597 let e = RustEnum {
598 name: "Shape".to_string(),
599 generics: vec![],
600 variants: vec![
601 RustVariant::Unit("Circle".to_string()),
602 RustVariant::Tuple("Rect".to_string(), vec![RustType::F64, RustType::F64]),
603 ],
604 attrs: vec![],
605 derives: vec!["Debug".to_string()],
606 visibility: RustVisibility::Pub,
607 };
608 let out = e.emit();
609 assert!(out.contains("#[derive(Debug)]"), "Got: {}", out);
610 assert!(out.contains("pub enum Shape {"), "Got: {}", out);
611 assert!(out.contains("Circle,"), "Got: {}", out);
612 assert!(out.contains("Rect(f64, f64),"), "Got: {}", out);
613 }
614 #[test]
615 pub(super) fn test_rust_impl_emit() {
616 let f = RustFn::new(
617 "area",
618 vec![(
619 "self".to_string(),
620 RustType::Custom("Self".to_string()),
621 false,
622 )],
623 Some(RustType::F64),
624 vec![],
625 );
626 let imp = RustImpl {
627 for_type: "Circle".to_string(),
628 trait_impl: None,
629 generics: vec![],
630 methods: vec![f],
631 associated_types: vec![],
632 };
633 let out = imp.emit();
634 assert!(out.contains("impl Circle {"), "Got: {}", out);
635 assert!(out.contains("fn area"), "Got: {}", out);
636 }
637 #[test]
638 pub(super) fn test_rust_impl_trait() {
639 let imp = RustImpl {
640 for_type: "MyType".to_string(),
641 trait_impl: Some("Display".to_string()),
642 generics: vec![],
643 methods: vec![],
644 associated_types: vec![],
645 };
646 let out = imp.emit();
647 assert!(out.contains("impl Display for MyType {"), "Got: {}", out);
648 }
649 #[test]
650 pub(super) fn test_rust_module_emit_use() {
651 let mut m = RustModule::new("my_module");
652 m.items.push(RustItem::Use {
653 path: "std::collections::HashMap".to_string(),
654 visibility: RustVisibility::Private,
655 });
656 let out = m.emit();
657 assert!(
658 out.contains("use std::collections::HashMap;"),
659 "Got: {}",
660 out
661 );
662 }
663 #[test]
664 pub(super) fn test_rust_module_const() {
665 let mut m = RustModule::new("consts");
666 m.items.push(RustItem::Const {
667 name: "MAX".to_string(),
668 ty: RustType::U64,
669 value: RustExpr::Lit(RustLit::UInt(1000)),
670 visibility: RustVisibility::Pub,
671 });
672 let out = m.emit();
673 assert!(out.contains("pub const MAX: u64 = 1000;"), "Got: {}", out);
674 }
675 #[test]
676 pub(super) fn test_mangle_name_keyword() {
677 let mut b = RustTargetBackend::new();
678 assert_eq!(b.mangle_name("type"), "type_");
679 assert_eq!(b.mangle_name("fn"), "fn_");
680 }
681 #[test]
682 pub(super) fn test_mangle_name_dot() {
683 let mut b = RustTargetBackend::new();
684 assert_eq!(b.mangle_name("Nat.add"), "Nat_add");
685 }
686 #[test]
687 pub(super) fn test_mangle_name_empty() {
688 let mut b = RustTargetBackend::new();
689 assert_eq!(b.mangle_name(""), "_anon");
690 }
691 #[test]
692 pub(super) fn test_fresh_var() {
693 let mut b = RustTargetBackend::new();
694 assert_eq!(b.fresh_var(), "_t0");
695 assert_eq!(b.fresh_var(), "_t1");
696 }
697 #[test]
698 pub(super) fn test_compile_decl_simple() {
699 let decl = LcnfFunDecl {
700 name: "answer".to_string(),
701 original_name: None,
702 params: vec![],
703 ret_type: LcnfType::Nat,
704 body: LcnfExpr::Return(LcnfArg::Lit(LcnfLit::Nat(42))),
705 is_recursive: false,
706 is_lifted: false,
707 inline_cost: 0,
708 };
709 let mut b = RustTargetBackend::new();
710 let func = b
711 .compile_decl(&decl)
712 .expect("func compilation should succeed");
713 assert_eq!(func.name, "answer");
714 let s = func.emit();
715 assert!(s.contains("fn answer()"), "Got: {}", s);
716 assert!(s.contains("-> u64"), "Got: {}", s);
717 assert!(s.contains("42"), "Got: {}", s);
718 }
719 #[test]
720 pub(super) fn test_compile_decl_with_param() {
721 let x_id = LcnfVarId(0);
722 let decl = LcnfFunDecl {
723 name: "identity".to_string(),
724 original_name: None,
725 params: vec![LcnfParam {
726 id: x_id,
727 name: "x".to_string(),
728 ty: LcnfType::Nat,
729 erased: false,
730 borrowed: false,
731 }],
732 ret_type: LcnfType::Nat,
733 body: LcnfExpr::Return(LcnfArg::Var(x_id)),
734 is_recursive: false,
735 is_lifted: false,
736 inline_cost: 0,
737 };
738 let mut b = RustTargetBackend::new();
739 let func = b
740 .compile_decl(&decl)
741 .expect("func compilation should succeed");
742 let s = func.emit();
743 assert!(s.contains("fn identity("), "Got: {}", s);
744 assert!(s.contains(": u64"), "Got: {}", s);
745 }
746 #[test]
747 pub(super) fn test_emit_module_multiple_decls() {
748 let decl1 = LcnfFunDecl {
749 name: "one".to_string(),
750 original_name: None,
751 params: vec![],
752 ret_type: LcnfType::Nat,
753 body: LcnfExpr::Return(LcnfArg::Lit(LcnfLit::Nat(1))),
754 is_recursive: false,
755 is_lifted: false,
756 inline_cost: 0,
757 };
758 let decl2 = LcnfFunDecl {
759 name: "two".to_string(),
760 original_name: None,
761 params: vec![],
762 ret_type: LcnfType::Nat,
763 body: LcnfExpr::Return(LcnfArg::Lit(LcnfLit::Nat(2))),
764 is_recursive: false,
765 is_lifted: false,
766 inline_cost: 0,
767 };
768 let mut b = RustTargetBackend::new();
769 let module = b.emit_module("test_mod", &[decl1, decl2]);
770 assert_eq!(module.items.len(), 2);
771 let s = module.emit();
772 assert!(s.contains("fn one()"), "Got: {}", s);
773 assert!(s.contains("fn two()"), "Got: {}", s);
774 }
775 #[test]
776 pub(super) fn test_rust_item_mod() {
777 let inner_use = RustItem::Use {
778 path: "super::*".to_string(),
779 visibility: RustVisibility::Private,
780 };
781 let m = RustItem::Mod {
782 name: "inner".to_string(),
783 items: vec![inner_use],
784 visibility: RustVisibility::Pub,
785 };
786 let out = m.emit();
787 assert!(out.contains("pub mod inner {"), "Got: {}", out);
788 assert!(out.contains("use super::*;"), "Got: {}", out);
789 }
790 #[test]
791 pub(super) fn test_rust_item_type_alias() {
792 let item = RustItem::TypeAlias {
793 name: "Bytes".to_string(),
794 generics: vec![],
795 ty: RustType::Vec(Box::new(RustType::U8)),
796 visibility: RustVisibility::Pub,
797 };
798 assert_eq!(item.emit(), "pub type Bytes = Vec<u8>;");
799 }
800 #[test]
801 pub(super) fn test_rust_item_static() {
802 let item = RustItem::Static {
803 name: "COUNTER".to_string(),
804 ty: RustType::U64,
805 value: RustExpr::Lit(RustLit::UInt(0)),
806 mutable: true,
807 visibility: RustVisibility::Private,
808 };
809 assert_eq!(item.emit(), "static mut COUNTER: u64 = 0;");
810 }
811 #[test]
812 pub(super) fn test_rust_visibility_display() {
813 assert_eq!(RustVisibility::Private.to_string(), "");
814 assert_eq!(RustVisibility::Pub.to_string(), "pub ");
815 assert_eq!(RustVisibility::PubCrate.to_string(), "pub(crate) ");
816 }
817}
818#[cfg(test)]
819mod Rust_infra_tests {
820 use super::*;
821 #[test]
822 pub(super) fn test_pass_config() {
823 let config = RustPassConfig::new("test_pass", RustPassPhase::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 = RustPassStats::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 = RustPassRegistry::new();
842 reg.register(RustPassConfig::new("pass_a", RustPassPhase::Analysis));
843 reg.register(RustPassConfig::new("pass_b", RustPassPhase::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 = RustAnalysisCache::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 = RustWorklist::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 = RustDominatorTree::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 = RustLivenessInfo::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!(RustConstantFoldingHelper::fold_add_i64(3, 4), Some(7));
894 assert_eq!(RustConstantFoldingHelper::fold_div_i64(10, 0), None);
895 assert_eq!(RustConstantFoldingHelper::fold_div_i64(10, 2), Some(5));
896 assert_eq!(
897 RustConstantFoldingHelper::fold_bitand_i64(0b1100, 0b1010),
898 0b1000
899 );
900 assert_eq!(RustConstantFoldingHelper::fold_bitnot_i64(0), -1);
901 }
902 #[test]
903 pub(super) fn test_dep_graph() {
904 let mut g = RustDepGraph::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}