1use std::collections::BTreeMap;
30use std::fmt;
31
32use crate::ast::Spanned;
33
34use super::expr::{
35 MirBinOp, MirCall, MirCallee, MirConstruct, MirEffectAnnotation, MirExpr,
36 MirIndependentProduct, MirLet, MirMatch, MirMatchArm, MirPattern, MirProject, MirRecordCreate,
37 MirRecordField, MirRecordUpdate, MirStrPart, MirTailCall,
38};
39use super::program::{MirFn, MirParam, MirProgram};
40
41impl fmt::Display for MirProgram {
42 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
43 writeln!(f, "MirProgram {{")?;
44 let sorted: BTreeMap<_, _> = self.fns.iter().collect();
48 for (fn_id, mir_fn) in sorted {
49 writeln!(f, " // FnId({})", fn_id.0)?;
50 write_fn(f, mir_fn, " ")?;
51 }
52 if !self.modules.is_empty() {
53 writeln!(f, " modules: [")?;
54 for m in &self.modules {
55 writeln!(f, " ModuleId({})", m.0)?;
56 }
57 writeln!(f, " ]")?;
58 }
59 writeln!(f, "}}")
60 }
61}
62
63impl fmt::Display for MirFn {
64 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
65 write_fn(f, self, "")
66 }
67}
68
69fn write_fn(f: &mut fmt::Formatter<'_>, mir_fn: &MirFn, indent: &str) -> fmt::Result {
70 write!(f, "{indent}fn {}(", mir_fn.name)?;
71 for (i, p) in mir_fn.params.iter().enumerate() {
72 if i > 0 {
73 write!(f, ", ")?;
74 }
75 write_param(f, p)?;
76 }
77 writeln!(f, ") -> {} {{", mir_fn.return_type)?;
78 if !mir_fn.effects.is_empty() {
79 write!(f, "{indent} effects: [")?;
80 for (i, e) in mir_fn.effects.iter().enumerate() {
81 if i > 0 {
82 write!(f, ", ")?;
83 }
84 write_effect(f, e)?;
85 }
86 writeln!(f, "]")?;
87 }
88 write!(f, "{indent} ")?;
89 write_expr(f, &mir_fn.body, &format!("{indent} "))?;
90 writeln!(f)?;
91 writeln!(f, "{indent}}}")
92}
93
94fn write_param(f: &mut fmt::Formatter<'_>, p: &MirParam) -> fmt::Result {
95 write!(f, "{}{}: {}", p.local, p.name, p.ty)
96}
97
98fn write_effect(f: &mut fmt::Formatter<'_>, e: &MirEffectAnnotation) -> fmt::Result {
99 write!(f, "{}", e.name)
100}
101
102fn write_expr(f: &mut fmt::Formatter<'_>, expr: &Spanned<MirExpr>, indent: &str) -> fmt::Result {
103 match &expr.node {
104 MirExpr::Literal(lit) => write!(f, "{:?}", lit.node),
105 MirExpr::Local(local) => write!(f, "{}", local.node),
106 MirExpr::FnValue(name) => write!(f, "fn_value({name})"),
107 MirExpr::Let(spanned) => write_let(f, &spanned.node, indent),
108 MirExpr::Call(spanned) => write_call(f, &spanned.node, indent),
109 MirExpr::TailCall(spanned) => write_tail_call(f, &spanned.node, indent),
110 MirExpr::BinOp(spanned) => write_bin_op(f, &spanned.node, indent),
111 MirExpr::Neg(inner) => {
112 write!(f, "-(")?;
113 write_expr(f, inner, indent)?;
114 write!(f, ")")
115 }
116 MirExpr::Match(spanned) => write_match(f, &spanned.node, indent),
117 MirExpr::IfThenElse(spanned) => {
118 let ite = &spanned.node;
119 write!(f, "if ")?;
120 write_expr(f, &ite.cond, indent)?;
121 write!(f, " then ")?;
122 write_expr(f, &ite.then_branch, indent)?;
123 write!(f, " else ")?;
124 write_expr(f, &ite.else_branch, indent)
125 }
126 MirExpr::Construct(spanned) => write_construct(f, &spanned.node, indent),
127 MirExpr::RecordCreate(spanned) => write_record_create(f, &spanned.node, indent),
128 MirExpr::RecordUpdate(spanned) => write_record_update(f, &spanned.node, indent),
129 MirExpr::Project(spanned) => write_project(f, &spanned.node, indent),
130 MirExpr::Try(inner) => {
131 write_expr(f, inner, indent)?;
132 write!(f, "?")
133 }
134 MirExpr::List(items) => write_list_or_tuple(f, "List", items, indent),
135 MirExpr::Tuple(items) => write_list_or_tuple(f, "Tuple", items, indent),
136 MirExpr::MapLiteral(pairs) => write_map_literal(f, pairs, indent),
137 MirExpr::InterpolatedStr(parts) => write_interp_str(f, parts, indent),
138 MirExpr::IndependentProduct(spanned) => write_independent_product(f, &spanned.node, indent),
139 MirExpr::Return(inner) => {
140 write!(f, "return ")?;
141 write_expr(f, inner, indent)
142 }
143 MirExpr::Box(inner) => {
146 write!(f, "box(")?;
147 write_expr(f, inner, indent)?;
148 write!(f, ")")
149 }
150 MirExpr::Unbox(inner) => {
151 write!(f, "unbox(")?;
152 write_expr(f, inner, indent)?;
153 write!(f, ")")
154 }
155 }
156}
157
158fn write_let(f: &mut fmt::Formatter<'_>, let_node: &MirLet, indent: &str) -> fmt::Result {
159 writeln!(f, "let {} =", let_node.binding)?;
160 let inner = format!("{indent} ");
161 write!(f, "{inner}")?;
162 write_expr(f, &let_node.value, &inner)?;
163 writeln!(f)?;
164 write!(f, "{indent}in ")?;
165 write_expr(f, &let_node.body, indent)
166}
167
168fn write_call(f: &mut fmt::Formatter<'_>, call: &MirCall, indent: &str) -> fmt::Result {
169 match &call.callee {
170 MirCallee::Fn(id) => write!(f, "FnId({}).call(", id.0)?,
171 MirCallee::Builtin(id) => write!(f, "Builtin(#{}).call(", id.0)?,
172 MirCallee::Intrinsic(i) => write!(f, "Intrinsic({i:?}).call(")?,
173 MirCallee::LocalSlot { slot, name, .. } => write!(f, "slot({slot}, {name}).call(")?,
174 }
175 write_args(f, &call.args, indent)?;
176 write!(f, ")")
177}
178
179fn write_tail_call(f: &mut fmt::Formatter<'_>, tc: &MirTailCall, indent: &str) -> fmt::Result {
180 write!(f, "tail FnId({}).call(", tc.target.0)?;
181 write_args(f, &tc.args, indent)?;
182 write!(f, ")")
183}
184
185fn write_args(f: &mut fmt::Formatter<'_>, args: &[Spanned<MirExpr>], indent: &str) -> fmt::Result {
186 for (i, a) in args.iter().enumerate() {
187 if i > 0 {
188 write!(f, ", ")?;
189 }
190 write_expr(f, a, indent)?;
191 }
192 Ok(())
193}
194
195fn write_bin_op(f: &mut fmt::Formatter<'_>, op: &MirBinOp, indent: &str) -> fmt::Result {
196 write!(f, "(")?;
197 write_expr(f, &op.lhs, indent)?;
198 write!(f, " {:?} ", op.op)?;
199 write_expr(f, &op.rhs, indent)?;
200 write!(f, ")")
201}
202
203fn write_match(f: &mut fmt::Formatter<'_>, m: &MirMatch, indent: &str) -> fmt::Result {
204 write!(f, "match ")?;
205 write_expr(f, &m.subject, indent)?;
206 writeln!(f, " {{")?;
207 let arm_indent = format!("{indent} ");
208 for arm in &m.arms {
209 write_arm(f, arm, &arm_indent)?;
210 }
211 write!(f, "{indent}}}")
212}
213
214fn write_arm(f: &mut fmt::Formatter<'_>, arm: &MirMatchArm, indent: &str) -> fmt::Result {
215 write!(f, "{indent}")?;
216 write_pattern(f, &arm.pattern)?;
217 write!(f, " => ")?;
218 write_expr(f, &arm.body, indent)?;
219 writeln!(f, ",")
220}
221
222fn write_pattern(f: &mut fmt::Formatter<'_>, p: &MirPattern) -> fmt::Result {
223 match p {
224 MirPattern::Wildcard => write!(f, "_"),
225 MirPattern::Literal(lit) => write!(f, "{lit:?}"),
226 MirPattern::Bind(local, _name) => write!(f, "{local}"),
227 MirPattern::EmptyList => write!(f, "[]"),
228 MirPattern::Cons { head, tail, .. } => write!(f, "[{head}, ..{tail}]"),
229 MirPattern::Tuple(items) => {
230 write!(f, "(")?;
231 for (i, sub) in items.iter().enumerate() {
232 if i > 0 {
233 write!(f, ", ")?;
234 }
235 write_pattern(f, sub)?;
236 }
237 write!(f, ")")
238 }
239 MirPattern::Ctor { ctor, bindings, .. } => {
240 write_ctor(f, *ctor)?;
241 write!(f, "(")?;
242 for (i, b) in bindings.iter().enumerate() {
243 if i > 0 {
244 write!(f, ", ")?;
245 }
246 write!(f, "{b}")?;
247 }
248 write!(f, ")")
249 }
250 }
251}
252
253fn write_construct(f: &mut fmt::Formatter<'_>, c: &MirConstruct, indent: &str) -> fmt::Result {
254 write_ctor(f, c.ctor)?;
255 write!(f, "(")?;
256 write_args(f, &c.args, indent)?;
257 write!(f, ")")
258}
259
260fn write_ctor(f: &mut fmt::Formatter<'_>, ctor: super::MirCtor) -> fmt::Result {
261 match ctor {
262 super::MirCtor::User(id) => write!(f, "CtorId({})", id.0),
263 super::MirCtor::Builtin(b) => match b {
264 super::BuiltinCtor::ResultOk => write!(f, "Result.Ok"),
265 super::BuiltinCtor::ResultErr => write!(f, "Result.Err"),
266 super::BuiltinCtor::OptionSome => write!(f, "Option.Some"),
267 super::BuiltinCtor::OptionNone => write!(f, "Option.None"),
268 },
269 }
270}
271
272fn write_record_create(
273 f: &mut fmt::Formatter<'_>,
274 r: &MirRecordCreate,
275 indent: &str,
276) -> fmt::Result {
277 match r.type_id {
278 Some(id) => write!(f, "TypeId({}) {{ ", id.0)?,
279 None => write!(f, "{} {{ ", r.type_name)?,
280 }
281 write_fields(f, &r.fields, indent)?;
282 write!(f, " }}")
283}
284
285fn write_record_update(
286 f: &mut fmt::Formatter<'_>,
287 r: &MirRecordUpdate,
288 indent: &str,
289) -> fmt::Result {
290 match r.type_id {
291 Some(id) => write!(f, "TypeId({}).update(", id.0)?,
292 None => write!(f, "{}.update(", r.type_name)?,
293 }
294 write_expr(f, &r.base, indent)?;
295 write!(f, ", ")?;
296 write_fields(f, &r.updates, indent)?;
297 write!(f, ")")
298}
299
300fn write_fields(
301 f: &mut fmt::Formatter<'_>,
302 fields: &[MirRecordField],
303 indent: &str,
304) -> fmt::Result {
305 for (i, field) in fields.iter().enumerate() {
306 if i > 0 {
307 write!(f, ", ")?;
308 }
309 write!(f, "{} = ", field.name)?;
310 write_expr(f, &field.value, indent)?;
311 }
312 Ok(())
313}
314
315fn write_project(f: &mut fmt::Formatter<'_>, p: &MirProject, indent: &str) -> fmt::Result {
316 write_expr(f, &p.base, indent)?;
317 write!(f, ".{}", p.field)
318}
319
320fn write_list_or_tuple(
321 f: &mut fmt::Formatter<'_>,
322 tag: &str,
323 items: &[Spanned<MirExpr>],
324 indent: &str,
325) -> fmt::Result {
326 write!(f, "{tag}[")?;
327 write_args(f, items, indent)?;
328 write!(f, "]")
329}
330
331fn write_map_literal(
332 f: &mut fmt::Formatter<'_>,
333 pairs: &[(Spanned<MirExpr>, Spanned<MirExpr>)],
334 indent: &str,
335) -> fmt::Result {
336 write!(f, "Map{{")?;
337 for (i, (k, v)) in pairs.iter().enumerate() {
338 if i > 0 {
339 write!(f, ", ")?;
340 }
341 write_expr(f, k, indent)?;
342 write!(f, " => ")?;
343 write_expr(f, v, indent)?;
344 }
345 write!(f, "}}")
346}
347
348fn write_interp_str(f: &mut fmt::Formatter<'_>, parts: &[MirStrPart], indent: &str) -> fmt::Result {
349 write!(f, "\"")?;
350 for part in parts {
351 match part {
352 MirStrPart::Literal(s) => write!(f, "{}", s.replace('"', "\\\""))?,
353 MirStrPart::Expr(e) => {
354 write!(f, "{{")?;
355 write_expr(f, e, indent)?;
356 write!(f, "}}")?;
357 }
358 }
359 }
360 write!(f, "\"")
361}
362
363fn write_independent_product(
364 f: &mut fmt::Formatter<'_>,
365 ip: &MirIndependentProduct,
366 indent: &str,
367) -> fmt::Result {
368 write!(f, "(")?;
369 write_args(f, &ip.items, indent)?;
370 if ip.unwrap_results {
371 write!(f, ")?!")
372 } else {
373 write!(f, ")!")
374 }
375}
376
377