Merge branch 'python-3.3-to-3.5' into python-2.4

This commit is contained in:
rocky
2021-12-17 06:25:54 -05:00
9 changed files with 71 additions and 33 deletions

View File

@@ -4,7 +4,10 @@ about: Tell us about uncompyle6 bugs
--- ---
<!-- __Note:__ Bugs are not for asking questions about a problem you <!-- __Note:__ If you are using this program to do something illegal - don't.
The issue may flagged to make it easier for those looking for illegal activity.
Bugs are not for asking questions about a problem you
are trying to solve that involve the use of uncompyle6 along the way, are trying to solve that involve the use of uncompyle6 along the way,
although I may be more tolerent of this if you sponsor the project. although I may be more tolerent of this if you sponsor the project.
@@ -12,16 +15,22 @@ Also, the unless you are a sponsor of the project, it may take a
while, maybe a week or so, before the bug report is noticed, let alone while, maybe a week or so, before the bug report is noticed, let alone
acted upon. acted upon.
To set expectations, some legitimate bugs can take years To set expectations, some legitimate bugs can take years to fix, but
to fix, but they eventually do get fixed. Funding the project was they eventually do get fixed.
added to address the problem that there are lots of people seeking
help and reporting bugs, but few people who are willing or capable of
providing help or fixing bugs.
Finally, have you read https://github.com/rocky/python-uncompyle6/blob/master/HOW-TO-REPORT-A-BUG.md Funding the project was added to partially address the problem that there are
? lots of people seeking help and reporting bugs, but few people who are
willing or capable of providing help or fixing bugs.
Tasks or the kinds of things others can do but you can't do or don't
want to do yourself are typically the kind of thing that you pay
someone to do, especially when you are the primary beneficiary of the
work, or the task is complex, long, or tedious. If your code is over
30 lines long, it fits into this category.
-->
<!--
Please remove any of the optional sections if they are not applicable. Please remove any of the optional sections if they are not applicable.
Prerequisites/Caveats Prerequisites/Caveats

View File

@@ -263,7 +263,7 @@ See Also
.. _Cython: https://en.wikipedia.org/wiki/Cython .. _Cython: https://en.wikipedia.org/wiki/Cython
.. _trepan: https://pypi.python.org/pypi/trepan2g .. _trepan: https://pypi.python.org/pypi/trepan3k
.. _compiler: https://pypi.python.org/pypi/spark_parser .. _compiler: https://pypi.python.org/pypi/spark_parser
.. _HISTORY: https://github.com/rocky/python-uncompyle6/blob/master/HISTORY.md .. _HISTORY: https://github.com/rocky/python-uncompyle6/blob/master/HISTORY.md
.. _debuggers: https://pypi.python.org/pypi/trepan3k .. _debuggers: https://pypi.python.org/pypi/trepan3k

View File

@@ -93,11 +93,11 @@ class Code(object):
the diassembled code is stored in the attribute '_tokens'. the diassembled code is stored in the attribute '_tokens'.
""" """
def __init__(self, co, scanner, classname=None): def __init__(self, co, scanner, classname=None, show_asm=None):
for i in dir(co): for i in dir(co):
if i.startswith("co_"): if i.startswith("co_"):
setattr(self, i, getattr(co, i)) setattr(self, i, getattr(co, i))
self._tokens, self._customize = scanner.ingest(co, classname) self._tokens, self._customize = scanner.ingest(co, classname, show_asm=show_asm)
class Scanner(object): class Scanner(object):

View File

@@ -194,6 +194,7 @@ class Scanner37Base(Scanner):
Also, when we encounter certain tokens, we add them to a set which will cause custom Also, when we encounter certain tokens, we add them to a set which will cause custom
grammar rules. Specifically, variable arg tokens like MAKE_FUNCTION or BUILD_LIST grammar rules. Specifically, variable arg tokens like MAKE_FUNCTION or BUILD_LIST
cause specific rules for the specific number of arguments they take. cause specific rules for the specific number of arguments they take.
""" """
def tokens_append(j, token): def tokens_append(j, token):
@@ -455,7 +456,7 @@ class Scanner37Base(Scanner):
# as CONTINUE, but that's okay since we add a grammar # as CONTINUE, but that's okay since we add a grammar
# rule for that. # rule for that.
pattr = argval pattr = argval
target = self.get_target(inst.offset) target = inst.argval
if target <= inst.offset: if target <= inst.offset:
next_opname = self.insts[i + 1].opname next_opname = self.insts[i + 1].opname

