Skip to content

Commit f121cb4

Browse files
committed
Tacky conversion for statements
1 parent 9f1ded5 commit f121cb4

1 file changed

Lines changed: 70 additions & 10 deletions

File tree

rust_src/ast_to_tacky.rs

Lines changed: 70 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,29 @@
11
//! AST to TACKY IR conversion routines
22
3-
use crate::{ast, tacky};
3+
use std::collections::HashSet;
4+
5+
use crate::{ast, shared_types::Identifier, tacky};
46

57
/// Converter object that does the work going from AST to TACKY
6-
struct AstToTacky {}
8+
struct AstToTacky {
9+
label_set: HashSet<String>,
10+
}
711

812
type InstructionVec = Vec<tacky::Instruction>;
913

1014
impl AstToTacky {
15+
fn new() -> AstToTacky {
16+
AstToTacky {
17+
label_set: HashSet::new(),
18+
}
19+
}
20+
1121
fn convert_program(&mut self, prog: &ast::Program) -> tacky::Program {
1222
let function = self.convert_function(&prog.function);
1323
return tacky::Program { function };
1424
}
1525

16-
fn convert_function(&self, func: &ast::Function) -> tacky::Function {
26+
fn convert_function(&mut self, func: &ast::Function) -> tacky::Function {
1727
// let mut instructions: InstructionVec = func
1828
// .body
1929
// .iter()
@@ -40,7 +50,7 @@ impl AstToTacky {
4050
function
4151
}
4252

43-
fn convert_block_item(&self, block: &ast::BlockItem, instructions: &mut InstructionVec) {
53+
fn convert_block_item(&mut self, block: &ast::BlockItem, instructions: &mut InstructionVec) {
4454
match block {
4555
ast::BlockItem::Declaration(identifier, expr) => {
4656
if let Some(init) = expr {
@@ -56,7 +66,7 @@ impl AstToTacky {
5666
};
5767
}
5868

59-
fn convert_stmt(&self, stmt: &ast::Stmt, instructions: &mut InstructionVec) {
69+
fn convert_stmt(&mut self, stmt: &ast::Stmt, instructions: &mut InstructionVec) {
6070
match stmt {
6171
ast::Stmt::Return(expr) => {
6272
let expr = self.convert_expr(expr, instructions);
@@ -74,26 +84,76 @@ impl AstToTacky {
7484
false_stmt,
7585
} => self.convert_if_stmt(cond, true_stmt, false_stmt.as_ref(), instructions),
7686
};
77-
todo!()
7887
}
7988

80-
fn convert_expr(&self, expr: &ast::Expr, instructions: &mut InstructionVec) -> tacky::Value {
89+
fn convert_expr(&mut self, expr: &ast::Expr, instructions: &mut InstructionVec) -> tacky::Value {
8190
todo!()
8291
}
8392

8493
fn convert_if_stmt(
85-
&self,
94+
&mut self,
8695
cond: &ast::Expr,
8796
true_stmt: &ast::Stmt,
8897
false_stmt: Option<&Box<ast::Stmt>>,
8998
instructions: &mut InstructionVec,
9099
) {
91-
todo!()
100+
let cond_val = self.convert_expr(cond, instructions);
101+
let end_name = "if_end_label";
102+
let end_label: tacky::Instruction = self.make_label(end_name);
103+
104+
if let Some(false_stmt) = false_stmt {
105+
/*
106+
* With an else branch we emit something like
107+
*
108+
* Condition instructions
109+
* Jump to else if condition is 0
110+
* True branch instructions
111+
* Jump to end
112+
* Else label
113+
* False branch instructions
114+
* End label
115+
*/
116+
let else_name = "else_label";
117+
let else_label = self.make_label(else_name);
118+
let jump_else = tacky::Instruction::JumpIfZero {
119+
cond: cond_val,
120+
target: Identifier::new(else_name),
121+
};
122+
let jump_end = tacky::Instruction::Jump(Identifier::new(end_name));
123+
instructions.push(jump_else);
124+
self.convert_stmt(true_stmt, instructions);
125+
instructions.push(jump_end);
126+
instructions.push(else_label);
127+
self.convert_stmt(false_stmt, instructions);
128+
instructions.push(end_label);
129+
} else {
130+
// Without an else branch we just jump to the end label if the
131+
// condition is false and execute the true branch statements otherwise
132+
let jump_end = tacky::Instruction::JumpIfZero {
133+
cond: cond_val,
134+
target: Identifier::new(end_name),
135+
};
136+
instructions.push(jump_end);
137+
self.convert_stmt(true_stmt, instructions);
138+
instructions.push(end_label);
139+
}
140+
}
141+
142+
fn make_label(&mut self, name: &str) -> tacky::Instruction {
143+
let mut counter = 0;
144+
let mut label_name: String = name.to_string();
145+
while self.label_set.contains(&label_name) {
146+
label_name = format!("{name}{counter}");
147+
counter += 1;
148+
}
149+
let label = tacky::Instruction::Label(Identifier::new(&label_name));
150+
self.label_set.insert(label_name);
151+
label
92152
}
93153
}
94154

95155
/// Convert an ast::Program to a tacky::Program
96156
pub fn ast_to_tacky(ast: &ast::Program) -> tacky::Program {
97-
let mut converter = AstToTacky {};
157+
let mut converter = AstToTacky::new();
98158
return converter.convert_program(ast);
99159
}

0 commit comments

Comments
 (0)