1use std::collections::BTreeMap;
4
5use cranelift_entity::PrimaryMap;
6
7use ruka_check::{CheckedProgram, Ty};
8use ruka_hir::HirProgram;
9use ruka_mir::{
10 MirBlockId, MirEnumDecl, MirEnumVariant, MirFuncId, MirFunction, MirProgram, MirStructDecl,
11 MirStructField, MirTypeExpr,
12};
13
14mod cfg;
15mod lowerer;
16
17pub use lowerer::LowerError;
18
19use lowerer::{FunctionLowerer, lower_struct_field_type};
20
21pub fn lower_program(
23 program: &HirProgram,
24 checked: &CheckedProgram,
25) -> Result<MirProgram, LowerError> {
26 let mut function_names = BTreeMap::new();
27 let mut functions: PrimaryMap<MirFuncId, MirFunction> = PrimaryMap::new();
28
29 for (_, function) in program.functions.iter() {
30 let id = functions.push(MirFunction {
31 name: function.name.clone(),
32 arity: function.params.len(),
33 return_ty: Ty::Unit,
34 locals: PrimaryMap::new(),
35 params: Vec::new(),
36 param_modes: Vec::new(),
37 entry: MirBlockId::from_u32(0),
38 blocks: PrimaryMap::new(),
39 });
40 function_names.insert(function.name.clone(), id);
41 }
42
43 for (_, source_function) in program.functions.iter() {
44 let mir_func_id = function_names
45 .get(&source_function.name)
46 .copied()
47 .expect("mir function id should exist");
48 let lowered =
49 FunctionLowerer::new(program, checked, &function_names, source_function).lower()?;
50 functions[mir_func_id] = lowered;
51 }
52
53 let mut enums = program
54 .enums
55 .iter()
56 .map(|decl| MirEnumDecl {
57 name: decl.name.clone(),
58 type_params: decl.type_params.clone(),
59 variants: decl
60 .variants
61 .iter()
62 .map(|variant| MirEnumVariant {
63 name: variant.name.clone(),
64 payload: variant
65 .payload
66 .iter()
67 .map(lower_struct_field_type)
68 .collect(),
69 })
70 .collect(),
71 })
72 .collect::<Vec<_>>();
73 if !enums.iter().any(|decl| decl.name == "Option") {
74 enums.push(MirEnumDecl {
75 name: "Option".to_owned(),
76 type_params: vec!["T".to_owned()],
77 variants: vec![
78 MirEnumVariant {
79 name: "None".to_owned(),
80 payload: Vec::new(),
81 },
82 MirEnumVariant {
83 name: "Some".to_owned(),
84 payload: vec![MirTypeExpr::Named("T".to_owned())],
85 },
86 ],
87 });
88 }
89
90 Ok(MirProgram {
91 functions,
92 function_names,
93 structs: program
94 .structs
95 .iter()
96 .map(|decl| MirStructDecl {
97 name: decl.name.clone(),
98 type_params: decl.type_params.clone(),
99 fields: decl
100 .fields
101 .iter()
102 .map(|field| MirStructField {
103 name: field.name.clone(),
104 ty: lower_struct_field_type(&field.ty),
105 })
106 .collect(),
107 })
108 .collect(),
109 enums,
110 })
111}