Author: Ronan Lamy <ronan.l...@gmail.com>
Branch: py3.5
Changeset: r90412:0436a099e10a
Date: 2017-02-28 09:58 +0000
http://bitbucket.org/pypy/pypy/changeset/0436a099e10a/

Log:    Merged in robert-zaremba/pypy/py3.5-fix-globals (pull request #521)

        (stevie, robert-zaremba)

        Approved-by: Richard Plangger

diff --git a/pypy/interpreter/astcompiler/symtable.py 
b/pypy/interpreter/astcompiler/symtable.py
--- a/pypy/interpreter/astcompiler/symtable.py
+++ b/pypy/interpreter/astcompiler/symtable.py
@@ -8,7 +8,7 @@
 # These are for internal use only:
 SYM_BLANK = 0
 SYM_GLOBAL = 1
-SYM_ASSIGNED = 2 # Or deleted actually.
+SYM_ASSIGNED = 2  # (DEF_LOCAL in CPython3). Or deleted actually.
 SYM_PARAM = 2 << 1
 SYM_NONLOCAL = 2 << 2
 SYM_USED = 2 << 3
@@ -123,12 +123,6 @@
     def _finalize_name(self, name, flags, local, bound, free, globs):
         """Decide on the scope of a name."""
         if flags & SYM_GLOBAL:
-            if flags & SYM_PARAM:
-                err = "name '%s' is parameter and global" % (name,)
-                raise SyntaxError(err, self.lineno, self.col_offset)
-            if flags & SYM_NONLOCAL:
-                err = "name '%s' is nonlocal and global" % (name,)
-                raise SyntaxError(err, self.lineno, self.col_offset)
             self.symbols[name] = SCOPE_GLOBAL_EXPLICIT
             globs[name] = None
             if bound:
@@ -137,12 +131,6 @@
                 except KeyError:
                     pass
         elif flags & SYM_NONLOCAL:
-            if flags & SYM_PARAM:
-                err = "name '%s' is parameter and nonlocal" % (name,)
-                raise SyntaxError(err, self.lineno, self.col_offset)
-            if bound is None:
-                err = "nonlocal declaration not allowed at module level"
-                raise SyntaxError(err, self.lineno, self.col_offset)
             if name not in bound:
                 err = "no binding for nonlocal '%s' found" % (name,)
                 raise SyntaxError(err, self.lineno, self.col_offset)
@@ -293,7 +281,8 @@
 
     def _pass_on_bindings(self, local, bound, globs, new_bound, new_globs):
         new_bound.update(local)
-        Scope._pass_on_bindings(self, local, bound, globs, new_bound, 
new_globs)
+        Scope._pass_on_bindings(self, local, bound, globs, new_bound,
+                                new_globs)
 
     def _finalize_cells(self, free):
         for name, role in self.symbols.iteritems():
@@ -496,20 +485,38 @@
                        "implemented in PyPy")
                 raise SyntaxError(msg, glob.lineno, glob.col_offset,
                                   filename=self.compile_info.filename)
+            if old_role & SYM_PARAM:
+                msg = "name '%s' is parameter and global" % (name,)
+                raise SyntaxError(msg, glob.lineno, glob.col_offset)
+            if old_role & SYM_NONLOCAL:
+                msg = "name '%s' is nonlocal and global" % (name,)
+                raise SyntaxError(msg, glob.lineno, glob.col_offset)
+
             if old_role & (SYM_USED | SYM_ASSIGNED):
                 if old_role & SYM_ASSIGNED:
-                    msg = "name '%s' is assigned to before global declaration" 
\
+                    msg = "name '%s' is assigned to before global declaration"\
                         % (name,)
                 else:
                     msg = "name '%s' is used prior to global declaration" % \
                         (name,)
