]> granicus.if.org Git - python/commitdiff
More unparse.py fixes:
authorMark Dickinson <dickinsm@gmail.com>
Tue, 29 Jun 2010 10:01:48 +0000 (10:01 +0000)
committerMark Dickinson <dickinsm@gmail.com>
Tue, 29 Jun 2010 10:01:48 +0000 (10:01 +0000)
 - parenthesize lambdas, to avoid turning (lambda : int)() into lambda: int()
 - unparse an infinite float literals in the AST as an overflowing finite value

unparse.py now successfully round-trips on all valid Lib/*.py and Lib/test/*.py files.

Demo/parser/test_unparse.py
Demo/parser/unparse.py

index 0d138973b3a702e0764ca9dffb27ee985623d7c8..b0a773dc4953fd9fb5aab9ea6f2ec8d595cd4726 100644 (file)
@@ -87,6 +87,13 @@ class UnparseTestCase(unittest.TestCase):
     def test_integer_parens(self):
         self.check_roundtrip("3 .__abs__()")
 
+    def test_huge_float(self):
+        self.check_roundtrip("1e1000")
+        self.check_roundtrip("-1e1000")
+
+    def test_lambda_parentheses(self):
+        self.check_roundtrip("(lambda: int)()")
+
     def test_chained_comparisons(self):
         self.check_roundtrip("1 < 4 <= 5")
         self.check_roundtrip("a is b is c is not d")
index 2c383a5eaced94daeb62b50bfecf67ed8806e69e..048f8ca43204dd2b6bf7f50df8096b5a59f26d4e 100644 (file)
@@ -1,5 +1,6 @@
 "Usage: unparse.py <path to source file>"
 import sys
+import math
 import ast
 import tokenize
 import io
@@ -302,17 +303,22 @@ class Unparser:
         self.write("`")
 
     def _Num(self, t):
-        # Add parentheses around numeric literals to avoid:
-        #
-        #  (1) turning (-1)**2 into -1**2, and
-        #  (2) turning 3 .__abs__() into 3.__abs__()
-        #
-        # For (1), note that Python doesn't actually have negative
-        # numeric literals, but (at least in Python 2.x) there's a CST
-        # transformation that can produce negative Nums in the AST.
-        self.write("(")
-        self.write(repr(t.n))
-        self.write(")")
+        if isinstance(t.n, float):
+            # A float literal should be nonnegative, and not a nan.
+            # It could be an infinity, though; in that case we
+            # substitute an overflowing decimal value.
+            assert not math.isnan(t.n)
+            assert math.copysign(1.0, t.n) > 0.0
+            if math.isinf(t.n):
+                self.write("1e" + repr(sys.float_info.max_10_exp + 1))
+            else:
+                self.write(repr(t.n))
+        else:
+            # Parenthesize integer literals to avoid turning
+            # "3 .__abs__()" into "3.__abs__()".
+            self.write("(")
+            self.write(repr(t.n))
+            self.write(")")
 
     def _List(self, t):
         self.write("[")
@@ -539,10 +545,12 @@ class Unparser:
         self.dispatch(t.value)
 
     def _Lambda(self, t):
+        self.write("(")
         self.write("lambda ")
         self.dispatch(t.args)
         self.write(": ")
         self.dispatch(t.body)
+        self.write(")")
 
     def _alias(self, t):
         self.write(t.name)