You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-03 08:49:51 +08:00
Compare commits
53 Commits
release-py
...
release-py
Author | SHA1 | Date | |
---|---|---|---|
|
44af6c42a2 | ||
|
12397d76b8 | ||
|
d7380dc549 | ||
|
2126e4cf32 | ||
|
b2f6e1cf1a | ||
|
4dfb85f062 | ||
|
7c9437f0a9 | ||
|
ebb9f1a53f | ||
|
b43d4909cd | ||
|
96ddef3920 | ||
|
c24934c0c3 | ||
|
8f88ed8c44 | ||
|
c1ed5d4bfd | ||
|
abf85faf79 | ||
|
162bb0a85f | ||
|
826c968d0a | ||
|
185ec4e306 | ||
|
70ddd71c0e | ||
|
1485d26aa2 | ||
|
e44ccd5787 | ||
|
ab4daf2879 | ||
|
db9eaa7503 | ||
|
a60104517d | ||
|
c4612b7484 | ||
|
731c5a2092 | ||
|
a0d10c2d4c | ||
|
c4f12e9b22 | ||
|
7efbd55b69 | ||
|
c6e20e4444 | ||
|
5dbec5b383 | ||
|
b2c082bba2 | ||
|
71a64299e8 | ||
|
0413342ee3 | ||
|
07ba16ac3a | ||
|
f28ad69c38 | ||
|
a4db92ce72 | ||
|
5b71cee487 | ||
|
9e92f65a27 | ||
|
49a71819a1 | ||
|
6c29f726bc | ||
|
22542eeab0 | ||
|
e4bfa6da13 | ||
|
ed7d11525a | ||
|
5b1dcccddc | ||
|
992a08f5ce | ||
|
4ea7b9aa2e | ||
|
49ef408699 | ||
|
0487f2fb7a | ||
|
abcb769fdf | ||
|
e43c8acd30 | ||
|
d66fedb921 | ||
|
8e6f1a5135 | ||
|
97604a93dd |
16
NEWS
16
NEWS
@@ -1,4 +1,16 @@
|
||||
uncompyle6 2.14.0 2017-01-09 Samish
|
||||
uncompyle6 2.14.3 2017-01-19
|
||||
|
||||
- Fix bug in 3.5+ await stmt
|
||||
- Better version to magic handling; handle 3.5.2 .. 3.5.4 versions
|
||||
- Improve/correct test_pyenvlib.py status messages
|
||||
- Fix some 2.7 and 2.6 parser bugs
|
||||
- Fix whilelse parsing bugs
|
||||
- Correct 2.5- decorator parsing
|
||||
- grammar for decorators matchies AST more a little better
|
||||
- better tests in setup.py for running the right version of Python
|
||||
- Fix 2.6- parsing of "for .. try/else" ... with "continue" inside
|
||||
|
||||
uncompyle6 2.14.2 2017-01-09 Samish
|
||||
|
||||
Decompilation bug fixes, mostly 3.6 and pre 2.7
|
||||
|
||||
@@ -16,7 +28,7 @@ Decompilation bug fixes, mostly 3.6 and pre 2.7
|
||||
Python versions
|
||||
- Match Python AST names more closely when possible
|
||||
|
||||
uncompyle6 2.14.0 2017-12-10 Dr. Gecko
|
||||
uncompyle6 2.14.1 2017-12-10 Dr. Gecko
|
||||
|
||||
- Many decompilation bugfixes
|
||||
- Grammar rule reduction and version isolation
|
||||
|
@@ -9,7 +9,7 @@
|
||||
|
||||
# Things that change more often go here.
|
||||
copyright = """
|
||||
Copyright (C) 2015-2017 Rocky Bernstein <rb@dustyfeet.com>.
|
||||
Copyright (C) 2015-2018 Rocky Bernstein <rb@dustyfeet.com>.
|
||||
"""
|
||||
|
||||
classifiers = ['Development Status :: 5 - Production/Stable',
|
||||
@@ -26,6 +26,7 @@ classifiers = ['Development Status :: 5 - Production/Stable',
|
||||
'Programming Language :: Python :: 3.4',
|
||||
'Programming Language :: Python :: 3.5',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
'Topic :: Software Development :: Debuggers',
|
||||
'Topic :: Software Development :: Libraries :: Python Modules',
|
||||
]
|
||||
@@ -40,12 +41,12 @@ entry_points = {
|
||||
]}
|
||||
ftp_url = None
|
||||
install_requires = ['spark-parser >= 1.8.5, < 1.9.0',
|
||||
'xdis >= 3.6.2, < 3.7.0']
|
||||
'xdis >= 3.6.6, < 3.7.0']
|
||||
license = 'MIT'
|
||||
mailing_list = 'python-debugger@googlegroups.com'
|
||||
modname = 'uncompyle6'
|
||||
py_modules = None
|
||||
short_desc = 'Python cross-version byte-code deparser'
|
||||
short_desc = 'Python cross-version byte-code decompiler'
|
||||
web = 'https://github.com/rocky/python-uncompyle6/'
|
||||
|
||||
# tracebacks in zip files are funky and not debuggable
|
||||
|
@@ -55,7 +55,7 @@
|
||||
$ . ./admin-tools/make-dist-older.sh
|
||||
$ git tag release-python-2.4-$VERSION
|
||||
|
||||
$ . /admin-tools/make-dist-newer.sh
|
||||
$ . ./admin-tools/make-dist-newer.sh
|
||||
$ git tag release-$VERSION
|
||||
|
||||
# Upload single package and look at Rst Formating
|
||||
|
15
setup.py
15
setup.py
@@ -1,7 +1,20 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""Setup script for the 'uncompyle6' distribution."""
|
||||
|
||||
import sys
|
||||
|
||||
SYS_VERSION = sys.version_info[0:2]
|
||||
if not ((2, 4) <= SYS_VERSION <= (2, 7)):
|
||||
mess = "Python Release 2.4 .. 2.7 are supported in this code branch."
|
||||
if ((3, 2) <= SYS_VERSION <= (3, 7)):
|
||||
mess += ("\nFor your Python, version %s, use the master code/branch." %
|
||||
sys.version[0:3])
|
||||
else:
|
||||
mess += ("\nThis package is not supported before Python 2.4. Your Python version is %s."
|
||||
% sys.version[0:3])
|
||||
print(mess)
|
||||
raise Exception(mess)
|
||||
|
||||
from __pkginfo__ import \
|
||||
author, author_email, install_requires, \
|
||||
license, long_description, classifiers, \
|
||||
|
BIN
test/bytecode_2.4/02_decorator.pyc
Normal file
BIN
test/bytecode_2.4/02_decorator.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_2.4/03_whileelse_bug.pyc
Normal file
BIN
test/bytecode_2.4/03_whileelse_bug.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_2.5/02_decorator.pyc
Normal file
BIN
test/bytecode_2.5/02_decorator.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_2.6/03_tryelse_continue.pyc
Normal file
BIN
test/bytecode_2.6/03_tryelse_continue.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_2.6/03_whileelse_bug.pyc
Normal file
BIN
test/bytecode_2.6/03_whileelse_bug.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_2.7/03_whileelse_bug.pyc
Normal file
BIN
test/bytecode_2.7/03_whileelse_bug.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_2.7/04_loop_try_else.pyc
Normal file
BIN
test/bytecode_2.7/04_loop_try_else.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.3/03_whileelse_bug.pyc
Normal file
BIN
test/bytecode_3.3/03_whileelse_bug.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.4/03_whileelse_bug.pyc
Normal file
BIN
test/bytecode_3.4/03_whileelse_bug.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.5/04_async_stmt.pyc
Normal file
BIN
test/bytecode_3.5/04_async_stmt.pyc
Normal file
Binary file not shown.
9
test/simple_source/bug25/02_decorator.py
Normal file
9
test/simple_source/bug25/02_decorator.py
Normal file
@@ -0,0 +1,9 @@
|
||||
# From python 2.5 make_decorators.py
|
||||
# Bug was in not recognizing @memoize which uses grammra rules
|
||||
# using nonterminals mkfuncdeco and mkfuncdeco0
|
||||
def memoize(func):
|
||||
pass
|
||||
def test_memoize(self):
|
||||
@memoize
|
||||
def double(x):
|
||||
return x * 2
|
25
test/simple_source/bug26/03_tryelse_continue.py
Normal file
25
test/simple_source/bug26/03_tryelse_continue.py
Normal file
@@ -0,0 +1,25 @@
|
||||
# 2.6- Try/else in a loop with a continue which
|
||||
# requires a tryelsestmtc
|
||||
# From 2.6- test_codecs.py
|
||||
def test_specific_values(self):
|
||||
for flags in self:
|
||||
if flags:
|
||||
try:
|
||||
self = 1
|
||||
except ValueError:
|
||||
continue
|
||||
else:
|
||||
self = 2
|
||||
|
||||
self = 3
|
||||
|
||||
# From 2.6 test_decorators.
|
||||
# Bug was thinking an "except" was some sort of if/then
|
||||
def call(*args):
|
||||
try:
|
||||
return 5
|
||||
except KeyError:
|
||||
return 2
|
||||
except TypeError:
|
||||
# Unhashable argument
|
||||
return 3
|
12
test/simple_source/bug27+/04_loop_try_else.py
Normal file
12
test/simple_source/bug27+/04_loop_try_else.py
Normal file
@@ -0,0 +1,12 @@
|
||||
# From Python 2.7 ihooks.py
|
||||
def ensure_fromlist(self, fromlist):
|
||||
for sub in fromlist:
|
||||
if sub:
|
||||
if not recursive:
|
||||
try:
|
||||
all = 5
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
all = 6
|
||||
continue
|
9
test/simple_source/bug35/04_async_stmt.py
Normal file
9
test/simple_source/bug35/04_async_stmt.py
Normal file
@@ -0,0 +1,9 @@
|
||||
# From 3.5 _collections.abc.py
|
||||
# Bug was not having \n after "await self.athrow()" stmt
|
||||
async def aclose(self):
|
||||
try:
|
||||
await self.athrow()
|
||||
except (GeneratorExit):
|
||||
pass
|
||||
else:
|
||||
raise RuntimeError
|
9
test/simple_source/looping/03_whileelse_bug.py
Normal file
9
test/simple_source/looping/03_whileelse_bug.py
Normal file
@@ -0,0 +1,9 @@
|
||||
# From idlelib/PyParse.py
|
||||
# Bug is "if" inside a nested while/else.
|
||||
def _study1(i, n):
|
||||
while i:
|
||||
while i:
|
||||
i = 0
|
||||
else:
|
||||
if i:
|
||||
i = 1
|
@@ -12,13 +12,8 @@ typeset -A SKIP_TESTS
|
||||
case $PYVERSION in
|
||||
2.4)
|
||||
SKIP_TESTS=(
|
||||
[test_codecs.py]=1 # need to fix tryelse
|
||||
[test_decorators.py]=1 # Syntax error decorators?
|
||||
[test_dis.py]=1 # We change line numbers - duh!
|
||||
[test_frozen.py]=1
|
||||
[test_grp.py]=1 # Long test - might work Control flow?
|
||||
[test_imp.py]=1 # Control flow?
|
||||
[test_import.py]=1 # Control flow?
|
||||
[test_math.py]=1 # Control flow?
|
||||
[test_pwd.py]=1 # Long test - might work? Control flow?
|
||||
[test_queue.py]=1 # Control flow?
|
||||
@@ -29,17 +24,12 @@ case $PYVERSION in
|
||||
;;
|
||||
2.5)
|
||||
SKIP_TESTS=(
|
||||
[test_codecs.py]=1 # need to fix tryelse
|
||||
[test_coercion.py]=1
|
||||
[test_contextlib.py]=1
|
||||
[test_decorators.py]=1 # Syntax error decorators?
|
||||
[test_dis.py]=1 # We change line numbers - duh!
|
||||
[test_exceptions.py]=1
|
||||
[test_frozen.py]=1
|
||||
[test_functools.py]=1
|
||||
[test_grammar.py]=1 # Too many stmts. Handle large stmts
|
||||
[test_grp.py]=1 # Long test - might work Control flow?
|
||||
[test_imp.py]=1
|
||||
[test_math.py]=1 # Control flow?
|
||||
[test_pdb.py]=1
|
||||
[test_pwd.py]=1 # Long test - might work? Control flow?
|
||||
@@ -53,23 +43,12 @@ case $PYVERSION in
|
||||
;;
|
||||
2.6)
|
||||
SKIP_TESTS=(
|
||||
[test_cmath.py]=1 # Control flow?
|
||||
[test_codecs.py]=1 # need to fix tryelse
|
||||
[test_coercion.py]=1 # Control flow?
|
||||
[test_decorators.py]=1 # Syntax Error - look at
|
||||
[test_frozen.py]=1 # Control flow?
|
||||
[test_ftplib.py]=1 # Control flow?
|
||||
[test_grp.py]=1 # Long test - might work Control flow?
|
||||
[test_imp.py]=1
|
||||
[test_opcodes.py]=1
|
||||
[test_pwd.py]=1 # Long test - might work? Control flow?
|
||||
[test_queue.py]=1 # Control flow?
|
||||
[test_re.py]=1 # Probably Control flow?
|
||||
[test_strftime.py]=1
|
||||
[test_trace.py]=1 # Line numbers are expected to be different
|
||||
# .pyenv/versions/2.6.9/lib/python2.6/lib2to3/refactor.pyc
|
||||
# .pyenv/versions/2.6.9/lib/python2.6/mailbox.pyc
|
||||
# .pyenv/versions/2.6.9/lib/python2.6/markupbase.pyc
|
||||
# .pyenv/versions/2.6.9/lib/python2.6/pstats.pyc
|
||||
# .pyenv/versions/2.6.9/lib/python2.6/pyclbr.pyc
|
||||
# .pyenv/versions/2.6.9/lib/python2.6/quopri.pyc -- look at ishex, is short
|
||||
# .pyenv/versions/2.6.9/lib/python2.6/random.pyc
|
||||
|
@@ -20,19 +20,25 @@ Step 2: Run the test:
|
||||
"""
|
||||
|
||||
from uncompyle6 import main, PYTHON3
|
||||
import os, time, shutil, sys
|
||||
import os, time, re, shutil, sys
|
||||
from fnmatch import fnmatch
|
||||
|
||||
from uncompyle6 import main, PYTHON3
|
||||
import xdis.magics as magics
|
||||
|
||||
#----- configure this for your needs
|
||||
|
||||
TEST_VERSIONS=('2.3.7', '2.4.6', '2.5.6', '2.6.9',
|
||||
python_versions = [v for v in magics.python_versions if
|
||||
re.match('^[0-9.]+$', v)]
|
||||
|
||||
# FIXME: we should remove Python versions that we don't support.
|
||||
# These include Jython, and Python bytecode changes pre release.
|
||||
|
||||
TEST_VERSIONS=(
|
||||
'pypy-2.4.0', 'pypy-2.6.1',
|
||||
'pypy-5.0.1', 'pypy-5.3.1', 'pypy3.5-5.7.1-beta',
|
||||
'2.7.10', '2.7.11', '2.7.12', '2.7.13', '2.7.14',
|
||||
'3.0.1', '3.1.5', '3.2.6',
|
||||
'3.3.5', '3.3.6',
|
||||
'3.4.2', '3.5.3', '3.6.0', '3.6.3',
|
||||
'native')
|
||||
'native') + tuple(python_versions)
|
||||
|
||||
|
||||
target_base = '/tmp/py-dis/'
|
||||
lib_prefix = os.path.join(os.environ['HOME'], '.pyenv/versions')
|
||||
@@ -46,6 +52,7 @@ PYOC = ('*.pyc', '*.pyo')
|
||||
test_options = {
|
||||
# name: (src_basedir, pattern, output_base_suffix)
|
||||
'test': ('./test', PYOC, 'test'),
|
||||
'max=': 200,
|
||||
}
|
||||
|
||||
for vers in TEST_VERSIONS:
|
||||
@@ -63,7 +70,8 @@ for vers in TEST_VERSIONS:
|
||||
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):
|
||||
def do_tests(src_dir, patterns, target_dir, start_with=None,
|
||||
do_verify=False, max_files=200):
|
||||
|
||||
def visitor(files, dirname, names):
|
||||
files.extend(
|
||||
@@ -97,14 +105,14 @@ def do_tests(src_dir, patterns, target_dir, start_with=None, do_verify=False):
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
if len(files) > 200:
|
||||
if len(files) > max_files:
|
||||
files = [file for file in files if not 'site-packages' in file]
|
||||
files = [file for file in files if not 'test' in file]
|
||||
if len(files) > 200:
|
||||
if len(files) > max_files:
|
||||
# print("Numer of files %d - truncating to last 200" % len(files))
|
||||
# files = files[-200:]
|
||||
print("Numer of files %d - truncating to first 200" % len(files))
|
||||
files = files[:200]
|
||||
print("Numer of files %d - truncating to first %s" %
|
||||
(len(files), max_files))
|
||||
files = files[:max_files]
|
||||
|
||||
print(time.ctime())
|
||||
main.main(src_dir, target_dir, files, [], do_verify=do_verify)
|
||||
@@ -121,9 +129,10 @@ if __name__ == '__main__':
|
||||
test_options_keys.sort()
|
||||
opts, args = getopt.getopt(sys.argv[1:], '',
|
||||
['start-with=', 'verify', 'weak-verify',
|
||||
'coverage', 'all', ] \
|
||||
'max=', 'coverage', 'all', ] \
|
||||
+ test_options_keys )
|
||||
vers = ''
|
||||
|
||||
for opt, val in opts:
|
||||
if opt == '--verify':
|
||||
do_verify = True
|
||||
@@ -137,6 +146,8 @@ if __name__ == '__main__':
|
||||
triple = test_options[opt[2:]]
|
||||
vers = triple[-1]
|
||||
test_dirs.append(triple)
|
||||
elif opt == '--max':
|
||||
test_options['max='] = int(val)
|
||||
elif opt == '--all':
|
||||
vers = 'all'
|
||||
for val in test_options_keys:
|
||||
@@ -152,7 +163,8 @@ if __name__ == '__main__':
|
||||
target_dir = os.path.join(target_base, target_dir)
|
||||
if os.path.exists(target_dir):
|
||||
shutil.rmtree(target_dir, ignore_errors=1)
|
||||
do_tests(src_dir, pattern, target_dir, start_with, do_verify)
|
||||
do_tests(src_dir, pattern, target_dir, start_with,
|
||||
do_verify, test_options['max='])
|
||||
else:
|
||||
print("### Path %s doesn't exist; skipping" % src_dir)
|
||||
|
||||
|
@@ -64,7 +64,7 @@ test_options = {
|
||||
PYOC, 'ok-2.7', 2.7),
|
||||
|
||||
'ok-3.2': (os.path.join(src_dir, 'ok_lib3.2'),
|
||||
PYOC, 'ok-3.2', 3.5),
|
||||
PYOC, 'ok-3.2', 3.2),
|
||||
|
||||
'base-2.7': (os.path.join(src_dir, 'base_tests', 'python2.7'),
|
||||
PYOC, 'base_2.7', 2.7),
|
||||
|
@@ -51,7 +51,7 @@ import uncompyle6.semantics.fragments
|
||||
# Export some functions
|
||||
from uncompyle6.main import decompile_file
|
||||
|
||||
# For compaitility
|
||||
# For compatibility
|
||||
uncompyle_file = decompile_file
|
||||
|
||||
# Conventience functions so you can say:
|
||||
|
@@ -191,7 +191,12 @@ def main(in_base, out_base, files, codes, outfile=None,
|
||||
print '\n# okay decompiling %s' % infile
|
||||
okay_files += 1
|
||||
else:
|
||||
print '\n# %s\n\t%s', infile, msg
|
||||
verify_failed_files += 1
|
||||
print('\n# %s\n\t%s', infile, msg)
|
||||
pass
|
||||
else:
|
||||
okay_files += 1
|
||||
pass
|
||||
except verify.VerifyCmpError, e:
|
||||
print(e)
|
||||
verify_failed_files += 1
|
||||
@@ -206,6 +211,9 @@ def main(in_base, out_base, files, codes, outfile=None,
|
||||
raise
|
||||
pass
|
||||
pass
|
||||
pass
|
||||
else:
|
||||
okay_files += 1
|
||||
pass
|
||||
elif do_verify:
|
||||
sys.stderr.write("\n### uncompile successful, "
|
||||
@@ -219,7 +227,8 @@ def main(in_base, out_base, files, codes, outfile=None,
|
||||
print mess, infile
|
||||
if current_outfile:
|
||||
sys.stdout.write("%s\r" %
|
||||
status_msg(do_verify, tot_files, okay_files, failed_files, verify_failed_files))
|
||||
status_msg(do_verify, tot_files, okay_files, failed_files,
|
||||
verify_failed_files, do_verify))
|
||||
sys.stdout.flush()
|
||||
if current_outfile:
|
||||
sys.stdout.write("\n")
|
||||
@@ -240,17 +249,21 @@ else:
|
||||
return ''
|
||||
|
||||
def status_msg(do_verify, tot_files, okay_files, failed_files,
|
||||
verify_failed_files):
|
||||
verify_failed_files, weak_verify):
|
||||
if weak_verify == 'weak':
|
||||
verification_type = 'weak'
|
||||
else:
|
||||
verification_type = 'strong'
|
||||
if tot_files == 1:
|
||||
if failed_files:
|
||||
return "\n# decompile failed"
|
||||
elif verify_failed_files:
|
||||
return "\n# decompile verify failed"
|
||||
return "\n# decompile %s verification failed" % verification_type
|
||||
else:
|
||||
return "\n# Successfully decompiled file"
|
||||
pass
|
||||
pass
|
||||
mess = "decompiled %i files: %i okay, %i failed" % (tot_files, okay_files, failed_files)
|
||||
if do_verify:
|
||||
mess += (", %i verify failed" % verify_failed_files)
|
||||
mess += (", %i %s verification failed" % (verify_failed_files, verification_type))
|
||||
return mess
|
||||
|
@@ -333,15 +333,15 @@ class PythonParser(GenericASTBuilder):
|
||||
|
||||
def p_function_def(self, args):
|
||||
'''
|
||||
stmt ::= function_def
|
||||
function_def ::= mkfunc store
|
||||
stmt ::= funcdefdeco
|
||||
funcdefdeco ::= mkfuncdeco store
|
||||
mkfuncdeco ::= expr mkfuncdeco CALL_FUNCTION_1
|
||||
mkfuncdeco ::= expr mkfuncdeco0 CALL_FUNCTION_1
|
||||
mkfuncdeco0 ::= mkfunc
|
||||
load_closure ::= load_closure LOAD_CLOSURE
|
||||
load_closure ::= LOAD_CLOSURE
|
||||
stmt ::= function_def
|
||||
function_def ::= mkfunc store
|
||||
stmt ::= function_def_deco
|
||||
function_def_deco ::= mkfuncdeco store
|
||||
mkfuncdeco ::= expr mkfuncdeco CALL_FUNCTION_1
|
||||
mkfuncdeco ::= expr mkfuncdeco0 CALL_FUNCTION_1
|
||||
mkfuncdeco0 ::= mkfunc
|
||||
load_closure ::= load_closure LOAD_CLOSURE
|
||||
load_closure ::= LOAD_CLOSURE
|
||||
'''
|
||||
|
||||
def p_generator_exp(self, args):
|
||||
@@ -420,7 +420,7 @@ class PythonParser(GenericASTBuilder):
|
||||
for_block POP_BLOCK _come_froms
|
||||
|
||||
forelsestmt ::= SETUP_LOOP expr for_iter store
|
||||
for_block POP_BLOCK else_suite _come_froms
|
||||
for_block POP_BLOCK else_suite _come_froms
|
||||
|
||||
forelselaststmt ::= SETUP_LOOP expr for_iter store
|
||||
for_block POP_BLOCK else_suitec _come_froms
|
||||
|
@@ -13,7 +13,6 @@ class Python21Parser(Python22Parser):
|
||||
|
||||
def p_forstmt21(self, args):
|
||||
"""
|
||||
for_iter ::= LOAD_CONST FOR_LOOP
|
||||
for ::= SETUP_LOOP expr for_iter store
|
||||
returns
|
||||
POP_BLOCK COME_FROM
|
||||
|
@@ -74,7 +74,6 @@ class Python25Parser(Python26Parser):
|
||||
classdefdeco2 ::= LOAD_CONST expr mkfunc CALL_FUNCTION_0 BUILD_CLASS
|
||||
kv3 ::= expr expr STORE_MAP
|
||||
kvlist ::= kvlist kv3
|
||||
mkfuncdeco ::= expr mkfuncdeco CALL_FUNCTION_1
|
||||
ret_cond ::= expr jmp_false_then expr RETURN_END_IF POP_TOP ret_expr_or_cond
|
||||
return_if_lambda ::= RETURN_END_IF_LAMBDA POP_TOP
|
||||
return_if_stmt ::= ret_expr RETURN_END_IF POP_TOP
|
||||
|
@@ -42,6 +42,8 @@ class Python26Parser(Python2Parser):
|
||||
except_handler else_suite come_froms
|
||||
tryelsestmtl ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK
|
||||
except_handler else_suitel
|
||||
tryelsestmtc ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK
|
||||
except_handler else_suitec
|
||||
|
||||
_ifstmts_jump ::= c_stmts_opt JUMP_FORWARD COME_FROM POP_TOP
|
||||
|
||||
@@ -140,8 +142,8 @@ class Python26Parser(Python2Parser):
|
||||
whilestmt ::= SETUP_LOOP testexpr returns POP_BLOCK COME_FROM
|
||||
|
||||
whileelsestmt ::= SETUP_LOOP testexpr l_stmts_opt jb_pop POP_BLOCK
|
||||
else_suite COME_FROM
|
||||
while1elsestmt ::= SETUP_LOOP l_stmts JUMP_BACK else_suite COME_FROM
|
||||
else_suitel COME_FROM
|
||||
while1elsestmt ::= SETUP_LOOP l_stmts JUMP_BACK else_suitel COME_FROM
|
||||
|
||||
return ::= ret_expr RETURN_END_IF POP_TOP
|
||||
return ::= ret_expr RETURN_VALUE POP_TOP
|
||||
|
@@ -50,6 +50,9 @@ class Python27Parser(Python2Parser):
|
||||
tryelsestmt ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK
|
||||
except_handler else_suite COME_FROM
|
||||
|
||||
tryelsestmtl ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK
|
||||
except_handler else_suitel JUMP_BACK COME_FROM
|
||||
|
||||
except_stmt ::= except_cond2 except_suite
|
||||
|
||||
except_cond1 ::= DUP_TOP expr COMPARE_OP
|
||||
@@ -120,9 +123,9 @@ class Python27Parser(Python2Parser):
|
||||
while1stmt ::= SETUP_LOOP l_stmts_opt JUMP_BACK POP_BLOCK COME_FROM
|
||||
whilestmt ::= SETUP_LOOP testexpr l_stmts_opt JUMP_BACK POP_BLOCK _come_froms
|
||||
while1elsestmt ::= SETUP_LOOP l_stmts JUMP_BACK POP_BLOCK
|
||||
else_suite COME_FROM
|
||||
else_suitel COME_FROM
|
||||
whileelsestmt ::= SETUP_LOOP testexpr l_stmts_opt JUMP_BACK POP_BLOCK
|
||||
else_suite COME_FROM
|
||||
else_suitel COME_FROM
|
||||
|
||||
ifstmt ::= testexpr return_if_stmts COME_FROM
|
||||
ifelsestmt ::= testexpr c_stmts_opt JUMP_FORWARD else_suite COME_FROM
|
||||
|
@@ -348,10 +348,10 @@ class Python3Parser(PythonParser):
|
||||
COME_FROM_LOOP
|
||||
|
||||
while1elsestmt ::= SETUP_LOOP l_stmts JUMP_BACK
|
||||
else_suite
|
||||
else_suitel
|
||||
|
||||
whileelsestmt ::= SETUP_LOOP testexpr l_stmts_opt JUMP_BACK POP_BLOCK
|
||||
else_suite COME_FROM_LOOP
|
||||
else_suitel COME_FROM_LOOP
|
||||
|
||||
whileTruestmt ::= SETUP_LOOP l_stmts_opt JUMP_BACK POP_BLOCK
|
||||
COME_FROM_LOOP
|
||||
@@ -1034,6 +1034,7 @@ class Python3Parser(PythonParser):
|
||||
self.check_reduce['aug_assign1'] = 'AST'
|
||||
self.check_reduce['aug_assign2'] = 'AST'
|
||||
self.check_reduce['while1stmt'] = 'noAST'
|
||||
self.check_reduce['while1elsestmt'] = 'noAST'
|
||||
self.check_reduce['annotate_tuple'] = 'noAST'
|
||||
self.check_reduce['kwarg'] = 'noAST'
|
||||
# FIXME: remove parser errors caused by the below
|
||||
@@ -1053,12 +1054,30 @@ class Python3Parser(PythonParser):
|
||||
else:
|
||||
return not (isinstance(arg, str) or isinstance(arg, unicode))
|
||||
elif lhs == 'while1elsestmt':
|
||||
|
||||
n = len(tokens)
|
||||
if last == n:
|
||||
# Adjust for fuzziness in parsing
|
||||
last -= 1
|
||||
|
||||
if tokens[last] == 'COME_FROM_LOOP':
|
||||
last -= 1
|
||||
elif tokens[last-1] == 'COME_FROM_LOOP':
|
||||
last -= 2
|
||||
if tokens[last] in ('JUMP_BACK', 'CONTINUE'):
|
||||
# These indicate inside a loop, but token[last]
|
||||
# should not be in a loop.
|
||||
# FIXME: Not quite righte: refine by using target
|
||||
return True
|
||||
|
||||
# if SETUP_LOOP target spans the else part, then this is
|
||||
# not while1else. Also do for whileTrue?
|
||||
last += 1
|
||||
while isinstance(tokens[last].offset, str):
|
||||
while last < n and isinstance(tokens[last].offset, str):
|
||||
last += 1
|
||||
return tokens[first].attr == tokens[last].offset
|
||||
if last == n:
|
||||
return False
|
||||
return tokens[first].attr >= tokens[last].offset
|
||||
elif lhs == 'while1stmt':
|
||||
|
||||
# If there is a fall through to the COME_FROM_LOOP. then this is
|
||||
|
@@ -19,9 +19,9 @@ class Python34Parser(Python33Parser):
|
||||
|
||||
|
||||
# FIXME the below masks a bug in not detecting COME_FROM_LOOP
|
||||
# grammar rules with COME_FROM -> COME_FROM_LOOP alreadly exist
|
||||
# grammar rules with COME_FROM -> COME_FROM_LOOP already exist
|
||||
whileelsestmt ::= SETUP_LOOP testexpr l_stmts_opt JUMP_BACK POP_BLOCK
|
||||
else_suite COME_FROM
|
||||
else_suitel COME_FROM
|
||||
|
||||
# Python 3.4+ optimizes the trailing two JUMPS away
|
||||
|
||||
|
@@ -15,13 +15,21 @@ import sys
|
||||
from uncompyle6 import PYTHON3, IS_PYPY
|
||||
from uncompyle6.scanners.tok import Token
|
||||
from xdis.bytecode import op_size
|
||||
from xdis.magics import py_str2float
|
||||
from xdis.magics import py_str2float, canonic_python_version
|
||||
from xdis.util import code2num
|
||||
|
||||
# The byte code versions we support
|
||||
PYTHON_VERSIONS = (1.5,
|
||||
2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7,
|
||||
3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7)
|
||||
# The byte code versions we support.
|
||||
# Note: these all have to be floats
|
||||
PYTHON_VERSIONS = frozenset((1.5,
|
||||
2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7,
|
||||
3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7))
|
||||
|
||||
CANONIC2VERSION = dict((canonic_python_version[str(v)], v) for v in PYTHON_VERSIONS)
|
||||
|
||||
# Magic changed mid version for Python 3.5.2. Compatibility was added for
|
||||
# the older 3.5 interpreter magic.
|
||||
CANONIC2VERSION['3.5.2'] = 3.5
|
||||
|
||||
|
||||
# FIXME: DRY
|
||||
if PYTHON3:
|
||||
@@ -299,7 +307,13 @@ def get_scanner(version, is_pypy=False, show_asm=None):
|
||||
|
||||
# If version is a string, turn that into the corresponding float.
|
||||
if isinstance(version, str):
|
||||
version = py_str2float(version)
|
||||
if version not in canonic_python_version:
|
||||
raise RuntimeError("Unknown Python version in xdis %s" % version)
|
||||
canonic_version = canonic_python_version[version]
|
||||
if canonic_version not in CANONIC2VERSION:
|
||||
raise RuntimeError("Unsupported Python version %s (canonic %s)"
|
||||
% (version, canonic_version))
|
||||
version = CANONIC2VERSION[canonic_version]
|
||||
|
||||
# Pick up appropriate scanner
|
||||
if version in PYTHON_VERSIONS:
|
||||
|
@@ -898,7 +898,6 @@ class Scanner2(Scanner):
|
||||
self.structs.append({'type': 'if-then',
|
||||
'start': start-3,
|
||||
'end': pre_rtarget})
|
||||
|
||||
self.thens[start] = end
|
||||
elif jump_op == 'JUMP_ABSOLUTE':
|
||||
if_then_maybe = {'type': 'if-then',
|
||||
@@ -941,13 +940,20 @@ class Scanner2(Scanner):
|
||||
'end': end})
|
||||
elif code_pre_rtarget == self.opc.RETURN_VALUE:
|
||||
if self.version == 2.7 or pre_rtarget not in self.ignore_if:
|
||||
self.structs.append({'type': 'if-then',
|
||||
'start': start,
|
||||
'end': rtarget})
|
||||
self.thens[start] = rtarget
|
||||
if self.version == 2.7 or code[pre_rtarget+1] != self.opc.JUMP_FORWARD:
|
||||
self.fixed_jumps[offset] = rtarget
|
||||
self.return_end_ifs.add(pre_rtarget)
|
||||
# 10 is exception-match. If there is an exception match in the
|
||||
# compare, then this is an exception clause not an if-then clause
|
||||
if (self.code[self.prev[offset]] != self.opc.COMPARE_OP or
|
||||
self.code[self.prev[offset]+1] != 10):
|
||||
self.structs.append({'type': 'if-then',
|
||||
'start': start,
|
||||
'end': rtarget})
|
||||
self.thens[start] = rtarget
|
||||
if self.version == 2.7 or code[pre_rtarget+1] != self.opc.JUMP_FORWARD:
|
||||
self.fixed_jumps[offset] = rtarget
|
||||
self.return_end_ifs.add(pre_rtarget)
|
||||
pass
|
||||
pass
|
||||
pass
|
||||
|
||||
elif op in self.pop_jump_if_or_pop:
|
||||
target = self.get_target(offset, op)
|
||||
|
@@ -204,7 +204,7 @@ TABLE_DIRECT = {
|
||||
'compare_chained2': ( '%[1]{pattr.replace("-", " ")} %p', (0, 19)),
|
||||
# 'classdef': (), # handled by n_classdef()
|
||||
'function_def': ( '\n\n%|def %c\n', -2), # -2 to handle closures
|
||||
'funcdefdeco': ( '\n\n%c', 0),
|
||||
'function_def_deco': ( '\n\n%c', 0),
|
||||
'mkfuncdeco': ( '%|@%c\n%c', 0, 1),
|
||||
'mkfuncdeco0': ( '%|def %c\n', 0),
|
||||
'classdefdeco': ( '\n\n%c', 0),
|
||||
|
@@ -441,7 +441,7 @@ class SourceWalker(GenericASTTraversal, object):
|
||||
if version >= 3.5:
|
||||
TABLE_DIRECT.update({
|
||||
'await_expr': ( 'await %c', 0),
|
||||
'await_stmt': ( '%|%c', 0),
|
||||
'await_stmt': ( '%|%c\n', 0),
|
||||
'async_for_stmt': (
|
||||
'%|async for %c in %c:\n%+%c%-\n\n', 9, 1, 25 ),
|
||||
'async_forelse_stmt': (
|
||||
@@ -548,7 +548,7 @@ class SourceWalker(GenericASTTraversal, object):
|
||||
TABLE_R.update({
|
||||
'CALL_FUNCTION_EX': ('%c(*%P)', 0, (1, 2, ', ', 100)),
|
||||
# Not quite right
|
||||
'CALL_FUNCTION_EX_KW': ('%c(**%C)', 0, (2,3, ',')),
|
||||
'CALL_FUNCTION_EX_KW': ('%c(**%C)', 0, (2, 3, ',')),
|
||||
})
|
||||
|
||||
def build_unpack_tuple_with_call(node):
|
||||
@@ -2317,13 +2317,12 @@ class SourceWalker(GenericASTTraversal, object):
|
||||
# lowest down the stack
|
||||
if self.version == 3.5:
|
||||
if str == '%c(%C, ':
|
||||
str = '%c(*%C, %c)'
|
||||
entry = ('%c(*%C, %c)', 0, p2, -2)
|
||||
elif str == '%c(%C':
|
||||
str = '%c(*%C)'
|
||||
p2 = (1, 100, '')
|
||||
entry = ('%c(*%C)', 0, (1, 100, ''))
|
||||
else:
|
||||
str += '*%c)'
|
||||
entry = (str, 0, p2, -2)
|
||||
entry = (str, 0, p2, -2)
|
||||
elif op == 'CALL_FUNCTION_KW':
|
||||
str += '**%c)'
|
||||
entry = (str, 0, p2, -2)
|
||||
|
@@ -1,3 +1,3 @@
|
||||
# This file is suitable for sourcing inside bash as
|
||||
# well as importing into Python
|
||||
VERSION='2.14.2'
|
||||
VERSION='2.14.3'
|
||||
|
Reference in New Issue
Block a user