bril_frontend/
printer.rs

1// Copyright (C) 2024 Ethan Uppal.
2//
3// This Source Code Form is subject to the terms of the Mozilla Public License,
4// v. 2.0. If a copy of the MPL was not distributed with this file, You can
5// obtain one at https://mozilla.org/MPL/2.0/.
6
7use std::fmt::{self, Write};
8
9use inform::common::IndentWriterCommon;
10
11use crate::ast;
12
13pub struct Printer<'writer, W: fmt::Write> {
14    w: inform::fmt::IndentWriter<'writer, W>,
15}
16
17impl<'writer, W: fmt::Write> Printer<'writer, W> {
18    pub fn new(writer: &'writer mut W, indent: usize) -> Self {
19        Self {
20            w: inform::fmt::IndentWriter::new(writer, indent),
21        }
22    }
23
24    pub fn print_imported_function_alias(
25        &mut self,
26        imported_function_alias: &ast::ImportedFunctionAlias,
27    ) -> fmt::Result {
28        write!(self.w, "as {}", imported_function_alias.name)
29    }
30
31    pub fn print_imported_function(
32        &mut self,
33        imported_function: &ast::ImportedFunction,
34    ) -> fmt::Result {
35        write!(self.w, "{}", imported_function.name)?;
36
37        if let Some(alias) = &imported_function.alias {
38            write!(self.w, " ")?;
39            self.print_imported_function_alias(alias)?;
40        }
41
42        Ok(())
43    }
44
45    pub fn print_import(&mut self, import: &ast::Import) -> fmt::Result {
46        write!(self.w, "from \"{}\" import ", import.path)?;
47        for (i, imported_function) in import.imported_functions.iter().enumerate() {
48            if i > 0 {
49                write!(self.w, ", ")?;
50            }
51            self.print_imported_function(imported_function)?;
52        }
53        writeln!(self.w, ";")?;
54
55        Ok(())
56    }
57
58    pub fn print_type(&mut self, ty: &ast::Type) -> fmt::Result {
59        match ty {
60            ast::Type::Int => write!(self.w, "int"),
61            ast::Type::Bool => write!(self.w, "bool"),
62            ast::Type::Float => write!(self.w, "float"),
63            ast::Type::Char => write!(self.w, "char"),
64            ast::Type::Ptr(inner) => {
65                write!(self.w, "ptr<")?;
66                self.print_type(inner)?;
67                write!(self.w, ">")
68            }
69        }
70    }
71
72    pub fn print_type_annotation(&mut self, type_annotation: &ast::TypeAnnotation) -> fmt::Result {
73        write!(self.w, ": ")?;
74        self.print_type(&type_annotation.ty)
75    }
76
77    pub fn print_label(&mut self, label: &ast::Label) -> fmt::Result {
78        write!(self.w, "{}", label.name)
79    }
80
81    pub fn print_constant_value(&mut self, constant_value: &ast::ConstantValue) -> fmt::Result {
82        match constant_value {
83            ast::ConstantValue::IntegerLiteral(integer) => {
84                write!(self.w, "{}", integer)
85            }
86            ast::ConstantValue::BooleanLiteral(boolean) => {
87                write!(self.w, "{}", boolean)
88            }
89            ast::ConstantValue::FloatLiteral(float) => {
90                write!(self.w, "{}", float)
91            }
92            ast::ConstantValue::CharacterLiteral(character) => {
93                write!(self.w, "{}", character)
94            }
95        }
96    }
97
98    pub fn print_constant(&mut self, constant: &ast::Constant) -> fmt::Result {
99        write!(self.w, "{}", constant.name)?;
100        if let Some(type_annotation) = &constant.type_annotation {
101            self.print_type_annotation(type_annotation)?;
102        }
103        write!(self.w, " = const ")?;
104        self.print_constant_value(&constant.value)?;
105        write!(self.w, ";")
106    }
107
108    pub fn print_value_operation_op(
109        &mut self,
110        value_operation_op: &ast::ValueOperationOp,
111    ) -> fmt::Result {
112        match value_operation_op {
113            ast::ValueOperationOp::Add(lhs, rhs) => {
114                write!(self.w, "add {} {}", lhs, rhs)
115            }
116            ast::ValueOperationOp::Mul(lhs, rhs) => {
117                write!(self.w, "mul {} {}", lhs, rhs)
118            }
119            ast::ValueOperationOp::Sub(lhs, rhs) => {
120                write!(self.w, "sub {} {}", lhs, rhs)
121            }
122            ast::ValueOperationOp::Div(lhs, rhs) => {
123                write!(self.w, "div {} {}", lhs, rhs)
124            }
125            ast::ValueOperationOp::Eq(lhs, rhs) => {
126                write!(self.w, "eq {} {}", lhs, rhs)
127            }
128            ast::ValueOperationOp::Lt(lhs, rhs) => {
129                write!(self.w, "lt {} {}", lhs, rhs)
130            }
131            ast::ValueOperationOp::Gt(lhs, rhs) => {
132                write!(self.w, "gt {} {}", lhs, rhs)
133            }
134            ast::ValueOperationOp::Le(lhs, rhs) => {
135                write!(self.w, "le {} {}", lhs, rhs)
136            }
137            ast::ValueOperationOp::Ge(lhs, rhs) => {
138                write!(self.w, "ge {} {}", lhs, rhs)
139            }
140            ast::ValueOperationOp::Not(value) => {
141                write!(self.w, "not {}", value)
142            }
143            ast::ValueOperationOp::And(lhs, rhs) => {
144                write!(self.w, "and {} {}", lhs, rhs)
145            }
146            ast::ValueOperationOp::Or(lhs, rhs) => {
147                write!(self.w, "or {} {}", lhs, rhs)
148            }
149            ast::ValueOperationOp::Call(function_name, arguments) => {
150                write!(
151                    self.w,
152                    "call {} {}",
153                    function_name,
154                    arguments
155                        .iter()
156                        .map(|argument| argument.to_string())
157                        .collect::<Vec<_>>()
158                        .join(" ")
159                )
160            }
161            ast::ValueOperationOp::Id(value) => {
162                write!(self.w, "id {}", value)
163            }
164            ast::ValueOperationOp::Fadd(lhs, rhs) => {
165                write!(self.w, "fadd {} {}", lhs, rhs)
166            }
167            ast::ValueOperationOp::Fmul(lhs, rhs) => {
168                write!(self.w, "fmul {} {}", lhs, rhs)
169            }
170            ast::ValueOperationOp::Fsub(lhs, rhs) => {
171                write!(self.w, "fsub {} {}", lhs, rhs)
172            }
173            ast::ValueOperationOp::Fdiv(lhs, rhs) => {
174                write!(self.w, "fdiv {} {}", lhs, rhs)
175            }
176            ast::ValueOperationOp::Feq(lhs, rhs) => {
177                write!(self.w, "feq {} {}", lhs, rhs)
178            }
179            ast::ValueOperationOp::Flt(lhs, rhs) => {
180                write!(self.w, "flt {} {}", lhs, rhs)
181            }
182            ast::ValueOperationOp::Fle(lhs, rhs) => {
183                write!(self.w, "fle {} {}", lhs, rhs)
184            }
185            ast::ValueOperationOp::Fgt(lhs, rhs) => {
186                write!(self.w, "fgt {} {}", lhs, rhs)
187            }
188            ast::ValueOperationOp::Fge(lhs, rhs) => {
189                write!(self.w, "fge {} {}", lhs, rhs)
190            }
191            ast::ValueOperationOp::Alloc(size) => {
192                write!(self.w, "alloc {}", size)
193            }
194            ast::ValueOperationOp::Load(pointer) => {
195                write!(self.w, "load {}", pointer)
196            }
197            ast::ValueOperationOp::PtrAdd(pointer, offset) => {
198                write!(self.w, "ptradd {} {}", pointer, offset)
199            }
200            ast::ValueOperationOp::Ceq(lhs, rhs) => {
201                write!(self.w, "ceq {} {}", lhs, rhs)
202            }
203            ast::ValueOperationOp::Clt(lhs, rhs) => {
204                write!(self.w, "clt {} {}", lhs, rhs)
205            }
206            ast::ValueOperationOp::Cle(lhs, rhs) => {
207                write!(self.w, "cle {} {}", lhs, rhs)
208            }
209            ast::ValueOperationOp::Cgt(lhs, rhs) => {
210                write!(self.w, "cgt {} {}", lhs, rhs)
211            }
212            ast::ValueOperationOp::Cge(lhs, rhs) => {
213                write!(self.w, "cge {} {}", lhs, rhs)
214            }
215            ast::ValueOperationOp::Char2Int(value) => write!(self.w, "char2int {}", value),
216            ast::ValueOperationOp::Int2Char(value) => write!(self.w, "int2char {}", value),
217        }
218    }
219
220    pub fn print_value_operation(&mut self, value_operation: &ast::ValueOperation) -> fmt::Result {
221        write!(self.w, "{}", value_operation.name)?;
222        if let Some(type_annotation) = &value_operation.type_annotation {
223            self.print_type_annotation(type_annotation)?;
224        }
225        write!(self.w, " = ")?;
226        self.print_value_operation_op(&value_operation.op)?;
227        write!(self.w, ";")
228    }
229
230    pub fn print_effect_operation_op(
231        &mut self,
232        effect_operation_op: &ast::EffectOperationOp,
233    ) -> fmt::Result {
234        match effect_operation_op {
235            ast::EffectOperationOp::Jmp(destination) => {
236                write!(self.w, "jmp ")?;
237                self.print_label(destination)
238            }
239            ast::EffectOperationOp::Br(condition, if_true, if_false) => {
240                write!(self.w, "br {} ", condition)?;
241                self.print_label(if_true)?;
242                write!(self.w, " ")?;
243                self.print_label(if_false)
244            }
245            ast::EffectOperationOp::Call(function_name, arguments) => {
246                write!(
247                    self.w,
248                    "call {} {}",
249                    function_name,
250                    arguments
251                        .iter()
252                        .map(|argument| argument.to_string())
253                        .collect::<Vec<_>>()
254                        .join(" ")
255                )
256            }
257            ast::EffectOperationOp::Ret(value) => {
258                write!(self.w, "ret")?;
259                if let Some(value) = value {
260                    write!(self.w, " {}", value)?;
261                }
262                Ok(())
263            }
264            ast::EffectOperationOp::Print(arguments) => {
265                write!(
266                    self.w,
267                    "print {}",
268                    arguments
269                        .iter()
270                        .map(|argument| argument.to_string())
271                        .collect::<Vec<_>>()
272                        .join(" ")
273                )
274            }
275            ast::EffectOperationOp::Nop => write!(self.w, "nop"),
276            ast::EffectOperationOp::Store(pointer, value) => {
277                write!(self.w, "store {} {}", pointer, value)
278            }
279            ast::EffectOperationOp::Free(pointer) => write!(self.w, "free {}", pointer),
280        }
281    }
282
283    pub fn print_effect_operation(
284        &mut self,
285        effect_operation: &ast::EffectOperation,
286    ) -> fmt::Result {
287        self.print_effect_operation_op(&effect_operation.op)?;
288        write!(self.w, ";")
289    }
290
291    pub fn print_instruction(&mut self, instruction: &ast::Instruction) -> fmt::Result {
292        match instruction {
293            ast::Instruction::Constant(constant) => self.print_constant(constant),
294            ast::Instruction::ValueOperation(value_operation) => {
295                self.print_value_operation(value_operation)
296            }
297            ast::Instruction::EffectOperation(effect_operation) => {
298                self.print_effect_operation(effect_operation)
299            }
300        }
301    }
302
303    pub fn print_function_code(&mut self, code: &ast::FunctionCode) -> fmt::Result {
304        match code {
305            ast::FunctionCode::Label { label, comment, .. } => {
306                self.w.decrease_indent();
307                self.print_label(label)?;
308                write!(self.w, ":")?;
309                self.w.increase_indent();
310                if let Some(comment) = comment {
311                    writeln!(self.w, " {}", comment)?;
312                }
313                writeln!(self.w)
314            }
315            ast::FunctionCode::Instruction { inner, comment } => {
316                self.print_instruction(inner)?;
317                if let Some(comment) = comment {
318                    writeln!(self.w, " {}", comment)?;
319                }
320                writeln!(self.w)
321            }
322            ast::FunctionCode::Comment(comment) => {
323                writeln!(self.w, "{}", comment)
324            }
325            ast::FunctionCode::EmptyLine(_) => writeln!(self.w),
326        }
327    }
328
329    pub fn print_function(&mut self, function: &ast::Function) -> fmt::Result {
330        write!(self.w, "{}(", function.name)?;
331
332        for (i, (name, type_annotation)) in function.parameters.iter().enumerate() {
333            if i > 0 {
334                write!(self.w, ", ")?;
335            }
336            write!(self.w, "{}", name)?;
337            self.print_type_annotation(type_annotation)?;
338        }
339
340        write!(self.w, ")")?;
341
342        if let Some(return_type) = &function.return_type {
343            self.print_type_annotation(return_type)?;
344        }
345
346        writeln!(self.w, " {{")?;
347        self.w.increase_indent();
348
349        for code in &function.body {
350            self.print_function_code(code)?;
351        }
352
353        self.w.decrease_indent();
354        writeln!(self.w, "}}")?;
355
356        Ok(())
357    }
358
359    pub fn print_comment(&mut self, comment: &str) -> fmt::Result {
360        writeln!(self.w, "{}", comment)
361    }
362
363    pub fn print_newline(&mut self) -> fmt::Result {
364        writeln!(self.w)
365    }
366
367    pub fn print_top_level_item(&mut self, item: &ast::TopLevelItem) -> fmt::Result {
368        match item {
369            ast::TopLevelItem::Import(import) => self.print_import(import),
370            ast::TopLevelItem::Function(function) => self.print_function(function),
371            ast::TopLevelItem::Comment(comment) => self.print_comment(comment),
372            ast::TopLevelItem::Newline(_) => self.print_newline(),
373        }
374    }
375
376    pub fn print_program(&mut self, program: &ast::Program) -> fmt::Result {
377        for item in &program.items {
378            self.print_top_level_item(item)?;
379        }
380
381        Ok(())
382    }
383}