Add uncompyle6 option to show fragments

This commit is contained in:
rocky
2018-01-29 21:14:34 -05:00
parent 9d852b48aa
commit 0a12dfb422
4 changed files with 44 additions and 18 deletions

View File

@@ -95,10 +95,10 @@ x = []
------
6
y = {}
--
-
Contained in...
y = {}
------
--
9
y = {}
-

View File

@@ -34,6 +34,7 @@ Options:
-d print timestamps
-p <integer> use <integer> number of processes
-r recurse directories looking for .pyc and .pyo files
--fragments use fragments deparser
--verify compare generated source with input byte-code
--verify-run compile generated source, run it and check exit code
--weak-verify compile generated source
@@ -85,7 +86,7 @@ def main_bin():
try:
opts, files = getopt.getopt(sys.argv[1:], 'hagtdrVo:c:p:',
'help asm grammar linemaps recurse timestamp tree '
'verify verify-run version weak-verify '
'fragments verify verify-run version weak-verify '
'showgrammar'.split(' '))
except getopt.GetoptError as e:
print('%s: %s' % (os.path.basename(sys.argv[0]), e), file=sys.stderr)
@@ -103,6 +104,8 @@ def main_bin():
options['do_verify'] = 'strong'
elif opt == '--weak-verify':
options['do_verify'] = 'weak'
elif opt == '--fragments':
options['do_fragments'] = True
elif opt == '--verify-run':
options['do_verify'] = 'verify-run'
elif opt == '--linemaps':

View File

@@ -7,9 +7,10 @@ from uncompyle6.disas import check_object_path
from uncompyle6.semantics import pysource
from uncompyle6.parser import ParserError
from uncompyle6.version import VERSION
from uncompyle6.linenumbers import line_number_mapping
# from uncompyle6.linenumbers import line_number_mapping
from uncompyle6.semantics.pysource import deparse_code
from uncompyle6.semantics.fragments import deparse_code as deparse_code_fragments
from uncompyle6.semantics.linemap import deparse_code_with_map
from xdis.load import load_module
@@ -29,7 +30,7 @@ def decompile(
bytecode_version, co, out=None, showasm=None, showast=False,
timestamp=None, showgrammar=False, code_objects={},
source_size=None, is_pypy=False, magic_int=None,
mapstream=None):
mapstream=None, do_fragments=False):
"""
ingests and deparses a given code block 'co'
@@ -75,9 +76,13 @@ def decompile(
sorted(deparsed.source_linemap.keys())]
mapstream.write("\n\n# %s\n" % linemap)
else:
deparsed = deparse_code(bytecode_version, co, out, showasm, showast,
showgrammar, code_objects=code_objects,
is_pypy=is_pypy)
if do_fragments:
deparse_fn = deparse_code_fragments
else:
deparse_fn = deparse_code
deparsed = deparse_fn(bytecode_version, co, out, showasm, showast,
showgrammar, code_objects=code_objects,
is_pypy=is_pypy)
pass
return deparsed
except pysource.SourceWalkerError as e:
@@ -85,7 +90,7 @@ def decompile(
raise pysource.SourceWalkerError(str(e))
def decompile_file(filename, outstream=None, showasm=None, showast=False,
showgrammar=False, mapstream=None):
showgrammar=False, mapstream=None, do_fragments=False):
"""
decompile Python byte-code file (.pyc). Return objects to
all of the deparsed objects found in `filename`.
@@ -109,7 +114,7 @@ def decompile_file(filename, outstream=None, showasm=None, showast=False,
timestamp, showgrammar,
code_objects=code_objects, source_size=source_size,
is_pypy=is_pypy, magic_int=magic_int,
mapstream=mapstream)]
mapstream=mapstream, do_fragments=do_fragments)]
co = None
return deparsed
@@ -118,7 +123,7 @@ def decompile_file(filename, outstream=None, showasm=None, showast=False,
def main(in_base, out_base, files, codes, outfile=None,
showasm=None, showast=False, do_verify=False,
showgrammar=False, raise_on_error=False,
do_linemaps=False):
do_linemaps=False, do_fragments=False):
"""
in_base base directory for input files
out_base base directory for output files (ignored when
@@ -189,7 +194,24 @@ def main(in_base, out_base, files, codes, outfile=None,
# Try to uncompile the input file
try:
decompile_file(infile, outstream, showasm, showast, showgrammar, linemap_stream)
deparsed = decompile_file(infile, outstream, showasm, showast, showgrammar,
linemap_stream, do_fragments)
if do_fragments:
for d in deparsed:
last_mod = None
offsets = d.offsets
for e in sorted(offsets.keys()):
if e[0] != last_mod:
line = '=' * len(e[0])
outstream.write("%s\n%s\n%s\n" % (line, e[0], line))
last_mod = e[0]
info = offsets[e]
extractInfo = d.extract_node_info(info)
outstream.write("%s" % info.node.format().strip() + "\n")
outstream.write(extractInfo.selectedLine + "\n")
outstream.write(extractInfo.markerLine + "\n\n")
pass
pass
tot_files += 1
except (ValueError, SyntaxError, ParserError, pysource.SourceWalkerError) as e:
sys.stdout.write("\n")

View File

@@ -1287,6 +1287,7 @@ class FragmentsWalker(pysource.SourceWalker, object):
sep = INDENT_PER_LEVEL[:-1]
start = len(self.f.getvalue())
self.write('{')
self.set_pos_info(node[0], start, start+1)
if self.version > 3.0:
if node[0].kind.startswith('kvlist'):
@@ -1355,9 +1356,6 @@ class FragmentsWalker(pysource.SourceWalker, object):
sep = line_seperator
self.write('}')
finish = len(self.f.getvalue())
for n in node:
n.parent = node
self.set_pos_info(n, start, finish)
self.set_pos_info(node, start, finish)
self.indent_less(INDENT_PER_LEVEL)
self.prec = p
@@ -1610,7 +1608,8 @@ class FragmentsWalker(pysource.SourceWalker, object):
pass
def deparse_code(version, co, out=StringIO(), showasm=False, showast=False,
showgrammar=False, is_pypy=False, walker=FragmentsWalker):
showgrammar=False, code_objects={}, compile_mode='exec',
is_pypy=False, walker=FragmentsWalker):
"""
Convert the code object co into a python source fragment.
@@ -1638,7 +1637,8 @@ def deparse_code(version, co, out=StringIO(), showasm=False, showast=False,
# store final output stream for case of error
scanner = get_scanner(version, is_pypy=is_pypy)
tokens, customize = scanner.ingest(co)
tokens, customize = scanner.ingest(co, code_objects=code_objects,
show_asm=showasm)
tokens, customize = scanner.ingest(co)
maybe_show_asm(showasm, tokens)
@@ -1651,7 +1651,8 @@ def deparse_code(version, co, out=StringIO(), showasm=False, showast=False,
# Build AST from disassembly.
# deparsed = pysource.FragmentsWalker(out, scanner, showast=showast)
deparsed = walker(version, scanner, showast=showast,
debug_parser=debug_parser)
debug_parser=debug_parser, compile_mode=compile_mode,
is_pypy=is_pypy)
deparsed.ast = deparsed.build_ast(tokens, customize)