[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