Merge branch 'pypy'

Conflicts:
	test/bytecode_2.7/05_for_try_except.pyc
	uncompyle6/scanners/scanner2.py
This commit is contained in:
rocky
2016-07-24 04:27:17 -04:00
66 changed files with 120 additions and 48 deletions

View File

@@ -37,7 +37,7 @@ entry_points={
]}
ftp_url = None
install_requires = ['spark-parser >= 1.4.0',
'xdis >= 1.1.7']
'xdis >= 2.0.0']
license = 'MIT'
mailing_list = 'python-debugger@googlegroups.com'
modname = 'uncompyle6'

View File

@@ -1 +1,2 @@
spark-parser >= 1.2.1
xdis >= 2.0.0

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -27,7 +27,8 @@ from fnmatch import fnmatch
#----- configure this for your needs
TEST_VERSIONS=('2.3.7', '2.4.6', '2.5.6', '2.6.9', '2.7.10', '2.7.11',
TEST_VERSIONS=('2.3.7', '2.4.6', '2.5.6', '2.6.9', 'pypy-2.6.1',
'2.7.10', '2.7.11',
'3.2.6', '3.3.5', '3.4.2', '3.5.1')
target_base = '/tmp/py-dis/'
@@ -45,9 +46,14 @@ test_options = {
}
for vers in TEST_VERSIONS:
short_vers = vers[:3]
test_options[vers] = (os.path.join(lib_prefix, vers, 'lib', 'python'+short_vers),
PYC, 'python-lib'+short_vers)
if vers.startswith('pypy-'):
short_vers = vers[0:-2]
test_options[vers] = (os.path.join(lib_prefix, vers, 'lib_pypy'),
PYC, 'python-lib'+short_vers)
else:
short_vers = vers[:3]
test_options[vers] = (os.path.join(lib_prefix, vers, 'lib', 'python'+short_vers),
PYC, 'python-lib'+short_vers)
def do_tests(src_dir, patterns, target_dir, start_with=None, do_verify=False):

View File

@@ -77,7 +77,7 @@ def disassemble_file(filename, outstream=None, native=False):
return
filename = check_object_path(filename)
version, timestamp, magic_int, co = load_module(filename)
version, timestamp, magic_int, co, is_pypy = load_module(filename)
if type(co) == list:
for con in co:
disco(version, con, outstream)

View File

@@ -1,7 +1,7 @@
from __future__ import print_function
import datetime, os, sys
from uncompyle6 import verify, PYTHON_VERSION
from uncompyle6 import verify, PYTHON_VERSION, IS_PYPY
from xdis.code import iscode
from uncompyle6.disas import check_object_path
from uncompyle6.semantics import pysource
@@ -9,8 +9,10 @@ from uncompyle6.parser import ParserError
from xdis.load import load_module
def uncompyle(version, co, out=None, showasm=False, showast=False,
timestamp=None, showgrammar=False, code_objects={}):
def uncompyle(
version, co, out=None, showasm=False, showast=False,
timestamp=None, showgrammar=False, code_objects={},
is_pypy=False):
"""
disassembles and deparses a given code block 'co'
"""
@@ -19,7 +21,10 @@ def uncompyle(version, co, out=None, showasm=False, showast=False,
# store final output stream for case of error
real_out = out or sys.stdout
print('# Python bytecode %s (decompiled from Python %s)' % (version, PYTHON_VERSION),
co_pypy_str = 'PyPy ' if is_pypy else ''
run_pypy_str = 'PyPy ' if IS_PYPY else ''
print('# %sPython bytecode %s (disassembled from %sPython %s)\n' %
(co_pypy_str, version, run_pypy_str, PYTHON_VERSION),
file=real_out)
if co.co_filename:
print('# Embedded file name: %s' % co.co_filename,
@@ -30,7 +35,7 @@ def uncompyle(version, co, out=None, showasm=False, showast=False,
try:
pysource.deparse_code(version, co, out, showasm, showast, showgrammar,
code_objects=code_objects)
code_objects=code_objects, is_pypy=is_pypy)
except pysource.SourceWalkerError as e:
# deparsing failed
print("\n")
@@ -49,16 +54,18 @@ def uncompyle_file(filename, outstream=None, showasm=False, showast=False,
filename = check_object_path(filename)
code_objects = {}
version, timestamp, magic_int, co = load_module(filename, code_objects)
version, timestamp, magic_int, co, is_pypy = load_module(filename, code_objects)
if type(co) == list:
for con in co:
uncompyle(version, con, outstream, showasm, showast,
timestamp, showgrammar, code_objects=code_objects)
timestamp, showgrammar, code_objects=code_objects,
is_pypy=is_pypy)
else:
uncompyle(version, co, outstream, showasm, showast,
timestamp, showgrammar, code_objects=code_objects)
timestamp, showgrammar, code_objects=code_objects,
is_pypy=is_pypy)
co = None
# FIXME: combine into an options parameter

View File

@@ -570,7 +570,9 @@ def parse(p, tokens, customize):
return ast
def get_python_parser(version, debug_parser, compile_mode='exec'):
def get_python_parser(
version, debug_parser, compile_mode='exec',
is_pypy = False):
"""Returns parser object for Python version 2 or 3, 3.2, 3.5on,
etc., depending on the parameters passed. *compile_mode* is either
'exec', 'eval', or 'single'. See
@@ -662,7 +664,7 @@ class PythonParserSingle(PythonParser):
def python_parser(version, co, out=sys.stdout, showasm=False,
parser_debug=PARSER_DEFAULT_DEBUG):
parser_debug=PARSER_DEFAULT_DEBUG, is_pypy=False):
"""
Parse a code object to an abstract syntax tree representation.
@@ -681,7 +683,7 @@ def python_parser(version, co, out=sys.stdout, showasm=False,
assert iscode(co)
from uncompyle6.scanner import get_scanner
scanner = get_scanner(version)
scanner = get_scanner(version, is_pypy)
tokens, customize = scanner.disassemble(co)
maybe_show_asm(showasm, tokens)
@@ -693,8 +695,8 @@ def python_parser(version, co, out=sys.stdout, showasm=False,
if __name__ == '__main__':
def parse_test(co):
from uncompyle6 import PYTHON_VERSION
ast = python_parser(PYTHON_VERSION, co, showasm=True)
from uncompyle6 import PYTHON_VERSION, IS_PYPY
ast = python_parser(PYTHON_VERSION, co, showasm=True, is_pypy=IS_PYPY)
print(ast)
return
parse_test(parse_test.__code__)

View File

@@ -15,6 +15,8 @@ class Python27Parser(Python2Parser):
def p_list_comprehension27(self, args):
"""
list_for ::= expr _for designator list_iter JUMP_BACK
list_compr ::= expr BUILD_LIST_FROM_ARG _for designator list_iter JUMP_BACK
"""
def p_try27(self, args):

View File

@@ -48,12 +48,15 @@ class Code(object):
class Scanner(object):
def __init__(self, version, show_asm=None):
def __init__(self, version, show_asm=None, is_pypy=False):
self.version = version
self.show_asm = show_asm
if version in PYTHON_VERSIONS:
v_str = "opcode_%s" % (int(version * 10))
if is_pypy and version != 3.2:
v_str = "opcode_pypy%s" % (int(version * 10))
else:
v_str = "opcode_%s" % (int(version * 10))
exec("from xdis.opcodes import %s" % v_str)
exec("self.opc = %s" % v_str)
else:
@@ -251,18 +254,26 @@ class Scanner(object):
def parse_fn_counts(argc):
return ((argc & 0xFF), (argc >> 8) & 0xFF, (argc >> 16) & 0x7FFF)
def get_scanner(version, show_asm=None):
def get_scanner(version, show_asm=None, is_pypy=False):
# Pick up appropriate scanner
if version in PYTHON_VERSIONS:
v_str = "%s" % (int(version * 10))
exec("import uncompyle6.scanners.scanner%s as scan" % v_str)
if PYTHON3:
import importlib
scan = importlib.import_module("uncompyle6.scanners.scanner%s" % v_str)
if is_pypy:
scan = importlib.import_module("uncompyle6.scanners.pypy%s" % v_str)
else:
scan = importlib.import_module("uncompyle6.scanners.scanner%s" % v_str)
if False: print(scan) # Avoid unused scan
else:
exec("import uncompyle6.scanners.scanner%s as scan" % v_str)
scanner = eval("scan.Scanner%s(show_asm=show_asm)" % v_str)
if is_pypy:
exec("import uncompyle6.scanners.pypy%s as scan" % v_str)
else:
exec("import uncompyle6.scanners.scanner%s as scan" % v_str)
if is_pypy:
scanner = eval("scan.ScannerPyPy%s(show_asm=show_asm)" % v_str)
else:
scanner = eval("scan.Scanner%s(show_asm=show_asm)" % v_str)
else:
raise RuntimeError("Unsupported Python version %s" % version)
return scanner

View File

@@ -27,13 +27,12 @@ from collections import namedtuple
from array import array
from xdis.code import iscode
from xdis.bytecode import findlinestarts
import uncompyle6.scanner as scan
class Scanner2(scan.Scanner):
def __init__(self, version, show_asm=None, is_pypy=False):
scan.Scanner.__init__(self, version, show_asm)
scan.Scanner.__init__(self, version, show_asm, is_pypy)
self.pop_jump_if = frozenset([self.opc.PJIF, self.opc.PJIT])
self.jump_forward = frozenset([self.opc.JUMP_ABSOLUTE, self.opc.JUMP_FORWARD])
# This is the 2.5+ default
@@ -277,7 +276,7 @@ class Scanner2(scan.Scanner):
# linestarts is a tuple of (offset, line number).
# Turn that in a has that we can index
self.linestarts = list(findlinestarts(co))
self.linestarts = list(self.opc.findlinestarts(co))
self.linestartoffsets = {}
for offset, lineno in self.linestarts:
self.linestartoffsets[offset] = lineno

View File

@@ -14,7 +14,6 @@ from uncompyle6 import PYTHON3
if PYTHON3:
intern = sys.intern
from xdis.bytecode import findlinestarts
import uncompyle6.scanners.scanner2 as scan
# bytecode verification, verify(), uses JUMP_OPs from here
@@ -103,7 +102,7 @@ class Scanner26(scan.Scanner2):
self.build_prev_op(n)
# linestarts contains block code adresses (addr,block)
self.linestarts = list(findlinestarts(co))
self.linestarts = list(self.opc.findlinestarts(co))
# class and names
if classname:

View File

@@ -22,8 +22,8 @@ from xdis.opcodes import opcode_27
JUMP_OPs = opcode_27.JUMP_OPs
class Scanner27(Scanner2):
def __init__(self, show_asm=False):
super(Scanner27, self).__init__(2.7, show_asm)
def __init__(self, show_asm=False, is_pypy=False):
super(Scanner27, self).__init__(2.7, show_asm, is_pypy)
# opcodes that start statements
self.stmt_opcodes = frozenset([

View File

@@ -26,7 +26,7 @@ from collections import namedtuple
from array import array
from xdis.code import iscode
from xdis.bytecode import Bytecode, findlinestarts
from xdis.bytecode import Bytecode
from uncompyle6.scanner import Token, parse_fn_counts
# Get all the opcodes into globals
@@ -46,8 +46,8 @@ import uncompyle6.scanner as scan
class Scanner3(scan.Scanner):
def __init__(self, version, show_asm=None):
super(Scanner3, self).__init__(version, show_asm)
def __init__(self, version, show_asm=None, is_pypy=False):
super(Scanner3, self).__init__(version, show_asm, is_pypy)
# Create opcode classification sets
# Note: super initilization above initializes self.opc
@@ -300,7 +300,7 @@ class Scanner3(scan.Scanner):
"""
# Offset: lineno pairs, only for offsets which start line.
# Locally we use list for more convenient iteration using indices
linestarts = list(findlinestarts(code_obj))
linestarts = list(self.opc.findlinestarts(code_obj))
self.linestarts = dict(linestarts)
# Plain set with offsets of first ops on line
self.linestart_offsets = set(a for (a, _) in linestarts)

View File

@@ -15,8 +15,8 @@ JUMP_OPs = map(lambda op: opc.opname[op], opc.hasjrel + opc.hasjabs)
from uncompyle6.scanners.scanner3 import Scanner3
class Scanner32(Scanner3):
def __init__(self, show_asm=None):
Scanner3.__init__(self, 3.2, show_asm)
def __init__(self, show_asm=None, is_pypy=False):
Scanner3.__init__(self, 3.2, show_asm, is_pypy)
return
pass

View File

@@ -118,7 +118,8 @@ class FragmentsWalker(pysource.SourceWalker, object):
stacked_params = ('f', 'indent', 'isLambda', '_globals')
def __init__(self, version, scanner, showast=False,
debug_parser=PARSER_DEFAULT_DEBUG):
debug_parser=PARSER_DEFAULT_DEBUG,
compile_mode='exec', is_pypy=False):
GenericASTTraversal.__init__(self, ast=None)
self.scanner = scanner
params = {
@@ -126,7 +127,10 @@ class FragmentsWalker(pysource.SourceWalker, object):
'indent': '',
}
self.version = version
self.p = get_python_parser(version, dict(debug_parser))
self.p = get_python_parser(
version, dict(debug_parser),
compile_mode=compile_mode, is_pypy=is_pypy
)
self.showast = showast
self.params = params
self.param_stack = []

View File

@@ -526,7 +526,7 @@ class SourceWalker(GenericASTTraversal, object):
def __init__(self, version, out, scanner, showast=False,
debug_parser=PARSER_DEFAULT_DEBUG,
compile_mode='exec'):
compile_mode='exec', is_pypy=False):
GenericASTTraversal.__init__(self, ast=None)
self.scanner = scanner
params = {
@@ -555,6 +555,7 @@ class SourceWalker(GenericASTTraversal, object):
self.hide_internal = True
self.name = None
self.version = version
self.is_pypy = is_pypy
if 2.0 <= version <= 2.3:
TABLE_DIRECT['tryfinallystmt'] = (
@@ -1022,6 +1023,9 @@ class SourceWalker(GenericASTTraversal, object):
p = self.prec
self.prec = 27
if self.version >= 2.7:
if self.is_pypy:
self.n_list_compr_pypy27(node)
return
n = node[-1]
elif node[-1] == 'del_stmt':
n = node[-3] if node[-2] == 'JUMP_BACK' else node[-2]
@@ -1053,6 +1057,42 @@ class SourceWalker(GenericASTTraversal, object):
self.prec = p
self.prune() # stop recursing
def n_list_compr_pypy27(self, node):
"""List comprehensions the way they are done in PYPY Python 2.7.
"""
p = self.prec
self.prec = 27
n = node[-2] if self.is_pypy and node[-1] == 'JUMP_BACK' else node[-1]
list_expr = node[0]
designator = node[3]
assert n == 'list_iter'
assert designator == 'designator'
# find innermost node
while n == 'list_iter':
n = n[0] # recurse one step
if n == 'list_for': n = n[3]
elif n == 'list_if': n = n[2]
elif n == 'list_if_not': n= n[2]
assert n == 'lc_body'
self.write( '[ ')
expr = n[0]
list_iter = node[-2] if self.is_pypy and node[-1] == 'JUMP_BACK' else node[-1]
assert expr == 'expr'
assert list_iter == 'list_iter'
self.preorder(expr)
self.write( ' for ')
self.preorder(designator)
self.write( ' in ')
self.preorder(list_expr)
self.write( ' ]')
self.prec = p
self.prune() # stop recursing
def comprehension_walk(self, node, iter_index, code_index=-5):
p = self.prec
self.prec = 27
@@ -2127,14 +2167,14 @@ class SourceWalker(GenericASTTraversal, object):
def deparse_code(version, co, out=sys.stdout, showasm=False, showast=False,
showgrammar=False, code_objects={}, compile_mode='exec'):
showgrammar=False, code_objects={}, compile_mode='exec', is_pypy=False):
"""
disassembles and deparses a given code block 'co'
"""
assert iscode(co)
# store final output stream for case of error
scanner = get_scanner(version)
scanner = get_scanner(version, is_pypy=is_pypy)
tokens, customize = scanner.disassemble(co, code_objects=code_objects)
maybe_show_asm(showasm, tokens)
@@ -2146,7 +2186,8 @@ def deparse_code(version, co, out=sys.stdout, showasm=False, showast=False,
# Build AST from disassembly.
deparsed = SourceWalker(version, out, scanner, showast=showast,
debug_parser=debug_parser, compile_mode=compile_mode)
debug_parser=debug_parser, compile_mode=compile_mode,
is_pypy = is_pypy)
isTopLevel = co.co_name == '<module>'
deparsed.ast = deparsed.build_ast(tokens, customize, isTopLevel=isTopLevel)

View File

@@ -364,7 +364,7 @@ class Token(scanner.Token):
def compare_code_with_srcfile(pyc_filename, src_filename):
"""Compare a .pyc with a source code file."""
version, timestamp, magic_int, code_obj1 = load_module(pyc_filename)
version, timestamp, magic_int, code_obj1, is_pypy = load_module(pyc_filename)
if magic_int != PYTHON_MAGIC_INT:
msg = ("Can't compare code - Python is running with magic %s, but code is magic %s "
% (PYTHON_MAGIC_INT, magic_int))
@@ -375,8 +375,8 @@ def compare_code_with_srcfile(pyc_filename, src_filename):
def compare_files(pyc_filename1, pyc_filename2):
"""Compare two .pyc files."""
version, timestamp, magic_int1, code_obj1 = uncompyle6.load_module(pyc_filename1)
version, timestamp, magic_int2, code_obj2 = uncompyle6.load_module(pyc_filename2)
version, timestamp, magic_int1, code_obj1, is_pypy = uncompyle6.load_module(pyc_filename1)
version, timestamp, magic_int2, code_obj2, is_pypy = uncompyle6.load_module(pyc_filename2)
cmp_code_objects(version, code_obj1, code_obj2)
if __name__ == '__main__':