Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle parens in generator better? #156

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions decompyle3/semantics/consts.py
Original file line number Diff line number Diff line change
Expand Up @@ -592,9 +592,12 @@
"store": MAP_R,
}

ASSIGN_TUPLE_PARAM = lambda param_name: SyntaxTree( # noqa
"expr", [Token("LOAD_FAST", pattr=param_name)]
)

def assign_tuple_parameter_tree(param_name) -> SyntaxTree:
return SyntaxTree("expr", [Token("LOAD_FAST", pattr=param_name)])


ASSIGN_TUPLE_PARAM = assign_tuple_parameter_tree

escape = re.compile(
r"""
Expand Down
31 changes: 21 additions & 10 deletions decompyle3/semantics/customize37.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from decompyle3.scanners.tok import Token
from decompyle3.semantics.consts import (
INDENT_PER_LEVEL,
NO_PARENTHESIS_EVER,
PRECEDENCE,
TABLE_DIRECT,
TABLE_R,
Expand All @@ -41,6 +42,7 @@ def escape_format(s):

FSTRING_CONVERSION_MAP = {1: "!s", 2: "!r", 3: "!a", "X": ":X"}


#######################
def customize_for_version37(self, version):
########################
Expand Down Expand Up @@ -162,7 +164,7 @@ def customize_for_version37(self, version):
"await_expr": ("await %p", (0, PRECEDENCE["await_expr"] - 1)),
"await_stmt": ("%|%c\n", 0),
"c_async_with_stmt": ("%|async with %c:\n%+%c%-", (0, "expr"), 3),
"call_ex": ("%c(%p)", (0, "expr"), (1, 100)),
"call_ex": ("%c(%p)", (0, "expr"), (1, NO_PARENTHESIS_EVER)),
"compare_chained_middlea_37": (
"%p %p",
(0, PRECEDENCE["compare"] - 1),
Expand Down Expand Up @@ -419,7 +421,7 @@ def customize_for_version37(self, version):

TABLE_R.update(
{
"CALL_FUNCTION_EX": ("%c(*%P)", 0, (1, 2, ", ", 100)),
"CALL_FUNCTION_EX": ("%c(*%P)", 0, (1, 2, ", ", NO_PARENTHESIS_EVER)),
# Not quite right
"CALL_FUNCTION_EX_KW": ("%c(**%C)", 0, (2, 3, ",")),
}
Expand Down Expand Up @@ -465,7 +467,7 @@ def call36_dict(node):
We will source-code use line breaks to guide us when to break.
"""
p = self.prec
self.prec = 100
self.prec = NO_PARENTHESIS_EVER

self.indent_more(INDENT_PER_LEVEL)
sep = INDENT_PER_LEVEL[:-1]
Expand Down Expand Up @@ -770,7 +772,7 @@ def n_call(node):
if args_node in ("pos_arg", "expr"):
args_node = args_node[0]
if args_node == "build_list_unpack":
template = ("*%P)", (0, len(args_node) - 1, ", *", 100))
template = ("*%P)", (0, len(args_node) - 1, ", *", NO_PARENTHESIS_EVER))
self.template_engine(template, args_node)
else:
if len(node) - nargs > 3:
Expand All @@ -789,10 +791,19 @@ def n_call(node):
and opname == "CALL_FUNCTION_1"
or not re.match(r"\d", opname[-1])
):
template = "(%c)(%p)" if node[0][0] == "lambda_body" else "%c(%p)"
self.template_engine(
(template, (0, "expr"), (1, PRECEDENCE["yield"] - 1)), node
)
if node[0][0] == "lambda_body":
self.template_engine(
(
"(\n%+%|%c%-\n)(%p)",
(0, ("expr", "arg")),
(1, PRECEDENCE["yield"] - 1),
),
node,
)
else:
self.template_engine(
("%c(%p)", (0, ("expr", "arg")), (1, NO_PARENTHESIS_EVER)), node
)
self.prec = p
self.prune()
else:
Expand Down Expand Up @@ -1190,7 +1201,7 @@ def n_call_ex_kw(node):
if value == "":
fmt = "%c(%p)"
else:
fmt = "%c" + ("(%s, " % value).replace('%', '%%') + "%p)"
fmt = "%c" + ("(%s, " % value).replace("%", "%%") + "%p)"

self.template_engine(
(fmt, (0, "expr"), (2, "build_map_unpack_with_call", 100)), node
Expand All @@ -1209,7 +1220,7 @@ def n_call_ex_kw2(node):
if value == "":
fmt = "%c(%p)"
else:
fmt = "%c" + ("(%s, " % value).replace('%', '%%') + "%p)"
fmt = "%c" + ("(%s, " % value).replace("%", "%%") + "%p)"

self.template_engine(
(fmt, (0, "expr"), (2, "build_map_unpack_with_call", 100)), node
Expand Down
4 changes: 2 additions & 2 deletions decompyle3/semantics/customize38.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
# Python 3.8+ changes
#######################

from decompyle3.semantics.consts import PRECEDENCE, TABLE_DIRECT
from decompyle3.semantics.consts import NO_PARENTHESIS_EVER, PRECEDENCE, TABLE_DIRECT
from decompyle3.semantics.customize37 import FSTRING_CONVERSION_MAP
from decompyle3.semantics.helper import escape_string, strip_quotes

Expand Down Expand Up @@ -380,7 +380,7 @@ def n_set_afor(node):

def n_formatted_value_debug(node):
p = self.prec
self.prec = 100
self.prec = NO_PARENTHESIS_EVER

formatted_value = node[1]
value_equal = node[0].attr
Expand Down
Binary file not shown.
84 changes: 84 additions & 0 deletions test/simple_source/generator_start/03_generator_compendium.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# These are adapted from generators found when byte compiling the
# entire set of 3.8 installed packages on my disk.
# Many examples come from packages like sympy or numpy

# fmt: off
# generator bugs
(i
for i
in
range(10)
)

tuple(j
for j
in t
if i != j)

# # 3.8.12 weakrefset.py
# (e
# for s
# in ("a", "b")
# for e
# in s)

# # Python 3.8.2 line 683 of git/refs/symbolic.py
# # Bug was in handling "or not"
# (r
# for r
# in (0, 1, 2, 3)
# if r
# or
# not
# 5 % 2)

# # line 1512 of sympy/core/mul.py
# # Bug was handling "and"
# (x
# and
# (x + 1 % 2)
# is True for
# x
# in (0, 1, 2)
# )

# # line 330 of 3.8.12 setuptools/config.py
# # Problem was in handling or True
# (
# path
# for path in __file__
# if (path or True))

# # Line 602 of 3.8.2 nltk/corpus/reader/framenet.py
# # Bug was handling looping jump of chained comparison inside comp_if.
# (1
# for x,
# y
# in __file__
# if 2 <= y
# < 3
# or 5
# <= x
# < 6)

# # The problem was handing IfExp as part of a tuple, i.e.
# # (None if .. and .. else)
# (
# (k,
# (None if
# k
# and v
# else v)
# )
# for k, v in
# {"foo": "bar"}
# )

# # line 1086 of 3.8.12 test/test_asyncgen.py
# # Bug was hooking genexpr_func_async to return_expr_lambda in grammar
# # and writing a semantic action for this when the code is decompiled
# # independant of the calling context.
# (i * 2
# async
# for i
# in range(10))