View File

@@ -84,12 +84,15 @@ def customize_for_version3(self, version):
"""List comprehensions in Python 3 when handled as a closure. """List comprehensions in Python 3 when handled as a closure.
See if we can combine code. See if we can combine code.
""" """
# FIXME: DRY with comprehension_walk_newer
p = self.prec p = self.prec
self.prec = 27 self.prec = 27
code_obj = node[1].attr code_obj = node[1].attr
assert iscode(code_obj) assert iscode(code_obj), node[1]
code = Code(code_obj, self.scanner, self.currentclass) code = Code(code_obj, self.scanner, self.currentclass, self.debug_opts["asm"])
ast = self.build_ast(code._tokens, code._customize, code) ast = self.build_ast(code._tokens, code._customize, code)
self.customize(code._customize) self.customize(code._customize)
@@ -103,6 +106,10 @@ def customize_for_version3(self, version):
n = ast[1] n = ast[1]
# Pick out important parts of the comprehension:
# * the variables we iterate over: "stores"
# * the results we accumulate: "n"
# collections is the name of the expression(s) we are iterating over # collections is the name of the expression(s) we are iterating over
collections = [node[-3]] collections = [node[-3]]
list_ifs = [] list_ifs = []

View File

@@ -1160,13 +1160,15 @@ class FragmentsWalker(pysource.SourceWalker, object):
n_classdefdeco2 = n_classdef n_classdefdeco2 = n_classdef
def gen_source(self, ast, name, customize, is_lambda=False, returnNone=False): def gen_source(self, ast, name, customize, is_lambda=False, returnNone=False,
debug_opts=None):
"""convert parse tree to Python source code""" """convert parse tree to Python source code"""
rn = self.return_none rn = self.return_none
self.return_none = returnNone self.return_none = returnNone
old_name = self.name old_name = self.name
self.name = name self.name = name
self.debug_opts = debug_opts
# if code would be empty, append 'pass' # if code would be empty, append 'pass'
if len(ast) == 0: if len(ast) == 0:
self.println(self.indent, "pass") self.println(self.indent, "pass")

View File

@@ -666,7 +666,12 @@ def make_function3(self, node, is_lambda, nested=1, code_node=None):
has_none = "None" in code.co_names has_none = "None" in code.co_names
rn = has_none and not find_none(ast) rn = has_none and not find_none(ast)
self.gen_source( self.gen_source(
ast, code.co_name, scanner_code._customize, is_lambda=is_lambda, returnNone=rn ast,
code.co_name,
scanner_code._customize,
is_lambda=is_lambda,
returnNone=rn,
debug_opts=self.debug_opts,
) )
# In obscure cases, a function may be a generator but the "yield" # In obscure cases, a function may be a generator but the "yield"

View File

@@ -37,7 +37,7 @@ from uncompyle6.show import maybe_show_tree_param_default
def make_function36(self, node, is_lambda, nested=1, code_node=None): def make_function36(self, node, is_lambda, nested=1, code_node=None):
"""Dump function definition, doc string, and function body in """Dump function definition, doc string, and function body in
Python version 3.6 and above. Python version 3.6 and above.
""" """
# MAKE_CLOSURE adds an additional closure slot # MAKE_CLOSURE adds an additional closure slot
@@ -50,8 +50,8 @@ def make_function36(self, node, is_lambda, nested=1, code_node=None):
def build_param(ast, name, default, annotation=None): def build_param(ast, name, default, annotation=None):
"""build parameters: """build parameters:
- handle defaults - handle defaults
- handle format tuple parameters - handle format tuple parameters
""" """
value = default value = default
maybe_show_tree_param_default(self.showast, name, value) maybe_show_tree_param_default(self.showast, name, value)
@@ -123,8 +123,6 @@ def make_function36(self, node, is_lambda, nested=1, code_node=None):
kw_node = node[pos_args] kw_node = node[pos_args]
if kw_node == "expr": if kw_node == "expr":
kw_node = kw_node[0] kw_node = kw_node[0]
if kw_node == "dict":
kw_pairs = kw_node[-1].attr
defparams = [] defparams = []
# FIXME: DRY with code below # FIXME: DRY with code below
@@ -149,7 +147,8 @@ def make_function36(self, node, is_lambda, nested=1, code_node=None):
code = code_node.attr code = code_node.attr
assert iscode(code) assert iscode(code)
scanner_code = Code(code, self.scanner, self.currentclass) debug_opts = self.debug_opts["asm"] if self.debug_opts else None
scanner_code = Code(code, self.scanner, self.currentclass, debug_opts)
# add defaults values to parameter names # add defaults values to parameter names
argc = code.co_argcount argc = code.co_argcount
@@ -349,7 +348,12 @@ def make_function36(self, node, is_lambda, nested=1, code_node=None):
has_none = "None" in code.co_names has_none = "None" in code.co_names
rn = has_none and not find_none(ast) rn = has_none and not find_none(ast)
self.gen_source( self.gen_source(
ast, code.co_name, scanner_code._customize, is_lambda=is_lambda, returnNone=rn ast,
code.co_name,
scanner_code._customize,
is_lambda=is_lambda,
returnNone=rn,
debug_opts=self.debug_opts,
) )
# In obscure cases, a function may be a generator but the "yield" # In obscure cases, a function may be a generator but the "yield"

