Continue/Break distinctions + IfThen

This commit is contained in:
Xinlong Hu
2025-08-04 23:28:46 -05:00
parent deb0408285
commit c381d60a96
2 changed files with 9 additions and 12 deletions
@@ -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(),
)
@@ -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