3.13 Preventing Loops from matching

This commit is contained in:
Xinlong Hu
2025-08-01 19:54:28 -05:00
parent 19a44f128f
commit 42763b367e
2 changed files with 13 additions and 6 deletions
@@ -7,7 +7,7 @@ from pylingual.editable_bytecode import Inst
import networkx as nx
from ..cft import ControlFlowTemplate, EdgeKind, SourceContext, SourceLine, register_template, EdgeCategory, out_edge_dict, MetaTemplate, indent_str
from ..utils import E, N, T, defer_source_to, remove_nodes, versions_from, without_instructions, has_no_lines, exact_instructions, make_try_match
from ..utils import E, N, T, defer_source_to, no_self_edges, remove_nodes, versions_from, without_instructions, has_no_lines, exact_instructions, make_try_match
if TYPE_CHECKING:
from pylingual.control_flow_reconstruction.cfg import CFG
@@ -58,14 +58,18 @@ class RemoveUnreachable(ControlFlowTemplate):
class JumpTemplate(ControlFlowTemplate):
template = T(
body=~N("jump", None).with_cond(without_instructions("CLEANUP_THROW")),
jump=N("tail", "block?").with_in_deg(1).with_cond(
jump=N("tail", "block?")
.with_cond(no_self_edges)
.with_in_deg(1)
.with_cond(
exact_instructions("JUMP_BACKWARD_NO_INTERRUPT"),
exact_instructions("POP_JUMP_IF_TRUE"),
exact_instructions("POP_JUMP_IF_TRUE"),
exact_instructions("JUMP_FORWARD"),
exact_instructions("JUMP_BACKWARD"),
exact_instructions("POP_JUMP_IF_NOT_NONE"),
exact_instructions("POP_JUMP_IF_NONE"),
exact_instructions("POP_JUMP_IF_FALSE")),
exact_instructions("POP_JUMP_IF_NOT_NONE"),
exact_instructions("POP_JUMP_IF_NONE"),
exact_instructions("POP_JUMP_IF_FALSE"),
),
block=N.tail(),
tail=N.tail(),
)
@@ -81,6 +85,7 @@ class JumpTemplate(ControlFlowTemplate):
to_indented_source = defer_source_to("body")
@register_template(0, 0, *versions_from(3, 11))
class NopTemplate(ControlFlowTemplate):
template = T(
@@ -119,6 +119,8 @@ def has_type(*template_type: type[ControlFlowTemplate]):
def no_back_edges(cfg: CFG, node: ControlFlowTemplate | None) -> bool:
return node is None or not any(cfg.dominates(succ, node) for succ in cfg.successors(node))
def no_self_edges(cfg: CFG, node: ControlFlowTemplate | None) -> bool:
return node is None or not any(cfg.has_edge(succ, node) and cfg.has_edge(node, succ) for succ in cfg.successors(node))
def has_incoming_edge_of_categories(*categories: str):
def check(cfg: CFG, node: ControlFlowTemplate | None) -> bool: