@@ -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