[Python-checkins] cpython: point errors related to nonlocals and globals to the statement declaring them

benjamin.peterson python-checkins at python.org
Thu Nov 1 01:26:50 CET 2012


http://hg.python.org/cpython/rev/fbfaef0a9c00
changeset:   80147:fbfaef0a9c00
parent:      80145:4ca6f43b12ef
user:        Benjamin Peterson <benjamin at python.org>
date:        Wed Oct 31 20:26:20 2012 -0400
summary:
  point errors related to nonlocals and globals to the statement declaring them (closes #10189)

files:
  Include/symtable.h |   1 +
  Misc/NEWS          |   3 +
  Python/symtable.c  |  57 +++++++++++++++++++++++++++++----
  3 files changed, 53 insertions(+), 8 deletions(-)


diff --git a/Include/symtable.h b/Include/symtable.h
--- a/Include/symtable.h
+++ b/Include/symtable.h
@@ -39,6 +39,7 @@
     PyObject *ste_name;      /* string: name of current block */
     PyObject *ste_varnames;  /* list of function parameters */
     PyObject *ste_children;  /* list of child blocks */
+    PyObject *ste_directives;/* locations of global and nonlocal statements */
     _Py_block_ty ste_type;   /* module, class, or function */
     int ste_unoptimized;     /* false if namespace is optimized */
     int ste_nested;      /* true if block is nested */
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,9 @@
 Core and Builtins
 -----------------
 
+- Issue #10189: Improve the error reporting of SyntaxErrors related to global
+  and nonlocal statements.
+
 - Issue #16086: PyTypeObject.tp_flags and PyType_Spec.flags are now unsigned
   (unsigned long and unsigned int) to avoid an undefined behaviour with
   Py_TPFLAGS_TYPE_SUBCLASS ((1 << 31). PyType_GetFlags() result type is
diff --git a/Python/symtable.c b/Python/symtable.c
--- a/Python/symtable.c
+++ b/Python/symtable.c
@@ -56,6 +56,8 @@
     if (ste->ste_children == NULL)
         goto fail;
 
+    ste->ste_directives = NULL;
+
     ste->ste_type = block;
     ste->ste_unoptimized = 0;
     ste->ste_nested = 0;
@@ -102,6 +104,7 @@
     Py_XDECREF(ste->ste_symbols);
     Py_XDECREF(ste->ste_varnames);
     Py_XDECREF(ste->ste_children);
+    Py_XDECREF(ste->ste_directives);
     PyObject_Del(ste);
 }
 
@@ -319,6 +322,24 @@
     return (PyLong_AS_LONG(v) >> SCOPE_OFFSET) & SCOPE_MASK;
 }
 
+static int
+error_at_directive(PySTEntryObject *ste, PyObject *name)
+{
+    Py_ssize_t i;
+    PyObject *data;
+    assert(ste->ste_directives);
+    for (i = 0; ; i++) {
+        data = PyList_GET_ITEM(ste->ste_directives, i);
+        assert(PyTuple_CheckExact(data));
+        if (PyTuple_GET_ITEM(data, 0) == name)
+            break;
+    }
+    PyErr_SyntaxLocationEx(ste->ste_table->st_filename,
+                           PyLong_AsLong(PyTuple_GET_ITEM(data, 1)),
+                           PyLong_AsLong(PyTuple_GET_ITEM(data, 2)));
+    return 0;
+}
+
 
 /* Analyze raw symbol information to determine scope of each name.
 
@@ -393,16 +414,13 @@
             PyErr_Format(PyExc_SyntaxError,
                         "name '%U' is parameter and global",
                         name);
-            PyErr_SyntaxLocationEx(ste->ste_table->st_filename,
-                                   ste->ste_lineno, ste->ste_col_offset);
-
-            return 0;
+            return error_at_directive(ste, name);
         }
         if (flags & DEF_NONLOCAL) {
             PyErr_Format(PyExc_SyntaxError,
                          "name '%U' is nonlocal and global",
                          name);
-            return 0;
+            return error_at_directive(ste, name);
         }
         SET_SCOPE(scopes, name, GLOBAL_EXPLICIT);
         if (PySet_Add(global, name) < 0)
@@ -416,19 +434,19 @@
             PyErr_Format(PyExc_SyntaxError,
                          "name '%U' is parameter and nonlocal",
                          name);
-            return 0;
+            return error_at_directive(ste, name);
         }
         if (!bound) {
             PyErr_Format(PyExc_SyntaxError,
                          "nonlocal declaration not allowed at module level");
-            return 0;
+            return error_at_directive(ste, name);
         }
         if (!PySet_Contains(bound, name)) {
             PyErr_Format(PyExc_SyntaxError,
                          "no binding for nonlocal '%U' found",
                          name);
 
-            return 0;
+            return error_at_directive(ste, name);
         }
         SET_SCOPE(scopes, name, FREE);
         ste->ste_free = 1;
@@ -1069,6 +1087,25 @@
 
 
 static int
+symtable_record_directive(struct symtable *st, identifier name, stmt_ty s)
+{
+    PyObject *data;
+    int res;
+    if (!st->st_cur->ste_directives) {
+        st->st_cur->ste_directives = PyList_New(0);
+        if (!st->st_cur->ste_directives)
+            return 0;
+    }
+    data = Py_BuildValue("(Oii)", name, s->lineno, s->col_offset);
+    if (!data)
+        return 0;
+    res = PyList_Append(st->st_cur->ste_directives, data);
+    Py_DECREF(data);
+    return res == 0;
+}
+
+
+static int
 symtable_visit_stmt(struct symtable *st, stmt_ty s)
 {
     switch (s->kind) {
@@ -1223,6 +1260,8 @@
             }
             if (!symtable_add_def(st, name, DEF_GLOBAL))
                 return 0;
+            if (!symtable_record_directive(st, name, s))
+                return 0;
         }
         break;
     }
@@ -1252,6 +1291,8 @@
             }
             if (!symtable_add_def(st, name, DEF_NONLOCAL))
                 return 0;
+            if (!symtable_record_directive(st, name, s))
+                return 0;
         }
         break;
     }

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list