Author: Ronan Lamy <[email protected]>
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
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit