From 498e80e61eabffe941de8bf59cd608a7e770d0ea Mon Sep 17 00:00:00 2001 From: Xinlong Hu <118075581+XinlongCS@users.noreply.github.com> Date: Thu, 24 Jul 2025 11:30:35 -0500 Subject: [PATCH] 3.11 TryExcept adjustments --- .../templates/Exception.py | 84 +++++++++++++++++-- .../control_flow_reconstruction/utils.py | 4 + 2 files changed, 82 insertions(+), 6 deletions(-) diff --git a/pylingual/control_flow_reconstruction/templates/Exception.py b/pylingual/control_flow_reconstruction/templates/Exception.py index 854c49e..1956553 100644 --- a/pylingual/control_flow_reconstruction/templates/Exception.py +++ b/pylingual/control_flow_reconstruction/templates/Exception.py @@ -13,6 +13,8 @@ from ..utils import ( with_instructions, without_instructions, ending_instructions, + has_no_lines, + has_some_lines, exact_instructions, no_back_edges, without_top_level_instructions, @@ -39,8 +41,8 @@ class Except3_11(ControlFlowTemplate): return x -@register_template(0, 0, *versions_from(3, 11)) -class Try3_11(ControlFlowTemplate): +@register_template(0, 0, *versions_from(3, 12)) +class Try3_12(ControlFlowTemplate): template = T( try_header=N("try_body"), try_body=N("tail.", None, "except_body"), @@ -71,8 +73,8 @@ class Try3_11(ControlFlowTemplate): """ -@register_template(0, 0, *versions_from(3, 11)) -class TryElse3_11(ControlFlowTemplate): +@register_template(0, 0, *versions_from(3, 12)) +class TryElse3_12(ControlFlowTemplate): template = T( try_header=N("try_body"), try_body=N("try_else.", None, "except_body"), @@ -105,6 +107,76 @@ class TryElse3_11(ControlFlowTemplate): else: {try_else} """ + + +@register_template(0, 0, (3, 11)) +class Try3_11(ControlFlowTemplate): + template = T( + try_header=N("try_body"), + try_body=N("try_else.", None, "except_body"), + except_body=N("tail.", None, "reraise").with_in_deg(1).of_subtemplate(Except3_11), + try_else=~N("tail.").with_in_deg(1).with_cond(has_no_lines), + reraise=reraise, + tail=N.tail(), + ) + + try_match = revert_on_fail( + make_try_match( + { + EdgeKind.Fall: "tail", + }, + "try_header", + "try_else", + "try_body", + "except_body", + "reraise", + ) + ) + + @to_indented_source + def to_indented_source(): + """ + {try_header} + try: + {try_body} + {except_body} + """ + + +@register_template(0, 0, (3, 11)) +class TryElse3_11(ControlFlowTemplate): + template = T( + try_header=N("try_body"), + try_body=N("try_else.", None, "except_body"), + except_body=N("tail.", None, "reraise").with_in_deg(1).of_subtemplate(Except3_11), + try_else=~N("tail.").with_in_deg(1).with_cond(has_some_lines), + reraise=reraise, + tail=N.tail(), + ) + + try_match = revert_on_fail( + make_try_match( + { + EdgeKind.Fall: "tail", + }, + "try_header", + "try_body", + "except_body", + "try_else", + "reraise", + ) + ) + + @to_indented_source + def to_indented_source(): + """ + {try_header} + try: + {try_body} + {except_body} + else: + {try_else} + """ class BareExcept3_11(Except3_11): @@ -225,7 +297,7 @@ class TryFinally3_11(ControlFlowTemplate): tail=N.tail(), ) template2 = T( - try_except=N("finally_body", None, "fail_body").of_type(Try3_11, TryElse3_11), + try_except=N("finally_body", None, "fail_body").of_type(Try3_11, TryElse3_11, Try3_12, TryElse3_12), finally_body=~N("tail.").with_in_deg(1).with_cond(no_back_edges), fail_body=N(E.exc("reraise")).with_cond(ending_instructions("POP_TOP", "RERAISE")), reraise=reraise, @@ -280,7 +352,7 @@ class TryFinally3_11(ControlFlowTemplate): def to_indented_source(self, source: SourceContext) -> list[SourceLine]: header = source[self.try_header] body = source[self.try_body, 1] - if isinstance(self.try_header, (Try3_11, TryElse3_11)) and self.members["try_body"] is None: + if isinstance(self.try_header, (Try3_11, TryElse3_11, Try3_12, TryElse3_12)) and self.members["try_body"] is None: s = header else: s = chain(header, self.line("try:"), body) diff --git a/pylingual/control_flow_reconstruction/utils.py b/pylingual/control_flow_reconstruction/utils.py index 020d7c9..66367ea 100644 --- a/pylingual/control_flow_reconstruction/utils.py +++ b/pylingual/control_flow_reconstruction/utils.py @@ -134,6 +134,10 @@ def has_no_lines(cfg: CFG, node: ControlFlowTemplate | None) -> bool: return node is None or all(i.starts_line is None for i in node.get_instructions()) +def has_some_lines(cfg: CFG, node: ControlFlowTemplate | None) -> bool: + return node is None or any(i.starts_line is not None for i in node.get_instructions()) + + def run_is(n: int): def check_run(cfg: CFG, node: ControlFlowTemplate | None) -> bool: return cfg.run == n