def test_dont_optimize_jumps_with_missing_label_in_chain(): start_ast = [ parser.LabelStmt("start"), parser.AssignOp(src="inbox", dst="emp"), parser.JumpOp(label_name="a"), parser.OutboxOp(), parser.JumpOp(label_name="start"), parser.LabelStmt("a"), parser.JumpOp(label_name="b"), parser.LabelStmt("b"), parser.JumpOp(label_name="misspelled_start"), parser.LabelStmt("misspelled_start"), ] expected_ast = [ parser.LabelStmt("start"), parser.AssignOp(src="inbox", dst="emp"), parser.JumpOp(label_name="misspelled_start"), parser.OutboxOp(), parser.JumpOp(label_name="start"), parser.LabelStmt("a"), parser.JumpOp(label_name="misspelled_start"), parser.LabelStmt("b"), parser.JumpOp(label_name="misspelled_start"), parser.LabelStmt("misspelled_start"), ] ast = compress_jumps(start_ast) assert ast == expected_ast
def test_convert_iftojump_nested(): code = [ p.IfOp("ez", [ p.IfOp("ez", [p.AssignOp("inbox", "emp")], [p.OutboxOp()]), ], [ p.IfOp("neg", [p.AssignOp("inbox", "emp")], [p.OutboxOp()]) ])] expected_ast = [ p.JumpCondOp(condition="jez", label_name="_hrm_1"), p.JumpCondOp(condition="jneg", label_name="_hrm_2"), p.OutboxOp(), p.JumpOp("_hrm_endif_2"), p.LabelStmt("_hrm_2"), p.AssignOp("inbox", "emp"), p.LabelStmt("_hrm_endif_2"), p.JumpOp("_hrm_endif_1"), p.LabelStmt("_hrm_1"), p.JumpCondOp(condition="jez", label_name="_hrm_3"), p.OutboxOp(), p.JumpOp("_hrm_endif_3"), p.LabelStmt("_hrm_3"), p.AssignOp("inbox", "emp"), p.LabelStmt("_hrm_endif_3"), p.LabelStmt("_hrm_endif_1")] ast = c.convert_iftojump(code) assert ast == expected_ast
def test_compress_jcond_single(): start_ast = [ parser.LabelStmt("start"), parser.AssignOp(src="inbox", dst="emp"), parser.JumpCondOp("if", "ez"), parser.OutboxOp(), parser.JumpOp("endif"), parser.LabelStmt("if"), parser.JumpOp("start"), parser.LabelStmt("endif"), parser.OutboxOp() ] expected_ast = [ parser.LabelStmt("start"), parser.AssignOp(src="inbox", dst="emp"), parser.JumpCondOp("start", "ez"), parser.OutboxOp(), parser.JumpOp("endif"), parser.LabelStmt("if"), parser.JumpOp("start"), parser.LabelStmt("endif"), parser.OutboxOp() ] ast = compress_jumps(start_ast) assert ast == expected_ast
def test_labelinast_nojump(): start_ast = [ parser.OutboxOp(), parser.LabelStmt("test"), parser.OutboxOp() ] labels_positions, _ = labels_in_ast(start_ast) assert "test" in labels_positions assert labels_positions["test"] == 2
def test_convert_jmpthenlabel_conditionaljumps_leading_to_same_instr(): start_ast = [ p.JumpCondOp(condition="ez", label_name="output"), p.LabelStmt("output"), p.OutboxOp() ] expected_ast = [p.OutboxOp()] ast = conversion.fix_jmp_then_label(start_ast) assert ast == expected_ast
def test_compress_jcond_no_compress(): start_ast = [ parser.JumpCondOp("label", "ez"), parser.OutboxOp(), parser.JumpOp("endif"), parser.LabelStmt("label"), parser.OutboxOp(), parser.LabelStmt("endif"), parser.OutboxOp() ] expected_ast = start_ast ast = compress_jumps(start_ast) assert ast == expected_ast
def test_convert_iftojump_onlyfalsebranch(): code = [ p.IfOp("ez", [], [ p.OutboxOp() ])] expected_ast = [ p.JumpCondOp(condition="jez", label_name="_hrm_1"), p.OutboxOp(), p.JumpOp("_hrm_endif_1"), p.LabelStmt("_hrm_1"), p.LabelStmt("_hrm_endif_1") ] ast = c.convert_iftojump(code) assert ast == expected_ast
def test_labelinast_no_labels(): start_ast = [] start_ast_2 = [parser.OutboxOp()] labels_positions, _ = labels_in_ast(start_ast) labels_positions_2, _ = labels_in_ast(start_ast_2) assert not len(labels_positions) assert not len(labels_positions_2)
def test_unreachable_condjumps(): start_ast = [ parser.AssignOp(src="inbox", dst="emp"), parser.JumpCondOp("_hrm_1", "jez"), parser.OutboxOp(), parser.LabelStmt("_hrm_1"), parser.LabelStmt("_hrm_endif_1") ] expected_ast = [ parser.AssignOp(src="inbox", dst="emp"), parser.JumpCondOp("_hrm_unreachable", "jez"), parser.OutboxOp(), parser.LabelStmt("_hrm_unreachable") ] ast = remove_unreachable_code(start_ast) assert ast == expected_ast
def test_labelinast_invalid_access(): start_ast = [ parser.OutboxOp(), parser.LabelStmt("test") ] labels_positions, _ = labels_in_ast(start_ast) assert "test" not in labels_positions
def test_compress_single_jump(): start_ast = [ parser.JumpOp("test"), parser.LabelStmt("test"), parser.JumpOp("wow"), parser.LabelStmt("wow"), parser.OutboxOp() ] expected_ast = [ parser.JumpOp("wow"), parser.LabelStmt("test"), parser.JumpOp("wow"), parser.LabelStmt("wow"), parser.OutboxOp() ] ast = compress_jumps(start_ast) assert ast == expected_ast
def test_no_compress(): expected_ast = start_ast = [ parser.JumpOp("test"), parser.LabelStmt("test"), parser.OutboxOp() ] ast = compress_jumps(start_ast) assert expected_ast == ast
def test_no_duplicated_labels_on_same_point(): start_ast = [ parser.AssignOp(src="inbox", dst="emp"), parser.JumpOp("skip"), parser.LabelStmt("comehere"), parser.OutboxOp(), parser.LabelStmt("skip"), parser.JumpOp("comehere") ] ast = remove_unreachable_code(start_ast) comehere_counter = sum(1 for ast_item in ast \ if type(ast_item) == parser.LabelStmt \ and ast_item.label_name == "comehere") assert comehere_counter == 1 start_ast = [ parser.AssignOp(src="inbox", dst="emp"), parser.JumpOp("comehere"), parser.LabelStmt("comehere"), parser.OutboxOp(), parser.LabelStmt("skip"), parser.JumpOp("comehere") ] ast = remove_unreachable_code(start_ast) comehere_counter = sum(1 for ast_item in ast \ if type(ast_item) == parser.LabelStmt \ and ast_item.label_name == "comehere") assert comehere_counter == 1 start_ast = [ parser.AssignOp(src="inbox", dst="emp"), parser.JumpCondOp("comehere", "jez"), parser.JumpOp("comehere"), parser.LabelStmt("comehere"), parser.OutboxOp(), parser.LabelStmt("skip"), parser.JumpOp("comehere") ] ast = remove_unreachable_code(start_ast) comehere_counter = sum(1 for ast_item in ast \ if type(ast_item) == parser.LabelStmt \ and ast_item.label_name == "comehere") assert comehere_counter == 1
def test_convert_jmpthenlabel_conditionaljumps_multiple(): start_ast = [ p.JumpCondOp(condition="jneg", label_name="other"), p.JumpCondOp(condition="jez", label_name="output"), p.LabelStmt("output"), p.OutboxOp(), p.LabelStmt("other"), p.AssignOp(src="inbox", dst="emp") ] expected_ast = [ p.JumpCondOp(condition="jneg", label_name="other"), p.OutboxOp(), p.LabelStmt("other"), p.AssignOp(src="inbox", dst="emp") ] ast = conversion.fix_jmp_then_label(start_ast) assert ast == expected_ast
def test_convert_iftojump_nothingchanged(): code = [ p.AssignOp("inbox", "emp"), p.SubOp("0"), p.OutboxOp() ] expected_ast = code ast = c.convert_iftojump(code) assert ast == expected_ast
def test_jcond_avoid_loop(): start_ast = [ parser.LabelStmt("test"), parser.JumpCondOp("test", "ez"), parser.OutboxOp(), parser.JumpOp("test"), ] expected_ast = start_ast ast = compress_jumps(start_ast) assert ast == expected_ast
def test_convert_iftojump_onlytruebranch_consecutive(): code = [ p.IfOp("ez", [p.OutboxOp()], []), p.IfOp("ez", [p.OutboxOp()], [])] expected_ast = [ # first IF p.JumpCondOp(condition="jez", label_name="_hrm_1"), p.JumpOp("_hrm_endif_1"), p.LabelStmt("_hrm_1"), p.OutboxOp(), p.LabelStmt("_hrm_endif_1"), # second IF p.JumpCondOp(condition="jez", label_name="_hrm_2"), p.JumpOp("_hrm_endif_2"), p.LabelStmt("_hrm_2"), p.OutboxOp(), p.LabelStmt("_hrm_endif_2")] ast = c.convert_iftojump(code) assert ast == expected_ast
def test_compress_multi_jump(): start_ast = [ parser.JumpOp("first"), parser.LabelStmt("first"), parser.JumpOp("second"), parser.LabelStmt("second"), parser.JumpOp("third"), parser.LabelStmt("third"), parser.JumpOp("fourth"), parser.LabelStmt("fourth"), parser.JumpOp("last"), parser.LabelStmt("last"), parser.OutboxOp() ] expected_ast = [ parser.JumpOp("last"), parser.LabelStmt("first"), parser.JumpOp("last"), parser.LabelStmt("second"), parser.JumpOp("last"), parser.LabelStmt("third"), parser.JumpOp("last"), parser.LabelStmt("fourth"), parser.JumpOp("last"), parser.LabelStmt("last"), parser.OutboxOp() ] ast = compress_jumps(start_ast) assert ast == expected_ast
def test_jcond_no_jump_in_false(): start_ast = [ parser.AssignOp("inbox", "emp"), parser.JumpCondOp(condition="ez", label_name="truebranch"), parser.OutboxOp(), parser.LabelStmt("truebranch"), parser.AddOp("tmp") ] ast = remove_unreachable_code(start_ast) assert ast == start_ast
def test_still_reachable(): start_ast = [ parser.JumpOp("skip"), parser.LabelStmt("ahah"), parser.OutboxOp(), parser.LabelStmt("skip"), parser.JumpOp("ahah") ] ast = remove_unreachable_code(start_ast) assert ast == start_ast
def test_if_doublebranch(): assembler = Assembler() transformed_ast = [ parser.IfOp("ez", [parser.OutboxOp()], [parser.AssignOp("inbox", "emp")]) ] assembler.convert(transformed_ast) assert assembler.code == [ "jez _hrm_1", "inbox", "jmp _hrm_endif_1", "_hrm_1:", "outbox", "_hrm_endif_1:" ]
def test_if_noelse(): assembler = Assembler() transformed_ast = [parser.IfOp("ez", [parser.OutboxOp()], [])] assembler.convert(transformed_ast) assert assembler.code == clean_output(""" jez _hrm_1 jmp _hrm_endif_1 _hrm_1: outbox _hrm_endif_1: """)
def test_dont_keep_only_last_label_on_instruction(): start_ast = [ parser.AssignOp(src='inbox', dst='emp'), parser.JumpCondOp(label_name='_hrm_1', condition='jez'), parser.OutboxOp(), parser.JumpOp(label_name="_hrm_endif_1"), parser.LabelStmt("_hrm_1"), parser.LabelStmt("_hrm_endif_1"), parser.AssignOp(src="inbox", dst="emp") ] ast = remove_unreachable_code(start_ast) assert parser.LabelStmt("_hrm_endif_1") in ast assert parser.LabelStmt("_hrm_1") in ast
def test_unreachable_jump_to_lone_label_in_jcond_false_path(): start_ast = [ parser.LabelStmt("start"), parser.AssignOp(src="inbox", dst="emp"), parser.JumpCondOp(condition="ez", label_name="isZero"), parser.JumpOp("loneLabel"), parser.LabelStmt("isZero"), parser.OutboxOp(), parser.JumpOp("start"), parser.LabelStmt("loneLabel") ] expected_ast = [ parser.LabelStmt("start"), parser.AssignOp(src="inbox", dst="emp"), parser.JumpCondOp(condition="ez", label_name="isZero"), parser.JumpOp("_hrm_unreachable"), parser.LabelStmt("isZero"), parser.OutboxOp(), parser.JumpOp("start"), parser.LabelStmt("_hrm_unreachable") ] ast = remove_unreachable_code(start_ast) assert ast == expected_ast
def test_if_multiple_ops(): code = """ start: emp = inbox if ez then outbox jmp start endif """ with StringIO(code) as f: ast = parser.parse_it(f) if_op = ast[2] assert type(if_op) == parser.IfOp assert if_op.condition == "ez" assert if_op.true_branch == [parser.OutboxOp(), parser.JumpOp("start")]
def test_skip_operation(): start_ast = [ parser.AssignOp("inbox", "emp"), parser.JumpOp("label"), parser.OutboxOp(), parser.LabelStmt("label"), parser.AddOp("tmp") ] expected_ast = [ parser.AssignOp("inbox", "emp"), parser.JumpOp("label"), parser.LabelStmt("label"), parser.AddOp("tmp") ] ast = remove_unreachable_code(start_ast) assert ast == expected_ast
def test_dont_optimize_conditional_jumps(): """ if ez then # nothing, but the `jez` must not be removed! # if removed, the program becomes only `outbox`, # that is incorrect. else outbox endif """ start_ast = [ parser.JumpCondOp(label_name='_hrm_1', condition='jez'), parser.OutboxOp(), parser.JumpOp(label_name="_hrm_endif_1"), parser.LabelStmt(label_name="_hrm_1"), parser.LabelStmt(label_name="_hrm_endif_1") ] ast = compress_jumps(start_ast) assert parser.JumpCondOp(label_name="_hrm_1", condition="jez") in ast
def test_convert_ifnojump_no_ifs_remaining(): code = [p.IfOp("ez", [p.OutboxOp()], [p.AssignOp("inbox", "emp")])] ast = c.convert_iftojump(code) assert not [ast_item for ast_item in ast if type(ast_item) == p.IfOp]
def test_outbox(): code = [parser.OutboxOp()] converter = Assembler() converter.convert(code) assert converter.code == [{"operation": "outbox"}]
def test_single_operation(): start_ast = [parser.OutboxOp()] ast = remove_unreachable_code(start_ast) assert start_ast == ast