From b6d96929cb05245d98e2cbd8a3d75a345a33fc78 Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 27 Feb 2018 17:48:26 -0500 Subject: [PATCH] Start simplifying higher-level API --- HISTORY.md | 2 +- uncompyle6/main.py | 22 ++++++---- uncompyle6/semantics/fragments.py | 71 ++++++++++++++++++++----------- 3 files changed, 61 insertions(+), 34 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index 654a22d7..280d46f0 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,4 +1,4 @@ -This project has history of over 17 years spanning back to Python 1.5 +This project has history of over 18 years spanning back to Python 1.5 There have been a number of people who have worked on this. I am awed by the amount of work, number of people who have contributed to this, diff --git a/uncompyle6/main.py b/uncompyle6/main.py index 234deecb..a6602de1 100644 --- a/uncompyle6/main.py +++ b/uncompyle6/main.py @@ -23,8 +23,8 @@ from uncompyle6.parser import ParserError from uncompyle6.version import VERSION # 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.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 @@ -43,7 +43,7 @@ def _get_outstream(outfile): 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, + source_size=None, is_pypy=None, magic_int=None, mapstream=None, do_fragments=False): """ ingests and deparses a given code block 'co' @@ -74,6 +74,12 @@ def decompile( if source_size: write('# Size of source mod 2**32: %d bytes' % source_size) + debug_opts = { + 'asm': showasm, + 'ast': showast, + 'grammar': showgrammar + } + try: if mapstream: if isinstance(mapstream, str): @@ -91,12 +97,12 @@ def decompile( mapstream.write("\n\n# %s\n" % linemap) else: if do_fragments: - deparse_fn = deparse_code_fragments + deparse_fn = code_deparse_fragments else: - deparse_fn = deparse_code - deparsed = deparse_fn(bytecode_version, co, out, showasm, showast, - showgrammar, code_objects=code_objects, - is_pypy=is_pypy) + deparse_fn = code_deparse + deparsed = deparse_fn(co, out, bytecode_version, + debug_opts = debug_opts, + is_pypy=is_pypy) pass return deparsed except pysource.SourceWalkerError as e: diff --git a/uncompyle6/semantics/fragments.py b/uncompyle6/semantics/fragments.py index 011c5fd9..205ea0bc 100644 --- a/uncompyle6/semantics/fragments.py +++ b/uncompyle6/semantics/fragments.py @@ -73,6 +73,7 @@ from uncompyle6 import parser from uncompyle6.scanner import Token, Code, get_scanner import uncompyle6.parser as python_parser from uncompyle6.semantics.check_ast import checker +from uncompyle6 import IS_PYPY from uncompyle6.show import ( maybe_show_asm, @@ -1717,9 +1718,29 @@ class FragmentsWalker(pysource.SourceWalker, object): pass +# +DEFAULT_DEBUG_OPTS = { + 'asm': False, + 'tree': False, + 'grammar': False +} + +# This interface is deprecated def deparse_code(version, co, out=StringIO(), showasm=False, showast=False, showgrammar=False, code_objects={}, compile_mode='exec', - is_pypy=False, walker=FragmentsWalker): + is_pypy=None, walker=FragmentsWalker): + debug_opts = { + 'asm': showasm, + 'ast': showast, + 'grammar': showgrammar + } + return code_deparse(co, out, version, debug_opts, code_objects, compile_mode, + is_pypy, walker) + +def code_deparse(co, out=StringIO(), version=None, is_pypy=None, + debug_opts=DEFAULT_DEBUG_OPTS, + code_objects={}, compile_mode='exec', + walker=FragmentsWalker): """ Convert the code object co into a python source fragment. @@ -1727,40 +1748,44 @@ def deparse_code(version, co, out=StringIO(), showasm=False, showast=False, example 2.6, 2.7, 3.2, 3.3, 3.4, 3.5 etc. :param co: The code object to parse. :param out: File like object to write the output to. - :param showasm: Flag which determines whether the ingestd code - is written to sys.stdout or not. (It is also to - pass a file like object, into which the asm will be - written). - :param showast: Flag which determines whether the constructed - parse tree is written to sys.stdout or - not. (It is also to pass a file like object, into - which the ast will be written). - :param showgrammar: Flag which determines whether the grammar reduction rules - is written to sys.stdout or not. (It is also to - pass a file like object, into which the grammar - will be written). + :param debug_opts: A dictionary with keys + 'asm': value determines whether to show + mangled bytecode disdassembly + 'ast': value determines whether to show + 'grammar': boolean determining whether to show + grammar reduction rules. + If value is a file-like object, output that object's write method will + be used rather than sys.stdout :return: The deparsed source fragment. """ assert iscode(co) - # store final output stream for case of error + + if version is None: + version = float(sys.version[0:3]) + if is_pypy is None: + is_pypy = IS_PYPY + scanner = get_scanner(version, is_pypy=is_pypy) + show_asm = debug_opts.get('asm', None) tokens, customize = scanner.ingest(co, code_objects=code_objects, - show_asm=showasm) + show_asm=show_asm) tokens, customize = scanner.ingest(co) - maybe_show_asm(showasm, tokens) + maybe_show_asm(show_asm, tokens) debug_parser = dict(PARSER_DEFAULT_DEBUG) - if showgrammar: - debug_parser['reduce'] = showgrammar + show_grammar = debug_opts.get('grammar', None) + if show_grammar: + debug_parser['reduce'] = show_grammar debug_parser['errorstack'] = True - # Build Syntax Tree from tokenized and massaged disassembly. + # Build Syntax Tree from tokenized and massaged disassembly. # deparsed = pysource.FragmentsWalker(out, scanner, showast=showast) - deparsed = walker(version, scanner, showast=showast, + show_ast = debug_opts.get('ast', None) + deparsed = walker(version, scanner, showast=show_ast, debug_parser=debug_parser, compile_mode=compile_mode, is_pypy=is_pypy) @@ -1870,12 +1895,8 @@ def deparsed_find(tup, deparsed, code): # if __name__ == '__main__': -# from uncompyle6 import IS_PYPY # def deparse_test(co, is_pypy=IS_PYPY): -# from xdis.magics import sysinfo2float -# float_version = sysinfo2float() -# deparsed = deparse_code(float_version, co, showasm=False, showast=False, -# showgrammar=False, is_pypy=IS_PYPY) +# deparsed = code_deparse(co, is_pypy=IS_PYPY) # print("deparsed source") # print(deparsed.text, "\n") # print('------------------------')