[pypy-commit] pypy py3.5: Use ast.NameConstant instead of ast.Name for None/True/False

arigo pypy.commits at gmail.com
Tue Sep 13 11:41:00 EDT 2016


Author: Armin Rigo <arigo at tunes.org>
Branch: py3.5
Changeset: r87081:19e8fc8dcfd0
Date: 2016-09-13 17:39 +0200
http://bitbucket.org/pypy/pypy/changeset/19e8fc8dcfd0/

Log:	Use ast.NameConstant instead of ast.Name for None/True/False (that
	class was not used so far)

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
@@ -1194,9 +1194,19 @@
         first_child = atom_node.get_child(0)
         first_child_type = first_child.type
         if first_child_type == tokens.NAME:
-            name = self.new_identifier(first_child.get_value())
-            return ast.Name(name, ast.Load, first_child.get_lineno(),
-                            first_child.get_column())
+            name = first_child.get_value()
+            if name == "None":
+                w_singleton = self.space.w_None
+            elif name == "True":
+                w_singleton = self.space.w_True
+            elif name == "False":
+                w_singleton = self.space.w_False
+            else:
+                name = self.new_identifier(name)
+                return ast.Name(name, ast.Load, first_child.get_lineno(),
+                                first_child.get_column())
+            return ast.NameConstant(w_singleton, first_child.get_lineno(),
+                                first_child.get_column())
         elif first_child_type == tokens.STRING:
             space = self.space
             encoding = self.compile_info.encoding
diff --git a/pypy/interpreter/astcompiler/asthelpers.py b/pypy/interpreter/astcompiler/asthelpers.py
--- a/pypy/interpreter/astcompiler/asthelpers.py
+++ b/pypy/interpreter/astcompiler/asthelpers.py
@@ -22,15 +22,19 @@
 class __extend__(ast.expr):
 
     constant = False
+    _description = None
 
     def as_node_list(self, space):
         return None
 
     def set_context(self, ctx):
+        d = self._description
+        if d is None:
+            d = "%r" % (self,)
         if ctx == ast.Del:
-            msg = "can't delete %s" % (self._description,)
+            msg = "can't delete %s" % (d,)
         else:
-            msg = "can't assign to %s" % (self._description,)
+            msg = "can't assign to %s" % (d,)
         raise UnacceptableExpressionContext(self, msg)
 
 
@@ -174,3 +178,9 @@
 
     _description = "Ellipsis"
     constant = True
+
+
+class __extend__(ast.NameConstant):
+
+    _description = "name constant"
+    constant = True
diff --git a/pypy/interpreter/astcompiler/codegen.py b/pypy/interpreter/astcompiler/codegen.py
--- a/pypy/interpreter/astcompiler/codegen.py
+++ b/pypy/interpreter/astcompiler/codegen.py
@@ -1271,6 +1271,10 @@
         self.update_position(name.lineno)
         self.name_op(name.id, name.ctx)
 
+    def visit_NameConstant(self, node):
+        self.update_position(node.lineno)
+        self.load_const(node.single)
+
     def visit_keyword(self, keyword):
         if keyword.arg is not None:
             self.load_const(self.space.wrap(keyword.arg.decode('utf-8')))
diff --git a/pypy/interpreter/astcompiler/optimize.py b/pypy/interpreter/astcompiler/optimize.py
--- a/pypy/interpreter/astcompiler/optimize.py
+++ b/pypy/interpreter/astcompiler/optimize.py
@@ -67,6 +67,11 @@
     def as_constant(self):
         return self.obj
 
+class __extend__(ast.NameConstant):
+
+    def as_constant(self):
+        return self.single
+
 class __extend__(ast.Index):
     def as_constant(self):
         return self.value.as_constant()
diff --git a/pypy/interpreter/astcompiler/test/test_validate.py b/pypy/interpreter/astcompiler/test/test_validate.py
--- a/pypy/interpreter/astcompiler/test/test_validate.py
+++ b/pypy/interpreter/astcompiler/test/test_validate.py
@@ -390,9 +390,21 @@
     def test_tuple(self):
         self._sequence(ast.Tuple)
 
+    def test_nameconstant(self):
+        node = ast.NameConstant("True", 0, 0)
+        self.expr(node, "singleton must be True, False, or None")
+
     def test_stdlib_validates(self):
         stdlib = os.path.join(os.path.dirname(ast.__file__), '../../../lib-python/3')
-        tests = ["os.py", "test/test_grammar.py", "test/test_unpack_ex.py"]
+        if 1:    # enable manually for a complete test
+            tests = [fn for fn in os.listdir(stdlib) if fn.endswith('.py')]
+            tests += ['test/'+fn for fn in os.listdir(stdlib+'/test')
+                                 if fn.endswith('.py')
+                                    and not fn.startswith('bad')]
+            tests.sort()
+        else:
+            tests = ["os.py", "test/test_grammar.py", "test/test_unpack_ex.py"]
+        #
         for module in tests:
             fn = os.path.join(stdlib, module)
             print 'compiling', fn
diff --git a/pypy/interpreter/astcompiler/validate.py b/pypy/interpreter/astcompiler/validate.py
--- a/pypy/interpreter/astcompiler/validate.py
+++ b/pypy/interpreter/astcompiler/validate.py
@@ -1,6 +1,6 @@
 """A visitor to validate an AST object."""
 
-from pypy.interpreter.error import OperationError, oefmt
+from pypy.interpreter.error import oefmt
 from pypy.interpreter.astcompiler import ast
 from rpython.tool.pairtype import pair, pairtype
 from pypy.interpreter.baseobjspace import W_Root
@@ -440,3 +440,10 @@
 
     def visit_Index(self, node):
         self._validate_expr(node.value)
+
+    def visit_NameConstant(self, node):
+        space = self.space
+        if (node.single is not space.w_None and
+            node.single is not space.w_True and
+            node.single is not space.w_False):
+            raise ValidationError("singleton must be True, False, or None")
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
@@ -689,10 +689,11 @@
             except NameError:
                 pass
         '''
-        code = self.compiler.compile(snippet, '<tmp>', 'exec', 0)
+        e = py.test.raises(OperationError, self.compiler.compile,
+                snippet, '<tmp>', 'exec', 0)
+        ex = e.value
         space = self.space
-        w_d = space.newdict()
-        space.exec_(code, w_d, w_d)
+        assert ex.match(space, space.w_SyntaxError)
 
     def test_from_future_import(self):
         source = """from __future__ import with_statement


More information about the pypy-commit mailing list