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
install_requires = ['spark-parser >= 1.4.0',
'xdis >= 1.1.4']
'xdis >= 1.1.5']
license = 'MIT'
mailing_list = 'python-debugger@googlegroups.com'
modname = 'uncompyle6'

View File

@ -43,7 +43,7 @@ check-disasm:
#: Check deparsing bytecode 2.x only
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-bytecode-3:
@ -57,6 +57,10 @@ check-bytecode: check-bytecode-3
check-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-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
"""
import os, sys, py_compile
assert len(sys.argv) == 2
path = sys.argv[1]
short = os.path.basename(path)
assert len(sys.argv) >= 2
version = sys.version[0:3]
cfile = "bytecode_%s/%s" % (version, short) + 'c'
print("byte-compiling %s to %s" % (path, cfile))
py_compile.compile(path, cfile)
if sys.version >= (2, 6, 0):
os.system("../bin/uncompyle6 -a -t %s" % cfile)
for path in sys.argv[1:]:
short = os.path.basename(path)
cfile = "bytecode_%s/%s" % (version, short) + 'c'
print("byte-compiling %s to %s" % (path, 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
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/'
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)
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
key = "bytecode-%s" % 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)
else:
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:
import uncompyle6.parsers.parse25 as parse25
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
"""
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
@ -41,5 +41,5 @@ class Python25ParserSingle(Python26Parser, PythonParserSingle):
if __name__ == '__main__':
# Check grammar
p = Python26Parser()
p = Python25Parser()
p.checkGrammar()

View File

@ -26,7 +26,7 @@ if 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)
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
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) 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
@ -10,7 +7,6 @@ Python 3 and other versions of Python. Also, we save token
information for later use in deparsing.
"""
from xdis.opcodes.opcode_25 import *
import uncompyle6.scanners.scanner26 as scan
import uncompyle6.scanners.scanner2 as scan2

View File

@ -961,8 +961,9 @@ class SourceWalker(GenericASTTraversal, object):
n_import_as_cont = n_import_as
def n_importfrom(self, node):
if node[0].pattr > 0:
node[2].pattr = '.'*node[0].pattr+node[2].pattr
relative_path_index = 0
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)
n_importstar = n_importfrom