Start handling Pyton 2.4 bytecodes

This commit is contained in:
rocky
2016-07-08 14:56:57 -04:00
parent 7fdb4d3e68
commit 62e60817f6
17 changed files with 125 additions and 21 deletions

View File

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

View File

@@ -43,7 +43,7 @@ check-disasm:
#: Check deparsing bytecode 2.x only #: Check deparsing bytecode 2.x only
check-bytecode-2: check-bytecode-2:
$(PYTHON) test_pythonlib.py --bytecode-2.3 --bytecode-2.5 --bytecode-2.6 --bytecode-2.7 $(PYTHON) test_pythonlib.py --bytecode-2.3 --bytecode-2.4 --bytecode-2.5 --bytecode-2.6 --bytecode-2.7
#: Check deparsing bytecode 3.x only #: Check deparsing bytecode 3.x only
check-bytecode-3: check-bytecode-3:
@@ -57,6 +57,10 @@ check-bytecode: check-bytecode-3
check-bytecode-2.3: check-bytecode-2.3:
$(PYTHON) test_pythonlib.py --bytecode-2.3 $(PYTHON) test_pythonlib.py --bytecode-2.3
#: Check deparsing Python 2.4
check-bytecode-2.4:
$(PYTHON) test_pythonlib.py --bytecode-2.4
#: Check deparsing Python 2.5 #: Check deparsing Python 2.5
check-bytecode-2.5: check-bytecode-2.5:
$(PYTHON) test_pythonlib.py --bytecode-2.5 $(PYTHON) test_pythonlib.py --bytecode-2.5

View File

@@ -2,12 +2,12 @@
""" Trivial helper program to bytecompile and run an uncompile """ Trivial helper program to bytecompile and run an uncompile
""" """
import os, sys, py_compile import os, sys, py_compile
assert len(sys.argv) == 2 assert len(sys.argv) >= 2
path = sys.argv[1]
short = os.path.basename(path)
version = sys.version[0:3] version = sys.version[0:3]
cfile = "bytecode_%s/%s" % (version, short) + 'c' for path in sys.argv[1:]:
print("byte-compiling %s to %s" % (path, cfile)) short = os.path.basename(path)
py_compile.compile(path, cfile) cfile = "bytecode_%s/%s" % (version, short) + 'c'
if sys.version >= (2, 6, 0): print("byte-compiling %s to %s" % (path, cfile))
os.system("../bin/uncompyle6 -a -t %s" % cfile) py_compile.compile(path, cfile)
if sys.version >= (2, 6, 0):
os.system("../bin/uncompyle6 -a -t %s" % cfile)

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 #----- configure this for your needs
TEST_VERSIONS=('2.3.7', '2.5.6', '2.6.9', '2.7.10', '2.7.11', '3.2.6', '3.3.5', '3.4.2', '3.5.1') TEST_VERSIONS=('2.3.7', '2.4.6', '2.5.6', '2.6.9', '2.7.10', '2.7.11',
'3.2.6', '3.3.5', '3.4.2', '3.5.1')
target_base = '/tmp/py-dis/' target_base = '/tmp/py-dis/'
lib_prefix = os.path.join(os.environ['HOME'], '.pyenv/versions') lib_prefix = os.path.join(os.environ['HOME'], '.pyenv/versions')

View File

@@ -78,7 +78,7 @@ for vers in (2.7, 3.4, 3.5):
test_options[key] = (os.path.join(src_dir, pythonlib), PYOC, key, vers) test_options[key] = (os.path.join(src_dir, pythonlib), PYOC, key, vers)
pass pass
for vers in (2.3, 2.5, 2.6, 2.7, 3.2, 3.3, 3.4, 3.5): for vers in (2.3, 2.4, 2.5, 2.6, 2.7, 3.2, 3.3, 3.4, 3.5):
bytecode = "bytecode_%s" % vers bytecode = "bytecode_%s" % vers
key = "bytecode-%s" % vers key = "bytecode-%s" % vers
test_options[key] = (bytecode, PYC, bytecode, vers) test_options[key] = (bytecode, PYC, bytecode, vers)

View File

