diff --git a/uncompyle6/bin/uncompile.py b/uncompyle6/bin/uncompile.py index a44bf76a..3980ffbd 100755 --- a/uncompyle6/bin/uncompile.py +++ b/uncompyle6/bin/uncompile.py @@ -46,6 +46,7 @@ Debugging Options: --asm -a include byte-code (disables --verify) --grammar -g show matching grammar --tree -t include syntax tree (disables --verify) + --tree++ add template rules to --tree when possible Extensions of generated files: '.pyc_dis' '.pyo_dis' successfully decompiled (and verified if --verify) @@ -61,7 +62,7 @@ from uncompyle6.version import VERSION def usage(): print("""usage: - %s [--verify | --weak-verify ] [--asm] [--tree] [--grammar] [-o ] FILE|DIR... + %s [--verify | --weak-verify ] [--asm] [--tree[+]] [--grammar] [-o ] FILE|DIR... %s [--help | -h | --version | -V] """ % (program, program)) sys.exit(1) @@ -87,8 +88,10 @@ def main_bin(): try: opts, files = getopt.getopt(sys.argv[1:], 'hagtdrVo:c:p:', - 'help asm grammar linemaps recurse timestamp tree ' - 'fragments verify verify-run version weak-verify ' + 'help asm grammar linemaps recurse ' + 'timestamp tree tree+ ' + '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) @@ -118,6 +121,9 @@ def main_bin(): elif opt in ('--tree', '-t'): options['showast'] = True options['do_verify'] = None + elif opt in ('--tree+',): + options['showast'] = 'Full' + options['do_verify'] = None elif opt in ('--grammar', '-g'): options['showgrammar'] = True elif opt == '-o': diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index e3a06470..d6d68d02 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -251,6 +251,55 @@ class SourceWalker(GenericASTTraversal, object): return + def str_with_template(self, ast): + stream = sys.stdout + stream.write(self.str_with_template1(ast, '', None)) + stream.write('\n') + + def str_with_template1(self, ast, indent, sibNum=None): + rv = str(ast.kind) + + if sibNum is not None: + rv = "%2d. %s" % (sibNum, rv) + enumerate_children = False + if len(ast) > 1: + rv += " (%d)" % (len(ast)) + enumerate_children = True + + mapping = self._get_mapping(ast) + table = mapping[0] + key = ast + for i in mapping[1:]: + key = key[i] + pass + + if key.kind in table: + rv += ": %s" % str(table[key.kind]) + + rv = indent + rv + indent += ' ' + i = 0 + for node in ast: + if hasattr(node, '__repr1__'): + if enumerate_children: + child = self.str_with_template1(node, indent, i) + else: + child = self.str_with_template1(node, indent, None) + else: + inst = node.format(line_prefix='L.') + if inst.startswith("\n"): + # Nuke leading \n + inst = inst[1:] + if enumerate_children: + child = indent + "%2d. %s" % (i, inst) + else: + child = indent + inst + pass + rv += "\n" + child + i += 1 + return rv + + def indent_if_source_nl(self, line_number, indent): if (line_number != self.line_number): self.write("\n" + self.indent + INDENT_PER_LEVEL[:-1]) @@ -2081,7 +2130,7 @@ class SourceWalker(GenericASTTraversal, object): self.p.insts = p_insts except (python_parser.ParserError, AssertionError) as e: raise ParserError(e, tokens) - maybe_show_tree(self.showast, ast) + maybe_show_tree(self, ast) return ast # The bytecode for the end of the main routine has a @@ -2114,7 +2163,8 @@ class SourceWalker(GenericASTTraversal, object): except (python_parser.ParserError, AssertionError) as e: raise ParserError(e, tokens) - maybe_show_tree(self.showast, ast) + # from trepan.api import debug; debug() + maybe_show_tree(self, ast) checker(ast, False, self.ast_errors) diff --git a/uncompyle6/show.py b/uncompyle6/show.py index 76675866..308c81a2 100644 --- a/uncompyle6/show.py +++ b/uncompyle6/show.py @@ -32,7 +32,7 @@ def maybe_show_asm(showasm, tokens): stream.write('\n') -def maybe_show_tree(show_tree, ast): +def maybe_show_tree(walker, ast): """ Show the ast based on the showast flag (or file object), writing to the appropriate stream depending on the type of the flag. @@ -42,9 +42,15 @@ def maybe_show_tree(show_tree, ast): like object, into which the ast will be written). :param ast: The ast to show. """ - if show_tree: - stream = show_tree if hasattr(show_tree, 'write') else sys.stdout - stream.write(str(ast)) + if walker.showast: + if hasattr(walker.showast, 'write'): + stream = walker.showast + else: + stream = sys.stdout + if walker.showast == 'Full': + walker.str_with_template(ast) + else: + stream.write(str(ast)) stream.write('\n')