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,
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
acted upon.
To set expectations, some legitimate bugs can take years
to fix, but they eventually do get fixed. Funding the project was
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.
To set expectations, some legitimate bugs can take years to fix, but
they eventually do get fixed.
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.
Prerequisites/Caveats

View File

@@ -263,7 +263,7 @@ See Also
.. _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
.. _HISTORY: https://github.com/rocky/python-uncompyle6/blob/master/HISTORY.md
.. _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'.
"""
def __init__(self, co, scanner, classname=None):
def __init__(self, co, scanner, classname=None, show_asm=None):
for i in dir(co):
if i.startswith("co_"):
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):

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
grammar rules. Specifically, variable arg tokens like MAKE_FUNCTION or BUILD_LIST
cause specific rules for the specific number of arguments they take.
"""
def tokens_append(j, token):
@@ -455,7 +456,7 @@ class Scanner37Base(Scanner):
# as CONTINUE, but that's okay since we add a grammar
# rule for that.
pattr = argval
target = self.get_target(inst.offset)
target = inst.argval
if target <= inst.offset:
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.
See if we can combine code.
"""
# FIXME: DRY with comprehension_walk_newer
p = self.prec
self.prec = 27
code_obj = node[1].attr
assert iscode(code_obj)
code = Code(code_obj, self.scanner, self.currentclass)
assert iscode(code_obj), node[1]
code = Code(code_obj, self.scanner, self.currentclass, self.debug_opts["asm"])
ast = self.build_ast(code._tokens, code._customize, code)
self.customize(code._customize)
@@ -103,6 +106,10 @@ def customize_for_version3(self, version):
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 = [node[-3]]
list_ifs = []

View File

@@ -1160,13 +1160,15 @@ class FragmentsWalker(pysource.SourceWalker, object):
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"""
rn = self.return_none
self.return_none = returnNone
old_name = self.name
self.name = name
self.debug_opts = debug_opts
# if code would be empty, append 'pass'
if len(ast) == 0:
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
rn = has_none and not find_none(ast)
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"

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):
"""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
@@ -50,8 +50,8 @@ def make_function36(self, node, is_lambda, nested=1, code_node=None):
def build_param(ast, name, default, annotation=None):
"""build parameters:
- handle defaults
- handle format tuple parameters
- handle defaults
- handle format tuple parameters
"""
value = default
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]
if kw_node == "expr":
kw_node = kw_node[0]
if kw_node == "dict":
kw_pairs = kw_node[-1].attr
defparams = []
# 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
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
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
rn = has_none and not find_none(ast)
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"

View File

@@ -183,6 +183,8 @@ from uncompyle6.show import maybe_show_tree
from uncompyle6.util import better_repr
from StringIO import StringIO
DEFAULT_DEBUG_OPTS = {"asm": False, "tree": False, "grammar": False}
class SourceWalkerError(Exception):
def __init__(self, errmsg):
@@ -645,7 +647,7 @@ class SourceWalker(GenericASTTraversal, object):
attr = node.attr
data = node.pattr
datatype = type(data)
if isinstance(data, float) :
if isinstance(data, float):
self.write(better_repr(data, self.version))
elif isinstance(data, complex):
self.write(better_repr(data, self.version))
@@ -1176,10 +1178,11 @@ class SourceWalker(GenericASTTraversal, object):
"""
p = self.prec
self.prec = 27
code = node[code_index].attr
assert iscode(code), node[code_index]
code = Code(code, self.scanner, self.currentclass)
code_obj = node[code_index].attr
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)
self.customize(code._customize)
@@ -2423,13 +2426,22 @@ class SourceWalker(GenericASTTraversal, object):
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"""
rn = self.return_none
self.return_none = returnNone
old_name = self.name
self.name = name
self.debug_opts = debug_opts
# if code would be empty, append 'pass'
if len(ast) == 0:
self.println(self.indent, "pass")
@@ -2523,10 +2535,6 @@ class SourceWalker(GenericASTTraversal, object):
return MAP.get(node, MAP_DIRECT)
#
DEFAULT_DEBUG_OPTS = {"asm": False, "tree": False, "grammar": False}
def code_deparse(
co,
out=sys.stdout,
@@ -2621,7 +2629,9 @@ def code_deparse(
)
# 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):
deparsed.write("# global %s ## Warning: Unused global\n" % g)