View File

@@ -183,6 +183,8 @@ from uncompyle6.show import maybe_show_tree
from uncompyle6.util import better_repr from uncompyle6.util import better_repr
from StringIO import StringIO from StringIO import StringIO
DEFAULT_DEBUG_OPTS = {"asm": False, "tree": False, "grammar": False}
class SourceWalkerError(Exception): class SourceWalkerError(Exception):
def __init__(self, errmsg): def __init__(self, errmsg):
@@ -645,7 +647,7 @@ class SourceWalker(GenericASTTraversal, object):
attr = node.attr attr = node.attr
data = node.pattr data = node.pattr
datatype = type(data) datatype = type(data)
if isinstance(data, float) : if isinstance(data, float):
self.write(better_repr(data, self.version)) self.write(better_repr(data, self.version))
elif isinstance(data, complex): elif isinstance(data, complex):
self.write(better_repr(data, self.version)) self.write(better_repr(data, self.version))
@@ -1176,10 +1178,11 @@ class SourceWalker(GenericASTTraversal, object):
""" """
p = self.prec p = self.prec
self.prec = 27 self.prec = 27
code = node[code_index].attr
assert iscode(code), node[code_index] code_obj = node[code_index].attr
code = Code(code, self.scanner, self.currentclass) assert iscode(code_obj), node[code_index]
code = Code(code_obj, self.scanner, self.currentclass, self.debug_opts["asm"])
ast = self.build_ast(code._tokens, code._customize, code) ast = self.build_ast(code._tokens, code._customize, code)
self.customize(code._customize) self.customize(code._customize)
@@ -2423,13 +2426,22 @@ class SourceWalker(GenericASTTraversal, object):
self.classes.pop(-1) self.classes.pop(-1)
def gen_source(self, ast, name, customize, is_lambda=False, returnNone=False): def gen_source(
self,
ast,
name,
customize,
is_lambda=False,
returnNone=False,
debug_opts=DEFAULT_DEBUG_OPTS,
):
"""convert SyntaxTree to Python source code""" """convert SyntaxTree to Python source code"""
rn = self.return_none rn = self.return_none
self.return_none = returnNone self.return_none = returnNone
old_name = self.name old_name = self.name
self.name = name self.name = name
self.debug_opts = debug_opts
# if code would be empty, append 'pass' # if code would be empty, append 'pass'
if len(ast) == 0: if len(ast) == 0:
self.println(self.indent, "pass") self.println(self.indent, "pass")
@@ -2523,10 +2535,6 @@ class SourceWalker(GenericASTTraversal, object):
return MAP.get(node, MAP_DIRECT) return MAP.get(node, MAP_DIRECT)
#
DEFAULT_DEBUG_OPTS = {"asm": False, "tree": False, "grammar": False}
def code_deparse( def code_deparse(
co, co,
out=sys.stdout, out=sys.stdout,
@@ -2621,7 +2629,9 @@ def code_deparse(
) )
# What we've been waiting for: Generate source from Syntax Tree! # What we've been waiting for: Generate source from Syntax Tree!
deparsed.gen_source(deparsed.ast, co.co_name, customize) deparsed.gen_source(
deparsed.ast, name=co.co_name, customize=customize, debug_opts=debug_opts
)
for g in sorted(deparsed.mod_globs): for g in sorted(deparsed.mod_globs):
deparsed.write("# global %s ## Warning: Unused global\n" % g) deparsed.write("# global %s ## Warning: Unused global\n" % g)