You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-02 16:44:46 +08:00
Start handling BUILD_MAP (a class of dict)
This commit is contained in:
@@ -210,6 +210,10 @@ class Scanner3(Scanner):
|
||||
def bound_collection_from_inst(
|
||||
self, insts: list, next_tokens: list, inst: Instruction, t: Token, i: int, collection_type: str
|
||||
) -> Optional[list]:
|
||||
"""
|
||||
Try to a sequence of instruction that ends with a BUILD_xxx into a sequence that can
|
||||
be parsed much faster, but inserting the token boundary at the beginning of the sequence.
|
||||
"""
|
||||
count = t.attr
|
||||
assert isinstance(count, int)
|
||||
|
||||
@@ -285,6 +289,94 @@ class Scanner3(Scanner):
|
||||
)
|
||||
return new_tokens
|
||||
|
||||
def bound_map_from_inst(
|
||||
self, insts: list, next_tokens: list, inst: Instruction, t: Token, i: int) -> Optional[list]:
|
||||
"""
|
||||
Try to a sequence of instruction that ends with a BUILD_MAP into a sequence that can
|
||||
be parsed much faster, but inserting the token boundary at the beginning of the sequence.
|
||||
"""
|
||||
count = t.attr
|
||||
assert isinstance(count, int)
|
||||
if count > i:
|
||||
return None
|
||||
|
||||
# For small lists don't bother
|
||||
if count < 5:
|
||||
return None
|
||||
|
||||
collection_start = i - (count * 2)
|
||||
assert (count * 2) <= i
|
||||
|
||||
for j in range(collection_start, i, 2):
|
||||
if insts[j].opname not in (
|
||||
"LOAD_CONST",
|
||||
):
|
||||
return None
|
||||
if insts[j+1].opname not in (
|
||||
"LOAD_CONST",
|
||||
):
|
||||
return None
|
||||
|
||||
collection_start = i - (2 * count)
|
||||
collection_enum = CONST_COLLECTIONS.index("CONST_MAP")
|
||||
|
||||
# If we get here, all instructions before tokens[i] are LOAD_CONST and we can replace
|
||||
# add a boundary marker and change LOAD_CONST to something else
|
||||
new_tokens = next_tokens[:-(2*count)]
|
||||
start_offset = insts[collection_start].offset
|
||||
new_tokens.append(
|
||||
Token(
|
||||
opname="COLLECTION_START",
|
||||
attr=collection_enum,
|
||||
pattr="CONST_MAP",
|
||||
offset=f"{start_offset}_0",
|
||||
linestart=False,
|
||||
has_arg=True,
|
||||
has_extended_arg=False,
|
||||
opc=self.opc,
|
||||
)
|
||||
)
|
||||
for j in range(collection_start, i, 2):
|
||||
new_tokens.append(
|
||||
Token(
|
||||
opname="ADD_KEY",
|
||||
attr=insts[j].argval,
|
||||
pattr=insts[j].argrepr,
|
||||
offset=insts[j].offset,
|
||||
linestart=insts[j].starts_line,
|
||||
has_arg=True,
|
||||
has_extended_arg=False,
|
||||
opc=self.opc,
|
||||
)
|
||||
)
|
||||
new_tokens.append(
|
||||
Token(
|
||||
opname="ADD_VALUE",
|
||||
attr=insts[j+1].argval,
|
||||
pattr=insts[j+1].argrepr,
|
||||
offset=insts[j+1].offset,
|
||||
linestart=insts[j+1].starts_line,
|
||||
has_arg=True,
|
||||
has_extended_arg=False,
|
||||
opc=self.opc,
|
||||
)
|
||||
)
|
||||
new_tokens.append(
|
||||
Token(
|
||||
opname=f"BUILD_DICT_OLDER",
|
||||
attr=t.attr,
|
||||
pattr=t.pattr,
|
||||
offset=t.offset,
|
||||
linestart=t.linestart,
|
||||
has_arg=t.has_arg,
|
||||
has_extended_arg=False,
|
||||
opc=t.opc,
|
||||
)
|
||||
)
|
||||
return new_tokens
|
||||
|
||||
|
||||
|
||||
def ingest(self, co, classname=None, code_objects={}, show_asm=None
|
||||
) -> Tuple[list, dict]:
|
||||
"""
|
||||
@@ -411,6 +503,15 @@ class Scanner3(Scanner):
|
||||
if try_tokens is not None:
|
||||
new_tokens = try_tokens
|
||||
continue
|
||||
elif opname in (
|
||||
"BUILD_MAP",
|
||||
):
|
||||
try_tokens = self.bound_map_from_inst(
|
||||
self.insts, new_tokens, inst, t, i,
|
||||
)
|
||||
if try_tokens is not None:
|
||||
new_tokens = try_tokens
|
||||
continue
|
||||
|
||||
argval = inst.argval
|
||||
op = inst.opcode
|
||||
|
Reference in New Issue
Block a user