You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-02 16:44:46 +08:00
Redo the way we handle complex literals and 3.7+ bug fixes...
In 3.7+ remove assert_expr* parser rules Fix "call" precidence in 3.7+ for it children
This commit is contained in:
@@ -96,8 +96,10 @@ def test_grammar():
|
||||
]
|
||||
)
|
||||
reduced_dup_rhs = dict((k, dup_rhs[k]) for k in dup_rhs if k not in expect_dup_rhs)
|
||||
for k in reduced_dup_rhs:
|
||||
print(k, reduced_dup_rhs[k])
|
||||
if reduced_dup_rhs:
|
||||
print("\nPossible duplicate RHS that might be folded, into one of the LHS symbols")
|
||||
for k in reduced_dup_rhs:
|
||||
print(k, reduced_dup_rhs[k])
|
||||
# assert not reduced_dup_rhs, reduced_dup_rhs
|
||||
|
||||
s = get_scanner(PYTHON_VERSION, IS_PYPY)
|
||||
|
@@ -37,5 +37,15 @@ def test_truediv():
|
||||
for y in simple_complex:
|
||||
check_div(x, y)
|
||||
|
||||
z2 = -1e1000j # Check that we can handle -inf as a complex number
|
||||
def test_plus_minus_0j():
|
||||
z1, z2 = (0j, (-0 - 0j))
|
||||
assert atan2(z1.imag, -1.0) == atan2(0.0, -1.0)
|
||||
assert atan2(z2.imag, -1.0), atan2(-0.0, -1.0)
|
||||
|
||||
# Check that we can handle -inf, and inf as a complex numbers.
|
||||
# And put it in a tuple and a list to make it harder.
|
||||
z1, z2 = (-1e1000j, 1e1000j)
|
||||
assert z1 in [-1e1000j, 1e1000j]
|
||||
assert z1 == z2
|
||||
test_truediv()
|
||||
test_plus_minus0j()
|
||||
|
@@ -197,7 +197,6 @@ case $PYVERSION in
|
||||
[test_collections.py]=1 # Investigate syntax error: self.assertEqual(p, Point(**))
|
||||
[test_compare.py]=1
|
||||
[test_compile.py]=1
|
||||
[test_complex.py]=1 # Investigate: NameError: global name 'infj' is not defined
|
||||
[test_contains.py]=1 # Code "while False: yield None" is optimized away in compilation
|
||||
[test_contextlib_async.py]=1 # Investigate
|
||||
[test_context.py]=1
|
||||
@@ -208,6 +207,7 @@ case $PYVERSION in
|
||||
[test_dis.py]=1 # We change line numbers - duh!
|
||||
# ...
|
||||
)
|
||||
;;
|
||||
3.8)
|
||||
SKIP_TESTS=(
|
||||
[test_contains.py]=1 # Code "while False: yield None" is optimized away in compilation
|
||||
|
@@ -91,8 +91,6 @@ class Python37Parser(Python37BaseParser):
|
||||
else_suitec ::= c_stmts
|
||||
else_suitec ::= returns
|
||||
|
||||
stmt ::= assert
|
||||
|
||||
stmt ::= classdef
|
||||
stmt ::= call_stmt
|
||||
|
||||
@@ -801,16 +799,6 @@ class Python37Parser(Python37BaseParser):
|
||||
classdefdeco ::= classdefdeco1 store
|
||||
|
||||
expr ::= LOAD_ASSERT
|
||||
assert ::= assert_expr jmp_true LOAD_ASSERT RAISE_VARARGS_1 COME_FROM
|
||||
stmt ::= assert2
|
||||
assert2 ::= assert_expr jmp_true LOAD_ASSERT expr
|
||||
CALL_FUNCTION_1 RAISE_VARARGS_1 COME_FROM
|
||||
|
||||
assert_expr ::= expr
|
||||
assert_expr ::= assert_expr_or
|
||||
assert_expr ::= assert_expr_and
|
||||
assert_expr_or ::= assert_expr jmp_true expr
|
||||
assert_expr_and ::= assert_expr jmp_false expr
|
||||
|
||||
ifstmt ::= testexpr _ifstmts_jump
|
||||
|
||||
@@ -971,7 +959,6 @@ class Python37Parser(Python37BaseParser):
|
||||
|
||||
and ::= expr JUMP_IF_FALSE_OR_POP expr COME_FROM
|
||||
and ::= expr JUMP_IF_FALSE expr COME_FROM
|
||||
and ::= expr jmp_false expr
|
||||
|
||||
## FIXME: Is the below needed or is it covered above??
|
||||
and ::= expr jmp_false expr COME_FROM
|
||||
|
@@ -537,12 +537,12 @@ class Python37BaseParser(PythonParser):
|
||||
"""
|
||||
stmt ::= assert_pypy
|
||||
stmt ::= assert2_pypy", nop_func)
|
||||
assert_pypy ::= JUMP_IF_NOT_DEBUG assert_expr jmp_true
|
||||
assert_pypy ::= JUMP_IF_NOT_DEBUG expr jmp_true
|
||||
LOAD_ASSERT RAISE_VARARGS_1 COME_FROM
|
||||
assert2_pypy ::= JUMP_IF_NOT_DEBUG assert_expr jmp_true
|
||||
LOAD_ASSERT expr CALL_FUNCTION_1
|
||||
RAISE_VARARGS_1 COME_FROM
|
||||
assert2_pypy ::= JUMP_IF_NOT_DEBUG assert_expr jmp_true
|
||||
assert2_pypy ::= JUMP_IF_NOT_DEBUG expr jmp_true
|
||||
LOAD_ASSERT expr CALL_FUNCTION_1
|
||||
RAISE_VARARGS_1 COME_FROM,
|
||||
""",
|
||||
|
@@ -42,6 +42,13 @@ else:
|
||||
# various templates we use odd values. Avoiding equal-precedent comparisons
|
||||
# avoids ambiguity what to do when the precedence is equal.
|
||||
|
||||
# The precidence of a key below applies the key, a node, and the its
|
||||
# *parent*. A node however sometimes sets the precidence for its
|
||||
# children. For example, "call" has precidence 2 so we don't get
|
||||
# additional the additional parenthesis of: ".. op (call())". However
|
||||
# for call's children, it parameters, we set the the precidence high,
|
||||
# say to 100, to make sure we avoid additional prenthesis in
|
||||
# call((.. op ..)).
|
||||
|
||||
PRECEDENCE = {
|
||||
'yield': 102,
|
||||
|
@@ -47,6 +47,7 @@ def customize_for_version(self, is_pypy, version):
|
||||
# Without PyPy
|
||||
#######################
|
||||
TABLE_DIRECT.update({
|
||||
# "assert" and "assert_expr" are added via transform rules.
|
||||
"assert": ("%|assert %c\n", (0, "assert_expr")),
|
||||
"assert2": ("%|assert %c, %c\n", (0, "assert_expr"), 3),
|
||||
|
||||
|
@@ -123,6 +123,8 @@ def customize_for_version35(self, version):
|
||||
self.n_build_list_unpack = n_build_list_unpack
|
||||
|
||||
def n_call(node):
|
||||
p = self.prec
|
||||
self.prec = 100
|
||||
mapping = self._get_mapping(node)
|
||||
table = mapping[0]
|
||||
key = node
|
||||
@@ -159,7 +161,7 @@ def customize_for_version35(self, version):
|
||||
kwargs = (argc >> 8) & 0xFF
|
||||
# FIXME: handle annotation args
|
||||
if nargs > 0:
|
||||
template = ("%c(%C, ", 0, (1, nargs + 1, ", "))
|
||||
template = ("%c(%P, ", 0, (1, nargs + 1, ", ", 100))
|
||||
else:
|
||||
template = ("%c(", 0)
|
||||
self.template_engine(template, node)
|
||||
@@ -172,14 +174,16 @@ def customize_for_version35(self, version):
|
||||
self.template_engine(template, args_node)
|
||||
else:
|
||||
if len(node) - nargs > 3:
|
||||
template = ("*%c, %C)", nargs + 1, (nargs + kwargs + 1, -1, ", "))
|
||||
template = ("*%c, %P)", nargs + 1, (nargs + kwargs + 1, -1, ", ", 100))
|
||||
else:
|
||||
template = ("*%c)", nargs + 1)
|
||||
self.template_engine(template, node)
|
||||
self.prec = p
|
||||
self.prune()
|
||||
else:
|
||||
gen_function_parens_adjust(key, node)
|
||||
|
||||
self.prec = 100
|
||||
self.default(node)
|
||||
|
||||
self.n_call = n_call
|
||||
|
@@ -171,6 +171,8 @@ from uncompyle6.semantics.consts import (
|
||||
|
||||
|
||||
from uncompyle6.show import maybe_show_tree
|
||||
from uncompyle6.util import better_repr
|
||||
|
||||
|
||||
if PYTHON3:
|
||||
from io import StringIO
|
||||
@@ -565,6 +567,9 @@ class SourceWalker(GenericASTTraversal, object):
|
||||
if n == "LOAD_CONST" and repr(n.pattr)[0] == "-":
|
||||
self.prec = 6
|
||||
|
||||
# print(n.kind, p, "<", self.prec)
|
||||
# print(self.f.getvalue())
|
||||
|
||||
if p < self.prec:
|
||||
self.write("(")
|
||||
self.preorder(node[0])
|
||||
@@ -608,7 +613,7 @@ class SourceWalker(GenericASTTraversal, object):
|
||||
for item in tup:
|
||||
self.write(sep)
|
||||
l += len(sep)
|
||||
s = repr(item)
|
||||
s = better_repr(item)
|
||||
l += len(s)
|
||||
self.write(s)
|
||||
sep = ","
|
||||
@@ -627,22 +632,10 @@ class SourceWalker(GenericASTTraversal, object):
|
||||
attr = node.attr
|
||||
data = node.pattr
|
||||
datatype = type(data)
|
||||
if isinstance(data, float) and str(data) in frozenset(
|
||||
["nan", "-nan", "inf", "-inf"]
|
||||
):
|
||||
# float values 'nan' and 'inf' are not directly
|
||||
# representable in Python before Python 3.5. In Python 3.5
|
||||
# it is accessible via a library constant math.inf. So we
|
||||
# will canonicalize representation of these value as
|
||||
# float('nan') and float('inf')
|
||||
self.write("float('%s')" % data)
|
||||
elif isinstance(data, complex) and str(data.imag) in frozenset(
|
||||
["nan", "-nan", "inf", "-inf"]
|
||||
):
|
||||
# Likewise, complex values with 'nan' and 'inf' are not
|
||||
# directly representable in Python. So we will
|
||||
# canonicalize like we did above.
|
||||
self.write("complex('%s%sj')" % (data.real, data.imag))
|
||||
if isinstance(data, float) :
|
||||
self.write(better_repr(data))
|
||||
elif isinstance(data, complex):
|
||||
self.write(better_repr(data))
|
||||
elif isinstance(datatype, int) and data == minint:
|
||||
# convert to hex, since decimal representation
|
||||
# would result in 'LOAD_CONST; UNARY_NEGATIVE'
|
||||
|
@@ -121,9 +121,9 @@ class TreeTransform(GenericASTTraversal, object):
|
||||
assert jump_cond == "jmp_false"
|
||||
kind = "assert2not"
|
||||
|
||||
if call[0] != "LOAD_ASSERT":
|
||||
LOAD_ASSERT = call[0].first_child()
|
||||
if LOAD_ASSERT != "LOAD_ASSERT":
|
||||
return node
|
||||
LOAD_ASSERT = call[0]
|
||||
if isinstance(call[1], SyntaxTree):
|
||||
expr = call[1][0]
|
||||
node = SyntaxTree(
|
||||
|
Reference in New Issue
Block a user