Merge branch 'master' into python-2.4

This commit is contained in:
rocky
2018-02-22 19:15:24 -05:00
10 changed files with 74 additions and 55 deletions

View File

@@ -1,7 +1,7 @@
"""
Copyright (c) 1999 John Aycock
Copyright (c) 2015, 2018 by Rocky Bernstein
Copyright (c) 2000 by hartmut Goebel <h.goebel@crazy-compilers.com>
Copyright (c) 2015 by Rocky Bernstein
Copyright (c) 1999 John Aycock
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@@ -55,6 +55,7 @@ from uncompyle6.main import decompile_file
uncompyle_file = decompile_file
# Conventience functions so you can say:
# from uncompyle6 import deparse_code
# from uncompyle6 import (deparse_code, deparse_code2str)
deparse_code = uncompyle6.semantics.pysource.deparse_code
deparse_code2str = uncompyle6.semantics.pysource.deparse_code2str

View File

@@ -136,7 +136,7 @@ class Python3Parser(PythonParser):
iflaststmtl ::= testexpr c_stmts_opt JUMP_BACK COME_FROM_LOOP
iflaststmtl ::= testexpr c_stmts_opt JUMP_BACK POP_BLOCK
# These are used to keep AST indices the same
# These are used to keep parse tree indices the same
jump_forward_else ::= JUMP_FORWARD ELSE
jump_absolute_else ::= JUMP_ABSOLUTE ELSE

View File

@@ -100,7 +100,7 @@ def align_deparse_code(version, co, out=sys.stderr, showasm=False, showast=False
debug_parser['reduce'] = showgrammar
debug_parser['errorstack'] = True
# Build AST from disassembly.
# Build a parse tree from tokenized and massaged disassembly.
deparsed = AligningWalker(version, scanner, out, showast=showast,
debug_parser=debug_parser, compile_mode=compile_mode,
is_pypy = is_pypy)
@@ -125,7 +125,7 @@ def align_deparse_code(version, co, out=sys.stderr, showasm=False, showast=False
except:
pass
# What we've been waiting for: Generate source from AST!
# What we've been waiting for: Generate Python source from the parse tree!
deparsed.gen_source(deparsed.ast, co.co_name, customize)
for g in deparsed.mod_globs:

View File

@@ -1,5 +1,5 @@
"""
Python AST grammar checker.
Python parse tree checker.
Our rules sometimes give erroneous results. Until we have perfect rules,
This checker will catch mistakes in decompilation we've made.

View File

