diff options
Diffstat (limited to 'Python/symtable.c')
-rw-r--r-- | Python/symtable.c | 77 |
1 files changed, 66 insertions, 11 deletions
diff --git a/Python/symtable.c b/Python/symtable.c index 1d76e0d025..5bac2a2c9e 100644 --- a/Python/symtable.c +++ b/Python/symtable.c @@ -8,9 +8,15 @@ #define GLOBAL_AFTER_ASSIGN \ "name '%.400s' is assigned to before global declaration" +#define NONLOCAL_AFTER_ASSIGN \ +"name '%.400s' is assigned to before nonlocal declaration" + #define GLOBAL_AFTER_USE \ "name '%.400s' is used prior to global declaration" +#define NONLOCAL_AFTER_USE \ +"name '%.400s' is used prior to nonlocal declaration" + #define IMPORT_STAR_WARNING "import * only allowed at module level" #define RETURN_VAL_IN_GENERATOR \ @@ -328,6 +334,8 @@ PyST_GetScope(PySTEntryObject *ste, PyObject *name) block, the name is treated as global until it is assigned to; then it is treated as a local. + TODO(jhylton): Discuss nonlocal + The symbol table requires two passes to determine the scope of each name. The first pass collects raw facts from the AST: the name is a parameter here, the name is used by not defined here, etc. The second pass analyzes @@ -378,6 +386,12 @@ analyze_name(PySTEntryObject *ste, PyObject *dict, PyObject *name, long flags, PyString_AS_STRING(name)); return 0; } + if (flags & DEF_NONLOCAL) { + PyErr_Format(PyExc_SyntaxError, + "name '%s' is nonlocal and global", + PyString_AS_STRING(name)); + return 0; + } SET_SCOPE(dict, name, GLOBAL_EXPLICIT); if (PyDict_SetItem(global, name, Py_None) < 0) return 0; @@ -387,6 +401,24 @@ analyze_name(PySTEntryObject *ste, PyObject *dict, PyObject *name, long flags, } return 1; } + if (flags & DEF_NONLOCAL) { + if (flags & DEF_PARAM) { + PyErr_Format(PyExc_SyntaxError, + "name '%s' is local and nonlocal", + PyString_AS_STRING(name)); + return 0; + } + if (!PyDict_GetItem(bound, name)) { + PyErr_Format(PyExc_SyntaxError, + "no binding for nonlocal '%s' found", + PyString_AS_STRING(name)); + + return 0; + } + SET_SCOPE(dict, name, FREE); + ste->ste_free = 1; + return PyDict_SetItem(free, name, Py_None) >= 0; + } if (flags & DEF_BOUND) { SET_SCOPE(dict, name, LOCAL); if (PyDict_SetItem(local, name, Py_None) < 0) @@ -405,24 +437,19 @@ analyze_name(PySTEntryObject *ste, PyObject *dict, PyObject *name, long flags, if (bound && PyDict_GetItem(bound, name)) { SET_SCOPE(dict, name, FREE); ste->ste_free = 1; - if (PyDict_SetItem(free, name, Py_None) < 0) - return 0; - return 1; + return PyDict_SetItem(free, name, Py_None) >= 0; } /* If a parent has a global statement, then call it global explicit? It could also be global implicit. */ - else if (global && PyDict_GetItem(global, name)) { + if (global && PyDict_GetItem(global, name)) { SET_SCOPE(dict, name, GLOBAL_EXPLICIT); return 1; } - else { - if (ste->ste_nested) - ste->ste_free = 1; - SET_SCOPE(dict, name, GLOBAL_IMPLICIT); - return 1; - } - return 0; /* Can't get here */ + if (ste->ste_nested) + ste->ste_free = 1; + SET_SCOPE(dict, name, GLOBAL_IMPLICIT); + return 1; } #undef SET_SCOPE @@ -782,6 +809,7 @@ symtable_add_def(struct symtable *st, PyObject *name, int flag) long val; PyObject *mangled = _Py_Mangle(st->st_private, name); + if (!mangled) return 0; dict = st->st_cur->ste_symbols; @@ -1075,6 +1103,33 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s) } break; } + case Nonlocal_kind: { + int i; + asdl_seq *seq = s->v.Nonlocal.names; + for (i = 0; i < asdl_seq_LEN(seq); i++) { + identifier name = (identifier)asdl_seq_GET(seq, i); + char *c_name = PyString_AS_STRING(name); + long cur = symtable_lookup(st, name); + if (cur < 0) + return 0; + if (cur & (DEF_LOCAL | USE)) { + char buf[256]; + if (cur & DEF_LOCAL) + PyOS_snprintf(buf, sizeof(buf), + NONLOCAL_AFTER_ASSIGN, + c_name); + else + PyOS_snprintf(buf, sizeof(buf), + NONLOCAL_AFTER_USE, + c_name); + if (!symtable_warn(st, buf, s->lineno)) + return 0; + } + if (!symtable_add_def(st, name, DEF_NONLOCAL)) + return 0; + } + break; + } case Expr_kind: VISIT(st, expr, s->v.Expr.value); break; |