-                misc.syntax_warning(self.space, msg, 
self.compile_info.filename,
+                misc.syntax_warning(self.space, msg,
+                                    self.compile_info.filename,
                                     glob.lineno, glob.col_offset)
             self.note_symbol(name, SYM_GLOBAL)
 
     def visit_Nonlocal(self, nonl):
         for name in nonl.names:
             old_role = self.scope.lookup_role(name)
+            msg = ""
+            if old_role & SYM_GLOBAL:
+                msg = "name '%s' is nonlocal and global" % (name,)
+            if old_role & SYM_PARAM:
+                msg = "name '%s' is parameter and nonlocal" % (name,)
+            if type(self.scope) == ModuleScope:
+                msg = "nonlocal declaration not allowed at module level"
+            if msg is not "":
+                raise SyntaxError(msg, nonl.lineno, nonl.col_offset)
+
             if (old_role & (SYM_USED | SYM_ASSIGNED) and not
                     (name == '__class__' and
                      self.scope._hide_bound_from_nested_scopes)):
@@ -519,8 +526,10 @@
                 else:
                     msg = "name '%s' is used prior to nonlocal declaration" % \
                         (name,)
-                misc.syntax_warning(self.space, msg, 
self.compile_info.filename,
+                misc.syntax_warning(self.space, msg,
+                                    self.compile_info.filename,
                                     nonl.lineno, nonl.col_offset)
+
             self.note_symbol(name, SYM_NONLOCAL)
 
     def visit_Lambda(self, lamb):
@@ -589,7 +598,7 @@
 
     def visit_arguments(self, arguments):
         scope = self.scope
-        assert isinstance(scope, FunctionScope) # Annotator hint.
+        assert isinstance(scope, FunctionScope)  # Annotator hint.
         if arguments.args:
             self._handle_params(arguments.args, True)
         if arguments.kwonlyargs:
diff --git a/pypy/interpreter/astcompiler/test/test_symtable.py 
b/pypy/interpreter/astcompiler/test/test_symtable.py
--- a/pypy/interpreter/astcompiler/test/test_symtable.py
+++ b/pypy/interpreter/astcompiler/test/test_symtable.py
@@ -283,7 +283,6 @@
     def test_global(self):
         scp = self.func_scope("def f():\n   global x\n   x = 4")
         assert scp.lookup("x") == symtable.SCOPE_GLOBAL_EXPLICIT
-        input = "def f(x):\n   global x"
         scp = self.func_scope("""def f():
     y = 3
     def x():
@@ -295,18 +294,38 @@
         xscp, zscp = scp.children
         assert xscp.lookup("y") == symtable.SCOPE_GLOBAL_EXPLICIT
         assert zscp.lookup("y") == symtable.SCOPE_FREE
-        exc = py.test.raises(SyntaxError, self.func_scope, input).value
+
+        src = "def f(x):\n   global x"
+        exc = py.test.raises(SyntaxError, self.func_scope, src).value
+        assert exc.lineno == 2
         assert exc.msg == "name 'x' is parameter and global"
 
+    def test_global_nested(self):
+        src = """
+def f(x):
+    def g(x):
+        global x"""
+        exc = py.test.raises(SyntaxError, self.func_scope, src).value
+        assert exc.lineno == 4
+        assert exc.msg == "name 'x' is parameter and global"
+
+        scp = self.func_scope("""
+def f(x):
+    def g():
+        global x""")
+        g = scp.children[0]
+        assert g.name == 'g'
+        x = g.lookup_role('x')
+        assert x == symtable.SYM_GLOBAL
+
     def test_nonlocal(self):
-        src = str(py.code.Source("""
-                     def f():
-                         nonlocal x
-                         global x
-                 """))
+        src = """
+x = 1
+def f():
+    nonlocal x"""
         exc = py.test.raises(SyntaxError, self.func_scope, src).value
-        assert exc.msg == "name 'x' is nonlocal and global"
-        #
+        assert exc.msg == "no binding for nonlocal 'x' found"
+
         src = str(py.code.Source("""
                      def f(x):
                          nonlocal x
@@ -324,6 +343,58 @@
         src = "nonlocal x"
         exc = py.test.raises(SyntaxError, self.func_scope, src).value
         assert exc.msg == "nonlocal declaration not allowed at module level"
+        assert exc.lineno == 1
+
+        src = "x = 2\nnonlocal x"
+        exc = py.test.raises(SyntaxError, self.func_scope, src).value
+        assert exc.msg == "nonlocal declaration not allowed at module level"
+        assert exc.lineno == 2
+
+    def test_nonlocal_and_global(self):
+        """This test differs from CPython3 behaviour. CPython points to the
+        first occurance of the global/local expression. PyPy will point to the
+        last expression which makes the problem."""
+        src = """
+def f():
+    nonlocal x
+    global x"""
+        exc = py.test.raises(SyntaxError, self.func_scope, src).value
+        assert exc.msg == "name 'x' is nonlocal and global"
+        assert exc.lineno == 4
+
+        src = """
+def f():
+    global x
+    nonlocal x """
+        exc = py.test.raises(SyntaxError, self.func_scope, src).value
+        assert exc.msg == "name 'x' is nonlocal and global"
+        assert exc.lineno == 4
+
+    def test_nonlocal_nested(self):
+        scp = self.func_scope("""
+def f(x):
+    def g():
+        nonlocal x""")
+        g = scp.children[0]
+        x = g.lookup_role('x')
+        assert x == symtable.SYM_NONLOCAL
+
+        scp = self.func_scope("""
+def f():
+    def g():
+        nonlocal x
+    x = 1""")
+        g = scp.children[0]
+        x = g.lookup_role('x')
+        assert x == symtable.SYM_NONLOCAL
+
+        src = """
+def f(x):
+    def g(x):
+        nonlocal x"""
+        exc = py.test.raises(SyntaxError, self.func_scope, src).value
+        assert exc.msg == "name 'x' is parameter and nonlocal"
+        assert exc.lineno == 4
 
     def test_optimization(self):
         assert not self.mod_scope("").can_be_optimized
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to