@@ -591,6 +591,12 @@ def get_python_parser(version, debug_parser, compile_mode='exec'):
p = parse23.Python23Parser(debug_parser) p = parse23.Python23Parser(debug_parser)
else: else:
p = parse23.Python23ParserSingle(debug_parser) p = parse23.Python23ParserSingle(debug_parser)
elif version == 2.4:
import uncompyle6.parsers.parse24 as parse24
if compile_mode == 'exec':
p = parse24.Python24Parser(debug_parser)
else:
p = parse24.Python24ParserSingle(debug_parser)
elif version == 2.5: elif version == 2.5:
import uncompyle6.parsers.parse25 as parse25 import uncompyle6.parsers.parse25 as parse25
if compile_mode == 'exec': if compile_mode == 'exec':

View File

@@ -0,0 +1,28 @@
# Copyright (c) 2016 Rocky Bernstein
"""
spark grammar differences over Python2.5 for Python 2.4.
"""
from uncompyle6.parser import PythonParserSingle
from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG
from uncompyle6.parsers.parse25 import Python25Parser
class Python24Parser(Python25Parser):
def __init__(self, debug_parser=PARSER_DEFAULT_DEBUG):
super(Python24Parser, self).__init__(debug_parser)
self.customized = {}
def p_misc24(self, args):
'''
# 2.5+ has two LOAD_CONSTs, one for the number '.'s in a relative import
importstmt ::= LOAD_CONST filler import_as
importfrom ::= LOAD_CONST filler IMPORT_NAME importlist2 POP_TOP
'''
class Python24ParserSingle(Python25Parser, PythonParserSingle):
pass
if __name__ == '__main__':
# Check grammar
p = Python24Parser()
p.checkGrammar()

View File

@@ -1,6 +1,6 @@
# Copyright (c) 2016 Rocky Bernstein # Copyright (c) 2016 Rocky Bernstein
""" """
spark grammar differences over Python2.6 for Python 2.6. spark grammar differences over Python2.6 for Python 2.5.
""" """
from uncompyle6.parser import PythonParserSingle from uncompyle6.parser import PythonParserSingle
@@ -41,5 +41,5 @@ class Python25ParserSingle(Python26Parser, PythonParserSingle):
if __name__ == '__main__': if __name__ == '__main__':
# Check grammar # Check grammar
p = Python26Parser() p = Python25Parser()
p.checkGrammar() p.checkGrammar()

View File

@@ -26,7 +26,7 @@ if PYTHON3:
# Need to work out Python 2.3. ord's in PYTHON3 # Need to work out Python 2.3. ord's in PYTHON3
PYTHON_VERSIONS = (2.5, 2.6, 2.7, 3.2, 3.3, 3.4, 3.5) PYTHON_VERSIONS = (2.5, 2.6, 2.7, 3.2, 3.3, 3.4, 3.5)
else: else:
PYTHON_VERSIONS = (2.3, 2.5, 2.6, 2.7, 3.2, 3.3, 3.4, 3.5) PYTHON_VERSIONS = (2.3, 2.4, 2.5, 2.6, 2.7, 3.2, 3.3, 3.4, 3.5)
# FIXME: DRY # FIXME: DRY
if PYTHON3: if PYTHON3:

View File

