diff --git a/pylingual/control_flow_reconstruction/templates/Exception.py b/pylingual/control_flow_reconstruction/templates/Exception.py index 266c736..8f67b7f 100644 --- a/pylingual/control_flow_reconstruction/templates/Exception.py +++ b/pylingual/control_flow_reconstruction/templates/Exception.py @@ -11,6 +11,7 @@ from ..utils import ( condense_mapping, defer_source_to, with_instructions, + without_instructions, ending_instructions, exact_instructions, no_back_edges, @@ -294,6 +295,21 @@ class TryFinally3_11(ControlFlowTemplate): return list(chain(s, self.line("finally:"), in_finally, after)) + + +class Except3_9(ControlFlowTemplate): + @classmethod + @override + def try_match(cls, cfg, node) -> ControlFlowTemplate | None: + if [x.opname for x in node.get_instructions()] == ["RERAISE"]: + return node + if x := ExceptExc3_9.try_match(cfg, node): + return x + if x := BareExcept3_9.try_match(cfg, node): + return x + if isinstance(node, Except3_9): + return node + class Except3_9(ControlFlowTemplate): @classmethod @@ -630,8 +646,8 @@ class TryElse3_6(ControlFlowTemplate): template = T( try_header=~N("try_body").with_cond(exact_instructions("SETUP_EXCEPT"), exact_instructions("SETUP_FINALLY")), try_body=N("try_footer.", None, "except_body"), - try_footer=~N("else_body").with_in_deg(1), - except_body=~N("tail.").with_in_deg(1).of_subtemplate(Except3_6), + try_footer=~N("else_body").with_in_deg(1), + except_body=~N("tail.").with_in_deg(1).of_subtemplate(Except3_6).with_cond(without_instructions("RETURN_VALUE")), else_body=~N("tail.").with_in_deg(1), tail=N.tail(), ) @@ -660,6 +676,36 @@ class TryElse3_6(ControlFlowTemplate): {else_body} """ +@register_template(0, 0, (3, 6), (3, 7), (3, 8)) +class ReturnFinally3_6(ControlFlowTemplate): + template = T( + try_header=~N("try_body").with_cond(exact_instructions("SETUP_FINALLY")), + try_body=N(None, None, "fail_body").with_cond(with_instructions("LOAD_CONST","RETURN_VALUE")), + fail_body=~N("tail."), + tail=N.tail(), + ) + + try_match = revert_on_fail( + make_try_match( + { + EdgeKind.Fall: "tail", + }, + "try_header", + "try_body", + "fail_body", + ) + ) + + @to_indented_source + def to_indented_source(): + """ + {try_header} + try: + {try_body} + finally: + {fail_body} + """ + class BareExcept3_6(Except3_6): template = T( @@ -687,16 +733,17 @@ class TryFinally3_6(ControlFlowTemplate): try_header=N("try_body"), try_body=N("finally_body", None, "fail_body"), finally_body=~N("fail_body").with_in_deg(1).with_cond(no_back_edges), - fail_body=N("tail.").with_cond(with_instructions("POP_TOP", "END_FINALLY")), + fail_body=N("tail.").with_cond(with_instructions("POP_TOP", "END_FINALLY"),with_instructions("LOAD_CONST", "RETURN_VALUE")), tail=N.tail(), ) template2 = T( - try_except=N("finally_tail", None, "fail_body").of_type(TryElse3_6, Try3_6), + try_except=N("finally_tail", None, "fail_body").of_type(TryElse3_6, Try3_6, ReturnFinally3_6), finally_tail=N("finally_body", None, "fail_body"), finally_body=~N("fail_body").with_in_deg(1).with_cond(no_back_edges), - fail_body=N("tail.").with_cond(with_instructions("POP_TOP", "END_FINALLY")), + fail_body=N("tail.").with_cond(with_instructions("POP_TOP", "END_FINALLY"),with_instructions("LOAD_CONST", "RETURN_VALUE")), tail=N.tail(), ) + cutoff: int @@ -731,3 +778,5 @@ class TryFinally3_6(ControlFlowTemplate): after = [] return list(chain(header, self.line("try:"), body, self.line("finally:"), in_finally, after)) + + diff --git a/test/TryExcept.py b/test/TryExcept.py index 04b0f42..ad81ab9 100644 --- a/test/TryExcept.py +++ b/test/TryExcept.py @@ -256,7 +256,7 @@ def k_TryExceptFinallyBare(): finally: print(3) print(4) - + def l_TryExceptFinallyBareSpecific(): try: print(1) @@ -383,6 +383,7 @@ def w_TryExceptRaise(): print(2) raise Exc + def x_TryExceptRaiseMulti(): try: print(1) @@ -440,6 +441,99 @@ def ab_TryExceptReturnNamed(): return 2 except A as a: print(2) + raise Exc + except b: + print(3) + raise Exc + +def TryEmptryFinally(): + try: + pass + finally: + print(1) + +def TryMultiple(): + try: + print(1) + except: + print(2) + + try: + print(3) + except: + print(4) + +def TryExceptElseTry(): + try: + print(1) + except: + print(2) + else: + try: + print(3) + except: + print(4) + +def TryFinallyNestedExcept(): + try: + print(1) + finally: + try: + print(2) + except: + print(3) + +def TryExceptTuple(): + try: + print(1) + except (A, B): + print(2) + +def TryFinallyReturn(): + try: + print(1) + finally: + return 2 + +def TryReturnFinally(): + try: + return 1 + finally: + print(2) + +def TryReturnFinallyReturn(): + try: + return 1 + finally: + return 2 + +def TryExceptRaise(): + try: + print(1) + return 2 + except: + raise Exception() + +''' +def TryExceptReturnFinally(): + try: + raise Exception() + except: + print(1) + return 2 + finally: + print(3) +''' + +''' +def TryFinallyRaise(): + try: + print(1) + return 2 + finally: + raise Exception() +''' + def ab1_TryExceptReturnNamed(): try: @@ -460,4 +554,5 @@ def ad_TryFinallyBare(): try: print(1) finally: - print(2) \ No newline at end of file + print(2) +