[pypy-commit] pypy py3k: Fix parsing of complex literals:

amauryfa noreply at buildbot.pypy.org
Sun Apr 28 16:37:17 CEST 2013


Author: Amaury Forgeot d'Arc <amauryfa at gmail.com>
Branch: py3k
Changeset: r63721:b76887f8dc72
Date: 2013-04-28 16:35 +0200
http://bitbucket.org/pypy/pypy/changeset/b76887f8dc72/

Log:	Fix parsing of complex literals:
	- complex('-1j') is parsed as 0-1j
	- unary minus should not be parsed with the numeric literal:
	  -1 is parsed as -(1), -1j is parsed as -(1j)
	- Unary minus will be constant-folded, but as an optimization pass
	on the tree.

	Yes, this means that -1j is now (-0-1j) and complex(-1j) is not
	identical to complex('-1j').

	Even more obscure: >>> -1j (-0-1j) >>> (-0-1j)
	   -1j

diff --git a/pypy/interpreter/astcompiler/astbuilder.py b/pypy/interpreter/astcompiler/astbuilder.py
--- a/pypy/interpreter/astcompiler/astbuilder.py
+++ b/pypy/interpreter/astcompiler/astbuilder.py
@@ -902,19 +902,6 @@
         return result
 
     def handle_factor(self, factor_node):
-        # Fold '-' on constant numbers.
-        if factor_node.children[0].type == tokens.MINUS and \
-                len(factor_node.children) == 2:
-            factor = factor_node.children[1]
-            if factor.type == syms.factor and len(factor.children) == 1:
-                power = factor.children[0]
-                if power.type == syms.power and len(power.children) == 1:
-                    atom = power.children[0]
-                    if atom.type == syms.atom and \
-                            atom.children[0].type == tokens.NUMBER:
-                        num = atom.children[0]
-                        num.value = "-" + num.value
-                        return self.handle_atom(atom)
         expr = self.handle_expr(factor_node.children[1])
         op_type = factor_node.children[0].type
         if op_type == tokens.PLUS:
diff --git a/pypy/interpreter/astcompiler/test/test_astbuilder.py b/pypy/interpreter/astcompiler/test/test_astbuilder.py
--- a/pypy/interpreter/astcompiler/test/test_astbuilder.py
+++ b/pypy/interpreter/astcompiler/test/test_astbuilder.py
@@ -1200,11 +1200,6 @@
         assert space.eq_w(get_num("0X53"), space.wrap(0x53))
         assert space.eq_w(get_num("0"), space.wrap(0))
         assert space.eq_w(get_num("00000"), space.wrap(0))
-        assert space.eq_w(get_num("-3"), space.wrap(-3))
-        assert space.eq_w(get_num("-0"), space.wrap(0))
-        assert space.eq_w(get_num("-0xAAAAAA"), space.wrap(-0xAAAAAAL))
-        n = get_num(str(-sys.maxint - 1))
-        assert space.isinstance_w(n, space.w_int)
         for num in ("0o53", "0O53", "0o0000053", "0O00053"):
             assert space.eq_w(get_num(num), space.wrap(053))
         for num in ("0b00101", "0B00101", "0b101", "0B101"):
diff --git a/pypy/interpreter/test/test_compiler.py b/pypy/interpreter/test/test_compiler.py
--- a/pypy/interpreter/test/test_compiler.py
+++ b/pypy/interpreter/test/test_compiler.py
@@ -741,9 +741,9 @@
         import math
         code = compile("x = -0.0; y = 0.0", "<test>", "exec")
         consts = code.co_consts
-        x, y, z = consts
-        assert isinstance(x, float) and isinstance(y, float)
-        assert math.copysign(1, x) != math.copysign(1, y)
+        x, y = consts
+        assert isinstance(x, float)
+        assert math.copysign(1, x) == 1
         ns = {}
         exec("z1, z2 = 0j, -0j", ns)
         assert math.atan2(ns["z1"].imag, -1.) == math.atan2(0., -1.)
diff --git a/pypy/objspace/std/complextype.py b/pypy/objspace/std/complextype.py
--- a/pypy/objspace/std/complextype.py
+++ b/pypy/objspace/std/complextype.py
@@ -71,10 +71,7 @@
                 imagpart = '-1.0'
             else:
                 imagpart = s[realstart:newstop]
-            if imagpart[0] == '-':
-                return '-0.0', imagpart
-            else:
-                return '0.0', imagpart
+            return '0.0', imagpart
         else:
             return s[realstart:realstop], '0.0'
 
diff --git a/pypy/objspace/std/test/test_complexobject.py b/pypy/objspace/std/test/test_complexobject.py
--- a/pypy/objspace/std/test/test_complexobject.py
+++ b/pypy/objspace/std/test/test_complexobject.py
@@ -44,7 +44,7 @@
         test_cparse('(1-6j)', '1', '-6')
         test_cparse(' ( +3.14-6J )', '+3.14', '-6')
         test_cparse(' +J', '0.0', '1.0')
-        test_cparse(' -J', '-0.0', '-1.0')
+        test_cparse(' -J', '0.0', '-1.0')
 
     def test_unpackcomplex(self):
         space = self.space
@@ -135,6 +135,23 @@
             else:
                 return a - b < eps
 
+    def w_floats_identical(self, x, y):
+        from math import isnan, copysign
+        msg = 'floats {!r} and {!r} are not identical'
+
+        if isnan(x) or isnan(y):
+            if isnan(x) and isnan(y):
+                return
+        elif x == y:
+            if x != 0.0:
+                return
+            # both zero; check that signs match
+            elif copysign(1.0, x) == copysign(1.0, y):
+                return
+            else:
+                msg += ': zeros have different signs'
+        assert False, msg.format(x, y)
+
     def test_div(self):
         from random import random
         # XXX this test passed but took waaaaay to long
@@ -420,6 +437,36 @@
         assert repr(complex(1e200*1e200)) == '(inf+0j)'
         assert repr(complex(1,-float("nan"))) == '(1+nanj)'
 
+    def test_repr_roundtrip(self):
+        # Copied from CPython
+        INF = float("inf")
+        NAN = float("nan")
+        vals = [0.0, 1e-500, 1e-315, 1e-200, 0.0123, 3.1415, 1e50, INF, NAN]
+        vals += [-v for v in vals]
+
+        # complex(repr(z)) should recover z exactly, even for complex
+        # numbers involving an infinity, nan, or negative zero
+        for x in vals:
+            for y in vals:
+                z = complex(x, y)
+                roundtrip = complex(repr(z))
+                self.floats_identical(z.real, roundtrip.real)
+                self.floats_identical(z.imag, roundtrip.imag)
+
+        # if we predefine some constants, then eval(repr(z)) should
+        # also work, except that it might change the sign of zeros
+        inf, nan = float('inf'), float('nan')
+        infj, nanj = complex(0.0, inf), complex(0.0, nan)
+        for x in vals:
+            for y in vals:
+                z = complex(x, y)
+                roundtrip = eval(repr(z))
+                # adding 0.0 has no effect beside changing -0.0 to 0.0
+                self.floats_identical(0.0 + z.real,
+                                      0.0 + roundtrip.real)
+                self.floats_identical(0.0 + z.imag,
+                                      0.0 + roundtrip.imag)
+
     def test_neg(self):
         assert -(1+6j) == -1-6j
 


More information about the pypy-commit mailing list