@@ -0,0 +1,68 @@
# Copyright (c) 2016 by Rocky Bernstein
"""
Python 2.4 bytecode scanner/deparser
This overlaps Python's 2.4's dis module, but it can be run from
Python 3 and other versions of Python. Also, we save token
information for later use in deparsing.
"""
import uncompyle6.scanners.scanner25 as scan
import uncompyle6.scanners.scanner2 as scan2
# bytecode verification, verify(), uses JUMP_OPs from here
from xdis.opcodes import opcode_24
JUMP_OPs = opcode_24.JUMP_OPs
# We base this off of 2.6 instead of the other way around
# because we cleaned things up this way.
# The history is that 2.7 support is the cleanest,
# then from that we got 2.6 and so on.
class Scanner24(scan.Scanner25):
def __init__(self, show_asm):
scan2.Scanner2.__init__(self, 2.4, show_asm)
self.stmt_opcodes = frozenset([
self.opc.SETUP_LOOP, self.opc.BREAK_LOOP,
self.opc.SETUP_FINALLY, self.opc.END_FINALLY,
self.opc.SETUP_EXCEPT, self.opc.POP_BLOCK,
self.opc.STORE_FAST, self.opc.DELETE_FAST,
self.opc.STORE_DEREF, self.opc.STORE_GLOBAL,
self.opc.DELETE_GLOBAL, self.opc.STORE_NAME,
self.opc.DELETE_NAME, self.opc.STORE_ATTR,
self.opc.DELETE_ATTR, self.opc.STORE_SUBSCR,
self.opc.DELETE_SUBSCR, self.opc.RETURN_VALUE,
self.opc.RAISE_VARARGS, self.opc.POP_TOP,
self.opc.PRINT_EXPR, self.opc.PRINT_ITEM,
self.opc.PRINT_NEWLINE, self.opc.PRINT_ITEM_TO,
self.opc.PRINT_NEWLINE_TO, self.opc.CONTINUE_LOOP,
self.opc.JUMP_ABSOLUTE, self.opc.EXEC_STMT,
])
# "setup" opcodes
self.setup_ops = frozenset([
self.opc.SETUP_EXCEPT, self.opc.SETUP_FINALLY,
])
# opcodes with expect a variable number pushed values whose
# count is in the opcode. For parsing we generally change the
# opcode name to include that number.
self.varargs_ops = frozenset([
self.opc.BUILD_LIST, self.opc.BUILD_TUPLE,
self.opc.BUILD_SLICE, self.opc.UNPACK_SEQUENCE,
self.opc.MAKE_FUNCTION, self.opc.CALL_FUNCTION,
self.opc.MAKE_CLOSURE, self.opc.CALL_FUNCTION_VAR,
self.opc.CALL_FUNCTION_KW, self.opc.CALL_FUNCTION_VAR_KW,
self.opc.DUP_TOPX, self.opc.RAISE_VARARGS])
# opcodes that store values into a variable
self.designator_ops = frozenset([
self.opc.STORE_FAST, self.opc.STORE_NAME,
self.opc.STORE_GLOBAL, self.opc.STORE_DEREF, self.opc.STORE_ATTR,
self.opc.STORE_SLICE_0, self.opc.STORE_SLICE_1, self.opc.STORE_SLICE_2,
self.opc.STORE_SLICE_3, self.opc.STORE_SUBSCR, self.opc.UNPACK_SEQUENCE,
self.opc.JA
])
# Python 2.7 has POP_JUMP_IF_{TRUE,FALSE}_OR_POP but < 2.7 doesn't
# Add an empty set make processing more uniform.
self.pop_jump_if_or_pop = frozenset([])
return

View File

@@ -1,7 +1,4 @@
# Copyright (c) 2015-2016 by Rocky Bernstein # Copyright (c) 2015-2016 by Rocky Bernstein
# Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org>
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
# Copyright (c) 1999 John Aycock
""" """
Python 2.5 bytecode scanner/deparser Python 2.5 bytecode scanner/deparser
@@ -10,7 +7,6 @@ Python 3 and other versions of Python. Also, we save token
information for later use in deparsing. information for later use in deparsing.
""" """
from xdis.opcodes.opcode_25 import *
import uncompyle6.scanners.scanner26 as scan import uncompyle6.scanners.scanner26 as scan
import uncompyle6.scanners.scanner2 as scan2 import uncompyle6.scanners.scanner2 as scan2

View File

@@ -961,8 +961,9 @@ class SourceWalker(GenericASTTraversal, object):
n_import_as_cont = n_import_as n_import_as_cont = n_import_as
def n_importfrom(self, node): def n_importfrom(self, node):
if node[0].pattr > 0: relative_path_index = 0
node[2].pattr = '.'*node[0].pattr+node[2].pattr if self.version >= 2.5 and node[relative_path_index].pattr > 0:
node[2].pattr = '.'*node[relative_path_index].pattr + node[2].pattr
self.default(node) self.default(node)
n_importstar = n_importfrom n_importstar = n_importfrom