@@ -1,4 +1,4 @@
# Copyright (c) 2017 by Rocky Bernstein
# Copyright (c) 2017, 2018 by Rocky Bernstein
"""Constants and initial table values used in pysource.py and fragments.py"""
import re, sys
@@ -16,8 +16,8 @@ else:
LINE_LENGTH = 80
# Some ASTs used for comparing code fragments (like 'return None' at
# the end of functions).
# Some parse trees created below are used for comparing code
# fragments (like 'return None' at the end of functions).
RETURN_LOCALS = AST('return',
[ AST('ret_expr', [AST('expr', [ Token('LOAD_LOCALS') ])]),

View File

@@ -1,7 +1,7 @@
# Copyright (c) 2015-2018 by Rocky Bernstein
"""
Creates Python source code from an uncompyle6 abstract syntax tree,
Creates Python source code from an uncompyle6 parse tree,
and indexes fragments which can be accessed by instruction offset
address.
@@ -61,7 +61,7 @@ from uncompyle6.semantics.check_ast import checker
from uncompyle6.show import (
maybe_show_asm,
maybe_show_ast,
maybe_show_tree,
)
from uncompyle6.parsers.astnode import AST
@@ -1062,7 +1062,7 @@ class FragmentsWalker(pysource.SourceWalker, object):
n_classdefdeco2 = n_classdef
def gen_source(self, ast, name, customize, is_lambda=False, returnNone=False):
"""convert AST to Python source code"""
"""convert parse tree to Python source code"""
rn = self.return_none
self.return_none = returnNone
@@ -1100,7 +1100,7 @@ class FragmentsWalker(pysource.SourceWalker, object):
self.p.insts = p_insts
except (parser.ParserError(e), AssertionError(e)):
raise ParserError(e, tokens)
maybe_show_ast(self.showast, ast)
maybe_show_tree(self.showast, ast)
return ast
# The bytecode for the end of the main routine has a
@@ -1128,7 +1128,7 @@ class FragmentsWalker(pysource.SourceWalker, object):
if len(tokens) == 0:
return PASS
# Build AST from disassembly.
# Build parse tree from tokenized and massaged disassembly.
try:
# FIXME: have p.insts update in a better way
# modularity is broken here
@@ -1139,7 +1139,7 @@ class FragmentsWalker(pysource.SourceWalker, object):
except (parser.ParserError(e), AssertionError(e)):
raise ParserError(e, tokens)
maybe_show_ast(self.showast, ast)
maybe_show_tree(self.showast, ast)
checker(ast, False, self.ast_errors)
@@ -1731,12 +1731,12 @@ def deparse_code(version, co, out=StringIO(), showasm=False, showast=False,
pass a file like object, into which the asm will be
written).
:param showast: Flag which determines whether the constructed
abstract syntax tree is written to sys.stdout or
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
: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 grammer
pass a file like object, into which the grammar
will be written).
:return: The deparsed source fragment.
@@ -1757,7 +1757,7 @@ def deparse_code(version, co, out=StringIO(), showasm=False, showast=False,
debug_parser['reduce'] = showgrammar
debug_parser['errorstack'] = True
# Build AST from disassembly.
# Build Syntax Tree from tokenized and massaged disassembly.
# deparsed = pysource.FragmentsWalker(out, scanner, showast=showast)
deparsed = walker(version, scanner, showast=showast,
debug_parser=debug_parser, compile_mode=compile_mode,

View File

@@ -16,7 +16,7 @@ read_global_ops = frozenset(('STORE_GLOBAL', 'DELETE_GLOBAL'))
# FIXME: this and find_globals could be paramaterized with one of the
# above global ops
def find_all_globals(node, globs):
"""Search AST node to find variable names that are global."""
"""Search Syntax Tree node to find variable names that are global."""
for n in node:
if isinstance(n, AST):
globs = find_all_globals(n, globs)
@@ -25,7 +25,8 @@ def find_all_globals(node, globs):
return globs
def find_globals(node, globs):
"""search AST node to find variable names that need a 'global' added."""
"""search a node of parse tree to find variable names that need a
'global' added."""
for n in node:
if isinstance(n, AST):
globs = find_globals(n, globs)

View File

@@ -12,7 +12,7 @@ from uncompyle6.semantics.helper import (
)
from uncompyle6.show import maybe_show_ast_param_default
from uncompyle6.show import maybe_show_tree_param_default
# FIXME: DRY the below code...
@@ -29,7 +29,7 @@ def make_function3_annotate(self, node, is_lambda, nested=1,
"""
if default:
value = self.traverse(default, indent='')
maybe_show_ast_param_default(self.showast, name, value)
maybe_show_tree_param_default(self.showast, name, value)
result = '%s=%s' % (name, value)
if result[-2:] == '= ': # default was 'LOAD_CONST None'
result += 'None'
@@ -284,7 +284,7 @@ def make_function2(self, node, is_lambda, nested=1, codeNode=None):
if default:
value = self.traverse(default, indent='')
maybe_show_ast_param_default(self.showast, name, value)
maybe_show_tree_param_default(self.showast, name, value)
result = '%s=%s' % (name, value)
if result[-2:] == '= ': # default was 'LOAD_CONST None'
result += 'None'
@@ -456,7 +456,7 @@ def make_function3(self, node, is_lambda, nested=1, codeNode=None):
value = default
else:
value = self.traverse(default, indent='')
maybe_show_ast_param_default(self.showast, name, value)
maybe_show_tree_param_default(self.showast, name, value)
result = '%s=%s' % (name, value)
if result[-2:] == '= ': # default was 'LOAD_CONST None'
result += 'None'

View File

@@ -3,7 +3,7 @@
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
# Copyright (c) 1999 John Aycock
"""Creates Python source code from an uncompyle6 abstract syntax tree.
"""Creates Python source code from an uncompyle6 parse tree.
The terminal symbols are CPython bytecode instructions. (See the
python documentation under module "dis" for a list of instructions
@@ -47,7 +47,7 @@ Python.
# In the diagram below, N is a nonterminal name, and K also a nonterminal
# name but the one used as a key in the table.
# we show where those are with respect to each other in the
# AST tree for N.
# parse tree for N.
#
#
# N&K N N
@@ -139,7 +139,7 @@ from uncompyle6.semantics.consts import (
from uncompyle6.show import (
maybe_show_ast,
maybe_show_tree,
)
if PYTHON3:
@@ -2567,7 +2567,7 @@ class SourceWalker(GenericASTTraversal, object):
raise ParserError(e, tokens)
except AssertionError, e:
raise ParserError(e, tokens)
maybe_show_ast(self.showast, ast)
maybe_show_tree(self.showast, ast)
return ast
# The bytecode for the end of the main routine has a
@@ -2589,7 +2589,7 @@ class SourceWalker(GenericASTTraversal, object):
if len(tokens) == 0:
return PASS
# Build AST from disassembly.
# Build a parse tree from a tokenized and massaged disassembly.
try:
# FIXME: have p.insts update in a better way
# modularity is broken here
@@ -2600,7 +2600,7 @@ class SourceWalker(GenericASTTraversal, object):
except python_parser.ParserError, e:
raise ParserError(e, tokens)
maybe_show_ast(self.showast, ast)
maybe_show_tree(self.showast, ast)
checker(ast, False, self.ast_errors)
@@ -2635,7 +2635,7 @@ def deparse_code(version, co, out=sys.stdout, showasm=None, showast=False,
debug_parser['reduce'] = showgrammar
debug_parser['errorstack'] = 'full'
# Build AST from disassembly.
# Build Syntax Tree from disassembly.
linestarts = dict(scanner.opc.findlinestarts(co))
deparsed = walker(version, out, scanner, showast=showast,
debug_parser=debug_parser, compile_mode=compile_mode,
@@ -2669,7 +2669,7 @@ def deparse_code(version, co, out=sys.stdout, showasm=None, showast=False,
deparsed.FUTURE_UNICODE_LITERALS = (
COMPILER_FLAG_BIT['FUTURE_UNICODE_LITERALS'] & co.co_flags != 0)
# What we've been waiting for: Generate source from AST!
# What we've been waiting for: Generate source from Syntax Tree!
deparsed.gen_source(deparsed.ast, co.co_name, customize)
for g in deparsed.mod_globs:
@@ -2686,13 +2686,30 @@ def deparse_code(version, co, out=sys.stdout, showasm=None, showast=False,
raise SourceWalkerError("Deparsing stopped due to parse error")
return deparsed
#
DEFAULT_DEBUG_OPTS = {
'asm': False,
'tree': False,
'grammar': False
}
def deparse_code2str(code, out=sys.stdout, version=None,
debug_opts=DEFAULT_DEBUG_OPTS,
code_objects={}, compile_mode='exec',
is_pypy=False, walker=SourceWalker):
"""Return the deparsed text for a Python code object. `out` is where any intermediate
output for assembly or tree output will be sent.
"""
return deparse_code(version, code, out, showasm=debug_opts.get('asm', None),
showast=debug_opts.get('tree', None),
showgrammar=debug_opts.get('grammar', None), code_objects=code_objects,
compile_mode=compile_mode, is_pypy=is_pypy, walker=walker).text
if __name__ == '__main__':
def deparse_test(co):
"This is a docstring"
sys_version = float(sys.version[0:3])
deparsed = deparse_code(sys_version, co, showasm='after', showast=True)
# deparsed = deparse_code(sys_version, co, showasm=None, showast=False,
# showgrammar=True)
print(deparsed.text)
s = deparse_code2str(co, debug_opts={'asm':'after', 'tree':True})
# s = deparse_code2str(co, showasm=None, showast=False,
# showgrammar=True)
print(s)
return
deparse_test(deparse_test.func_code)

View File

@@ -21,41 +21,41 @@ def maybe_show_asm(showasm, tokens):
stream.write('\n')
def maybe_show_ast(showast, ast):
def maybe_show_tree(show_tree, ast):
"""
Show the ast based on the showast flag (or file object), writing to the
appropriate stream depending on the type of the flag.
:param showasm: Flag which determines whether the abstract syntax 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 show_tree: Flag which determines whether the 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 ast: The ast to show.
"""
if showast:
if hasattr(showast, 'write'):
stream = showast
if show_tree:
if hasattr(show_tree, 'write'):
stream = show_tree
else:
stream = sys.stdout
stream.write(str(ast))
stream.write('\n')
def maybe_show_ast_param_default(showast, name, default):
def maybe_show_tree_param_default(show_tree, name, default):
"""
Show a function parameter with default for an ast based on the showast flag
Show a function parameter with default for an grammar-tree based on the show_tree flag
(or file object), writing to the appropriate stream depending on the type
of the flag.
:param showasm: Flag which determines whether the function parameter with
default is written to sys.stdout or not. (It is also to
pass a file like object, into which the ast will be
written).
:param show_tree: Flag which determines whether the function parameter with
default is written to sys.stdout or not. (It is also to
pass a file like object, into which the ast will be
written).
:param name: The function parameter name.
:param default: The function parameter default.
"""
if showast:
if hasattr(showast, 'write'):
stream = showast
if show_tree:
if hasattr(show_tree, 'write'):
stream = show_tree
else:
stream = sys.stdout
stream.write('\n')