showasm and showast now accept file like objects which are used for writing the the asm or ast to.

This commit is contained in:
Daniel Bradburn
2016-06-01 10:02:04 +02:00
parent 52731bb5cd
commit b3182e804d
4 changed files with 118 additions and 28 deletions

View File

@@ -12,6 +12,8 @@ import sys
from xdis.code import iscode
from spark_parser import GenericASTBuilder, DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG
from uncompyle6.show import maybe_show_asm
class ParserError(Exception):
def __init__(self, token, offset):
@@ -506,15 +508,30 @@ class PythonParserSingle(PythonParser):
call_stmt ::= expr PRINT_EXPR
'''
def python_parser(version, co, out=sys.stdout, showasm=False,
parser_debug=PARSER_DEFAULT_DEBUG):
"""
Parse a code object to an abstract syntax tree representation.
:param version: The python version this code is from as a float, for
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 disassembled 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 parser_debug: dict containing debug flags for the spark parser.
:return: Abstract syntax tree representation of the code object.
"""
assert 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)
maybe_show_asm(showasm, tokens)
# For heavy grammar debugging
parser_debug = {'rules': True, 'transition': True, 'reduce' : True,

View File

@@ -34,6 +34,11 @@ from uncompyle6.semantics import pysource
from uncompyle6.parser import get_python_parser
from uncompyle6 import parser
from uncompyle6.scanner import Token, Code, get_scanner
from uncompyle6.show import (
maybe_show_asm,
maybe_show_ast,
maybe_show_ast_param_default,
)
from uncompyle6.semantics.pysource import AST, INDENT_PER_LEVEL, NONE, PRECEDENCE, \
ParserError, TABLE_DIRECT, escape, find_all_globals, find_globals, find_none, minint, MAP
@@ -750,8 +755,7 @@ class FragmentsWalker(pysource.SourceWalker, object):
ast = parser.parse(self.p, tokens, customize)
except (parser.ParserError, AssertionError) as e:
raise ParserError(e, tokens)
if self.showast:
print(repr(ast))
maybe_show_ast(self.showast, ast)
return ast
# The bytecode for the end of the main routine has a
@@ -777,8 +781,7 @@ class FragmentsWalker(pysource.SourceWalker, object):
except (parser.ParserError, AssertionError) as e:
raise ParserError(e, tokens)
if self.showast:
print(repr(ast))
maybe_show_ast(self.showast, ast)
return ast
@@ -1338,12 +1341,7 @@ class FragmentsWalker(pysource.SourceWalker, object):
pass
if default:
if self.showast:
print()
print('--', name)
print(default)
print('--')
pass
maybe_show_ast_param_default(self.showast, name, default)
result = '%s=' % name
old_last_finish = self.last_finish
self.last_finish = len(result)
@@ -1452,6 +1450,28 @@ class FragmentsWalker(pysource.SourceWalker, object):
def deparse_code(version, co, out=StringIO(), showasm=False, showast=False,
showgrammar=False):
"""
Convert the code object co into a python source fragment.
:param version: The python version this code is from as a float, for
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 disassembled 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
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 showgrammar: Flag which determines whether the grammar
is written to sys.stdout or not. (It is also to
pass a file like object, into which the grammer
will be written).
:return: The deparsed source fragment.
"""
assert iscode(co)
# store final output stream for case of error
@@ -1460,9 +1480,7 @@ def deparse_code(version, co, out=StringIO(), showasm=False, showast=False,
tokens, customize = scanner.disassemble(co)
tokens, customize = scanner.disassemble(co)
if showasm:
for t in tokens:
print(t)
maybe_show_asm(showasm, tokens)
debug_parser = dict(PARSER_DEFAULT_DEBUG)
if showgrammar:

View File

@@ -77,6 +77,11 @@ from spark_parser import GenericASTTraversal, DEFAULT_DEBUG as PARSER_DEFAULT_DE
from uncompyle6.scanner import Code, get_scanner
from uncompyle6.scanners.tok import Token, NoneToken
import uncompyle6.parser as python_parser
from uncompyle6.show import (
maybe_show_asm,
maybe_show_ast,
maybe_show_ast_param_default,
)
if PYTHON3:
from itertools import zip_longest
@@ -1636,11 +1641,7 @@ class SourceWalker(GenericASTTraversal, object):
pass
if default:
if self.showast:
print()
print('--', name)
print(default)
print('--')
maybe_show_ast_param_default(self.showast, name, default)
result = '%s=%s' % (name, self.traverse(default, indent='') )
if result[-2:] == '= ': # default was 'LOAD_CONST None'
result += 'None'
@@ -1835,8 +1836,7 @@ class SourceWalker(GenericASTTraversal, object):
ast = python_parser.parse(self.p, tokens, customize)
except (python_parser.ParserError, AssertionError) as e:
raise ParserError(e, tokens)
if self.showast:
self.println(repr(ast))
maybe_show_ast(self.showast, ast)
return ast
# The bytecode for the end of the main routine has a
@@ -1863,8 +1863,7 @@ class SourceWalker(GenericASTTraversal, object):
except (python_parser.ParserError, AssertionError) as e:
raise ParserError(e, tokens)
if self.showast:
self.println(repr(ast))
maybe_show_ast(self.showast, ast)
return ast
@@ -1884,9 +1883,7 @@ def deparse_code(version, co, out=sys.stdout, showasm=False, showast=False,
scanner = get_scanner(version)
tokens, customize = scanner.disassemble(co, code_objects=code_objects)
if showasm:
for t in tokens:
print(t)
maybe_show_asm(showasm, tokens)
debug_parser = dict(PARSER_DEFAULT_DEBUG)
if showgrammar:

View File

@@ -0,0 +1,58 @@
import sys
def maybe_show_asm(showasm, tokens):
"""
Show the asm based on the showasm flag (or file object), writing to the
appropriate stream depending on the type of the flag.
:param showasm: Flag which determines whether the disassembled 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 tokens: The asm tokens to show.
"""
if showasm:
stream = showasm if hasattr(showasm, 'write') else sys.stdout
for t in tokens:
stream.write(t)
stream.write('\n')
def maybe_show_ast(showast, 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 ast: The ast to show.
"""
if showast:
stream = showast if hasattr(showast, 'write') else sys.stdout
stream.write(repr(ast))
stream.write('\n')
def maybe_show_ast_param_default(showast, name, default):
"""
Show a function parameter with default for an 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 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:
stream = showast if hasattr(showast, 'write') else sys.stdout
stream.write('\n')
stream.write('--' + name)
stream.write('\n')
stream.write(default)
stream.write('\n')
stream.write('--')
stream.write('\n')