diff --git a/pytest/test_grammar.py b/pytest/test_grammar.py index 5248d8a1..0978553c 100644 --- a/pytest/test_grammar.py +++ b/pytest/test_grammar.py @@ -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) diff --git a/test/simple_source/bug31/10_complex.py b/test/simple_source/bug31/10_complex.py index 7f1b29b3..62c0d463 100644 --- a/test/simple_source/bug31/10_complex.py +++ b/test/simple_source/bug31/10_complex.py @@ -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() diff --git a/test/stdlib/runtests.sh b/test/stdlib/runtests.sh index 617df0da..071ad332 100755 --- a/test/stdlib/runtests.sh +++ b/test/stdlib/runtests.sh @@ -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 diff --git a/uncompyle6/parsers/parse37.py b/uncompyle6/parsers/parse37.py index 007dcccd..3c405733 100644 --- a/uncompyle6/parsers/parse37.py +++ b/uncompyle6/parsers/parse37.py @@ -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 diff --git a/uncompyle6/parsers/parse37base.py b/uncompyle6/parsers/parse37base.py index c7f169a1..9a6a8afb 100644 --- a/uncompyle6/parsers/parse37base.py +++ b/uncompyle6/parsers/parse37base.py @@ -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, """, diff --git a/uncompyle6/semantics/consts.py b/uncompyle6/semantics/consts.py index 76b7f705..15150cf4 100644 --- a/uncompyle6/semantics/consts.py +++ b/uncompyle6/semantics/consts.py @@ -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, diff --git a/uncompyle6/semantics/customize.py b/uncompyle6/semantics/customize.py index 99b642c4..f632fac8 100644 --- a/uncompyle6/semantics/customize.py +++ b/uncompyle6/semantics/customize.py @@ -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), diff --git a/uncompyle6/semantics/customize35.py b/uncompyle6/semantics/customize35.py index 6e2cd770..587eadc5 100644 --- a/uncompyle6/semantics/customize35.py +++ b/uncompyle6/semantics/customize35.py @@ -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 diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index b2876d1c..6b146a91 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -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' diff --git a/uncompyle6/semantics/transform.py b/uncompyle6/semantics/transform.py index d521f7c5..3a0fafe8 100644 --- a/uncompyle6/semantics/transform.py +++ b/uncompyle6/semantics/transform.py @@ -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(