Files
python-uncompyle6/uncompyle6/semantics/helper.py
rocky 5fe8303184 Two bugs and a refactor ..
1. parse2.py: try except in a loop with a (virtual) continue
   treat CONTINUE like JUMP_ABSOLUTE which it is
2. in taking methods off of constants, a parenthesis needs to be added

Some refactoring of global code done
2017-12-03 10:46:22 -05:00

187 lines
6.3 KiB
Python

import sys
from uncompyle6.parsers.astnode import AST
from uncompyle6 import PYTHON3
if PYTHON3:
minint = -sys.maxsize-1
maxint = sys.maxsize
else:
minint = -sys.maxint-1
maxint = sys.maxint
read_write_global_ops = frozenset(('STORE_GLOBAL', 'DELETE_GLOBAL', 'LOAD_GLOBAL'))
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."""
for n in node:
if isinstance(n, AST):
globs = find_all_globals(n, globs)
elif n.kind in read_write_global_ops:
globs.add(n.pattr)
return globs
def find_globals(node, globs):
"""search AST node to find variable names that need a 'global' added."""
for n in node:
if isinstance(n, AST):
globs = find_globals(n, globs)
elif n.kind in read_global_ops:
globs.add(n.pattr)
return globs
# def find_globals(node, globs, global_ops=mkfunc_globals):
# """Find globals in this statement."""
# for n in node:
# # print("XXX", n.kind, global_ops)
# if isinstance(n, AST):
# # FIXME: do I need a caser for n.kind="mkfunc"?
# if n.kind in ("conditional_lambda", "return_lambda"):
# globs = find_globals(n, globs, mklambda_globals)
# else:
# globs = find_globals(n, globs, global_ops)
# elif n.kind in frozenset(global_ops):
# globs.add(n.pattr)
# return globs
def find_none(node):
for n in node:
if isinstance(n, AST):
if n not in ('return_stmt', 'return_if_stmt'):
if find_none(n):
return True
elif n.kind == 'LOAD_CONST' and n.pattr is None:
return True
return False
def print_docstring(self, indent, docstring):
try:
if docstring.find('"""') == -1:
quote = '"""'
else:
quote = "'''"
docstring = docstring.replace("'''", "\\'''")
except:
return False
self.write(indent)
if not PYTHON3 and not isinstance(docstring, str):
# Must be unicode in Python2
self.write('u')
docstring = repr(docstring.expandtabs())[2:-1]
else:
docstring = repr(docstring.expandtabs())[1:-1]
for (orig, replace) in (('\\\\', '\t'),
('\\r\\n', '\n'),
('\\n', '\n'),
('\\r', '\n'),
('\\"', '"'),
("\\'", "'")):
docstring = docstring.replace(orig, replace)
# Do a raw string if there are backslashes but no other escaped characters:
# also check some edge cases
if ('\t' in docstring
and '\\' not in docstring
and len(docstring) >= 2
and docstring[-1] != '\t'
and (docstring[-1] != '"'
or docstring[-2] == '\t')):
self.write('r') # raw string
# restore backslashes unescaped since raw
docstring = docstring.replace('\t', '\\')
else:
# Escape '"' if it's the last character, so it doesn't
# ruin the ending triple quote
if len(docstring) and docstring[-1] == '"':
docstring = docstring[:-1] + '\\"'
# Restore escaped backslashes
docstring = docstring.replace('\t', '\\\\')
# Escape triple quote when needed
if quote == '""""':
docstring = docstring.replace('"""', '\\"\\"\\"')
lines = docstring.split('\n')
calculate_indent = maxint
for line in lines[1:]:
stripped = line.lstrip()
if len(stripped) > 0:
calculate_indent = min(calculate_indent, len(line) - len(stripped))
calculate_indent = min(calculate_indent, len(lines[-1]) - len(lines[-1].lstrip()))
# Remove indentation (first line is special):
trimmed = [lines[0]]
if calculate_indent < maxint:
trimmed += [line[calculate_indent:] for line in lines[1:]]
self.write(quote)
if len(trimmed) == 0:
self.println(quote)
elif len(trimmed) == 1:
self.println(trimmed[0], quote)
else:
self.println(trimmed[0])
for line in trimmed[1:-1]:
self.println( indent, line )
self.println(indent, trimmed[-1], quote)
return True
# if __name__ == '__main__':
# if PYTHON3:
# from io import StringIO
# else:
# from StringIO import StringIO
# class PrintFake():
# def __init__(self):
# self.pending_newlines = 0
# self.f = StringIO()
# def write(self, *data):
# if (len(data) == 0) or (len(data) == 1 and data[0] == ''):
# return
# out = ''.join((str(j) for j in data))
# n = 0
# for i in out:
# if i == '\n':
# n += 1
# if n == len(out):
# self.pending_newlines = max(self.pending_newlines, n)
# return
# elif n:
# self.pending_newlines = max(self.pending_newlines, n)
# out = out[n:]
# break
# else:
# break
# if self.pending_newlines > 0:
# self.f.write('\n'*self.pending_newlines)
# self.pending_newlines = 0
# for i in out[::-1]:
# if i == '\n':
# self.pending_newlines += 1
# else:
# break
# if self.pending_newlines:
# out = out[:-self.pending_newlines]
# self.f.write(out)
# def println(self, *data):
# if data and not(len(data) == 1 and data[0] ==''):
# self.write(*data)
# self.pending_newlines = max(self.pending_newlines, 1)
# return
# pass
# for doc in (
# "Now is the time",
# r'''func placeholder - with ("""\nstring\n""")''',
# r'''func placeholder - ' and with ("""\nstring\n""")''',
# r"""func placeholder - ' and with ('''\nstring\n''') and \"\"\"\nstring\n\"\"\" """
# ):
# o = PrintFake()
# print_docstring(o, ' ', doc)
# print(o.f.getvalue())