Skip to content

Decompiler Regressions in f-strings, Ternaries, and Loops #69

Description

@sahebbiswas

Ternary/Compound Condition Mangling (Issues 1 & 2): The "mini-decompiler" (_eval_ternary_branch) used for speculative evaluation of ternary branches and compound conditions is missing support for f-string opcodes (FORMAT_VALUE, FORMAT_SIMPLE, BUILD_STRING). This causes it to silently drop literal string fragments and expressions, resulting in broken assignments like expr = ret_expr if params else ret_expr.
Mangled F-strings (Issue 3): The current _op_build_string implementation incorrectly processes literal string fragments that are already quoted on the stack, leading to nested quote corruption and missing characters.
Integer Dict Keys (Issue 4): A bug in _op_build_const_key_map unconditionally strips quotes from constant keys, causing integer keys to be treated as strings and then re-quoted incorrectly.
Corrupted Loop Unpacking (Issue 5): The peephole logic in _op_for_iter is unaware of combined 3.14 opcodes like STORE_FAST_STORE_FAST. This causes it to fall back to an incomplete _item unpacking strategy that fails to emit the necessary assignment instructions

def ternary_fstring_repro(params, ret_expr):
    # Issue 1: Ternary with f-string
    expr = f"lambda {params}: {ret_expr}" if params else f"lambda: {ret_expr}"
    return expr

def compound_cond_fstring_repro(raw_expr, is_or_jump):
    # Issue 2: Compound condition with f-string
    cond_str = f"{raw_expr} is None" if is_or_jump else f"{raw_expr} is not None"
    return cond_str

def complex_fstring_repro(expr, args):
    # Issue 3: Complex f-string
    return f"({expr})({', '.join(str(a) for a in args)})"

def dict_int_keys_repro():
    # Issue 4: Dict with int keys
    # Note: Modern Python often uses BUILD_CONST_KEY_MAP for this
    _AUG_ASSIGN_MAP = {
        13: "+=",  14: "&=",  15: "//=", 16: "<<=", 17: "@=",
        18: "*=",  19: "%=",  20: "|=",  21: "**=", 22: ">>=",
        23: "-=",  24: "/=",  25: "^=",
    }
    return _AUG_ASSIGN_MAP

def loop_unpacking_repro(instrs):
    # Issue 5: Loop unpacking
    results = []
    for target_off, count in instrs:
        results.append((target_off, count))
    return results

if __name__ == "__main__":
    print(ternary_fstring_repro("x, y", "x + y"))
    print(compound_cond_fstring_repro("val", True))
    print(complex_fstring_repro("func", [1, 2, 3]))
    print(dict_int_keys_repro())
    print(loop_unpacking_repro([(1, 2), (3, 4)]))

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions