Add LICENSE. Add demo programs and DRY code a little

This commit is contained in:
rocky
2015-12-16 16:23:18 -05:00
parent 06653a6163
commit a362b47b15
5 changed files with 123 additions and 98 deletions

View File

@@ -1,12 +1,11 @@
# Copyright (c) 1999 John Aycock
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
# Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org>
# Copyright (c) 2015 by Rocky Bernstein
# See LICENSE for license
""" """
Deparsing saving text fragment information indexed by offset Deparsing saving text fragment information indexed by offset
Copyright (c) 1999 John Aycock
Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org>
Copyright (c) 2015 by Rocky Bernstein
See main module for license.
Decompilation (walking AST) Decompilation (walking AST)
@@ -55,6 +54,7 @@ from uncompyle6.walker import AST, NONE, find_all_globals
from uncompyle6.walker import find_globals, find_none, INDENT_PER_LEVEL from uncompyle6.walker import find_globals, find_none, INDENT_PER_LEVEL
from uncompyle6.walker import ParserError from uncompyle6.walker import ParserError
from uncompyle6 import parser from uncompyle6 import parser
from uncompyle6.scanner import Token, Code, get_scanner
try: try:
from StringIO import StringIO from StringIO import StringIO
@@ -70,13 +70,6 @@ from uncompyle6.spark import GenericASTTraversal
from uncompyle6.spark import GenericASTTraversalPruningException from uncompyle6.spark import GenericASTTraversalPruningException
from types import CodeType from types import CodeType
try:
from uncompyle6.Scanner import Token, Code
older_uncompyle = True
except ImportError:
from uncompyle6.scanner import Token, Code
older_uncompyle = False
from collections import namedtuple from collections import namedtuple
NodeInfo = namedtuple("NodeInfo", "node start finish") NodeInfo = namedtuple("NodeInfo", "node start finish")
ExtractInfo = namedtuple("ExtractInfo", ExtractInfo = namedtuple("ExtractInfo",
@@ -1118,27 +1111,7 @@ def deparse(version, co, out=StringIO(), showasm=0, showast=0):
assert inspect.iscode(co) assert inspect.iscode(co)
# store final output stream for case of error # store final output stream for case of error
__real_out = out or sys.stdout __real_out = out or sys.stdout
try: scanner = get_scanner(version)
import uncompyle6.Scanner as scan
scanner = scan.Scanner(version)
except ImportError:
if version == 2.5:
import uncompyle6.scanners.scanner25 as scan
scanner = scan.Scanner25()
elif version == 2.6:
import uncompyle6.scanners.scanner26 as scan
scanner = scan.Scanner26()
elif version == 2.7:
import uncompyle6.scanners.scanner27 as scan
scanner = scan.Scanner27()
elif version == 3.2:
import uncompyle6.scanners.scanner34 as scan
scanner = scan.Scanner32()
elif version == 3.4:
import uncompyle6.scanners.scanner34 as scan
scanner = scan.Scanner34()
scanner.setShowAsm(showasm, out)
tokens, customize = scanner.disassemble(co) tokens, customize = scanner.disassemble(co)
# Build AST from disassembly. # Build AST from disassembly.
@@ -1146,10 +1119,7 @@ def deparse(version, co, out=StringIO(), showasm=0, showast=0):
walk = Traverser(scanner, showast=showast) walk = Traverser(scanner, showast=showast)
try: try:
if older_uncompyle: walk.ast = walk.build_ast_d(tokens, customize)
walk.ast = walk.build_ast_d(tokens, customize)
else:
walk.ast = walk.build_ast_d(tokens, customize)
except walker.ParserError as e : # parser failed, dump disassembly except walker.ParserError as e : # parser failed, dump disassembly
print(e, file=__real_out) print(e, file=__real_out)
raise raise

View File

@@ -20,6 +20,7 @@ from __future__ import print_function
import importlib, inspect, os, sys import importlib, inspect, os, sys
import uncompyle6 import uncompyle6
from uncompyle6.scanner import get_scanner
def check_object_path(path): def check_object_path(path):
if path.endswith(".py"): if path.endswith(".py"):
@@ -44,23 +45,7 @@ def disco(version, co, out=None):
print('# Embedded file name: %s' % co.co_filename, print('# Embedded file name: %s' % co.co_filename,
file=real_out) file=real_out)
# Pick up appropriate scanner scanner = get_scanner(version)
if version == 2.7:
import uncompyle6.scanners.scanner27 as scan
scanner = scan.Scanner27()
elif version == 2.6:
import uncompyle6.scanners.scanner26 as scan
scanner = scan.Scanner26()
elif version == 2.5:
import uncompyle6.scanners.scanner25 as scan
scanner = scan.Scanner25()
elif version == 3.2:
import uncompyle6.scanners.scanner32 as scan
scanner = scan.Scanner32()
elif version == 3.4:
import uncompyle6.scanners.scanner34 as scan
scanner = scan.Scanner34()
scanner.setShowAsm(True, out)
tokens, customize = scanner.disassemble(co) tokens, customize = scanner.disassemble(co)
for t in tokens: for t in tokens:

View File

@@ -1,23 +1,16 @@
from __future__ import print_function # Copyright (c) 1999 John Aycock
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
# Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org>
# Copyright (c) 2015 Rocky Bernstein
"""
Spark parser for Python.
"""
''' from uncompyle6 import PYTHON3
Copyright (c) 1999 John Aycock from uncompyle6.spark import GenericASTBuilder
Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org>
See main module for license. import sys
''' if PYTHON3:
__all__ = ['parse', 'AST', 'ParserError', 'Parser']
try:
from spark import GenericASTBuilder
except ImportError:
from .spark import GenericASTBuilder
import string, sys
if (sys.version_info >= (3, 0)):
intern = sys.intern intern = sys.intern
from collections import UserList from collections import UserList
else: else:
@@ -794,3 +787,24 @@ def parse(tokens, customize):
ast = p.parse(tokens) ast = p.parse(tokens)
# p.cleanup() # p.cleanup()
return ast return ast
def parser(version, co, out=sys.stdout, showasm=False):
import inspect
assert inspect.iscode(co)
from uncompyle6.scanner import get_scanner
scanner = get_scanner(version)
tokens, customize = scanner.disassemble(co)
if showasm:
for t in tokens:
print(t)
return parse(tokens, customize)
if __name__ == '__main__':
def parse_test(co):
sys_version = sys.version_info.major + (sys.version_info.minor / 10.0)
ast = parser(sys_version, co, showasm=True)
print(ast)
return
parse_test(parse_test.__code__)

View File

@@ -2,10 +2,10 @@
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com> # Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
# Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org> # Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org>
# #
# See main module for license. # See LICENSE
# #
""" """
scanner/disassembler module. From here we call various verison-specific scanner/disassembler module. From here we call various version-specific
scanners, e.g. for Python 2.7 or 3.4. scanners, e.g. for Python 2.7 or 3.4.
This overlaps Python's dis module, but it can be run from Python 2 or This overlaps Python's dis module, but it can be run from Python 2 or
@@ -16,8 +16,6 @@ for later use in deparsing.
from __future__ import print_function from __future__ import print_function
__all__ = ['Token', 'Scanner', 'Code']
import sys import sys
from uncompyle6 import PYTHON3 from uncompyle6 import PYTHON3
@@ -328,10 +326,32 @@ class Scanner(object):
target = parent['end'] target = parent['end']
return target return target
def get_scanner(version):
# Pick up appropriate scanner
if version == 2.7:
import uncompyle6.scanners.scanner27 as scan
scanner = scan.Scanner27()
elif version == 2.6:
import uncompyle6.scanners.scanner26 as scan
scanner = scan.Scanner26()
elif version == 2.5:
import uncompyle6.scanners.scanner25 as scan
scanner = scan.Scanner25()
elif version == 3.2:
import uncompyle6.scanners.scanner32 as scan
scanner = scan.Scanner32()
elif version == 3.4:
import uncompyle6.scanners.scanner34 as scan
scanner = scan.Scanner34()
else:
raise RuntimeError("Unsupported Python version %d" % version)
return scanner
if __name__ == "__main__": if __name__ == "__main__":
import inspect, uncompyle6 import inspect, uncompyle6
co = inspect.currentframe().f_code co = inspect.currentframe().f_code
tokens, customize = Scanner(uncompyle6.PYTHON_VERSION).disassemble(co) tokens, customize = Scanner(uncompyle6.PYTHON_VERSION).disassemble(co)
print('-' * 30)
for t in tokens: for t in tokens:
print(t) print(t)
pass pass

View File

@@ -1,13 +1,8 @@
from __future__ import print_function # Copyright (c) 1999 John Aycock
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
''' # Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org>
Copyright (c) 1999 John Aycock
Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org>
See main module for license.
"""
Decompilation (walking AST) Decompilation (walking AST)
All table-driven. Step 1 determines a table (T) and a path to a All table-driven. Step 1 determines a table (T) and a path to a
@@ -41,17 +36,19 @@ from __future__ import print_function
The '%' may optionally be followed by a number (C) in square brackets, which The '%' may optionally be followed by a number (C) in square brackets, which
makes the engine walk down to N[C] before evaluating the escape code. makes the engine walk down to N[C] before evaluating the escape code.
''' """
import sys, re from __future__ import print_function
import inspect, sys, re
from uncompyle6 import PYTHON3
from uncompyle6.spark import GenericASTTraversal from uncompyle6.spark import GenericASTTraversal
from uncompyle6.parser import AST from uncompyle6.parser import AST
from uncompyle6.scanner import Token, Code from uncompyle6.scanner import Token, Code, get_scanner
if (sys.version_info >= (3, 0)): if PYTHON3:
from io import StringIO from io import StringIO
import uncompyle6
minint = -sys.maxsize-1 minint = -sys.maxsize-1
maxint = sys.maxsize maxint = sys.maxsize
else: else:
@@ -59,11 +56,8 @@ else:
minint = -sys.maxint-1 minint = -sys.maxint-1
maxint = sys.maxint maxint = sys.maxint
from types import CodeType
import uncompyle6.parser as dparser import uncompyle6.parser as dparser
# Some ASTs used for comparing code fragments (like 'return None' at # Some ASTs used for comparing code fragments (like 'return None' at
# the end of functions). # the end of functions).
@@ -451,7 +445,7 @@ def find_none(node):
class Walker(GenericASTTraversal, object): class Walker(GenericASTTraversal, object):
stacked_params = ('f', 'indent', 'isLambda', '_globals') stacked_params = ('f', 'indent', 'isLambda', '_globals')
def __init__(self, out, scanner, showast=0): def __init__(self, out, scanner, showast=False):
GenericASTTraversal.__init__(self, ast=None) GenericASTTraversal.__init__(self, ast=None)
self.scanner = scanner self.scanner = scanner
params = { params = {
@@ -920,7 +914,7 @@ class Walker(GenericASTTraversal, object):
self.prec = 27 self.prec = 27
code = node[-5].attr code = node[-5].attr
assert type(code) == CodeType assert inspect.iscode(code)
code = Code(code, self.scanner, self.currentclass) code = Code(code, self.scanner, self.currentclass)
# assert isinstance(code, Code) # assert isinstance(code, Code)
@@ -1283,7 +1277,7 @@ class Walker(GenericASTTraversal, object):
defparams = node[:node[-1].attr] # node[-1] == MAKE_xxx_n defparams = node[:node[-1].attr] # node[-1] == MAKE_xxx_n
code = node[-2].attr code = node[-2].attr
assert type(code) == CodeType assert inspect.iscode(code)
code = Code(code, self.scanner, self.currentclass) code = Code(code, self.scanner, self.currentclass)
# assert isinstance(code, Code) # assert isinstance(code, Code)
@@ -1349,7 +1343,7 @@ class Walker(GenericASTTraversal, object):
def build_class(self, code): def build_class(self, code):
"""Dump class definition, doc string and class body.""" """Dump class definition, doc string and class body."""
assert type(code) == CodeType assert inspect.iscode(code)
code = Code(code, self.scanner, self.currentclass) code = Code(code, self.scanner, self.currentclass)
# assert isinstance(code, Code) # assert isinstance(code, Code)
@@ -1431,3 +1425,45 @@ class Walker(GenericASTTraversal, object):
self.print_(repr(ast)) self.print_(repr(ast))
return ast return ast
def walker(version, co, out=sys.stdout, showasm=False, showast=False):
assert inspect.iscode(co)
# store final output stream for case of error
__real_out = out or sys.stdout
scanner = get_scanner(version)
tokens, customize = scanner.disassemble(co)
if showasm:
for t in tokens:
print(t)
# Build AST from disassembly.
walk = Walker(out, scanner, showast=showast)
try:
walk.ast = walk.build_ast(tokens, customize)
except ParserError as e : # parser failed, dump disassembly
print(e, file=__real_out)
raise
del tokens # save memory
# convert leading '__doc__ = "..." into doc string
assert walk.ast == 'stmts'
walk.mod_globs = find_globals(walk.ast, set())
walk.gen_source(walk.ast, customize)
for g in walk.mod_globs:
walk.write('global %s ## Warning: Unused global' % g)
if walk.ERROR:
raise walk.ERROR
return walk
if __name__ == '__main__':
def walk_test(co):
sys_version = sys.version_info.major + (sys.version_info.minor / 10.0)
walker(sys_version, co, showasm=True, showast=True)
print()
return
walk_test(walk_test.__code__)