1use crate::ast::*;
11
12use super::{
13 Ty, Types, bin_prec, escape, format_float, indent, op_str, rust_ident, to_pascal, to_snake,
14 ty_from_ann,
15};
16
17struct Gen {
18 t: Types,
19 out: String,
20 indent: usize,
21 uses_read_line: bool,
24 uses_run: bool,
27}
28
29const READ_LINE_HELPER: &str = "\
32fn read_line() -> Option<String> {
33 let mut line = String::new();
34 match std::io::stdin().read_line(&mut line) {
35 Ok(0) | Err(_) => None,
36 Ok(_) => Some(line.trim_end_matches(['\\n', '\\r']).to_string()),
37 }
38}
39";
40
41const RUN_HELPER: &str = "\
45#[derive(Debug, Clone, PartialEq)]
46struct Output {
47 status: i64,
48 stdout: String,
49 stderr: String,
50}
51
52fn run(program: String, args: Vec<String>) -> Result<Output, String> {
53 match std::process::Command::new(&program)
54 .args(&args)
55 .stdin(std::process::Stdio::null())
56 .output()
57 {
58 Ok(out) => Ok(Output {
59 status: out.status.code().unwrap_or(-1) as i64,
60 stdout: String::from_utf8_lossy(&out.stdout).into_owned(),
61 stderr: String::from_utf8_lossy(&out.stderr).into_owned(),
62 }),
63 Err(e) => Err(e.to_string()),
64 }
65}
66";
67
68pub fn to_rust(program: &[Stmt]) -> String {
70 let mut g = Gen {
71 t: Types::new(program),
72 out: String::new(),
73 indent: 0,
74 uses_read_line: false,
75 uses_run: false,
76 };
77
78 for stmt in program {
79 if let Stmt::Struct { name, fields, .. } = stmt {
80 g.emit_struct(name, fields);
81 }
82 }
83 for stmt in program {
84 if let Stmt::Enum { name, variants, .. } = stmt {
85 g.emit_enum(name, variants);
86 }
87 }
88 for stmt in program {
89 if let Stmt::Func {
90 name,
91 params,
92 ret,
93 body,
94 ..
95 } = stmt
96 {
97 g.emit_func(name, params, ret.as_ref(), body);
98 }
99 }
100
101 g.line("fn main() {".into());
102 g.indent += 1;
103 g.t.push_scope();
104 for stmt in program {
105 if !matches!(
106 stmt,
107 Stmt::Struct { .. } | Stmt::Enum { .. } | Stmt::Func { .. }
108 ) {
109 g.emit_stmt(stmt);
110 }
111 }
112 g.t.pop_scope();
113 g.indent -= 1;
114 g.line("}".into());
115
116 let mut preamble = String::new();
117 if g.uses_run {
118 preamble.push_str(RUN_HELPER);
119 preamble.push('\n');
120 }
121 if g.uses_read_line {
122 preamble.push_str(READ_LINE_HELPER);
123 preamble.push('\n');
124 }
125 format!("{}{}", preamble, g.out)
126}
127
128fn ty_text(t: &Ty) -> String {
130 match t {
131 Ty::Int => "i64".into(),
132 Ty::Float => "f64".into(),
133 Ty::Str => "String".into(),
134 Ty::Bool => "bool".into(),
135 Ty::Array(t) => format!("Vec<{}>", ty_text(t)),
136 Ty::User(n) => n.clone(),
137 Ty::Option(t) => format!("Option<{}>", ty_text(t)),
138 Ty::Result(a, b) => format!("Result<{}, {}>", ty_text(a), ty_text(b)),
139 Ty::Range => "std::ops::Range<i64>".into(),
140 Ty::Unit => "()".into(),
141 Ty::Unknown => "_".into(),
142 }
143}
144
145fn zero(t: &Ty) -> String {
147 match t {
148 Ty::Int => "0".into(),
149 Ty::Float => "0.0".into(),
150 Ty::Bool => "false".into(),
151 Ty::Str => "String::new()".into(),
152 Ty::Array(_) => "Vec::new()".into(),
153 Ty::Option(_) => "None".into(),
154 _ => "Default::default()".into(),
155 }
156}
157
158impl Gen {
159 fn line(&mut self, s: String) {
160 self.out.push_str(&indent(self.indent));
161 self.out.push_str(&s);
162 self.out.push('\n');
163 }
164
165 fn blank(&mut self) {
166 self.out.push('\n');
167 }
168
169 fn emit_struct(&mut self, name: &str, fields: &[FieldDef]) {
172 self.line("#[derive(Debug, Clone, PartialEq)]".into());
173 self.line(format!("struct {} {{", name));
174 for f in fields {
175 self.line(format!(
176 " {}: {},",
177 to_snake(&f.name),
178 ty_text(&ty_from_ann(&f.ty))
179 ));
180 }
181 self.line("}".into());
182 self.blank();
183 }
184
185 fn emit_enum(&mut self, name: &str, variants: &[VariantDef]) {
186 self.line("#[derive(Debug, Clone, PartialEq)]".into());
187 self.line(format!("enum {} {{", name));
188 for v in variants {
189 if v.fields.is_empty() {
190 self.line(format!(" {},", to_pascal(&v.name)));
191 } else {
192 let tys: Vec<String> = v
193 .fields
194 .iter()
195 .map(|f| ty_text(&ty_from_ann(&f.ty)))
196 .collect();
197 self.line(format!(" {}({}),", to_pascal(&v.name), tys.join(", ")));
198 }
199 }
200 self.line("}".into());
201 self.blank();
202 }
203
204 fn emit_func(&mut self, name: &str, params: &[Param], ret: Option<&TypeAnn>, body: &[Stmt]) {
205 let ps: Vec<String> = params
206 .iter()
207 .map(|p| {
208 format!(
209 "{}: {}",
210 rust_ident(&to_snake(&p.name)),
211 ty_text(&ty_from_ann(&p.ty))
212 )
213 })
214 .collect();
215 let r = ret
216 .map(|t| format!(" -> {}", ty_text(&ty_from_ann(t))))
217 .unwrap_or_default();
218 self.line(format!(
219 "fn {}({}){} {{",
220 rust_ident(&to_snake(name)),
221 ps.join(", "),
222 r
223 ));
224 self.indent += 1;
225 self.t.push_scope();
226 for p in params {
227 self.t.declare(p.name.clone(), ty_from_ann(&p.ty));
228 }
229 for stmt in body {
230 self.emit_stmt(stmt);
231 }
232 self.t.pop_scope();
233 self.indent -= 1;
234 self.line("}".into());
235 self.blank();
236 }
237
238 fn emit_stmt(&mut self, stmt: &Stmt) {
241 match stmt {
242 Stmt::Let {
243 name, ty, value, ..
244 } => self.emit_binding(name, ty.as_ref(), value, false),
245 Stmt::Var {
246 name,
247 ty,
248 value: Some(value),
249 ..
250 } => self.emit_binding(name, ty.as_ref(), value, true),
251 Stmt::Var {
252 name,
253 ty: Some(ann),
254 value: None,
255 ..
256 } => {
257 let vty = ty_from_ann(ann);
258 let z = zero(&vty);
259 let snake = rust_ident(&to_snake(name));
260 self.t.declare(name.clone(), vty.clone());
261 self.line(format!("let mut {}: {} = {};", snake, ty_text(&vty), z));
262 }
263 Stmt::Var { value: None, .. } => {} Stmt::Assign {
265 name, op, value, ..
266 } => self.emit_assign(name, *op, value),
267 Stmt::Return { value, .. } => match value {
268 Some(v) => {
269 let e = self.emit_expr(v);
270 self.line(format!("return {};", e));
271 }
272 None => self.line("return;".into()),
273 },
274 Stmt::If {
275 cond,
276 then_body,
277 else_body,
278 ..
279 } => self.emit_if(cond, then_body, else_body.as_deref()),
280 Stmt::While { cond, body, .. } => {
281 let c = self.emit_expr(cond);
282 self.line(format!("while {} {{", c));
283 self.block(body);
284 self.line("}".into());
285 }
286 Stmt::For {
287 var, iter, body, ..
288 } => self.emit_for(var, iter, body),
289 Stmt::Expr(e) => {
290 let s = self.emit_expr(e);
291 self.line(format!("{};", s));
292 }
293 Stmt::Func {
295 name,
296 params,
297 ret,
298 body,
299 ..
300 } => self.emit_func(name, params, ret.as_ref(), body),
301 Stmt::Struct { .. } | Stmt::Enum { .. } => {}
302 }
303 }
304
305 fn block(&mut self, body: &[Stmt]) {
307 self.indent += 1;
308 self.t.push_scope();
309 for stmt in body {
310 self.emit_stmt(stmt);
311 }
312 self.t.pop_scope();
313 self.indent -= 1;
314 }
315
316 fn emit_binding(&mut self, name: &str, ann: Option<&TypeAnn>, value: &Expr, mutable: bool) {
317 let snake = rust_ident(&to_snake(name));
318 let vty = ann
319 .map(ty_from_ann)
320 .unwrap_or_else(|| self.t.type_of(value));
321 let value_open = self.t.type_of(value).has_unknown();
324 let annotate = !vty.has_unknown() && ((ann.is_some() && value_open) || vty.has_int());
325 let kw = if mutable { "let mut" } else { "let" };
326 let expr = self.emit_expr(value);
327 if annotate {
328 self.line(format!("{} {}: {} = {};", kw, snake, ty_text(&vty), expr));
329 } else {
330 self.line(format!("{} {} = {};", kw, snake, expr));
331 }
332 self.t.declare(name.to_string(), vty);
333 }
334
335 fn emit_assign(&mut self, name: &str, op: AssignOp, value: &Expr) {
336 let snake = rust_ident(&to_snake(name));
337 let lty = self.t.lookup(name);
338 match op {
339 AssignOp::Set => {
340 let e = self.emit_expr(value);
341 self.line(format!("{} = {};", snake, e));
342 }
343 AssignOp::Add => match lty {
344 Ty::Str => {
345 if let Expr::Str(s, _) = value {
347 self.line(format!("{}.push_str(\"{}\");", snake, escape(s)));
348 } else {
349 let e = self.emit_expr(value);
350 self.line(format!("{}.push_str(&{});", snake, e));
351 }
352 }
353 Ty::Array(_) => {
354 let e = self.emit_expr(value);
356 self.line(format!("{}.push({});", snake, e));
357 }
358 _ => {
359 let e = self.emit_expr(value);
360 self.line(format!("{} += {};", snake, e));
361 }
362 },
363 AssignOp::Sub => {
364 let e = self.emit_expr(value);
365 self.line(format!("{} -= {};", snake, e));
366 }
367 }
368 }
369
370 fn emit_if(&mut self, cond: &Expr, then_body: &[Stmt], mut els: Option<&[Stmt]>) {
371 let c = self.emit_expr(cond);
372 self.line(format!("if {} {{", c));
373 self.block(then_body);
374 loop {
375 match els {
376 None => {
377 self.line("}".into());
378 break;
379 }
380 Some(e) if e.len() == 1 && matches!(e[0], Stmt::If { .. }) => {
382 if let Stmt::If {
383 cond,
384 then_body,
385 else_body,
386 ..
387 } = &e[0]
388 {
389 let c = self.emit_expr(cond);
390 self.line(format!("}} else if {} {{", c));
391 self.block(then_body);
392 els = else_body.as_deref();
393 }
394 }
395 Some(e) => {
396 self.line("} else {".into());
397 self.block(e);
398 self.line("}".into());
399 break;
400 }
401 }
402 }
403 }
404
405 fn emit_for(&mut self, var: &str, iter: &Expr, body: &[Stmt]) {
406 let svar = to_snake(var);
407 let (iter_str, elem_ty) = match self.t.type_of(iter) {
408 Ty::Range => (self.emit_expr(iter), Ty::Int),
409 Ty::Array(t) => {
410 let base = self.emit_expr(iter);
411 (format!("{}.iter().cloned()", base), *t)
414 }
415 _ => (self.emit_expr(iter), Ty::Unknown),
416 };
417 self.line(format!("for {} in {} {{", svar, iter_str));
418 self.indent += 1;
419 self.t.push_scope();
420 self.t.declare(var.to_string(), elem_ty);
421 for stmt in body {
422 self.emit_stmt(stmt);
423 }
424 self.t.pop_scope();
425 self.indent -= 1;
426 self.line("}".into());
427 }
428
429 fn emit_expr(&mut self, e: &Expr) -> String {
432 match e {
433 Expr::Int(n, _) => n.to_string(),
434 Expr::Float(f, _) => format_float(*f),
435 Expr::Str(s, _) => format!("\"{}\".to_string()", escape(s)),
436 Expr::Bool(b, _) => b.to_string(),
437 Expr::Ident(name, _) => {
438 if name == "none" {
439 "None".to_string()
440 } else {
441 rust_ident(&to_snake(name))
442 }
443 }
444 Expr::Array(els, _) => {
445 let parts: Vec<String> = els.iter().map(|x| self.emit_expr(x)).collect();
446 format!("vec![{}]", parts.join(", "))
447 }
448 Expr::Unary { op, rhs, .. } => {
449 let r = if matches!(**rhs, Expr::Binary { .. }) {
452 let inner = self.emit_expr(rhs);
453 format!("({})", inner)
454 } else {
455 self.emit_expr(rhs)
456 };
457 match op {
458 UnOp::Neg => format!("-{}", r),
459 UnOp::Not => format!("!{}", r),
460 }
461 }
462 Expr::Binary { op, lhs, rhs, .. } => {
463 if *op == BinOp::Add && self.t.type_of(lhs) == Ty::Str {
464 let l = self.display_arg(lhs);
465 let r = self.display_arg(rhs);
466 format!("format!(\"{{}}{{}}\", {}, {})", l, r)
467 } else {
468 let p = bin_prec(*op);
469 let l = self.emit_child(lhs, p, false);
470 let r = self.emit_child(rhs, p, true);
471 format!("{} {} {}", l, op_str(*op), r)
472 }
473 }
474 Expr::Index { base, index, .. } => {
475 let b = self.emit_expr(base);
476 let idx = if let Expr::Int(n, _) = **index {
477 n.to_string()
478 } else {
479 let e = self.emit_expr(index);
480 format!("({}) as usize", e)
481 };
482 format!("{}[{}]", b, idx)
483 }
484 Expr::Range { start, end, .. } => {
485 let s = self.emit_expr(start);
486 let e = self.emit_expr(end);
487 format!("{}..{}", s, e)
488 }
489 Expr::Call { name, args, .. } => self.emit_call(name, args),
490 Expr::StructLit { name, fields, .. } => {
491 let parts: Vec<String> = fields
492 .iter()
493 .map(|(k, v)| {
494 let val = self.emit_expr(v);
495 format!("{}: {}", to_snake(k), val)
496 })
497 .collect();
498 format!("{} {{ {} }}", name, parts.join(", "))
499 }
500 Expr::EnumLit {
501 enum_name,
502 variant,
503 fields,
504 ..
505 } => self.emit_enum_lit(enum_name, variant, fields),
506 Expr::Field { base, field, .. } => {
507 if let Expr::Ident(n, _) = &**base
510 && let Some(variants) = self.t.env.enums.get(n)
511 && variants.iter().any(|v| v.name == *field)
512 {
513 return format!("{}::{}", n, to_pascal(field));
514 }
515 let b = self.emit_expr(base);
516 format!("{}.{}", b, to_snake(field))
517 }
518 Expr::Match {
519 scrutinee, arms, ..
520 } => self.emit_match(scrutinee, arms),
521 }
522 }
523
524 fn emit_child(&mut self, e: &Expr, parent: u8, is_right: bool) -> String {
528 let s = self.emit_expr(e);
529 if let Expr::Binary { op, .. } = e {
530 let p = bin_prec(*op);
531 let wrap = if is_right { p <= parent } else { p < parent };
532 if wrap {
533 return format!("({})", s);
534 }
535 }
536 s
537 }
538
539 fn emit_call_arg(&mut self, a: &Expr) -> String {
543 let clone = !is_copy(&self.t.type_of(a)) && is_place(a);
544 let s = self.emit_expr(a);
545 if clone { format!("{}.clone()", s) } else { s }
546 }
547
548 fn display_arg(&mut self, e: &Expr) -> String {
551 if let Expr::Str(s, _) = e {
552 format!("\"{}\"", escape(s))
553 } else {
554 self.emit_expr(e)
555 }
556 }
557
558 fn println_call(&mut self, mac: &str, args: &[Expr]) -> String {
561 let mut fmt = String::new();
562 let mut parts = Vec::new();
563 for (i, a) in args.iter().enumerate() {
564 if i > 0 {
565 fmt.push(' ');
566 }
567 let ty = self.t.type_of(a);
570 fmt.push_str(if ty == Ty::Float || !ty.is_scalar() {
571 "{:?}"
572 } else {
573 "{}"
574 });
575 parts.push(self.display_arg(a));
576 }
577 if parts.is_empty() {
578 format!("{}!()", mac)
579 } else {
580 format!("{}!(\"{}\", {})", mac, fmt, parts.join(", "))
581 }
582 }
583
584 fn emit_call(&mut self, name: &str, args: &[Expr]) -> String {
585 match name {
586 "print" => self.println_call("println", args),
587 "eprint" => self.println_call("eprintln", args),
588 "readFile" => {
591 let p = self.emit_call_arg(&args[0]);
592 format!("std::fs::read_to_string({}).map_err(|e| e.to_string())", p)
593 }
594 "writeFile" => {
595 let p = self.emit_call_arg(&args[0]);
596 let c = self.emit_call_arg(&args[1]);
597 format!("std::fs::write({}, {}).map_err(|e| e.to_string())", p, c)
598 }
599 "args" => "std::env::args().collect::<Vec<String>>()".to_string(),
600 "readLine" => {
601 self.uses_read_line = true;
602 "read_line()".to_string()
603 }
604 "run" => {
605 self.uses_run = true;
606 let p = self.emit_call_arg(&args[0]);
607 let a = self.emit_call_arg(&args[1]);
608 format!("run({}, {})", p, a)
609 }
610 "string" => {
611 let is_float = self.t.type_of(&args[0]) == Ty::Float;
614 let e = self.emit_expr(&args[0]);
615 if is_float {
616 format!("format!(\"{{:?}}\", {})", e)
617 } else {
618 format!("({}).to_string()", e)
619 }
620 }
621 "int" => {
622 let inner = self.t.type_of(&args[0]);
623 let e = self.emit_expr(&args[0]);
624 match inner {
625 Ty::Int => e,
626 _ => format!("({}) as i64", e),
627 }
628 }
629 "float" => {
630 let inner = self.t.type_of(&args[0]);
631 let e = self.emit_expr(&args[0]);
632 match inner {
633 Ty::Float => e,
634 _ => format!("({}) as f64", e),
635 }
636 }
637 "parseInt" => {
639 let e = self.emit_call_arg(&args[0]);
640 format!("{}.trim().parse::<i64>().ok()", e)
641 }
642 "parseFloat" => {
643 let e = self.emit_call_arg(&args[0]);
644 format!("{}.trim().parse::<f64>().ok()", e)
645 }
646 "length" => {
647 let inner = self.t.type_of(&args[0]);
648 let e = self.emit_expr(&args[0]);
649 if inner == Ty::Str {
650 format!("({}).chars().count() as i64", e)
651 } else {
652 format!("({}).len() as i64", e)
653 }
654 }
655 "some" => {
656 let e = self.emit_expr(&args[0]);
657 format!("Some({})", e)
658 }
659 "ok" => {
660 let e = self.emit_expr(&args[0]);
661 format!("Ok({})", e)
662 }
663 "err" => {
664 let e = self.emit_expr(&args[0]);
665 format!("Err({})", e)
666 }
667 _ => {
668 let parts: Vec<String> = args.iter().map(|a| self.emit_call_arg(a)).collect();
669 format!("{}({})", rust_ident(&to_snake(name)), parts.join(", "))
670 }
671 }
672 }
673
674 fn emit_enum_lit(
675 &mut self,
676 enum_name: &str,
677 variant: &str,
678 fields: &[(String, Expr)],
679 ) -> String {
680 let order: Option<Vec<String>> = self.t.env.enums.get(enum_name).and_then(|variants| {
683 variants
684 .iter()
685 .find(|v| v.name == variant)
686 .map(|v| v.fields.iter().map(|f| f.name.clone()).collect())
687 });
688 let args: Vec<String> = match order {
689 Some(names) => names
690 .iter()
691 .map(|fname| {
692 let expr = fields.iter().find(|(k, _)| k == fname).map(|(_, e)| e);
693 match expr {
694 Some(e) => self.emit_expr(e),
695 None => "()".to_string(),
696 }
697 })
698 .collect(),
699 None => fields.iter().map(|(_, e)| self.emit_expr(e)).collect(),
700 };
701 if args.is_empty() {
702 format!("{}::{}", enum_name, to_pascal(variant))
703 } else {
704 format!("{}::{}({})", enum_name, to_pascal(variant), args.join(", "))
705 }
706 }
707
708 fn emit_match(&mut self, scrutinee: &Expr, arms: &[MatchArm]) -> String {
709 let base = self.indent;
710 let ind = indent(base);
711 let ind1 = indent(base + 1);
712 let st = self.t.type_of(scrutinee);
713 let needs_as_str = arms.iter().any(|a| matches!(a.pattern, Pattern::Str(..)));
714 let scrut = if needs_as_str {
715 let s = self.emit_expr(scrutinee);
716 format!("{}.as_str()", s)
717 } else {
718 self.emit_expr(scrutinee)
719 };
720 let mut s = format!("match {} {{\n", scrut);
721 for arm in arms {
722 let pat = self.emit_pattern(&arm.pattern, &st);
723 self.t.push_scope();
726 self.declare_bindings(&arm.pattern, &st);
727 self.indent = base + 1;
729 let body = self.emit_expr(&arm.body);
730 self.indent = base;
731 self.t.pop_scope();
732 s.push_str(&format!("{}{} => {},\n", ind1, pat, body));
733 }
734 s.push_str(&format!("{}}}", ind));
735 s
736 }
737
738 fn emit_pattern(&mut self, pat: &Pattern, st: &Ty) -> String {
739 match pat {
740 Pattern::Wildcard(_) => "_".to_string(),
741 Pattern::Int(n, _) => n.to_string(),
742 Pattern::Str(s, _) => format!("\"{}\"", escape(s)),
743 Pattern::Bool(b, _) => b.to_string(),
744 Pattern::Variant { name, bindings, .. } => {
745 let binds: Vec<String> = bindings.iter().map(|b| to_snake(b)).collect();
746 let inner = if binds.is_empty() {
747 String::new()
748 } else {
749 format!("({})", binds.join(", "))
750 };
751 match st {
752 Ty::Option(_) => match name.as_str() {
753 "some" => format!("Some{}", paren_or_empty(&binds)),
754 _ => "None".to_string(),
755 },
756 Ty::Result(_, _) => match name.as_str() {
757 "ok" => format!("Ok{}", paren_or_empty(&binds)),
758 _ => format!("Err{}", paren_or_empty(&binds)),
759 },
760 Ty::User(en) => format!("{}::{}{}", en, to_pascal(name), inner),
761 _ => format!("{}{}", to_pascal(name), inner),
762 }
763 }
764 }
765 }
766
767 fn declare_bindings(&mut self, pat: &Pattern, st: &Ty) {
769 let Pattern::Variant { name, bindings, .. } = pat else {
770 return;
771 };
772 let types: Vec<Ty> = match st {
773 Ty::Option(t) if name == "some" => vec![(**t).clone()],
774 Ty::Result(o, _) if name == "ok" => vec![(**o).clone()],
775 Ty::Result(_, e) if name == "err" => vec![(**e).clone()],
776 Ty::User(en) => self
777 .t
778 .env
779 .enums
780 .get(en)
781 .and_then(|vs| vs.iter().find(|v| v.name == *name))
782 .map(|v| v.fields.iter().map(|f| ty_from_ann(&f.ty)).collect())
783 .unwrap_or_default(),
784 _ => Vec::new(),
785 };
786 for (b, t) in bindings.iter().zip(types) {
787 self.t.declare(b.clone(), t);
788 }
789 }
790}
791
792fn paren_or_empty(binds: &[String]) -> String {
793 if binds.is_empty() {
794 String::new()
795 } else {
796 format!("({})", binds.join(", "))
797 }
798}
799
800fn is_copy(t: &Ty) -> bool {
802 matches!(t, Ty::Int | Ty::Float | Ty::Bool)
803}
804
805fn is_place(e: &Expr) -> bool {
808 match e {
809 Expr::Ident(n, _) => n != "none",
810 Expr::Field { .. } | Expr::Index { .. } => true,
811 _ => false,
812 }
813}