From d80b35ec3daf1d4defd50ed7a8c12e8cc8e07a8d Mon Sep 17 00:00:00 2001 From: Xinlong Hu <118075581+XinlongCS@users.noreply.github.com> Date: Wed, 30 Jul 2025 11:52:01 -0500 Subject: [PATCH 1/8] Break/Continue adjustments --- .../templates/Conditional.py | 6 ++-- .../templates/Loop.py | 35 +++++++++++++++---- 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/pylingual/control_flow_reconstruction/templates/Conditional.py b/pylingual/control_flow_reconstruction/templates/Conditional.py index 41989cc..d76bef0 100644 --- a/pylingual/control_flow_reconstruction/templates/Conditional.py +++ b/pylingual/control_flow_reconstruction/templates/Conditional.py @@ -1,14 +1,14 @@ from ..cft import ControlFlowTemplate, EdgeKind, register_template from ..utils import T, N, defer_source_to, run_is, has_no_lines, with_instructions, has_instval, starting_instructions, to_indented_source, make_try_match, without_top_level_instructions -from .Loop import BreakTemplate +from .Loop import BreakTemplate, ContinueTemplate @register_template(1, 40) class IfElse(ControlFlowTemplate): template = T( if_header=~N("if_body", "else_body").with_cond(without_top_level_instructions("WITH_EXCEPT_START", "CHECK_EXC_MATCH", "FOR_ITER")), - if_body=N.tail().with_in_deg(1).of_type(BreakTemplate) | ~N("tail.").with_in_deg(1), - else_body=N.tail().with_in_deg(1).of_type(BreakTemplate) | ~N("tail.").with_cond(without_top_level_instructions("RERAISE", "END_FINALLY")).with_in_deg(1), + if_body=N(None).with_in_deg(1).of_type(BreakTemplate, ContinueTemplate) | ~N("tail.").with_in_deg(1), + else_body=N("tail.").with_in_deg(1).of_type(BreakTemplate, ContinueTemplate) | ~N("tail.").with_cond(without_top_level_instructions("RERAISE", "END_FINALLY")).with_in_deg(1), tail=N.tail(), ) diff --git a/pylingual/control_flow_reconstruction/templates/Loop.py b/pylingual/control_flow_reconstruction/templates/Loop.py index 3faeca4..db78f71 100644 --- a/pylingual/control_flow_reconstruction/templates/Loop.py +++ b/pylingual/control_flow_reconstruction/templates/Loop.py @@ -90,9 +90,21 @@ class InlinedComprehensionTemplate(ControlFlowTemplate): class BreakTemplate(ControlFlowTemplate): @classmethod def try_match(cls, cfg, node): - if isinstance(node, BreakTemplate) or has_no_lines(cfg, node) or with_instructions("RAISE_VARARGS")(cfg, node): + if isinstance(node, BreakTemplate) or has_no_lines(cfg, node): return None - return condense_mapping(cls, cfg, {"child": node}, "child") + + 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: + return condense_mapping(cls, cfg, {"child": node}, "child") + else: + i -= 1 + continue + else: + return None + return None def to_indented_source(self, source): return self.child.to_indented_source(source) + self.line("break") @@ -103,9 +115,18 @@ class ContinueTemplate(ControlFlowTemplate): def try_match(cls, cfg, node): if isinstance(node, ContinueTemplate) or has_no_lines(cfg, node): return None - instruction = node.get_instructions()[-1].opname - if instruction in {"JUMP_ABSOLUTE", "JUMP_BACKWARD", "CONTINUE_LOOP"} and (node.get_instructions()[-1].starts_line is not None or node.get_instructions()[-2].starts_line is not None): - return condense_mapping(cls, cfg, {"child": node}, "child") + + 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: + return condense_mapping(cls, cfg, {"child": node}, "child") + else: + i -= 1 + continue + else: + return None return None def to_indented_source(self, source): @@ -151,11 +172,11 @@ class FixLoop(ControlFlowTemplate): # Find the candidate end that break connects to candidate_end = None for succ in cfg.successors(node): - if cfg.get_edge_data(node, succ).get("kind") == EdgeKind.FalseJump and cfg.out_degree(succ) <= 1: + if cfg.get_edge_data(node, succ).get("kind") == EdgeKind.FalseJump: candidate_end = succ # Candidate end is a buffer node - if cfg.in_degree(candidate_end) == 1 and all(x.opname in {"POP_TOP", "POP_BLOCK", "END_FOR", "RETURN_CONST", "LOAD_CONST", "RETURN_VALUE", "JUMP_BACKWARD"} for x in candidate_end.get_instructions()): + if cfg.in_degree(candidate_end) == 1: for ss in cfg.successors(candidate_end): if cfg.get_edge_data(candidate_end, ss).get("kind") != EdgeKind.Exception: candidate_end = ss From 6a3d869868ab917a0b363d555ab26885190b8e86 Mon Sep 17 00:00:00 2001 From: Xinlong Hu Date: Fri, 1 Aug 2025 19:46:51 -0500 Subject: [PATCH 2/8] While Loops + Breaks/Continues --- .../templates/Loop.py | 118 ++++++++++++++---- .../control_flow_reconstruction/utils.py | 13 ++ 2 files changed, 110 insertions(+), 21 deletions(-) diff --git a/pylingual/control_flow_reconstruction/templates/Loop.py b/pylingual/control_flow_reconstruction/templates/Loop.py index db78f71..3c10946 100644 --- a/pylingual/control_flow_reconstruction/templates/Loop.py +++ b/pylingual/control_flow_reconstruction/templates/Loop.py @@ -1,17 +1,27 @@ from __future__ import annotations +from itertools import chain from typing import TYPE_CHECKING + +from pylingual.control_flow_reconstruction.source import SourceContext, SourceLine + from ..cft import ControlFlowTemplate, EdgeKind, register_template from ..utils import ( T, N, + no_back_edges, + versions_below, + versions_from, with_instructions, exact_instructions, has_no_lines, + has_some_lines, condense_mapping, defer_source_to, starting_instructions, to_indented_source, make_try_match, + with_top_level_instructions, + without_top_level_instructions, ) if TYPE_CHECKING: @@ -36,9 +46,11 @@ class ForLoop(ControlFlowTemplate): """ -@register_template(0, 2) -class SelfLoop(ControlFlowTemplate): - template = T(loop_body=~N("loop_body", None)) +@register_template(0, 2, *versions_below(3, 10)) +class SelfLoop3_6(ControlFlowTemplate): + template = T( + loop_body=~N("loop_body", None) + ) try_match = make_try_match({}, "loop_body") @@ -50,6 +62,26 @@ class SelfLoop(ControlFlowTemplate): """ +@register_template(0, 2, *versions_from(3, 10)) +class SelfLoop3_10(ControlFlowTemplate): + template = T( + loop_header=~N("loop_body", "RET_CONST?").with_cond(no_back_edges), + loop_body=~N("loop_body", None), + RET_CONST=N.tail(), + ) + + try_match = make_try_match({}, "loop_header", "loop_body", "RET_CONST") + + def to_indented_source(self, source: SourceContext) -> list[SourceLine]: + header = source[self.loop_header] + body = source[self.loop_body, 1] + RET_CONST = source[self.RET_CONST] + if not any(source.lines[i.starts_line - 1].strip().startswith("while ") for i in self.loop_header.get_instructions() if i.starts_line is not None): + return list(chain(header, self.line("while True:"), body)) + else: + return list(chain(header, body)) + + @register_template(0, 2) class TrueSelfLoop(ControlFlowTemplate): template = T(loop_body=~N("tail.", "loop_body"), tail=N.tail()) @@ -68,6 +100,28 @@ class TrueSelfLoop(ControlFlowTemplate): """ +@register_template(1, 39) +class WhileIfElseLoop(ControlFlowTemplate): + template = T( + if_header=~N("if_body", "else_body").with_cond(without_top_level_instructions("WITH_EXCEPT_START", "CHECK_EXC_MATCH", "FOR_ITER")), + else_body=~N("if_header").with_in_deg(1), + if_body=~N("tail.").with_cond(without_top_level_instructions("RERAISE", "END_FINALLY")).with_in_deg(1), + tail=N.tail(), + ) + + try_match = make_try_match({EdgeKind.Fall: "tail"}, "if_header", "if_body", "else_body") + + @to_indented_source + def to_indented_source(): + """ + while True: + {if_header} + {if_body} + {else_body?else:} + {else_body} + """ + + @register_template(0, 3) class InlinedComprehensionTemplate(ControlFlowTemplate): template = T( @@ -90,7 +144,7 @@ class InlinedComprehensionTemplate(ControlFlowTemplate): class BreakTemplate(ControlFlowTemplate): @classmethod def try_match(cls, cfg, node): - if isinstance(node, BreakTemplate) 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")(cfg, node) or has_no_lines(cfg, node): return None i = len(node.get_instructions()) - 1 @@ -113,7 +167,7 @@ class BreakTemplate(ControlFlowTemplate): class ContinueTemplate(ControlFlowTemplate): @classmethod def try_match(cls, cfg, node): - if isinstance(node, ContinueTemplate) or has_no_lines(cfg, node): + if not with_top_level_instructions("JUMP_ABSOLUTE", "JUMP_BACKWARD", "CONTINUE_LOOP", "POP_EXCEPT")(cfg, node) or has_no_lines(cfg, node): return None i = len(node.get_instructions()) - 1 @@ -153,8 +207,8 @@ class FixLoop(ControlFlowTemplate): # A back edge exists if the predecessor is reachable from the node (node dominates predecessor) if cfg.dominates(node, predecessor): back_edges.append(predecessor) - - if not back_edges: + + if not 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 @@ -172,7 +226,7 @@ class FixLoop(ControlFlowTemplate): # Find the candidate end that break connects to candidate_end = None for succ in cfg.successors(node): - if cfg.get_edge_data(node, succ).get("kind") == EdgeKind.FalseJump: + if cfg.get_edge_data(node, succ).get("kind") == EdgeKind.FalseJump and not any(n == node for n in cfg.successors(succ)): candidate_end = succ # Candidate end is a buffer node @@ -181,21 +235,43 @@ class FixLoop(ControlFlowTemplate): if cfg.get_edge_data(candidate_end, ss).get("kind") != EdgeKind.Exception: candidate_end = ss break - - if encompassed_nodes is not None: - for succ in encompassed_nodes: - if cfg.get_edge_data(succ, candidate_end) != None: - edges_to_remove.append((succ, candidate_end)) - for pred, succ in edges_to_remove: - break_node = BreakTemplate.try_match(cfg, pred) - if break_node is not None: - cfg.remove_edge(break_node, succ) + if candidate_end == None: + # While loops + for candidate in back_edges: + cont_node = ContinueTemplate.try_match(cfg, candidate) + if cont_node is not None and not cfg.has_edge(node, cont_node): + cfg.remove_edge(cont_node, node) + + dfs_edges = cfg.dfs_labeled_edges_no_loop(source=node) + candidates = [v for u, v, d in dfs_edges if d == "forward"][1:] - for candidate in back_edges: - cont_node = ContinueTemplate.try_match(cfg, candidate) - if cont_node is not None and cfg.in_degree(node) > 2: - cfg.remove_edge(cont_node, node) + for n in candidates: + for s in cfg.successors(n): + if cfg.get_edge_data(n, s).get("kind") != EdgeKind.Exception and not all(cfg.get_edge_data(p, n).get("kind") == EdgeKind.Exception for p in cfg.predecessors(n)): + edges_to_remove.append((n, s)) + + for pred, succ in edges_to_remove: + break_node = BreakTemplate.try_match(cfg, pred) + if break_node is not None and cfg.in_degree(succ) > 2: + cfg.remove_edge(break_node, succ) + + else: + # For loops + if encompassed_nodes is not None: + for succ in encompassed_nodes: + if cfg.get_edge_data(succ, candidate_end) != None: + edges_to_remove.append((succ, candidate_end)) + + for candidate in back_edges: + cont_node = ContinueTemplate.try_match(cfg, candidate) + if cont_node is not None and cfg.in_degree(node) > 2: + cfg.remove_edge(cont_node, node) + + for pred, succ in edges_to_remove: + break_node = BreakTemplate.try_match(cfg, pred) + if break_node is not None: + cfg.remove_edge(break_node, succ) cfg.iterate() return diff --git a/pylingual/control_flow_reconstruction/utils.py b/pylingual/control_flow_reconstruction/utils.py index 66367ea..6320723 100644 --- a/pylingual/control_flow_reconstruction/utils.py +++ b/pylingual/control_flow_reconstruction/utils.py @@ -96,6 +96,19 @@ def without_top_level_instructions(*opnames: str): return check_instructions +def with_top_level_instructions(*opnames: str): + from .templates.Block import BlockTemplate + + def check_instructions(cfg: CFG, node: ControlFlowTemplate | None) -> bool: + if isinstance(node, BlockTemplate): + return any(x.inst.opname in opnames for x in node.members if isinstance(x, InstTemplate)) + if isinstance(node, InstTemplate): + return node.inst.opname in opnames + return False + + return check_instructions + + def has_type(*template_type: type[ControlFlowTemplate]): def check_type(cfg: CFG, node: ControlFlowTemplate | None) -> bool: return isinstance(node, template_type) From 19a44f128f6ddd556359e7275773a5077da4d8f7 Mon Sep 17 00:00:00 2001 From: Xinlong Hu Date: Fri, 1 Aug 2025 19:47:48 -0500 Subject: [PATCH 3/8] 3.12/3.13 AsyncForLoops --- .../templates/Loop.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/pylingual/control_flow_reconstruction/templates/Loop.py b/pylingual/control_flow_reconstruction/templates/Loop.py index 3c10946..c5ec983 100644 --- a/pylingual/control_flow_reconstruction/templates/Loop.py +++ b/pylingual/control_flow_reconstruction/templates/Loop.py @@ -100,6 +100,25 @@ class TrueSelfLoop(ControlFlowTemplate): """ +@register_template(0, 1, *versions_from(3, 12)) +class AsyncForLoop3_12(ControlFlowTemplate): + template = T( + for_iter=N("for_body", None, "tail"), + for_body=~N("for_iter").with_in_deg(1), + tail=N.tail(), + ) + + try_match = make_try_match({}, "tail", "for_iter", "for_body") + + @to_indented_source + def to_indented_source(): + """ + {for_iter} + {for_body} + {tail} + """ + + @register_template(1, 39) class WhileIfElseLoop(ControlFlowTemplate): template = T( From 42763b367e83b6aab544d31c0366e462a2ee0d42 Mon Sep 17 00:00:00 2001 From: Xinlong Hu Date: Fri, 1 Aug 2025 19:54:28 -0500 Subject: [PATCH 4/8] 3.13 Preventing Loops from matching --- .../templates/Block.py | 17 +++++++++++------ pylingual/control_flow_reconstruction/utils.py | 2 ++ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/pylingual/control_flow_reconstruction/templates/Block.py b/pylingual/control_flow_reconstruction/templates/Block.py index 0398879..c93af82 100644 --- a/pylingual/control_flow_reconstruction/templates/Block.py +++ b/pylingual/control_flow_reconstruction/templates/Block.py @@ -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( diff --git a/pylingual/control_flow_reconstruction/utils.py b/pylingual/control_flow_reconstruction/utils.py index 6320723..16edadb 100644 --- a/pylingual/control_flow_reconstruction/utils.py +++ b/pylingual/control_flow_reconstruction/utils.py @@ -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: From 97123891bf2456ec6c73be55ec5f44cbcab7a2fb Mon Sep 17 00:00:00 2001 From: Xinlong Hu Date: Fri, 1 Aug 2025 20:05:34 -0500 Subject: [PATCH 5/8] Exception fail_body matching adjustment --- .../templates/Exception.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pylingual/control_flow_reconstruction/templates/Exception.py b/pylingual/control_flow_reconstruction/templates/Exception.py index 1956553..b6141f3 100644 --- a/pylingual/control_flow_reconstruction/templates/Exception.py +++ b/pylingual/control_flow_reconstruction/templates/Exception.py @@ -292,14 +292,14 @@ class TryFinally3_11(ControlFlowTemplate): try_header=N("try_body"), try_body=N("finally_body", None, "fail_body"), 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"), ending_instructions("DELETE_SUBSCR", "RERAISE")), + fail_body=N(E.exc("reraise")).with_cond(without_top_level_instructions("DELETE_FAST")), reraise=reraise, tail=N.tail(), ) template2 = T( 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")), + fail_body=N(E.exc("reraise")).with_cond(without_top_level_instructions("DELETE_FAST")), reraise=reraise, tail=N.tail(), ) @@ -531,14 +531,14 @@ class TryFinally3_9(ControlFlowTemplate): try_header=N("try_body"), try_body=N("finally_body", None, "fail_body"), finally_body=~N("tail.").with_in_deg(1).with_cond(no_back_edges), - fail_body=N("tail.").with_cond(ending_instructions("POP_TOP", "RERAISE"), ending_instructions("DELETE_SUBSCR", "RERAISE")), + fail_body=N("tail.").with_cond(without_top_level_instructions("DELETE_FAST")), tail=N.tail(), ) template2 = T( try_except=N("finally_tail", None, "fail_body").of_type(TryElse3_9, Try3_9), finally_tail=N("finally_body", None, "fail_body"), finally_body=~N("tail.").with_in_deg(1).with_cond(no_back_edges), - fail_body=N("tail.").with_cond(ending_instructions("POP_TOP", "RERAISE")), + fail_body=N("tail.").with_cond(without_top_level_instructions("DELETE_FAST")), tail=N.tail(), ) @@ -790,14 +790,14 @@ 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"), with_instructions("LOAD_CONST", "RETURN_VALUE"), with_instructions("DELETE_SUBSCR", "END_FINALLY")), + fail_body=N("tail.").with_cond(without_top_level_instructions("DELETE_FAST")), tail=N.tail(), ) template2 = T( 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"), with_instructions("LOAD_CONST", "RETURN_VALUE")), + fail_body=N("tail.").with_cond(without_top_level_instructions("DELETE_FAST")), tail=N.tail(), ) From 659d22a99f5ffbd7560ee4e64c5b0d110c7db0ae Mon Sep 17 00:00:00 2001 From: Xinlong Hu Date: Fri, 1 Aug 2025 21:18:00 -0500 Subject: [PATCH 6/8] Prevent template from removing lines for CDG --- pylingual/control_flow_reconstruction/templates/Block.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pylingual/control_flow_reconstruction/templates/Block.py b/pylingual/control_flow_reconstruction/templates/Block.py index c93af82..18a6b8f 100644 --- a/pylingual/control_flow_reconstruction/templates/Block.py +++ b/pylingual/control_flow_reconstruction/templates/Block.py @@ -48,7 +48,7 @@ class RemoveUnreachable(ControlFlowTemplate): return None valid = list(nx.dfs_preorder_nodes(cfg, source=cfg.start)) - invalid = [n for n in cfg.nodes if n not in valid] + invalid = [n for n in cfg.nodes if n not in valid and has_no_lines(cfg, n)] if invalid: cfg.remove_nodes_from(invalid) return node From 45aa5e8ea725b1fa738a4326b1dfd57a093624a8 Mon Sep 17 00:00:00 2001 From: Xinlong Hu Date: Fri, 1 Aug 2025 21:37:11 -0500 Subject: [PATCH 7/8] 3.6/3.7/3.8 Adjusting With --- pylingual/control_flow_reconstruction/templates/With.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pylingual/control_flow_reconstruction/templates/With.py b/pylingual/control_flow_reconstruction/templates/With.py index 65bcf7c..c24a33b 100644 --- a/pylingual/control_flow_reconstruction/templates/With.py +++ b/pylingual/control_flow_reconstruction/templates/With.py @@ -1,5 +1,5 @@ from ..cft import ControlFlowTemplate, EdgeKind, register_template -from ..utils import T, N, exact_instructions, starting_instructions, without_instructions, to_indented_source, make_try_match, versions_from +from ..utils import T, N, exact_instructions, starting_instructions, without_top_level_instructions, to_indented_source, make_try_match, versions_from class WithCleanup3_11(ControlFlowTemplate): @@ -83,7 +83,7 @@ class With3_9(ControlFlowTemplate): @register_template(0, 10, (3, 6), (3, 7), (3, 8)) class With3_6(ControlFlowTemplate): template = T( - setup_with=~N("with_body", None).with_cond(without_instructions("SETUP_FINALLY")), + setup_with=~N("with_body", None).with_cond(without_top_level_instructions("SETUP_FINALLY", "SETUP_EXCEPT")), with_body=N("buffer_block.", None, "normal_cleanup").with_in_deg(1), buffer_block=~N("normal_cleanup.", None).with_in_deg(1), normal_cleanup=~N.tail(), From 6be3472082c0b46c9331eaaca60d2d6b55997cdd Mon Sep 17 00:00:00 2001 From: Joel Flores Date: Sat, 2 Aug 2025 13:07:40 -0500 Subject: [PATCH 8/8] update 3.13 models --- pylingual/decompiler_config.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pylingual/decompiler_config.yaml b/pylingual/decompiler_config.yaml index 6b34438..18bd989 100644 --- a/pylingual/decompiler_config.yaml +++ b/pylingual/decompiler_config.yaml @@ -77,11 +77,11 @@ v3.12: v3.13: SEGMENTATION_MODEL: - REPO: syssec-utd/py313-pylingual-v1-segmenter + REPO: syssec-utd/py313-pylingual-v1.1-segmenter REVISION: main - TOKENIZER: syssec-utd/py313-pylingual-v1-tokenizer + TOKENIZER: syssec-utd/py313-pylingual-v1.1-tokenizer STATEMENT_MODEL: - REPO: syssec-utd/py313-pylingual-v1-statement + REPO: syssec-utd/py313-pylingual-v1.1-statement REVISION: main - TOKENIZER: syssec-utd/py313-pylingual-v1-tok + TOKENIZER: syssec-utd/py313-pylingual-v1.1-tok