From c381d60a96d983cd9a56932279252cd5f09b098d Mon Sep 17 00:00:00 2001 From: Xinlong Hu Date: Mon, 4 Aug 2025 23:28:46 -0500 Subject: [PATCH] Continue/Break distinctions + IfThen --- .../templates/Conditional.py | 4 ++-- .../templates/Loop.py | 17 +++++++---------- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/pylingual/control_flow_reconstruction/templates/Conditional.py b/pylingual/control_flow_reconstruction/templates/Conditional.py index d76bef0..1e00c31 100644 --- a/pylingual/control_flow_reconstruction/templates/Conditional.py +++ b/pylingual/control_flow_reconstruction/templates/Conditional.py @@ -50,8 +50,8 @@ class IfElseLoop(ControlFlowTemplate): @register_template(2, 41) class IfThen(ControlFlowTemplate): template = T( - if_header=~N("if_body", "tail").with_cond(without_top_level_instructions("WITH_EXCEPT_START", "CHECK_EXC_MATCH", "FOR_ITER")), - if_body=~N("tail").with_in_deg(1) | ~N("tail.").with_in_deg(1).with_cond(run_is(2)), + if_header=~N("if_body", "tail").with_cond(without_top_level_instructions("WITH_EXCEPT_START", "CHECK_EXC_MATCH", "FOR_ITER", "JUMP_IF_NOT_EXC_MATCH")), + if_body=~N(None).with_in_deg(1).of_type(BreakTemplate, ContinueTemplate) | ~N("tail").with_in_deg(1) | ~N("tail.").with_in_deg(1).with_cond(run_is(2)), tail=N.tail(), ) diff --git a/pylingual/control_flow_reconstruction/templates/Loop.py b/pylingual/control_flow_reconstruction/templates/Loop.py index c5ec983..0188718 100644 --- a/pylingual/control_flow_reconstruction/templates/Loop.py +++ b/pylingual/control_flow_reconstruction/templates/Loop.py @@ -11,10 +11,7 @@ from ..utils import ( no_back_edges, versions_below, versions_from, - with_instructions, - exact_instructions, has_no_lines, - has_some_lines, condense_mapping, defer_source_to, starting_instructions, @@ -163,14 +160,14 @@ class InlinedComprehensionTemplate(ControlFlowTemplate): class BreakTemplate(ControlFlowTemplate): @classmethod def try_match(cls, cfg, node): - if not with_top_level_instructions("POP_TOP", "LOAD_CONST", "RETURN_VALUE", "RETURN_CONST", "JUMP_ABSOLUTE", "JUMP_FORWARD", "JUMP_BACKWARD", "BREAK_LOOP")(cfg, node) or has_no_lines(cfg, node): + if not with_top_level_instructions("POP_TOP", "LOAD_CONST", "RETURN_VALUE", "RETURN_CONST", "JUMP_ABSOLUTE", "JUMP_FORWARD", "JUMP_BACKWARD", "BREAK_LOOP", "POP_BLOCK")(cfg, node) or has_no_lines(cfg, node): return None i = len(node.get_instructions()) - 1 while i >= 0: instruction = node.get_instructions()[i].opname - if instruction in {"POP_TOP", "LOAD_CONST", "RETURN_VALUE", "RETURN_CONST", "JUMP_ABSOLUTE", "JUMP_FORWARD", "JUMP_BACKWARD", "BREAK_LOOP"}: - if node.get_instructions()[i].starts_line is not None: + if instruction in {"POP_TOP", "LOAD_CONST", "RETURN_VALUE", "RETURN_CONST", "JUMP_ABSOLUTE", "JUMP_FORWARD", "JUMP_BACKWARD", "BREAK_LOOP", "POP_BLOCK"}: + if node.get_instructions()[i].starts_line is not None and node.get_instructions()[i].source_line not in {"pass", "...", "return"}: return condense_mapping(cls, cfg, {"child": node}, "child") else: i -= 1 @@ -186,14 +183,14 @@ class BreakTemplate(ControlFlowTemplate): class ContinueTemplate(ControlFlowTemplate): @classmethod def try_match(cls, cfg, node): - if not with_top_level_instructions("JUMP_ABSOLUTE", "JUMP_BACKWARD", "CONTINUE_LOOP", "POP_EXCEPT")(cfg, node) or has_no_lines(cfg, node): + if not with_top_level_instructions("JUMP_ABSOLUTE", "JUMP_BACKWARD", "CONTINUE_LOOP", "POP_EXCEPT", "POP_BLOCK")(cfg, node) or has_no_lines(cfg, node): return None i = len(node.get_instructions()) - 1 while i >= 0: instruction = node.get_instructions()[i].opname - if instruction in {"JUMP_ABSOLUTE", "JUMP_BACKWARD", "CONTINUE_LOOP", "POP_EXCEPT"}: - if node.get_instructions()[i].starts_line is not None: + if instruction in {"JUMP_ABSOLUTE", "JUMP_BACKWARD", "CONTINUE_LOOP", "POP_EXCEPT", "POP_BLOCK"}: + if node.get_instructions()[i].starts_line is not None and node.get_instructions()[i].source_line not in {"pass", "...", "return"}: return condense_mapping(cls, cfg, {"child": node}, "child") else: i -= 1 @@ -227,7 +224,7 @@ class FixLoop(ControlFlowTemplate): if cfg.dominates(node, predecessor): back_edges.append(predecessor) - if not back_edges or with_top_level_instructions("SEND")(cfg, node): + if not back_edges or all(n == node for n in back_edges) or with_top_level_instructions("SEND")(cfg, node): return None # Get all nodes encompassed by the loop excluding source node and initial false jump