From e833907ee0e36f84320ac86266b6d2cde72dcea6 Mon Sep 17 00:00:00 2001 From: Xinlong Hu <118075581+XinlongCS@users.noreply.github.com> Date: Thu, 18 Dec 2025 14:50:13 -0600 Subject: [PATCH 1/2] replace new 3.14 equivalent opcodes LOAD_FAST_BORROW -> LOAD_FAST LOAD_FAST_BORROW_LOAD_FAST_BORROW -> LOAD_FAST_LOAD_FAST For TryExceptElse template equivalence Co-Authored-By: jdw170000 <50096766+jdw170000@users.noreply.github.com> --- .../editable_bytecode/bytecode_patches/__init__.py | 1 + .../bytecode_patches/replace_borrow.py | 14 ++++++++++++++ pylingual/equivalence_check.py | 6 +++--- 3 files changed, 18 insertions(+), 3 deletions(-) create mode 100644 pylingual/editable_bytecode/bytecode_patches/replace_borrow.py diff --git a/pylingual/editable_bytecode/bytecode_patches/__init__.py b/pylingual/editable_bytecode/bytecode_patches/__init__.py index 53bb73f..f0d11ec 100644 --- a/pylingual/editable_bytecode/bytecode_patches/__init__.py +++ b/pylingual/editable_bytecode/bytecode_patches/__init__.py @@ -4,3 +4,4 @@ from .remove_docstrings import remove_docstrings from .remove_nop import remove_nop from .fix_indirect_jump import fix_indirect_jump from .replace_firstlno import replace_firstlno +from .replace_borrow import replace_borrow diff --git a/pylingual/editable_bytecode/bytecode_patches/replace_borrow.py b/pylingual/editable_bytecode/bytecode_patches/replace_borrow.py new file mode 100644 index 0000000..68c406e --- /dev/null +++ b/pylingual/editable_bytecode/bytecode_patches/replace_borrow.py @@ -0,0 +1,14 @@ +from ..EditableBytecode import EditableBytecode + +def replace_borrow(bytecode: EditableBytecode): + if bytecode.version < (3,14): + return + load_fast_borrows = [inst for inst in bytecode.instructions if inst.opname == "LOAD_FAST_BORROW"] + for borrow in load_fast_borrows: + borrow.opname = "LOAD_FAST" + borrow.opcode = bytecode.opcode.LOAD_FAST + + double_load_fast_borrows = [inst for inst in bytecode.instructions if inst.opname == "LOAD_FAST_BORROW_LOAD_FAST_BORROW"] + for double_borrow in double_load_fast_borrows: + double_borrow.opname = "LOAD_FAST_LOAD_FAST" + double_borrow.opcode = bytecode.opcode.LOAD_FAST_LOAD_FAST diff --git a/pylingual/equivalence_check.py b/pylingual/equivalence_check.py index 1aa3b9b..4b02db0 100644 --- a/pylingual/equivalence_check.py +++ b/pylingual/equivalence_check.py @@ -7,7 +7,7 @@ from pathlib import Path import networkx as nx from pylingual.control_flow_reconstruction.cfg import CFG from pylingual.editable_bytecode import EditableBytecode, Inst, PYCFile -from pylingual.editable_bytecode.bytecode_patches import fix_indirect_jump, fix_unreachable, remove_extended_arg, remove_nop, replace_firstlno +from pylingual.editable_bytecode.bytecode_patches import fix_indirect_jump, fix_unreachable, remove_extended_arg, remove_nop, replace_firstlno, replace_borrow from pylingual.editable_bytecode.control_flow_graph import bytecode_to_control_flow_graph @@ -191,8 +191,8 @@ def compare_pyc(pyc_a: PYCFile | Path, pyc_b: PYCFile | Path) -> list[TestResult pyc_a = pyc_a.copy() if isinstance(pyc_a, PYCFile) else PYCFile(pyc_a) pyc_b = pyc_b.copy() if isinstance(pyc_b, PYCFile) else PYCFile(pyc_b) - pyc_a.apply_patches([remove_extended_arg, remove_nop, fix_indirect_jump, fix_unreachable, remove_extended_arg, replace_firstlno]) - pyc_b.apply_patches([remove_extended_arg, remove_nop, fix_indirect_jump, fix_unreachable, remove_extended_arg, replace_firstlno]) + pyc_a.apply_patches([remove_extended_arg, remove_nop, fix_indirect_jump, fix_unreachable, remove_extended_arg, replace_firstlno, replace_borrow]) + pyc_b.apply_patches([remove_extended_arg, remove_nop, fix_indirect_jump, fix_unreachable, remove_extended_arg, replace_firstlno, replace_borrow]) results = [] From a4c113ec312012d23bbb7c6b8e6c5551eba80271 Mon Sep 17 00:00:00 2001 From: XinlongCS Date: Thu, 18 Dec 2025 15:38:03 -0600 Subject: [PATCH 2/2] Ast fix for old deprecated values Fixes AttributeError: module 'ast' has no attribute 'Str' Co-Authored-By: jdw170000 <50096766+jdw170000@users.noreply.github.com> --- dev_scripts/dataset_generation/normalize_source.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dev_scripts/dataset_generation/normalize_source.py b/dev_scripts/dataset_generation/normalize_source.py index f9b684c..1269acc 100644 --- a/dev_scripts/dataset_generation/normalize_source.py +++ b/dev_scripts/dataset_generation/normalize_source.py @@ -35,8 +35,8 @@ def normalize_source( tree = ast.parse(source, feature_version=version) if replace_docstrings: for node in ast.walk(tree): - if isinstance(node, ast.Expr) and isinstance(node.value, ast.Str): - node.value.s = "pass" + if isinstance(node, ast.Expr) and isinstance(node.value, ast.Constant) and isinstance(node.value.value, str): + node.value.value = "pass" return ast.unparse(tree)