Skip to content

Commit d058fad

Browse files
committed
TACKY pretty printer and tests
1 parent f47df70 commit d058fad

3 files changed

Lines changed: 359 additions & 38 deletions

File tree

rust_src/ast_to_tacky.rs

Lines changed: 175 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -126,10 +126,8 @@ impl AstToTacky {
126126
* end label
127127
*/
128128
let res = self.make_temp();
129-
let end_name = "cond_end_label";
130-
let end_label = self.make_label(end_name);
131-
let false_name = "cond_false_label";
132-
let false_label = self.make_label(false_name);
129+
let (end_label, end_name) = self.make_label("cond_end_label");
130+
let (false_label, false_name) = self.make_label("cond_false_label");
133131
let mut true_instrs: InstructionVec = Vec::new();
134132
let true_val = self.convert_expr(true_expr, &mut true_instrs);
135133
let mut false_instrs: InstructionVec = Vec::new();
@@ -138,15 +136,15 @@ impl AstToTacky {
138136
let cond_val = self.convert_expr(cond, instructions);
139137
instructions.push(tacky::Instruction::JumpIfZero {
140138
cond: cond_val,
141-
target: Identifier::new(false_name),
139+
target: Identifier::new(&false_name),
142140
});
143141
instructions.append(&mut true_instrs);
144142
instructions.extend_from_slice(&[
145143
tacky::Instruction::Copy {
146144
src: true_val,
147145
dst: res.clone(),
148146
},
149-
tacky::Instruction::Jump(Identifier::new(end_name)),
147+
tacky::Instruction::Jump(Identifier::new(&end_name)),
150148
false_label,
151149
]);
152150
instructions.append(&mut false_instrs);
@@ -180,10 +178,9 @@ impl AstToTacky {
180178
false
181179
};
182180
let target_name = if is_and { "false_label" } else { "true_label" };
183-
let target_id = Identifier::new(target_name);
184-
let short_circuit_label = self.make_label(target_name);
185-
let end_name = "end";
186-
let end_label = self.make_label(end_name);
181+
let (short_circuit_label, target_name) = self.make_label(target_name);
182+
let target_id = Identifier::new(&target_name);
183+
let (end_label, end_name) = self.make_label("end");
187184
let jump_factory = if is_and {
188185
|cond, target| tacky::Instruction::JumpIfZero { cond, target }
189186
} else {
@@ -206,7 +203,7 @@ impl AstToTacky {
206203
instructions.extend_from_slice(&[
207204
second_jump,
208205
copy1,
209-
tacky::Instruction::Jump(Identifier::new(end_name)),
206+
tacky::Instruction::Jump(Identifier::new(&end_name)),
210207
short_circuit_label,
211208
copy2,
212209
end_label,
@@ -287,8 +284,7 @@ impl AstToTacky {
287284
instructions: &mut InstructionVec,
288285
) {
289286
let cond_val = self.convert_expr(cond, instructions);
290-
let end_name = "if_end_label";
291-
let end_label: tacky::Instruction = self.make_label(end_name);
287+
let (end_label, end_name) = self.make_label("if_end_label");
292288

293289
if let Some(false_stmt) = false_stmt {
294290
/*
@@ -302,13 +298,12 @@ impl AstToTacky {
302298
* False branch instructions
303299
* End label
304300
*/
305-
let else_name = "else_label";
306-
let else_label = self.make_label(else_name);
301+
let (else_label, else_name) = self.make_label("else_label");
307302
let jump_else = tacky::Instruction::JumpIfZero {
308303
cond: cond_val,
309-
target: Identifier::new(else_name),
304+
target: Identifier::new(&else_name),
310305
};
311-
let jump_end = tacky::Instruction::Jump(Identifier::new(end_name));
306+
let jump_end = tacky::Instruction::Jump(Identifier::new(&end_name));
312307
instructions.push(jump_else);
313308
self.convert_stmt(true_stmt, instructions);
314309
instructions.push(jump_end);
@@ -320,24 +315,24 @@ impl AstToTacky {
320315
// condition is false and execute the true branch statements otherwise
321316
let jump_end = tacky::Instruction::JumpIfZero {
322317
cond: cond_val,
323-
target: Identifier::new(end_name),
318+
target: Identifier::new(&end_name),
324319
};
325320
instructions.push(jump_end);
326321
self.convert_stmt(true_stmt, instructions);
327322
instructions.push(end_label);
328323
}
329324
}
330325

331-
fn make_label(&mut self, name: &str) -> tacky::Instruction {
326+
fn make_label(&mut self, name: &str) -> (tacky::Instruction, String) {
332327
let mut counter = 0;
333328
let mut label_name: String = name.to_string();
334329
while self.label_set.contains(&label_name) {
335330
label_name = format!("{name}{counter}");
336331
counter += 1;
337332
}
338333
let label = tacky::Instruction::Label(Identifier::new(&label_name));
339-
self.label_set.insert(label_name);
340-
label
334+
self.label_set.insert(label_name.clone());
335+
(label, label_name)
341336
}
342337

343338
fn make_temp(&mut self) -> tacky::Value {
@@ -358,28 +353,173 @@ mod tests {
358353
use super::*;
359354
use crate::pretty_print_tacky::pretty_print_tacky;
360355
use crate::semantics::run_semantic_analysis;
361-
use crate::test_tools::run_parser;
356+
use crate::test_tools::{assert_tacky_has_pretty_print, run_parser};
362357
use pretty_assertions::assert_eq;
363358
#[test]
364-
fn basic_tacky() -> Result<(), Box<dyn std::error::Error>> {
359+
fn logical_ops() {
360+
let main = "int main(void) {
361+
return !(3 < 4 <= 5 > 6 >= 7 == 8 != 9);
362+
}";
363+
let expected = r#"
364+
Function main () {
365+
Less($3,$4,%notcc.tmp.0)
366+
LessEqual(%notcc.tmp.0,$5,%notcc.tmp.1)
367+
Greater(%notcc.tmp.1,$6,%notcc.tmp.2)
368+
GreaterEqual(%notcc.tmp.2,$7,%notcc.tmp.3)
369+
Equal(%notcc.tmp.3,$8,%notcc.tmp.4)
370+
NotEqual(%notcc.tmp.4,$9,%notcc.tmp.5)
371+
Not(%notcc.tmp.5, %notcc.tmp.6)
372+
Return(%notcc.tmp.6)
373+
}
374+
"#;
375+
assert_tacky_has_pretty_print(main, expected);
376+
}
377+
378+
#[test]
379+
fn short_circuiting_and() {
380+
let code = r#"int main(void) {
381+
return (1*2) && (2-3);
382+
}"#;
383+
let expected = r#"
384+
Function main () {
385+
Multiply($1,$2,%notcc.tmp.0)
386+
JumpIfZero(%notcc.tmp.0, false_label)
387+
Subtract($2,$3,%notcc.tmp.1)
388+
JumpIfZero(%notcc.tmp.1, false_label)
389+
Copy($1, %notcc.tmp.2)
390+
Jump(end)
391+
Label(false_label)
392+
Copy($0, %notcc.tmp.2)
393+
Label(end)
394+
Return(%notcc.tmp.2)
395+
}
396+
"#;
397+
assert_tacky_has_pretty_print(code, expected);
398+
}
399+
400+
#[test]
401+
fn short_circuiting_or() {
402+
let code = r#"
403+
int main(void) {
404+
return 1 < 2 || 2 >= 3;
405+
}
406+
"#;
407+
let expected = r#"
408+
Function main () {
409+
Less($1,$2,%notcc.tmp.0)
410+
JumpIfNotZero(%notcc.tmp.0, true_label)
411+
GreaterEqual($2,$3,%notcc.tmp.1)
412+
JumpIfNotZero(%notcc.tmp.1, true_label)
413+
Copy($0, %notcc.tmp.2)
414+
Jump(end)
415+
Label(true_label)
416+
Copy($1, %notcc.tmp.2)
417+
Label(end)
418+
Return(%notcc.tmp.2)
419+
}
420+
"#;
421+
assert_tacky_has_pretty_print(code, expected);
422+
}
423+
424+
#[test]
425+
fn label_mangling() {
426+
let code = r#"
427+
int main(void) {
428+
return 1 && 2 && 3;
429+
}
430+
"#;
431+
let expected = r#"
432+
Function main () {
433+
JumpIfZero($1, false_label)
434+
JumpIfZero($2, false_label)
435+
Copy($1, %notcc.tmp.0)
436+
Jump(end)
437+
Label(false_label)
438+
Copy($0, %notcc.tmp.0)
439+
Label(end)
440+
JumpIfZero(%notcc.tmp.0, false_label0)
441+
JumpIfZero($3, false_label0)
442+
Copy($1, %notcc.tmp.1)
443+
Jump(end0)
444+
Label(false_label0)
445+
Copy($0, %notcc.tmp.1)
446+
Label(end0)
447+
Return(%notcc.tmp.1)
448+
}
449+
"#;
450+
assert_tacky_has_pretty_print(code, expected);
451+
}
452+
453+
#[test]
454+
fn assign() {
365455
let code = r#"
366456
int main(void) {
367457
int x = 2;
368458
int y;
369-
y = x + 3;
370-
if (y > 4)
371-
x = x + 1;
372-
else
373-
y = y - 1;
459+
y = 4;
460+
int z = x * y;
461+
return z + (y = 3) + 2;
462+
}
463+
"#;
464+
let expected = r#"
465+
Function main () {
466+
Copy($2, %x.0)
467+
Copy($4, %y.1)
468+
Multiply(%x.0,%y.1,%notcc.tmp.0)
469+
Copy(%notcc.tmp.0, %z.2)
470+
Copy($3, %y.1)
471+
Plus(%z.2,%y.1,%notcc.tmp.1)
472+
Plus(%notcc.tmp.1,$2,%notcc.tmp.2)
473+
Return(%notcc.tmp.2)
474+
}
475+
"#;
476+
assert_tacky_has_pretty_print(code, expected);
477+
}
374478

375-
return x+y;
479+
#[test]
480+
fn no_return() {
481+
let code = "int main(void) { int x = 0; }";
482+
let expected = r#"
483+
Function main () {
484+
Copy($0, %x.0)
485+
Return($0)
486+
}
487+
"#;
488+
assert_tacky_has_pretty_print(code, expected);
489+
}
490+
491+
#[test]
492+
fn if_conditional() {
493+
let code = r#"
494+
int main(void) {
495+
int x = 2;
496+
int y;
497+
if (x)
498+
y = x+1 ? 1 : 2;
499+
else
500+
y = 3;
501+
return y;
376502
}
377503
"#;
378-
let mut prog = run_parser(code)?;
379-
run_semantic_analysis(&mut prog)?;
380-
let tacky = ast_to_tacky(&prog);
381-
assert_eq!(tacky.function.name, "main");
382-
assert!(pretty_print_tacky(&tacky).contains("main"));
383-
Ok(())
504+
let expected = r#"
505+
Function main () {
506+
Copy($2, %x.0)
507+
JumpIfZero(%x.0, else_label)
508+
Plus(%x.0,$1,%notcc.tmp.1)
509+
JumpIfZero(%notcc.tmp.1, cond_false_label)
510+
Copy($1, %notcc.tmp.0)
511+
Jump(cond_end_label)
512+
Label(cond_false_label)
513+
Copy($2, %notcc.tmp.0)
514+
Label(cond_end_label)
515+
Copy(%notcc.tmp.0, %y.1)
516+
Jump(if_end_label)
517+
Label(else_label)
518+
Copy($3, %y.1)
519+
Label(if_end_label)
520+
Return(%y.1)
521+
}
522+
"#;
523+
assert_tacky_has_pretty_print(code, expected);
384524
}
385525
}

0 commit comments

Comments
 (0)