Mercurial > cpython-lru_cache-weakref
diff Python/compile.c @ 16781:5a1230de436a legacy-trunk
Preliminary support for future nested scopes
compile.h: #define NESTED_SCOPES_DEFAULT 0 for Python 2.1
__future__ feature name: "nested_scopes"
symtable.h: Add st_nested_scopes slot. Define flags to track exec and
import star.
Lib/test/test_scope.py: requires nested scopes
compile.c: Fiddle with error messages.
Reverse the sense of ste_optimized flag on
PySymtableEntryObjects. If it is true, there is an optimization
conflict.
Modify get_ref_type to respect st_nested_scopes flags.
Refactor symtable_load_symbols() into several smaller functions,
which use struct symbol_info to share variables. In new function
symtable_update_flags(), raise an error or warning for import * or
bare exec that conflicts with nested scopes. Also, modify handle
for free variables to respect st_nested_scopes flag.
In symtable_init() assign st_nested_scopes flag to
NESTED_SCOPES_DEFAULT (defined in compile.h).
Add preliminary and often incorrect implementation of
symtable_check_future().
Add symtable_lookup() helper for future use.
| author | Jeremy Hylton <jeremy@alum.mit.edu> |
|---|---|
| date | Tue, 27 Feb 2001 04:23:34 +0000 |
| parents | 2f585cbe71da |
| children | 4feea99be777 |
line wrap: on
line diff
--- a/Python/compile.c Tue Feb 27 04:21:58 2001 +0000 +++ b/Python/compile.c Tue Feb 27 04:23:34 2001 +0000 @@ -55,6 +55,18 @@ #define ILLEGAL_DYNAMIC_SCOPE \ "%.100s: exec or 'import *' makes names ambiguous in nested scope" +#define UNDEFINED_FUTURE_FEATURE \ +"future feature %.100s is not defined" + +#define GLOBAL_AFTER_ASSIGN \ +"name '%.400s' is assigned to before global declaration" + +#define GLOBAL_AFTER_USE \ +"name '%.400s' is used prior to global declaration" + +#define LOCAL_GLOBAL \ +"name '%.400s' is a function paramter and declared global" + #define MANGLE_LEN 256 #define OFF(x) offsetof(PyCodeObject, x) @@ -424,7 +436,6 @@ set_error_location(c->c_filename, c->c_lineno); } - /* Interface to the block stack */ static void @@ -449,7 +460,6 @@ } } - /* Prototype forward declarations */ static int com_init(struct compiling *, char *); @@ -2106,6 +2116,9 @@ com_make_closure(struct compiling *c, PyCodeObject *co) { int i, free = PyTuple_GET_SIZE(co->co_freevars); + /* If the code is compiled with st->st_nested_scopes == 0, + then no variable will ever be added to co_freevars. + */ if (free == 0) return 0; for (i = 0; i < free; ++i) { @@ -2295,7 +2308,7 @@ if (NCH(n) > 1) { if (assigning > OP_APPLY) { com_error(c, PyExc_SyntaxError, - "augmented assign to tuple not possible"); + "augmented assign to tuple not possible"); return; } com_assign_sequence(c, n, assigning); @@ -3939,18 +3952,31 @@ get_ref_type(struct compiling *c, char *name) { PyObject *v; - if (PyDict_GetItemString(c->c_cellvars, name) != NULL) - return CELL; - if (PyDict_GetItemString(c->c_locals, name) != NULL) - return LOCAL; - if (PyDict_GetItemString(c->c_freevars, name) != NULL) - return FREE; - v = PyDict_GetItemString(c->c_globals, name); - if (v) { - if (v == Py_None) - return GLOBAL_EXPLICIT; - else { - return GLOBAL_IMPLICIT; + if (c->c_symtable->st_nested_scopes) { + if (PyDict_GetItemString(c->c_cellvars, name) != NULL) + return CELL; + if (PyDict_GetItemString(c->c_locals, name) != NULL) + return LOCAL; + if (PyDict_GetItemString(c->c_freevars, name) != NULL) + return FREE; + v = PyDict_GetItemString(c->c_globals, name); + if (v) { + if (v == Py_None) + return GLOBAL_EXPLICIT; + else { + return GLOBAL_IMPLICIT; + } + } + } else { + if (PyDict_GetItemString(c->c_locals, name) != NULL) + return LOCAL; + v = PyDict_GetItemString(c->c_globals, name); + if (v) { + if (v == Py_None) + return GLOBAL_EXPLICIT; + else { + return GLOBAL_IMPLICIT; + } } } { @@ -3984,14 +4010,145 @@ } static int +symtable_init_compiling_symbols(struct compiling *c) +{ + PyObject *varnames; + + varnames = c->c_symtable->st_cur->ste_varnames; + if (varnames == NULL) { + varnames = PyList_New(0); + if (varnames == NULL) + return -1; + c->c_symtable->st_cur->ste_varnames = varnames; + Py_INCREF(varnames); + } else + Py_INCREF(varnames); + c->c_varnames = varnames; + + c->c_globals = PyDict_New(); + if (c->c_globals == NULL) + return -1; + c->c_freevars = PyDict_New(); + if (c->c_freevars == NULL) + return -1; + c->c_cellvars = PyDict_New(); + if (c->c_cellvars == NULL) + return -1; + return 0; +} + +struct symbol_info { + int si_nlocals; + int si_ncells; + int si_nfrees; + int si_nimplicit; +}; + +static void +symtable_init_info(struct symbol_info *si) +{ + si->si_nlocals = 0; + si->si_ncells = 0; + si->si_nfrees = 0; + si->si_nimplicit = 0; +} + +static int +symtable_resolve_free(struct compiling *c, PyObject *name, + struct symbol_info *si) +{ + PyObject *dict, *v; + + /* Seperate logic for DEF_FREE. If it occurs in a function, + it indicates a local that we must allocate storage for (a + cell var). If it occurs in a class, then the class has a + method and a free variable with the same name. + */ + + if (c->c_symtable->st_cur->ste_type == TYPE_FUNCTION) { + v = PyInt_FromLong(si->si_ncells++); + dict = c->c_cellvars; + } else { + v = PyInt_FromLong(si->si_nfrees++); + dict = c->c_freevars; + } + if (v == NULL) + return -1; + if (PyDict_SetItem(dict, name, v) < 0) { + Py_DECREF(v); + return -1; + } + Py_DECREF(v); + return 0; +} + +static int +symtable_freevar_offsets(PyObject *freevars, int offset) +{ + PyObject *name, *v; + int pos; + + /* The cell vars are the first elements of the closure, + followed by the free vars. Update the offsets in + c_freevars to account for number of cellvars. */ + pos = 0; + while (PyDict_Next(freevars, &pos, &name, &v)) { + int i = PyInt_AS_LONG(v) + offset; + PyObject *o = PyInt_FromLong(i); + if (o == NULL) + return -1; + if (PyDict_SetItem(freevars, name, o) < 0) { + Py_DECREF(o); + return -1; + } + Py_DECREF(o); + } + return 0; +} + +static int +symtable_update_flags(struct compiling *c, PySymtableEntryObject *ste, + struct symbol_info *si) +{ + if (ste->ste_type != TYPE_MODULE) + c->c_flags |= CO_NEWLOCALS; + if (ste->ste_type == TYPE_FUNCTION) { + c->c_nlocals = si->si_nlocals; + if (ste->ste_optimized == 0) + c->c_flags |= CO_OPTIMIZED; + else if (si->si_ncells || si->si_nfrees + || (ste->ste_nested && si->si_nimplicit) + || ste->ste_child_free) { + if (c->c_symtable->st_nested_scopes) { + PyErr_Format(PyExc_SyntaxError, + ILLEGAL_DYNAMIC_SCOPE, + PyString_AS_STRING(ste->ste_name)); + set_error_location(c->c_symtable->st_filename, + ste->ste_lineno); + return -1; + } else { + char buf[200]; + sprintf(buf, ILLEGAL_DYNAMIC_SCOPE, + PyString_AS_STRING(ste->ste_name)); + if (PyErr_Warn(PyExc_SyntaxWarning, + buf) < 0) { + return -1; + } + } + } + } + return 0; +} + +static int symtable_load_symbols(struct compiling *c) { static PyObject *implicit = NULL; + struct symtable *st = c->c_symtable; + PySymtableEntryObject *ste = st->st_cur; PyObject *name, *varnames, *v; int i, flags, pos; - int nlocals, nfrees, ncells, nimplicit; - struct symtable *st = c->c_symtable; - PySymtableEntryObject *ste = st->st_cur; + struct symbol_info si; if (implicit == NULL) { implicit = PyInt_FromLong(1); @@ -4000,33 +4157,14 @@ } v = NULL; - varnames = st->st_cur->ste_varnames; - if (varnames == NULL) { - varnames = PyList_New(0); - if (varnames == NULL) - return -1; - ste->ste_varnames = varnames; - Py_INCREF(varnames); - } else - Py_INCREF(varnames); - c->c_varnames = varnames; - - c->c_globals = PyDict_New(); - if (c->c_globals == NULL) + if (symtable_init_compiling_symbols(c) < 0) goto fail; - c->c_freevars = PyDict_New(); - if (c->c_freevars == NULL) - goto fail; - c->c_cellvars = PyDict_New(); - if (c->c_cellvars == NULL) - goto fail; - - nlocals = PyList_GET_SIZE(varnames); - c->c_argcount = nlocals; - nfrees = 0; - ncells = 0; - nimplicit = 0; - for (i = 0; i < nlocals; ++i) { + symtable_init_info(&si); + varnames = st->st_cur->ste_varnames; + si.si_nlocals = PyList_GET_SIZE(varnames); + c->c_argcount = si.si_nlocals; + + for (i = 0; i < si.si_nlocals; ++i) { v = PyInt_FromLong(i); if (PyDict_SetItem(c->c_locals, PyList_GET_ITEM(varnames, i), v) < 0) @@ -4041,32 +4179,12 @@ flags = PyInt_AS_LONG(v); if (flags & DEF_FREE_GLOBAL) - /* undo the original DEF_FREE */ - flags &= ~(DEF_FREE | DEF_FREE_CLASS); - - /* Seperate logic for DEF_FREE. If it occurs in a - function, it indicates a local that we must - allocate storage for (a cell var). If it occurs in - a class, then the class has a method and a free - variable with the same name. - */ + /* undo the original DEF_FREE */ + flags &= ~(DEF_FREE | DEF_FREE_CLASS); if ((flags & (DEF_FREE | DEF_FREE_CLASS)) - && (flags & (DEF_LOCAL | DEF_PARAM))) { - PyObject *dict; - if (ste->ste_type == TYPE_FUNCTION) { - v = PyInt_FromLong(ncells++); - dict = c->c_cellvars; - } else { - v = PyInt_FromLong(nfrees++); - dict = c->c_freevars; - } - if (v == NULL) - return -1; - if (PyDict_SetItem(dict, name, v) < 0) - goto fail; - Py_DECREF(v); - } + && (flags & (DEF_LOCAL | DEF_PARAM))) + symtable_resolve_free(c, name, &si); if (flags & DEF_STAR) { c->c_argcount--; @@ -4077,23 +4195,22 @@ } else if (flags & DEF_INTUPLE) c->c_argcount--; else if (flags & DEF_GLOBAL) { - if ((flags & DEF_PARAM) - && (PyString_AS_STRING(name)[0] != '.')){ - PyErr_Format(PyExc_SyntaxError, - "name '%.400s' is local and global", + if (flags & DEF_PARAM) { + PyErr_Format(PyExc_SyntaxError, LOCAL_GLOBAL, PyString_AS_STRING(name)); - set_error_location(st->st_filename, + set_error_location(st->st_filename, ste->ste_lineno); + st->st_errors++; goto fail; } if (PyDict_SetItem(c->c_globals, name, Py_None) < 0) goto fail; } else if (flags & DEF_FREE_GLOBAL) { - nimplicit++; + si.si_nimplicit++; if (PyDict_SetItem(c->c_globals, name, implicit) < 0) goto fail; } else if ((flags & DEF_LOCAL) && !(flags & DEF_PARAM)) { - v = PyInt_FromLong(nlocals++); + v = PyInt_FromLong(si.si_nlocals++); if (v == NULL) goto fail; if (PyDict_SetItem(c->c_locals, name, v) < 0) @@ -4103,15 +4220,15 @@ if (PyList_Append(c->c_varnames, name) < 0) goto fail; } else if (is_free(flags)) { - if (ste->ste_nested) { - v = PyInt_FromLong(nfrees++); + if (ste->ste_nested && st->st_nested_scopes) { + v = PyInt_FromLong(si.si_nfrees++); if (v == NULL) goto fail; if (PyDict_SetItem(c->c_freevars, name, v) < 0) goto fail; Py_DECREF(v); } else { - nimplicit++; + si.si_nimplicit++; if (PyDict_SetItem(c->c_globals, name, implicit) < 0) goto fail; @@ -4119,40 +4236,9 @@ } } - /* The cell vars are the first elements of the closure, - followed by the free vars. Update the offsets in - c_freevars to account for number of cellvars. */ - pos = 0; - while (PyDict_Next(c->c_freevars, &pos, &name, &v)) { - int i = PyInt_AS_LONG(v) + ncells; - PyObject *o = PyInt_FromLong(i); - if (PyDict_SetItem(c->c_freevars, name, o) < 0) { - Py_DECREF(o); - return -1; - } - Py_DECREF(o); - } - - if (ste->ste_type == TYPE_FUNCTION) - c->c_nlocals = nlocals; - - if (ste->ste_type != TYPE_MODULE) - c->c_flags |= CO_NEWLOCALS; - if (ste->ste_type == TYPE_FUNCTION) { - if (ste->ste_optimized) - c->c_flags |= CO_OPTIMIZED; - else if (ncells || nfrees - || (ste->ste_nested && nimplicit) - || ste->ste_child_free) { - PyErr_Format(PyExc_SyntaxError, ILLEGAL_DYNAMIC_SCOPE, - PyString_AS_STRING(ste->ste_name)); - set_error_location(st->st_filename, ste->ste_lineno); - return -1; - } - } - - return 0; - + if (symtable_freevar_offsets(c->c_freevars, si.si_ncells) < 0) + return -1; + return symtable_update_flags(c, ste, &si); fail: /* is this always the right thing to do? */ Py_XDECREF(v); @@ -4168,6 +4254,7 @@ if (st == NULL) return NULL; st->st_pass = 1; + st->st_nested_scopes = NESTED_SCOPES_DEFAULT; st->st_filename = NULL; if ((st->st_stack = PyList_New(0)) == NULL) goto fail; @@ -4193,6 +4280,44 @@ PyMem_Free((void *)st); } +/* XXX this code is a placeholder for correct code. + from __future__ import name set language options */ + +static int +symtable_check_future(struct symtable *st, node *n) +{ + int i; + node *name = CHILD(n, 1); + + if (strcmp(STR(CHILD(name, 0)), "__future__") != 0) + return 0; + /* It is only legal to define __future__ features at the top + of a module. If the current scope is not the module level + or if there are any symbols defined, it is too late. */ + if (st->st_cur->ste_symbols != st->st_global + || PyDict_Size(st->st_cur->ste_symbols) != 0) { + PyErr_SetString(PyExc_SyntaxError, + "imports from __future__ are only legal at the beginning of a module"); + return -1; + } + for (i = 3; i < NCH(n); ++i) { + char *feature = STR(CHILD(CHILD(n, i), 0)); + /* Do a linear search through the defined features, + assuming there aren't very many of them. */ + if (strcmp(feature, FUTURE_NESTED_SCOPES) == 0) { + st->st_nested_scopes = 1; + } else { + PyErr_Format(PyExc_SyntaxError, + UNDEFINED_FUTURE_FEATURE, feature); + set_error_location(st->st_filename, + st->st_cur->ste_lineno); + st->st_errors++; + return -1; + } + } + return 1; +} + /* When the compiler exits a scope, it must should update the scope's free variable information with the list of free variables in its children. @@ -4322,12 +4447,17 @@ return 0; } +/* symtable_enter_scope() gets a reference via PySymtableEntry_New(). + This reference is released when the scope is exited, via the DECREF + in symtable_exit_scope(). +*/ + static int symtable_exit_scope(struct symtable *st) { int end; - if (st->st_pass == 1) + if (st->st_pass == 1 && st->st_nested_scopes) symtable_update_free_vars(st); Py_DECREF(st->st_cur); end = PyList_GET_SIZE(st->st_stack) - 1; @@ -4364,6 +4494,27 @@ } static int +symtable_lookup(struct symtable *st, char *name) +{ + char buffer[MANGLE_LEN]; + PyObject *v; + int flags; + + if (mangle(st->st_private, name, buffer, sizeof(buffer))) + name = buffer; + v = PyDict_GetItemString(st->st_cur->ste_symbols, name); + if (v == NULL) { + if (PyErr_Occurred()) + return -1; + else + return 0; + } + + flags = PyInt_AS_LONG(v); + return flags; +} + +static int symtable_add_def(struct symtable *st, char *name, int flag) { PyObject *s; @@ -4485,10 +4636,12 @@ symtable_import(st, n); break; case exec_stmt: { - st->st_cur->ste_optimized = 0; + st->st_cur->ste_optimized |= OPT_EXEC; symtable_node(st, CHILD(n, 1)); if (NCH(n) > 2) symtable_node(st, CHILD(n, 3)); + else + st->st_cur->ste_optimized |= OPT_BARE_EXEC; if (NCH(n) > 4) symtable_node(st, CHILD(n, 5)); break; @@ -4698,8 +4851,10 @@ { int i; - for (i = 1; i < NCH(n); i += 2) - symtable_add_def(st, STR(CHILD(n, i)), DEF_GLOBAL); + for (i = 1; i < NCH(n); i += 2) { + char *name = STR(CHILD(n, i)); + symtable_add_def(st, name, DEF_GLOBAL); + } } static void @@ -4725,10 +4880,10 @@ ('*' | import_as_name (',' import_as_name)*) import_as_name: NAME [NAME NAME] */ - if (STR(CHILD(n, 0))[0] == 'f') { /* from */ + symtable_check_future(st, n); if (TYPE(CHILD(n, 3)) == STAR) { - st->st_cur->ste_optimized = 0; + st->st_cur->ste_optimized |= OPT_IMPORT_STAR; } else { for (i = 3; i < NCH(n); i += 2) { node *c = CHILD(n, i); @@ -4740,7 +4895,7 @@ DEF_IMPORT); } } - } else { + } else { for (i = 1; i < NCH(n); i += 2) { symtable_assign(st, CHILD(n, i), DEF_IMPORT); }
