You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-03 08:49:51 +08:00
Merge branch 'master' into python-3.3-to-3.5
This commit is contained in:
12
.github/ISSUE_TEMPLATE/bug-report.md
vendored
12
.github/ISSUE_TEMPLATE/bug-report.md
vendored
@@ -7,6 +7,11 @@ about: Tell us about uncompyle6 bugs
|
|||||||
<!-- __Note:__ If you are using this program to do something illegal - don't.
|
<!-- __Note:__ If you are using this program to do something illegal - don't.
|
||||||
The issue may be flagged to make it easier for those looking for illegal activity.
|
The issue may be flagged to make it easier for those looking for illegal activity.
|
||||||
|
|
||||||
|
If you are reporting a bug in decompilation, it will probably not be acted upon
|
||||||
|
unless it is narrowed to a small example. You may have to do some work remove
|
||||||
|
extraneous code from the source example. Most bugs can be expressed in 30 lines of
|
||||||
|
code.
|
||||||
|
|
||||||
Bugs are not for asking questions about a problem you
|
Bugs are not for asking questions about a problem you
|
||||||
are trying to solve that involve the use of uncompyle6 along the way,
|
are trying to solve that involve the use of uncompyle6 along the way,
|
||||||
although I may be more tolerant of this if you sponsor the project.
|
although I may be more tolerant of this if you sponsor the project.
|
||||||
@@ -50,6 +55,7 @@ Prerequisites/Caveats
|
|||||||
|
|
||||||
* Make sure the bytecode you have can be disassembled with a
|
* Make sure the bytecode you have can be disassembled with a
|
||||||
disassembler and produces valid results.
|
disassembler and produces valid results.
|
||||||
|
* Try to make the bytecode that exhibits a bug as small as possible.
|
||||||
* Don't put bytecode and corresponding source code on any service that
|
* Don't put bytecode and corresponding source code on any service that
|
||||||
requires registration to download.
|
requires registration to download.
|
||||||
* When you open a bug report there is no privacy. If you need privacy, then
|
* When you open a bug report there is no privacy. If you need privacy, then
|
||||||
@@ -118,7 +124,11 @@ Please modify for your setup
|
|||||||
|
|
||||||
## Priority
|
## Priority
|
||||||
|
|
||||||
<!-- If this is blocking some important activity let us know what activity it blocks. -->
|
<!-- If this is important for a particular public good state that here.
|
||||||
|
If this is blocking some important activity let us know what activity it blocks.
|
||||||
|
|
||||||
|
Otherwise, we'll assume this has the lowest priority in addressing.
|
||||||
|
-->
|
||||||
|
|
||||||
## Additional Context
|
## Additional Context
|
||||||
|
|
||||||
|
@@ -5,4 +5,4 @@ if [[ $0 == ${BASH_SOURCE[0]} ]] ; then
|
|||||||
echo "This script should be *sourced* rather than run directly through bash"
|
echo "This script should be *sourced* rather than run directly through bash"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
export PYVERSIONS='3.6.15 pypy3.6-7.3.1 3.7.16 pypy3.7-7.3.9 pypy3.8-7.3.10 pyston-2.3.5 3.8.16'
|
export PYVERSIONS='3.6.15 pypy3.6-7.3.1 3.7.16 pypy3.7-7.3.9 pypy3.8-7.3.10 pyston-2.3.5 3.8.17'
|
||||||
|
Binary file not shown.
Binary file not shown.
@@ -726,9 +726,12 @@ values = {
|
|||||||
|
|
||||||
assert sorted(values.values())[1:] == list(range(2, 34))
|
assert sorted(values.values())[1:] == list(range(2, 34))
|
||||||
|
|
||||||
|
def assert_equal(x, y):
|
||||||
|
assert x == y
|
||||||
|
|
||||||
# Check that we can distinguish names from strings in literal collections, e.g. lists.
|
# Check that we can distinguish names from strings in literal collections, e.g. lists.
|
||||||
# The list has to have more than 4 items to get accumulated in a collection
|
# The list has to have more than 4 items to get accumulated in a collection
|
||||||
a = ["y", 'Exception', "x", Exception, "z"]
|
a = ["y", 'Exception', "x", Exception, "z"]
|
||||||
assert a[1] == "Exception"
|
|
||||||
assert a[3] == Exception
|
assert_equal(a[1], "Exception")
|
||||||
|
assert_equal(a[3], Exception)
|
||||||
|
@@ -25,7 +25,6 @@ SKIP_TESTS=(
|
|||||||
[test_nis.py]=1 # it fails on its own
|
[test_nis.py]=1 # it fails on its own
|
||||||
[test_normalization.py]=1 # it fails on its own
|
[test_normalization.py]=1 # it fails on its own
|
||||||
[test_ossaudiodev.py]=1 # it fails on its own
|
[test_ossaudiodev.py]=1 # it fails on its own
|
||||||
[test_pep277.py]=1 # it fails on its own
|
|
||||||
[test_plistlib.py]=1 # it fails on its own
|
[test_plistlib.py]=1 # it fails on its own
|
||||||
[test_rgbimg.py]=1 # it fails on its own
|
[test_rgbimg.py]=1 # it fails on its own
|
||||||
[test_scriptpackages.py]=1 # it fails on its own
|
[test_scriptpackages.py]=1 # it fails on its own
|
||||||
|
@@ -1,10 +1,13 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# Mode: -*- python -*-
|
# Mode: -*- python -*-
|
||||||
#
|
#
|
||||||
# Copyright (c) 2015-2016, 2018, 2020, 2022 by Rocky Bernstein <rb@dustyfeet.com>
|
# Copyright (c) 2015-2016, 2018, 2020, 2022-2023 by Rocky Bernstein <rb@dustyfeet.com>
|
||||||
#
|
#
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
import sys, os, getopt
|
|
||||||
|
import getopt
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
from uncompyle6.code_fns import disassemble_file
|
from uncompyle6.code_fns import disassemble_file
|
||||||
from uncompyle6.version import __version__
|
from uncompyle6.version import __version__
|
||||||
@@ -40,13 +43,19 @@ Options:
|
|||||||
-V | --version show version and stop
|
-V | --version show version and stop
|
||||||
-h | --help show this message
|
-h | --help show this message
|
||||||
|
|
||||||
""".format(program)
|
""".format(
|
||||||
|
program
|
||||||
|
)
|
||||||
|
|
||||||
|
PATTERNS = ("*.pyc", "*.pyo")
|
||||||
|
|
||||||
PATTERNS = ('*.pyc', '*.pyo')
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
Usage_short = """usage: %s FILE...
|
Usage_short = (
|
||||||
Type -h for for full help.""" % program
|
"""usage: %s FILE...
|
||||||
|
Type -h for for full help."""
|
||||||
|
% program
|
||||||
|
)
|
||||||
|
|
||||||
if len(sys.argv) == 1:
|
if len(sys.argv) == 1:
|
||||||
print("No file(s) given", file=sys.stderr)
|
print("No file(s) given", file=sys.stderr)
|
||||||
@@ -54,17 +63,18 @@ Type -h for for full help.""" % program
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
opts, files = getopt.getopt(sys.argv[1:], 'hVU',
|
opts, files = getopt.getopt(
|
||||||
['help', 'version', 'uncompyle6'])
|
sys.argv[1:], "hVU", ["help", "version", "uncompyle6"]
|
||||||
|
)
|
||||||
except getopt.GetoptError as e:
|
except getopt.GetoptError as e:
|
||||||
print('%s: %s' % (os.path.basename(sys.argv[0]), e), file=sys.stderr)
|
print("%s: %s" % (os.path.basename(sys.argv[0]), e), file=sys.stderr)
|
||||||
sys.exit(-1)
|
sys.exit(-1)
|
||||||
|
|
||||||
for opt, val in opts:
|
for opt, val in opts:
|
||||||
if opt in ('-h', '--help'):
|
if opt in ("-h", "--help"):
|
||||||
print(__doc__)
|
print(__doc__)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
elif opt in ('-V', '--version'):
|
elif opt in ("-V", "--version"):
|
||||||
print("%s %s" % (program, __version__))
|
print("%s %s" % (program, __version__))
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
else:
|
else:
|
||||||
@@ -76,11 +86,11 @@ Type -h for for full help.""" % program
|
|||||||
if os.path.exists(files[0]):
|
if os.path.exists(files[0]):
|
||||||
disassemble_file(file, sys.stdout)
|
disassemble_file(file, sys.stdout)
|
||||||
else:
|
else:
|
||||||
print("Can't read %s - skipping" % files[0],
|
print("Can't read %s - skipping" % files[0], file=sys.stderr)
|
||||||
file=sys.stderr)
|
|
||||||
pass
|
pass
|
||||||
pass
|
pass
|
||||||
return
|
return
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
@@ -1,14 +1,19 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# Mode: -*- python -*-
|
# Mode: -*- python -*-
|
||||||
#
|
#
|
||||||
# Copyright (c) 2015-2017, 2019-2020 by Rocky Bernstein
|
# Copyright (c) 2015-2017, 2019-2020, 2023 by Rocky Bernstein
|
||||||
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
|
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
|
||||||
#
|
#
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
import sys, os, getopt, time
|
|
||||||
|
import getopt
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
from xdis.version_info import version_tuple_to_str
|
from xdis.version_info import version_tuple_to_str
|
||||||
|
|
||||||
program = 'uncompyle6'
|
program = "uncompyle6"
|
||||||
|
|
||||||
__doc__ = """
|
__doc__ = """
|
||||||
Usage:
|
Usage:
|
||||||
@@ -58,14 +63,17 @@ Extensions of generated files:
|
|||||||
'.pyc_dis' '.pyo_dis' successfully decompiled (and verified if --verify)
|
'.pyc_dis' '.pyo_dis' successfully decompiled (and verified if --verify)
|
||||||
+ '_unverified' successfully decompile but --verify failed
|
+ '_unverified' successfully decompile but --verify failed
|
||||||
+ '_failed' decompile failed (contact author for enhancement)
|
+ '_failed' decompile failed (contact author for enhancement)
|
||||||
""" % ((program,) * 5)
|
""" % (
|
||||||
|
(program,) * 5
|
||||||
|
)
|
||||||
|
|
||||||
program = 'uncompyle6'
|
program = "uncompyle6"
|
||||||
|
|
||||||
from uncompyle6 import verify
|
from uncompyle6 import verify
|
||||||
from uncompyle6.main import main, status_msg
|
from uncompyle6.main import main, status_msg
|
||||||
from uncompyle6.version import __version__
|
from uncompyle6.version import __version__
|
||||||
|
|
||||||
|
|
||||||
def usage():
|
def usage():
|
||||||
print(__doc__)
|
print(__doc__)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
@@ -83,74 +91,77 @@ def main_bin():
|
|||||||
|
|
||||||
do_verify = recurse_dirs = False
|
do_verify = recurse_dirs = False
|
||||||
numproc = 0
|
numproc = 0
|
||||||
outfile = '-'
|
outfile = "-"
|
||||||
out_base = None
|
out_base = None
|
||||||
source_paths = []
|
source_paths = []
|
||||||
timestamp = False
|
timestamp = False
|
||||||
timestampfmt = "# %Y.%m.%d %H:%M:%S %Z"
|
timestampfmt = "# %Y.%m.%d %H:%M:%S %Z"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
opts, pyc_paths = getopt.getopt(sys.argv[1:], 'hac:gtTdrVo:p:',
|
opts, pyc_paths = getopt.getopt(
|
||||||
'help asm compile= grammar linemaps recurse '
|
sys.argv[1:],
|
||||||
'timestamp tree= tree+ '
|
"hac:gtTdrVo:p:",
|
||||||
'fragments verify verify-run version '
|
"help asm compile= grammar linemaps recurse "
|
||||||
'syntax-verify '
|
"timestamp tree= tree+ "
|
||||||
'showgrammar encoding='.split(' '))
|
"fragments verify verify-run version "
|
||||||
|
"syntax-verify "
|
||||||
|
"showgrammar encoding=".split(" "),
|
||||||
|
)
|
||||||
except getopt.GetoptError as e:
|
except getopt.GetoptError as e:
|
||||||
print('%s: %s' % (os.path.basename(sys.argv[0]), e), file=sys.stderr)
|
print("%s: %s" % (os.path.basename(sys.argv[0]), e), file=sys.stderr)
|
||||||
sys.exit(-1)
|
sys.exit(-1)
|
||||||
|
|
||||||
options = {}
|
options = {}
|
||||||
for opt, val in opts:
|
for opt, val in opts:
|
||||||
if opt in ('-h', '--help'):
|
if opt in ("-h", "--help"):
|
||||||
print(__doc__)
|
print(__doc__)
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
elif opt in ('-V', '--version'):
|
elif opt in ("-V", "--version"):
|
||||||
print("%s %s" % (program, __version__))
|
print("%s %s" % (program, __version__))
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
elif opt == '--verify':
|
elif opt == "--verify":
|
||||||
options['do_verify'] = 'strong'
|
options["do_verify"] = "strong"
|
||||||
elif opt == '--syntax-verify':
|
elif opt == "--syntax-verify":
|
||||||
options['do_verify'] = 'weak'
|
options["do_verify"] = "weak"
|
||||||
elif opt == '--fragments':
|
elif opt == "--fragments":
|
||||||
options['do_fragments'] = True
|
options["do_fragments"] = True
|
||||||
elif opt == '--verify-run':
|
elif opt == "--verify-run":
|
||||||
options['do_verify'] = 'verify-run'
|
options["do_verify"] = "verify-run"
|
||||||
elif opt == '--linemaps':
|
elif opt == "--linemaps":
|
||||||
options['do_linemaps'] = True
|
options["do_linemaps"] = True
|
||||||
elif opt in ('--asm', '-a'):
|
elif opt in ("--asm", "-a"):
|
||||||
options['showasm'] = 'after'
|
options["showasm"] = "after"
|
||||||
options['do_verify'] = None
|
options["do_verify"] = None
|
||||||
elif opt in ('--tree', '-t'):
|
elif opt in ("--tree", "-t"):
|
||||||
if 'showast' not in options:
|
if "showast" not in options:
|
||||||
options['showast'] = {}
|
options["showast"] = {}
|
||||||
if val == 'before':
|
if val == "before":
|
||||||
options['showast'][val] = True
|
options["showast"][val] = True
|
||||||
elif val == 'after':
|
elif val == "after":
|
||||||
options['showast'][val] = True
|
options["showast"][val] = True
|
||||||
else:
|
else:
|
||||||
options['showast']['before'] = True
|
options["showast"]["before"] = True
|
||||||
options['do_verify'] = None
|
options["do_verify"] = None
|
||||||
elif opt in ('--tree+', '-T'):
|
elif opt in ("--tree+", "-T"):
|
||||||
if 'showast' not in options:
|
if "showast" not in options:
|
||||||
options['showast'] = {}
|
options["showast"] = {}
|
||||||
options['showast']['after'] = True
|
options["showast"]["after"] = True
|
||||||
options['showast']['before'] = True
|
options["showast"]["before"] = True
|
||||||
options['do_verify'] = None
|
options["do_verify"] = None
|
||||||
elif opt in ('--grammar', '-g'):
|
elif opt in ("--grammar", "-g"):
|
||||||
options['showgrammar'] = True
|
options["showgrammar"] = True
|
||||||
elif opt == '-o':
|
elif opt == "-o":
|
||||||
outfile = val
|
outfile = val
|
||||||
elif opt in ('--timestamp', '-d'):
|
elif opt in ("--timestamp", "-d"):
|
||||||
timestamp = True
|
timestamp = True
|
||||||
elif opt in ('--compile', '-c'):
|
elif opt in ("--compile", "-c"):
|
||||||
source_paths.append(val)
|
source_paths.append(val)
|
||||||
elif opt == '-p':
|
elif opt == "-p":
|
||||||
numproc = int(val)
|
numproc = int(val)
|
||||||
elif opt in ('--recurse', '-r'):
|
elif opt in ("--recurse", "-r"):
|
||||||
recurse_dirs = True
|
recurse_dirs = True
|
||||||
elif opt == '--encoding':
|
elif opt == "--encoding":
|
||||||
options['source_encoding'] = val
|
options["source_encoding"] = val
|
||||||
else:
|
else:
|
||||||
print(opt, file=sys.stderr)
|
print(opt, file=sys.stderr)
|
||||||
usage()
|
usage()
|
||||||
@@ -162,7 +173,7 @@ def main_bin():
|
|||||||
if os.path.isdir(f):
|
if os.path.isdir(f):
|
||||||
for root, _, dir_files in os.walk(f):
|
for root, _, dir_files in os.walk(f):
|
||||||
for df in dir_files:
|
for df in dir_files:
|
||||||
if df.endswith('.pyc') or df.endswith('.pyo'):
|
if df.endswith(".pyc") or df.endswith(".pyo"):
|
||||||
expanded_files.append(os.path.join(root, df))
|
expanded_files.append(os.path.join(root, df))
|
||||||
pyc_paths = expanded_files
|
pyc_paths = expanded_files
|
||||||
|
|
||||||
@@ -173,36 +184,39 @@ def main_bin():
|
|||||||
if src_base[-1:] != os.sep:
|
if src_base[-1:] != os.sep:
|
||||||
src_base = os.path.dirname(src_base)
|
src_base = os.path.dirname(src_base)
|
||||||
if src_base:
|
if src_base:
|
||||||
sb_len = len( os.path.join(src_base, '') )
|
sb_len = len(os.path.join(src_base, ""))
|
||||||
pyc_paths = [f[sb_len:] for f in pyc_paths]
|
pyc_paths = [f[sb_len:] for f in pyc_paths]
|
||||||
|
|
||||||
if not pyc_paths and not source_paths:
|
if not pyc_paths and not source_paths:
|
||||||
print("No input files given to decompile", file=sys.stderr)
|
print("No input files given to decompile", file=sys.stderr)
|
||||||
usage()
|
usage()
|
||||||
|
|
||||||
if outfile == '-':
|
if outfile == "-":
|
||||||
outfile = None # use stdout
|
outfile = None # use stdout
|
||||||
elif outfile and os.path.isdir(outfile):
|
elif outfile and os.path.isdir(outfile):
|
||||||
out_base = outfile; outfile = None
|
out_base = outfile
|
||||||
|
outfile = None
|
||||||
elif outfile and len(pyc_paths) > 1:
|
elif outfile and len(pyc_paths) > 1:
|
||||||
out_base = outfile; outfile = None
|
out_base = outfile
|
||||||
|
outfile = None
|
||||||
|
|
||||||
if timestamp:
|
if timestamp:
|
||||||
print(time.strftime(timestampfmt))
|
print(time.strftime(timestampfmt))
|
||||||
|
|
||||||
if numproc <= 1:
|
if numproc <= 1:
|
||||||
try:
|
try:
|
||||||
result = main(src_base, out_base, pyc_paths, source_paths, outfile,
|
result = main(
|
||||||
**options)
|
src_base, out_base, pyc_paths, source_paths, outfile, **options
|
||||||
result = [options.get('do_verify', None)] + list(result)
|
)
|
||||||
|
result = [options.get("do_verify", None)] + list(result)
|
||||||
if len(pyc_paths) > 1:
|
if len(pyc_paths) > 1:
|
||||||
mess = status_msg(*result)
|
mess = status_msg(*result)
|
||||||
print('# ' + mess)
|
print("# " + mess)
|
||||||
pass
|
pass
|
||||||
except ImportError as e:
|
except ImportError as e:
|
||||||
print(str(e))
|
print(str(e))
|
||||||
sys.exit(2)
|
sys.exit(2)
|
||||||
except (KeyboardInterrupt):
|
except KeyboardInterrupt:
|
||||||
pass
|
pass
|
||||||
except verify.VerifyCmpError:
|
except verify.VerifyCmpError:
|
||||||
raise
|
raise
|
||||||
@@ -214,7 +228,7 @@ def main_bin():
|
|||||||
except ImportError:
|
except ImportError:
|
||||||
from queue import Empty
|
from queue import Empty
|
||||||
|
|
||||||
fqueue = Queue(len(pyc_paths)+numproc)
|
fqueue = Queue(len(pyc_paths) + numproc)
|
||||||
for f in pyc_paths:
|
for f in pyc_paths:
|
||||||
fqueue.put(f)
|
fqueue.put(f)
|
||||||
for i in range(numproc):
|
for i in range(numproc):
|
||||||
@@ -224,13 +238,17 @@ def main_bin():
|
|||||||
|
|
||||||
def process_func():
|
def process_func():
|
||||||
try:
|
try:
|
||||||
(tot_files, okay_files, failed_files, verify_failed_files) = (0, 0, 0, 0)
|
(tot_files, okay_files, failed_files, verify_failed_files) = (
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
)
|
||||||
while 1:
|
while 1:
|
||||||
f = fqueue.get()
|
f = fqueue.get()
|
||||||
if f is None:
|
if f is None:
|
||||||
break
|
break
|
||||||
(t, o, f, v) = \
|
(t, o, f, v) = main(src_base, out_base, [f], [], outfile, **options)
|
||||||
main(src_base, out_base, [f], [], outfile, **options)
|
|
||||||
tot_files += t
|
tot_files += t
|
||||||
okay_files += o
|
okay_files += o
|
||||||
failed_files += f
|
failed_files += f
|
||||||
@@ -247,7 +265,12 @@ def main_bin():
|
|||||||
for p in procs:
|
for p in procs:
|
||||||
p.join()
|
p.join()
|
||||||
try:
|
try:
|
||||||
(tot_files, okay_files, failed_files, verify_failed_files) = (0, 0, 0, 0)
|
(tot_files, okay_files, failed_files, verify_failed_files) = (
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
)
|
||||||
while True:
|
while True:
|
||||||
(t, o, f, v) = rqueue.get(False)
|
(t, o, f, v) = rqueue.get(False)
|
||||||
tot_files += t
|
tot_files += t
|
||||||
@@ -256,8 +279,10 @@ def main_bin():
|
|||||||
verify_failed_files += v
|
verify_failed_files += v
|
||||||
except Empty:
|
except Empty:
|
||||||
pass
|
pass
|
||||||
print('# decompiled %i files: %i okay, %i failed, %i verify failed' %
|
print(
|
||||||
(tot_files, okay_files, failed_files, verify_failed_files))
|
"# decompiled %i files: %i okay, %i failed, %i verify failed"
|
||||||
|
% (tot_files, okay_files, failed_files, verify_failed_files)
|
||||||
|
)
|
||||||
except (KeyboardInterrupt, OSError):
|
except (KeyboardInterrupt, OSError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -266,5 +291,6 @@ def main_bin():
|
|||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
|
if __name__ == "__main__":
|
||||||
main_bin()
|
main_bin()
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
# Copyright (C) 2018-2022 Rocky Bernstein <rocky@gnu.org>
|
# Copyright (C) 2018-2023 Rocky Bernstein <rocky@gnu.org>
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -13,23 +13,25 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import datetime, py_compile, os, sys
|
import datetime
|
||||||
|
import os
|
||||||
|
import py_compile
|
||||||
|
import sys
|
||||||
|
|
||||||
from xdis import iscode
|
from xdis import iscode
|
||||||
|
from xdis.load import load_module
|
||||||
from xdis.version_info import IS_PYPY, PYTHON_VERSION_TRIPLE, version_tuple_to_str
|
from xdis.version_info import IS_PYPY, PYTHON_VERSION_TRIPLE, version_tuple_to_str
|
||||||
|
|
||||||
from uncompyle6.code_fns import check_object_path
|
from uncompyle6.code_fns import check_object_path
|
||||||
from uncompyle6.semantics import pysource
|
|
||||||
from uncompyle6.semantics.pysource import PARSER_DEFAULT_DEBUG
|
|
||||||
from uncompyle6.parser import ParserError
|
from uncompyle6.parser import ParserError
|
||||||
|
from uncompyle6.semantics import pysource
|
||||||
|
from uncompyle6.semantics.fragments import code_deparse as code_deparse_fragments
|
||||||
|
from uncompyle6.semantics.linemap import deparse_code_with_map
|
||||||
|
from uncompyle6.semantics.pysource import PARSER_DEFAULT_DEBUG, code_deparse
|
||||||
from uncompyle6.version import __version__
|
from uncompyle6.version import __version__
|
||||||
|
|
||||||
# from uncompyle6.linenumbers import line_number_mapping
|
# from uncompyle6.linenumbers import line_number_mapping
|
||||||
|
|
||||||
from uncompyle6.semantics.pysource import code_deparse
|
|
||||||
from uncompyle6.semantics.fragments import code_deparse as code_deparse_fragments
|
|
||||||
from uncompyle6.semantics.linemap import deparse_code_with_map
|
|
||||||
|
|
||||||
from xdis.load import load_module
|
|
||||||
|
|
||||||
def _get_outstream(outfile):
|
def _get_outstream(outfile):
|
||||||
dir = os.path.dirname(outfile)
|
dir = os.path.dirname(outfile)
|
||||||
@@ -54,7 +56,7 @@ def decompile(
|
|||||||
source_encoding=None,
|
source_encoding=None,
|
||||||
code_objects={},
|
code_objects={},
|
||||||
source_size=None,
|
source_size=None,
|
||||||
is_pypy=None,
|
is_pypy=False,
|
||||||
magic_int=None,
|
magic_int=None,
|
||||||
mapstream=None,
|
mapstream=None,
|
||||||
do_fragments=False,
|
do_fragments=False,
|
||||||
@@ -144,8 +146,8 @@ def decompile(
|
|||||||
out,
|
out,
|
||||||
bytecode_version,
|
bytecode_version,
|
||||||
debug_opts=debug_opts,
|
debug_opts=debug_opts,
|
||||||
is_pypy=is_pypy,
|
|
||||||
compile_mode=compile_mode,
|
compile_mode=compile_mode,
|
||||||
|
is_pypy=is_pypy,
|
||||||
)
|
)
|
||||||
pass
|
pass
|
||||||
return deparsed
|
return deparsed
|
||||||
@@ -187,7 +189,7 @@ def decompile_file(
|
|||||||
|
|
||||||
filename = check_object_path(filename)
|
filename = check_object_path(filename)
|
||||||
code_objects = {}
|
code_objects = {}
|
||||||
(version, timestamp, magic_int, co, is_pypy, source_size, sip_hash) = load_module(
|
version, timestamp, magic_int, co, is_pypy, source_size, _ = load_module(
|
||||||
filename, code_objects
|
filename, code_objects
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -393,14 +395,14 @@ def main(
|
|||||||
try:
|
try:
|
||||||
# FIXME: Something is weird with Pypy here
|
# FIXME: Something is weird with Pypy here
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
except:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
if current_outfile:
|
if current_outfile:
|
||||||
sys.stdout.write("\n")
|
sys.stdout.write("\n")
|
||||||
try:
|
try:
|
||||||
# FIXME: Something is weird with Pypy here
|
# FIXME: Something is weird with Pypy here
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
except:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
pass
|
pass
|
||||||
return (tot_files, okay_files, failed_files, verify_failed_files)
|
return (tot_files, okay_files, failed_files, verify_failed_files)
|
||||||
@@ -416,7 +418,6 @@ if sys.platform.startswith("linux") and os.uname()[2][:2] in ["2.", "3.", "4."]:
|
|||||||
mi.close()
|
mi.close()
|
||||||
return int(mu) / 1000000
|
return int(mu) / 1000000
|
||||||
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|
||||||
def __memUsage():
|
def __memUsage():
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
# Copyright (c) 2015-2022 Rocky Bernstein
|
# Copyright (c) 2015-2023 Rocky Bernstein
|
||||||
# Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org>
|
# Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org>
|
||||||
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
|
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
|
||||||
# Copyright (c) 1999 John Aycock
|
# Copyright (c) 1999 John Aycock
|
||||||
@@ -44,8 +44,8 @@ def nop_func(self, args):
|
|||||||
|
|
||||||
|
|
||||||
class PythonParser(GenericASTBuilder):
|
class PythonParser(GenericASTBuilder):
|
||||||
def __init__(self, SyntaxTree, start, debug):
|
def __init__(self, syntax_tree_class, start, debug):
|
||||||
super(PythonParser, self).__init__(SyntaxTree, start, debug)
|
super(PythonParser, self).__init__(syntax_tree_class, start, debug)
|
||||||
# FIXME: customize per python parser version
|
# FIXME: customize per python parser version
|
||||||
|
|
||||||
# These are the non-terminals we should collect into a list.
|
# These are the non-terminals we should collect into a list.
|
||||||
@@ -103,6 +103,7 @@ class PythonParser(GenericASTBuilder):
|
|||||||
)
|
)
|
||||||
# Instructions filled in from scanner
|
# Instructions filled in from scanner
|
||||||
self.insts = []
|
self.insts = []
|
||||||
|
self.version = tuple()
|
||||||
|
|
||||||
def ast_first_offset(self, ast):
|
def ast_first_offset(self, ast):
|
||||||
if hasattr(ast, "offset"):
|
if hasattr(ast, "offset"):
|
||||||
@@ -151,9 +152,9 @@ class PythonParser(GenericASTBuilder):
|
|||||||
Remove recursive references to allow garbage
|
Remove recursive references to allow garbage
|
||||||
collector to collect this object.
|
collector to collect this object.
|
||||||
"""
|
"""
|
||||||
for dict in (self.rule2func, self.rules, self.rule2name):
|
for rule_dict in (self.rule2func, self.rules, self.rule2name):
|
||||||
for i in list(dict.keys()):
|
for i in list(rule_dict.keys()):
|
||||||
dict[i] = None
|
rule_dict[i] = None
|
||||||
for i in dir(self):
|
for i in dir(self):
|
||||||
setattr(self, i, None)
|
setattr(self, i, None)
|
||||||
|
|
||||||
@@ -164,11 +165,11 @@ class PythonParser(GenericASTBuilder):
|
|||||||
|
|
||||||
def fix(c):
|
def fix(c):
|
||||||
s = str(c)
|
s = str(c)
|
||||||
last_token_pos = s.find("_")
|
token_pos = s.find("_")
|
||||||
if last_token_pos == -1:
|
if token_pos == -1:
|
||||||
return s
|
return s
|
||||||
else:
|
else:
|
||||||
return s[:last_token_pos]
|
return s[:token_pos]
|
||||||
|
|
||||||
prefix = ""
|
prefix = ""
|
||||||
if parent and tokens:
|
if parent and tokens:
|
||||||
@@ -267,13 +268,13 @@ class PythonParser(GenericASTBuilder):
|
|||||||
print(children)
|
print(children)
|
||||||
return GenericASTBuilder.ambiguity(self, children)
|
return GenericASTBuilder.ambiguity(self, children)
|
||||||
|
|
||||||
def resolve(self, list):
|
def resolve(self, rule: list):
|
||||||
if len(list) == 2 and "function_def" in list and "assign" in list:
|
if len(rule) == 2 and "function_def" in rule and "assign" in rule:
|
||||||
return "function_def"
|
return "function_def"
|
||||||
if "grammar" in list and "expr" in list:
|
if "grammar" in rule and "expr" in rule:
|
||||||
return "expr"
|
return "expr"
|
||||||
# print >> sys.stderr, 'resolve', str(list)
|
# print >> sys.stderr, 'resolve', str(rule)
|
||||||
return GenericASTBuilder.resolve(self, list)
|
return GenericASTBuilder.resolve(self, rule)
|
||||||
|
|
||||||
###############################################
|
###############################################
|
||||||
# Common Python 2 and Python 3 grammar rules #
|
# Common Python 2 and Python 3 grammar rules #
|
||||||
@@ -667,7 +668,7 @@ def get_python_parser(
|
|||||||
if compile_mode == "exec":
|
if compile_mode == "exec":
|
||||||
p = parse10.Python10Parser(debug_parser)
|
p = parse10.Python10Parser(debug_parser)
|
||||||
else:
|
else:
|
||||||
p = parse10.Python01ParserSingle(debug_parser)
|
p = parse10.Python10ParserSingle(debug_parser)
|
||||||
elif version == (1, 1):
|
elif version == (1, 1):
|
||||||
import uncompyle6.parsers.parse11 as parse11
|
import uncompyle6.parsers.parse11 as parse11
|
||||||
|
|
||||||
@@ -873,6 +874,7 @@ def python_parser(
|
|||||||
:param showasm: Flag which determines whether the disassembled and
|
:param showasm: Flag which determines whether the disassembled and
|
||||||
ingested code is written to sys.stdout or not.
|
ingested code is written to sys.stdout or not.
|
||||||
:param parser_debug: dict containing debug flags for the spark parser.
|
:param parser_debug: dict containing debug flags for the spark parser.
|
||||||
|
:param is_pypy: True if we are running PyPY
|
||||||
|
|
||||||
:return: Abstract syntax tree representation of the code object.
|
:return: Abstract syntax tree representation of the code object.
|
||||||
"""
|
"""
|
||||||
|
@@ -1,11 +1,12 @@
|
|||||||
# Copyright (c) 2018 Rocky Bernstein
|
# Copyright (c) 2018, 2023 Rocky Bernstein
|
||||||
|
|
||||||
from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG
|
from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG
|
||||||
|
|
||||||
from uncompyle6.parser import PythonParserSingle
|
from uncompyle6.parser import PythonParserSingle
|
||||||
from uncompyle6.parsers.parse14 import Python14Parser
|
from uncompyle6.parsers.parse14 import Python14Parser
|
||||||
|
|
||||||
class Python13Parser(Python14Parser):
|
|
||||||
|
|
||||||
|
class Python13Parser(Python14Parser):
|
||||||
def p_misc13(self, args):
|
def p_misc13(self, args):
|
||||||
"""
|
"""
|
||||||
# Nothing here yet, but will need to add LOAD_GLOBALS
|
# Nothing here yet, but will need to add LOAD_GLOBALS
|
||||||
@@ -24,7 +25,6 @@ class Python13Parser(Python14Parser):
|
|||||||
# """)
|
# """)
|
||||||
# self.check_reduce['doc_junk'] = 'tokens'
|
# self.check_reduce['doc_junk'] = 'tokens'
|
||||||
|
|
||||||
|
|
||||||
# def reduce_is_invalid(self, rule, ast, tokens, first, last):
|
# def reduce_is_invalid(self, rule, ast, tokens, first, last):
|
||||||
# invalid = super(Python14Parser,
|
# invalid = super(Python14Parser,
|
||||||
# self).reduce_is_invalid(rule, ast,
|
# self).reduce_is_invalid(rule, ast,
|
||||||
@@ -35,11 +35,11 @@ class Python13Parser(Python14Parser):
|
|||||||
# return not isinstance(tokens[first].pattr, str)
|
# return not isinstance(tokens[first].pattr, str)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Python13ParserSingle(Python13Parser, PythonParserSingle):
|
class Python13ParserSingle(Python13Parser, PythonParserSingle):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
|
if __name__ == "__main__":
|
||||||
# Check grammar
|
# Check grammar
|
||||||
p = Python13Parser()
|
p = Python13Parser()
|
||||||
p.check_grammar()
|
p.check_grammar()
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
# Copyright (c) 2016-2018, 2020, 2022 Rocky Bernstein
|
# Copyright (c) 2016-2018, 2020, 2022-2023 Rocky Bernstein
|
||||||
"""
|
"""
|
||||||
spark grammar differences over Python2.5 for Python 2.4.
|
spark grammar differences over Python2.5 for Python 2.4.
|
||||||
"""
|
"""
|
||||||
@@ -115,8 +115,8 @@ class Python24Parser(Python25Parser):
|
|||||||
|
|
||||||
lhs = rule[0]
|
lhs = rule[0]
|
||||||
if lhs == "nop_stmt":
|
if lhs == "nop_stmt":
|
||||||
l = len(tokens)
|
token_len = len(tokens)
|
||||||
if 0 <= l < len(tokens):
|
if 0 <= token_len < len(tokens):
|
||||||
return not int(tokens[first].pattr) == tokens[last].offset
|
return not int(tokens[first].pattr) == tokens[last].offset
|
||||||
elif lhs == "try_except":
|
elif lhs == "try_except":
|
||||||
if last == len(tokens):
|
if last == len(tokens):
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
# Copyright (c) 2015-2019, 2021-2022 by Rocky Bernstein
|
# Copyright (c) 2015-2019, 2021-2023 by Rocky Bernstein
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -1169,11 +1169,14 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
|||||||
self.p.insts = self.scanner.insts
|
self.p.insts = self.scanner.insts
|
||||||
self.p.offset2inst_index = self.scanner.offset2inst_index
|
self.p.offset2inst_index = self.scanner.offset2inst_index
|
||||||
ast = python_parser.parse(self.p, tokens, customize, code)
|
ast = python_parser.parse(self.p, tokens, customize, code)
|
||||||
|
self.customize(customize)
|
||||||
self.p.insts = p_insts
|
self.p.insts = p_insts
|
||||||
|
|
||||||
except (python_parser.ParserError, AssertionError) as e:
|
except (python_parser.ParserError, AssertionError) as e:
|
||||||
raise ParserError(e, tokens)
|
raise ParserError(e, tokens)
|
||||||
|
transform_tree = self.treeTransform.transform(ast, code)
|
||||||
maybe_show_tree(self, ast)
|
maybe_show_tree(self, ast)
|
||||||
return ast
|
return transform_tree
|
||||||
|
|
||||||
# The bytecode for the end of the main routine has a
|
# The bytecode for the end of the main routine has a
|
||||||
# "return None". However you can't issue a "return" statement in
|
# "return None". However you can't issue a "return" statement in
|
||||||
@@ -1199,23 +1202,28 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
|||||||
if len(tokens) == 0:
|
if len(tokens) == 0:
|
||||||
return PASS
|
return PASS
|
||||||
|
|
||||||
# Build parse tree from tokenized and massaged disassembly.
|
# Build a parse tree from tokenized and massaged disassembly.
|
||||||
try:
|
try:
|
||||||
# FIXME: have p.insts update in a better way
|
# FIXME: have p.insts update in a better way
|
||||||
# modularity is broken here
|
# modularity is broken here
|
||||||
p_insts = self.p.insts
|
p_insts = self.p.insts
|
||||||
self.p.insts = self.scanner.insts
|
self.p.insts = self.scanner.insts
|
||||||
self.p.offset2inst_index = self.scanner.offset2inst_index
|
self.p.offset2inst_index = self.scanner.offset2inst_index
|
||||||
|
self.p.opc = self.scanner.opc
|
||||||
ast = parser.parse(self.p, tokens, customize, code)
|
ast = parser.parse(self.p, tokens, customize, code)
|
||||||
self.p.insts = p_insts
|
self.p.insts = p_insts
|
||||||
except (parser.ParserError, AssertionError) as e:
|
except (python_parser.ParserError, AssertionError) as e:
|
||||||
raise ParserError(e, tokens, {})
|
raise ParserError(e, tokens, {})
|
||||||
|
|
||||||
maybe_show_tree(self, ast)
|
|
||||||
|
|
||||||
checker(ast, False, self.ast_errors)
|
checker(ast, False, self.ast_errors)
|
||||||
|
|
||||||
return ast
|
self.customize(customize)
|
||||||
|
transform_tree = self.treeTransform.transform(ast, code)
|
||||||
|
|
||||||
|
maybe_show_tree(self, ast)
|
||||||
|
|
||||||
|
del ast # Save memory
|
||||||
|
return transform_tree
|
||||||
|
|
||||||
# FIXME: we could provide another customized routine
|
# FIXME: we could provide another customized routine
|
||||||
# that fixes up parents along a particular path to a node that
|
# that fixes up parents along a particular path to a node that
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
# Copyright (c) 2022 by Rocky Bernstein
|
# Copyright (c) 2022-2023 by Rocky Bernstein
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -159,7 +159,7 @@ class NonterminalActions:
|
|||||||
# * class_name - the name of the class
|
# * class_name - the name of the class
|
||||||
# * subclass_info - the parameters to the class e.g.
|
# * subclass_info - the parameters to the class e.g.
|
||||||
# class Foo(bar, baz)
|
# class Foo(bar, baz)
|
||||||
# -----------
|
# ------------
|
||||||
# * subclass_code - the code for the subclass body
|
# * subclass_code - the code for the subclass body
|
||||||
|
|
||||||
if node == "classdefdeco2":
|
if node == "classdefdeco2":
|
||||||
@@ -181,7 +181,7 @@ class NonterminalActions:
|
|||||||
subclass_code = build_class[-3][1].attr
|
subclass_code = build_class[-3][1].attr
|
||||||
class_name = node[0][0].pattr
|
class_name = node[0][0].pattr
|
||||||
else:
|
else:
|
||||||
raise "Internal Error n_classdef: cannot find class name"
|
raise RuntimeError("Internal Error n_classdef: cannot find class name")
|
||||||
|
|
||||||
if node == "classdefdeco2":
|
if node == "classdefdeco2":
|
||||||
self.write("\n")
|
self.write("\n")
|
||||||
@@ -228,7 +228,8 @@ class NonterminalActions:
|
|||||||
else:
|
else:
|
||||||
# from trepan.api import debug; debug()
|
# from trepan.api import debug; debug()
|
||||||
raise TypeError(
|
raise TypeError(
|
||||||
"Internal Error: n_const_list expects dict, list set, or set; got %s" % lastnodetype
|
("Internal Error: n_const_list expects dict, list set, or set; got %s"
|
||||||
|
% lastnodetype)
|
||||||
)
|
)
|
||||||
|
|
||||||
self.indent_more(INDENT_PER_LEVEL)
|
self.indent_more(INDENT_PER_LEVEL)
|
||||||
@@ -267,7 +268,10 @@ class NonterminalActions:
|
|||||||
if elem == "add_value":
|
if elem == "add_value":
|
||||||
elem = elem[0]
|
elem = elem[0]
|
||||||
if elem == "ADD_VALUE":
|
if elem == "ADD_VALUE":
|
||||||
value = "%r" % elem.pattr
|
if self.version < (3, 0, 0):
|
||||||
|
value = "%r" % elem.pattr
|
||||||
|
else:
|
||||||
|
value = "%s" % elem.pattr
|
||||||
else:
|
else:
|
||||||
assert elem.kind == "ADD_VALUE_VAR"
|
assert elem.kind == "ADD_VALUE_VAR"
|
||||||
value = "%s" % elem.pattr
|
value = "%s" % elem.pattr
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
# Copyright (C) 2018, 2020 Rocky Bernstein <rocky@gnu.org>
|
# Copyright (C) 2018, 2020, 2023 Rocky Bernstein <rocky@gnu.org>
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# (C) Copyright 2015-2018, 2020-2021 by Rocky Bernstein
|
# (C) Copyright 2015-2018, 2020-2021, 2023 by Rocky Bernstein
|
||||||
# (C) Copyright 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
|
# (C) Copyright 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
@@ -411,7 +411,7 @@ def cmp_code_objects(version, is_pypy, code_obj1, code_obj2, verify, name=""):
|
|||||||
check_jumps[dest1].append((i1, i2, dest2))
|
check_jumps[dest1].append((i1, i2, dest2))
|
||||||
else:
|
else:
|
||||||
check_jumps[dest1] = [(i1, i2, dest2)]
|
check_jumps[dest1] = [(i1, i2, dest2)]
|
||||||
except:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
i1 += 1
|
i1 += 1
|
||||||
|
Reference in New Issue
Block a user