You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-04 09:22:40 +08:00
Sync with decompyle start using types more.
This commit is contained in:
43
uncompyle6/scanner.py
Executable file → Normal file
43
uncompyle6/scanner.py
Executable file → Normal file
@@ -21,9 +21,10 @@ scanner/ingestion module. From here we call various version-specific
|
|||||||
scanners, e.g. for Python 2.7 or 3.4.
|
scanners, e.g. for Python 2.7 or 3.4.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from typing import Optional
|
||||||
from array import array
|
from array import array
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
import sys
|
from sys import intern
|
||||||
|
|
||||||
from uncompyle6.scanners.tok import Token
|
from uncompyle6.scanners.tok import Token
|
||||||
from xdis.version_info import IS_PYPY, version_tuple_to_str
|
from xdis.version_info import IS_PYPY, version_tuple_to_str
|
||||||
@@ -32,8 +33,8 @@ from xdis import (
|
|||||||
Bytecode,
|
Bytecode,
|
||||||
canonic_python_version,
|
canonic_python_version,
|
||||||
code2num,
|
code2num,
|
||||||
instruction_size,
|
|
||||||
extended_arg_val,
|
extended_arg_val,
|
||||||
|
instruction_size,
|
||||||
next_offset,
|
next_offset,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -77,7 +78,6 @@ CANONIC2VERSION["3.5.2"] = 3.5
|
|||||||
|
|
||||||
|
|
||||||
# FIXME: DRY
|
# FIXME: DRY
|
||||||
intern = sys.intern
|
|
||||||
L65536 = 65536
|
L65536 = 65536
|
||||||
|
|
||||||
def long(num):
|
def long(num):
|
||||||
@@ -100,7 +100,7 @@ class Code(object):
|
|||||||
|
|
||||||
|
|
||||||
class Scanner(object):
|
class Scanner(object):
|
||||||
def __init__(self, version, show_asm=None, is_pypy=False):
|
def __init__(self, version: tuple, show_asm=None, is_pypy=False):
|
||||||
self.version = version
|
self.version = version
|
||||||
self.show_asm = show_asm
|
self.show_asm = show_asm
|
||||||
self.is_pypy = is_pypy
|
self.is_pypy = is_pypy
|
||||||
@@ -109,7 +109,7 @@ class Scanner(object):
|
|||||||
v_str = f"""opcode_{version_tuple_to_str(version, start=0, end=2, delimiter="")}"""
|
v_str = f"""opcode_{version_tuple_to_str(version, start=0, end=2, delimiter="")}"""
|
||||||
if is_pypy:
|
if is_pypy:
|
||||||
v_str += "pypy"
|
v_str += "pypy"
|
||||||
exec("from xdis.opcodes import %s" % v_str)
|
exec(f"""from xdis.opcodes import {v_str}""")
|
||||||
exec("self.opc = %s" % v_str)
|
exec("self.opc = %s" % v_str)
|
||||||
else:
|
else:
|
||||||
raise TypeError(
|
raise TypeError(
|
||||||
@@ -193,7 +193,7 @@ class Scanner(object):
|
|||||||
for _ in range(instruction_size(op, self.opc)):
|
for _ in range(instruction_size(op, self.opc)):
|
||||||
self.prev_op.append(offset)
|
self.prev_op.append(offset)
|
||||||
|
|
||||||
def is_jump_forward(self, offset):
|
def is_jump_forward(self, offset: int) -> bool:
|
||||||
"""
|
"""
|
||||||
Return True if the code at offset is some sort of jump forward.
|
Return True if the code at offset is some sort of jump forward.
|
||||||
That is, it is ether "JUMP_FORWARD" or an absolute jump that
|
That is, it is ether "JUMP_FORWARD" or an absolute jump that
|
||||||
@@ -206,10 +206,10 @@ class Scanner(object):
|
|||||||
return False
|
return False
|
||||||
return offset < self.get_target(offset)
|
return offset < self.get_target(offset)
|
||||||
|
|
||||||
def prev_offset(self, offset):
|
def prev_offset(self, offset: int) -> int:
|
||||||
return self.insts[self.offset2inst_index[offset] - 1].offset
|
return self.insts[self.offset2inst_index[offset] - 1].offset
|
||||||
|
|
||||||
def get_inst(self, offset):
|
def get_inst(self, offset: int):
|
||||||
# Instructions can get moved as a result of EXTENDED_ARGS removal.
|
# Instructions can get moved as a result of EXTENDED_ARGS removal.
|
||||||
# So if "offset" is not in self.offset2inst_index, then
|
# So if "offset" is not in self.offset2inst_index, then
|
||||||
# we assume that it was an instruction moved back.
|
# we assume that it was an instruction moved back.
|
||||||
@@ -220,7 +220,7 @@ class Scanner(object):
|
|||||||
assert self.code[offset] == self.opc.EXTENDED_ARG
|
assert self.code[offset] == self.opc.EXTENDED_ARG
|
||||||
return self.insts[self.offset2inst_index[offset]]
|
return self.insts[self.offset2inst_index[offset]]
|
||||||
|
|
||||||
def get_target(self, offset, extended_arg=0):
|
def get_target(self, offset: int, extended_arg: int = 0) -> int:
|
||||||
"""
|
"""
|
||||||
Get next instruction offset for op located at given <offset>.
|
Get next instruction offset for op located at given <offset>.
|
||||||
NOTE: extended_arg is no longer used
|
NOTE: extended_arg is no longer used
|
||||||
@@ -233,11 +233,11 @@ class Scanner(object):
|
|||||||
target = next_offset(inst.opcode, self.opc, inst.offset)
|
target = next_offset(inst.opcode, self.opc, inst.offset)
|
||||||
return target
|
return target
|
||||||
|
|
||||||
def get_argument(self, pos):
|
def get_argument(self, pos: int):
|
||||||
arg = self.code[pos + 1] + self.code[pos + 2] * 256
|
arg = self.code[pos + 1] + self.code[pos + 2] * 256
|
||||||
return arg
|
return arg
|
||||||
|
|
||||||
def next_offset(self, op, offset):
|
def next_offset(self, op, offset: int) -> int:
|
||||||
return xdis.next_offset(op, self.opc, offset)
|
return xdis.next_offset(op, self.opc, offset)
|
||||||
|
|
||||||
def print_bytecode(self):
|
def print_bytecode(self):
|
||||||
@@ -249,7 +249,7 @@ class Scanner(object):
|
|||||||
else:
|
else:
|
||||||
print("%i\t%s\t" % (i, self.opname[op]))
|
print("%i\t%s\t" % (i, self.opname[op]))
|
||||||
|
|
||||||
def first_instr(self, start, end, instr, target=None, exact=True):
|
def first_instr(self, start: int, end: int, instr, target=None, exact=True):
|
||||||
"""
|
"""
|
||||||
Find the first <instr> in the block from start to end.
|
Find the first <instr> in the block from start to end.
|
||||||
<instr> is any python bytecode instruction or a list of opcodes
|
<instr> is any python bytecode instruction or a list of opcodes
|
||||||
@@ -283,7 +283,9 @@ class Scanner(object):
|
|||||||
result_offset = offset
|
result_offset = offset
|
||||||
return result_offset
|
return result_offset
|
||||||
|
|
||||||
def last_instr(self, start, end, instr, target=None, exact=True):
|
def last_instr(
|
||||||
|
self, start: int, end: int, instr, target=None, exact=True
|
||||||
|
) -> Optional[int]:
|
||||||
"""
|
"""
|
||||||
Find the last <instr> in the block from start to end.
|
Find the last <instr> in the block from start to end.
|
||||||
<instr> is any python bytecode instruction or a list of opcodes
|
<instr> is any python bytecode instruction or a list of opcodes
|
||||||
@@ -379,7 +381,9 @@ class Scanner(object):
|
|||||||
# FIXME: this is broken on 3.6+. Replace remaining (2.x-based) calls
|
# FIXME: this is broken on 3.6+. Replace remaining (2.x-based) calls
|
||||||
# with inst_matches
|
# with inst_matches
|
||||||
|
|
||||||
def all_instr(self, start, end, instr, target=None, include_beyond_target=False):
|
def all_instr(
|
||||||
|
self, start: int, end: int, instr, target=None, include_beyond_target=False
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
Find all `instr` in the block from start to end.
|
Find all `instr` in the block from start to end.
|
||||||
`instr` is any Python opcode or a list of opcodes
|
`instr` is any Python opcode or a list of opcodes
|
||||||
@@ -506,14 +510,13 @@ class Scanner(object):
|
|||||||
def resetTokenClass(self):
|
def resetTokenClass(self):
|
||||||
return self.setTokenClass(Token)
|
return self.setTokenClass(Token)
|
||||||
|
|
||||||
def restrict_to_parent(self, target, parent):
|
def restrict_to_parent(self, target: int, parent) -> int:
|
||||||
"""Restrict target to parent structure boundaries."""
|
"""Restrict target to parent structure boundaries."""
|
||||||
if not (parent["start"] < target < parent["end"]):
|
if not (parent["start"] < target < parent["end"]):
|
||||||
target = parent["end"]
|
target = parent["end"]
|
||||||
return target
|
return target
|
||||||
|
|
||||||
def setTokenClass(self, tokenClass):
|
def setTokenClass(self, tokenClass) -> Token:
|
||||||
# assert isinstance(tokenClass, types.ClassType)
|
|
||||||
self.Token = tokenClass
|
self.Token = tokenClass
|
||||||
return self.Token
|
return self.Token
|
||||||
|
|
||||||
@@ -571,8 +574,7 @@ def get_scanner(version, is_pypy=False, show_asm=None):
|
|||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
"Unsupported Python version, %s, for decompilation"
|
f"Unsupported Python version, {version_tuple_to_str(version)}, for decompilation"
|
||||||
% version_tuple_to_str(version)
|
|
||||||
)
|
)
|
||||||
return scanner
|
return scanner
|
||||||
|
|
||||||
@@ -583,5 +585,6 @@ if __name__ == "__main__":
|
|||||||
co = inspect.currentframe().f_code
|
co = inspect.currentframe().f_code
|
||||||
# scanner = get_scanner('2.7.13', True)
|
# scanner = get_scanner('2.7.13', True)
|
||||||
# scanner = get_scanner(sys.version[:5], False)
|
# scanner = get_scanner(sys.version[:5], False)
|
||||||
scanner = get_scanner(uncompyle6.PYTHON_VERSION, IS_PYPY, True)
|
from xdis.version_info import PYTHON_VERSION_TRIPLE
|
||||||
|
scanner = get_scanner(uncompyle6.PYTHON_VERSION_TRIPLE, IS_PYPY, True)
|
||||||
tokens, customize = scanner.ingest(co, {}, show_asm="after")
|
tokens, customize = scanner.ingest(co, {}, show_asm="after")
|
||||||
|
Reference in New Issue
Block a user