diff options
author | Jeremy Hylton <jeremy@alum.mit.edu> | 2007-02-27 06:50:52 (GMT) |
---|---|---|
committer | Jeremy Hylton <jeremy@alum.mit.edu> | 2007-02-27 06:50:52 (GMT) |
commit | 81e9502df69394821416309c7c4b5357af51f4d5 (patch) | |
tree | ad38831cbebfb32890c0c57cb8b36f653300c69f /Python/symtable.c | |
parent | 8b41c3dc28a16da97af50cc5f7b884db2cea7b0c (diff) | |
download | cpython-81e9502df69394821416309c7c4b5357af51f4d5.zip cpython-81e9502df69394821416309c7c4b5357af51f4d5.tar.gz cpython-81e9502df69394821416309c7c4b5357af51f4d5.tar.bz2 |
Provisional implementation of PEP 3104.
Add nonlocal_stmt to Grammar and Nonlocal node to AST. They both
parallel the definitions for globals. The symbol table treats
variables declared as nonlocal just like variables that are free
implicitly.
This change is missing the language spec changes, but makes some
decisions about what the spec should say via the unittests. The PEP
is silent on a number of decisions, so we should review those before
claiming that nonlocal is complete.
Thomas Wouters made the grammer and ast changes. Jeremy Hylton added
the symbol table changes and the tests. Pete Shinners and Neal
Norwitz helped review the code.
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 1d76e0d..5bac2a2 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; |