From 0d32ec028ce41ac1e3da5fe7787f45644dfeba97 Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 24 Jan 2018 04:23:14 -0500 Subject: [PATCH] Add deparse_code_with_fragments_and_map and simplify --- pytest/test_disasm.py | 18 ++++++----------- uncompyle6/disas.py | 15 +++++---------- uncompyle6/semantics/fragments.py | 5 +++-- uncompyle6/semantics/linemap.py | 32 +++++++++++++++++++++++++++---- 4 files changed, 42 insertions(+), 28 deletions(-) diff --git a/pytest/test_disasm.py b/pytest/test_disasm.py index e6b810c1..97ed847c 100644 --- a/pytest/test_disasm.py +++ b/pytest/test_disasm.py @@ -11,20 +11,14 @@ src_dir = get_srcdir() os.chdir(src_dir) -@pytest.mark.parametrize(("test_tuple", "function_to_test"), [ - ( - ('../test/bytecode_2.7/05_if.pyc', 'testdata/if-2.7.right',), - disassemble_file - ), - ( - ('../test/bytecode_2.7/05_ifelse.pyc', 'testdata/ifelse-2.7.right',), - disassemble_file - ), +@pytest.mark.parametrize(("test_tuple"), [ + ('../test/bytecode_2.7/05_if.pyc', 'testdata/if-2.7.right',), + ('../test/bytecode_2.7/05_ifelse.pyc', 'testdata/ifelse-2.7.right',), ]) -def test_funcoutput(capfd, test_tuple, function_to_test): +def test_funcoutput(capfd, test_tuple): - in_file , filename_expected = test_tuple - function_to_test(in_file, native=False) + in_file, filename_expected = test_tuple + disassemble_file(in_file) resout, reserr = capfd.readouterr() expected = open(filename_expected, "r").read() if resout != expected: diff --git a/uncompyle6/disas.py b/uncompyle6/disas.py index 8989c4be..15db5de4 100644 --- a/uncompyle6/disas.py +++ b/uncompyle6/disas.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015-2016 by Rocky Bernstein +# Copyright (c) 2015-2016, 2818 by Rocky Bernstein # Copyright (c) 2005 by Dan Pascu # Copyright (c) 2000-2002 by hartmut Goebel # Copyright (c) 1999 John Aycock @@ -13,7 +13,7 @@ that is doing the extraction. Second, we need structured instruction information for the (de)-parsing step. Python 3.4 and up provides this, but we still do -want to run on Python 2.7. +want to run on earlier Python versions. """ from __future__ import print_function @@ -23,7 +23,6 @@ from collections import deque import uncompyle6 -from xdis.main import disassemble_file as xdisassemble_file from xdis.code import iscode from xdis.load import check_object_path, load_module from uncompyle6.scanner import get_scanner @@ -65,17 +64,13 @@ def disco_loop(disasm, queue, real_out): pass pass -def disassemble_file(filename, outstream=None, native=False): +def disassemble_file(filename, outstream=None): """ disassemble Python byte-code file (.pyc) If given a Python source file (".py") file, we'll try to find the corresponding compiled object. """ - if native: - xdisassemble_file(filename, outstream) - return - filename = check_object_path(filename) (version, timestamp, magic_int, co, is_pypy, source_size) = load_module(filename) @@ -90,14 +85,14 @@ def _test(): """Simple test program to disassemble a file.""" argc = len(sys.argv) if argc != 2: - if argc == 1 and uncompyle6.PYTHON3: + if argc == 1: fn = __file__ else: sys.stderr.write("usage: %s [-|CPython compiled file]\n" % __file__) sys.exit(2) else: fn = sys.argv[1] - disassemble_file(fn, native=True) + disassemble_file(fn) if __name__ == "__main__": _test() diff --git a/uncompyle6/semantics/fragments.py b/uncompyle6/semantics/fragments.py index a77a6c81..da1d4052 100644 --- a/uncompyle6/semantics/fragments.py +++ b/uncompyle6/semantics/fragments.py @@ -1643,7 +1643,7 @@ class FragmentsWalker(pysource.SourceWalker, object): pass def deparse_code(version, co, out=StringIO(), showasm=False, showast=False, - showgrammar=False, is_pypy=False): + showgrammar=False, is_pypy=False, walker=FragmentsWalker): """ Convert the code object co into a python source fragment. @@ -1683,7 +1683,8 @@ def deparse_code(version, co, out=StringIO(), showasm=False, showast=False, # Build AST from disassembly. # deparsed = pysource.FragmentsWalker(out, scanner, showast=showast) - deparsed = FragmentsWalker(version, scanner, showast=showast, debug_parser=debug_parser) + deparsed = walker(version, scanner, showast=showast, + debug_parser=debug_parser) deparsed.ast = deparsed.build_ast(tokens, customize) diff --git a/uncompyle6/semantics/linemap.py b/uncompyle6/semantics/linemap.py index 80a6e779..f8f28842 100644 --- a/uncompyle6/semantics/linemap.py +++ b/uncompyle6/semantics/linemap.py @@ -1,10 +1,9 @@ +# Copyright (c) 2018 by Rocky Bernstein from uncompyle6.semantics.pysource import SourceWalker, deparse_code +import uncompyle6.semantics.fragments as fragments # FIXME: does this handle nested code, and lambda properly class LineMapWalker(SourceWalker): - def __init__(self, *args, **kwargs): - if 'first_line' not in kwargs: - first_line = 0 def __init__(self, *args, **kwargs): super(LineMapWalker, self).__init__(*args, **kwargs) self.source_linemap = {} @@ -28,6 +27,12 @@ class LineMapWalker(SourceWalker): self.source_linemap[self.current_line_number] = node.linestart return super(LineMapWalker, self).default(node) +class LineMapFragmentWalker(fragments.FragmentsWalker, LineMapWalker): + def __init__(self, *args, **kwargs): + super(LineMapFragmentWalker, self).__init__(*args, **kwargs) + self.source_linemap = {} + self.current_line_number = 0 + def deparse_code_with_map(*args, **kwargs): """ Like deparse_code but saves line number correspondences. @@ -35,13 +40,21 @@ def deparse_code_with_map(*args, **kwargs): kwargs['walker'] = LineMapWalker return deparse_code(*args, **kwargs) +def deparse_code_with_fragments_and_map(*args, **kwargs): + """ + Like deparse_code_with_map but saves fragments. + """ + kwargs['walker'] = LineMapFragmentWalker + return fragments.deparse_code(*args, **kwargs) + if __name__ == '__main__': def deparse_test(co): "This is a docstring" import sys sys_version = float(sys.version[0:3]) # deparsed = deparse_code(sys_version, co, showasm=True, showast=True) - deparsed = deparse_code_with_map(sys_version, co, showasm=False, showast=False, + deparsed = deparse_code_with_map(sys_version, co, showasm=False, + showast=False, showgrammar=False) a = 1; b = 2 print("\n") @@ -49,5 +62,16 @@ if __name__ == '__main__': for line_no in sorted(deparsed.source_linemap.keys())] print(linemap) + deparsed = deparse_code_with_fragments_and_map(sys_version, + co, showasm=False, + showast=False, + showgrammar=False) + a = 1; b = 2 + print("\n") + linemap2 = [(line_no, deparsed.source_linemap[line_no]) + for line_no in + sorted(deparsed.source_linemap.keys())] + print(linemap2) + assert linemap == linemap2 return deparse_test(deparse_test.__code__)