]> granicus.if.org Git - python/commitdiff
Relax the rules for using 'from ... import *' and exec in the presence
authorJeremy Hylton <jeremy@alum.mit.edu>
Fri, 9 Feb 2001 22:22:18 +0000 (22:22 +0000)
committerJeremy Hylton <jeremy@alum.mit.edu>
Fri, 9 Feb 2001 22:22:18 +0000 (22:22 +0000)
of nested functions.  Either is allowed in a function if it contains
no defs or lambdas or the defs and lambdas it contains have no free
variables.  If a function is itself nested and has free variables,
either is illegal.

Revise the symtable to use a PySymtableEntryObject, which holds all
the revelent information for a scope, rather than using a bunch of
st_cur_XXX pointers in the symtable struct.  The changes simplify the
internal management of the current symtable scope and of the stack.

Added new C source file: Python/symtable.c.  (Does the Windows build
process need to be updated?)

As part of these changes, the initial _symtable module interface
introduced in 2.1a2 is replaced.  A dictionary of
PySymtableEntryObjects are returned.

Include/symtable.h
Makefile.pre.in
Modules/symtablemodule.c
Python/compile.c
Python/symtable.c [new file with mode: 0644]

index beea9f50b64e5147bebd755235f74c21340e403e..f96ed0c43c9ba7afd9fc29da4892527990f88b2b 100644 (file)
@@ -14,61 +14,51 @@ extern "C" {
    block; the integer values are used to store several flags,
    e.g. DEF_PARAM indicates that a variable is a parameter to a
    function. 
-
-   The slots st_cur_XXX pointers always refer to the current code
-   block.  The st_cur slot is the symbol dictionary.  The st_cur_id
-   slot is the id is the key in st_symbols.  The st_cur_name slot is
-   the name of the current scope. The st_cur_type slot is one of
-   TYPE_FUNCTION, TYPE_CLASS, or TYPE_MODULE.  The st_cur_children is
-   a list of the ids of the current node's children.
-
-   The st_symbols slot is a dictionary that maps code block ids to
-   symbol dictionaries.  The keys are generated by a counter that is
-   incremented each time a new code block is found.  The counter is
-   identifies a specific scope, because both passes walk the parse
-   tree in the same order.
-
-   The st_varnames slot is a dictionary that maps code block ids to
-   parameter lists.  The st_global slot always refers to the symbol 
-   dictionary for the module.
-
-   The st_children slot is a dictionary that maps ids to a list
-   containing the ids of its children.
-
-   If st_keep is true then the namespace info pushed on st_stack will
-   also be stored in st_scopes.  This is useful if the symbol table is
-   being passed to something other than the compiler.
 */
 
+struct _symtable_entry;
+
 struct symtable {
        int st_pass;             /* pass == 1 or 2 */
-       int st_keep;             /* true if symtable will be returned */
        char *st_filename;       /* name of file being compiled */
-       PyObject *st_symbols;    /* dictionary of symbol tables */
-       PyObject *st_varnames;   /* dictionary of parameter lists */
+       struct _symtable_entry *st_cur; /* current symbol table entry */
+       PyObject *st_symbols;    /* dictionary of symbol table entries */
         PyObject *st_stack;      /* stack of namespace info */
-       PyObject *st_scopes;     /* dictionary of namespace info */
-       PyObject *st_children;   /* dictionary (id=[ids]) */
-       PyObject *st_cur;        /* borrowed ref to dict in st_symbols */
-       PyObject *st_cur_name;   /* string, name of current scope */
-       PyObject *st_cur_id;     /* int id of current code block */
-       PyObject *st_cur_children; /* ref to current children list */
-       int st_cur_type;         /* type of current scope */ 
-       int st_cur_lineno;       /* line number where current scope begins */
        PyObject *st_global;     /* borrowed ref to MODULE in st_symbols */
        int st_nscopes;          /* number of scopes */
        int st_errors;           /* number of errors */
        char *st_private;        /* name of current class or NULL */
        int st_tmpname;          /* temporary name counter */
-       int st_nested;           /* bool (true if nested scope) */
 };
 
+typedef struct _symtable_entry {
+       PyObject_HEAD
+       PyObject *ste_id;        /* int: key in st_symbols) */
+       PyObject *ste_symbols;   /* dict: name to flags) */
+       PyObject *ste_name;      /* string: name of scope */
+       PyObject *ste_varnames;  /* list of variable names */
+       PyObject *ste_children;  /* list of child ids */
+       int ste_type;            /* module, class, or function */
+       int ste_lineno;          /* first line of scope */
+       int ste_optimized;       /* true if namespace is optimized */
+       int ste_nested;          /* true if scope is nested */
+       int ste_child_free;      /* true if a child scope has free variables,
+                                   including free refs to globals */
+       struct symtable *ste_table;
+} PySymtableEntryObject;
+
+extern DL_IMPORT(PyTypeObject) PySymtableEntry_Type;
+
+#define PySymtableEntry_Check(op) ((op)->ob_type == &PySymtableEntry_Type)
+
+extern DL_IMPORT(PyObject *) PySymtableEntry_New(struct symtable *,
+                                                char *, int, int);
+
 DL_IMPORT(struct symtable *) PyNode_CompileSymtable(struct _node *, char *);
 DL_IMPORT(void) PySymtable_Free(struct symtable *);
 
 
 #define TOP "global"
-#define NOOPT ".noopt"
 
 /* Flags for def-use information */
 
index 43d1dad6dbc1c6ca77f6d299ad18e08112aac2bc..f6dabe60d3950b76f32c829a527010e19efba46b 100644 (file)
@@ -228,6 +228,7 @@ PYTHON_OBJS=        \
                Python/pystate.o \
                Python/pythonrun.o \
                Python/structmember.o \
+               Python/symtable.o \
                Python/sysmodule.o \
                Python/traceback.o \
                Python/getopt.o \
index ccf4aba39cd1efd7bff06bff13948ac9805114a3..ce1f206cfcbe504ca0789adabdfc4c430ec61ccd 100644 (file)
@@ -31,7 +31,7 @@ symtable_symtable(PyObject *self, PyObject *args)
        st = Py_SymtableString(str, filename, start);
        if (st == NULL)
                return NULL;
-       t = Py_BuildValue("OO", st->st_symbols, st->st_scopes);
+       t = Py_BuildValue("O", st->st_symbols);
        PySymtable_Free(st);
        return t;
 }
index 2a93a57cd2c79880fc624fdaf7755c8e50946372..eb2ba908ca976f51edfe1ee4f87ab02c1096ad8f 100644 (file)
@@ -52,8 +52,8 @@ int Py_OptimizeFlag = 0;
 #define DUPLICATE_ARGUMENT \
 "duplicate argument '%s' in function definition"
 
-#define ILLEGAL_IMPORT_STAR \
-"'from ... import *' may only occur in a module scope"
+#define ILLEGAL_DYNAMIC_SCOPE \
+"%.100s: exec or 'import *' makes names ambiguous in nested scope"
 
 #define MANGLE_LEN 256
 
@@ -484,10 +484,9 @@ static int get_ref_type(struct compiling *, char *);
 /* symtable operations */
 static int symtable_build(struct compiling *, node *);
 static int symtable_load_symbols(struct compiling *);
-static struct symtable *symtable_init(int);
+static struct symtable *symtable_init(void);
 static void symtable_enter_scope(struct symtable *, char *, int, int);
 static int symtable_exit_scope(struct symtable *);
-static int symtable_update_cur(struct symtable *);
 static int symtable_add_def(struct symtable *, char *, int);
 static int symtable_add_def_o(struct symtable *, PyObject *, PyObject *, int);
 
@@ -638,10 +637,6 @@ com_addbyte(struct compiling *c, int byte)
        /*fprintf(stderr, "%3d: %3d\n", c->c_nexti, byte);*/
        assert(byte >= 0 && byte <= 255);
        if (byte < 0 || byte > 255) {
-               /*
-               fprintf(stderr, "XXX compiling bad byte: %d\n", byte);
-               fatal("com_addbyte: byte out of range");
-               */
                com_error(c, PyExc_SystemError,
                          "com_addbyte: byte out of range");
        }
@@ -838,7 +833,6 @@ mangle(char *p, char *name, char *buffer, size_t maxlen)
        buffer[0] = '_';
        strncpy(buffer+1, p, plen);
        strcpy(buffer+1+plen, name);
-       /* fprintf(stderr, "mangle %s -> %s\n", name, buffer); */
        return 1;
 }
 
@@ -897,7 +891,7 @@ com_addop_varname(struct compiling *c, int kind, char *name)
        reftype = get_ref_type(c, name);
        switch (reftype) {
        case LOCAL:
-               if (c->c_symtable->st_cur_type == TYPE_FUNCTION)
+               if (c->c_symtable->st_cur->ste_type == TYPE_FUNCTION)
                        scope = NAME_LOCAL;
                break;
        case GLOBAL_EXPLICIT:
@@ -982,7 +976,6 @@ com_addop_varname(struct compiling *c, int kind, char *name)
                break;
        }
 done:
-/*     fprintf(stderr, "         addoparg(op=%d, arg=%d)\n", op, i);*/
        com_addoparg(c, op, i);
 }
 
@@ -1426,7 +1419,6 @@ com_atom(struct compiling *c, node *n)
                com_push(c, 1);
                break;
        default:
-               /* XXX fprintf(stderr, "node type %d\n", TYPE(ch)); */
                com_error(c, PyExc_SystemError,
                          "com_atom: unexpected node type");
        }
@@ -2150,6 +2142,10 @@ com_test(struct compiling *c, node *n)
                symtable_enter_scope(c->c_symtable, "lambda", lambdef,
                                     n->n_lineno);
                co = (PyObject *) icompile(CHILD(n, 0), c);
+               if (co == NULL) {
+                       c->c_errors++;
+                       return;
+               }
                symtable_exit_scope(c->c_symtable);
                if (co == NULL) {
                        c->c_errors++;
@@ -2326,8 +2322,8 @@ com_assign(struct compiling *c, node *n, int assigning, node *augn)
                        n = CHILD(n, 0);
                        break;
                
-               case power: /* atom trailer* ('**' power)* */
-/* ('+'|'-'|'~') factor | atom trailer* */
+               case power: /* atom trailer* ('**' power)*
+                              ('+'|'-'|'~') factor | atom trailer* */
                        if (TYPE(CHILD(n, 0)) != atom) {
                                com_error(c, PyExc_SyntaxError,
                                          "can't assign to operator");
@@ -2408,7 +2404,6 @@ com_assign(struct compiling *c, node *n, int assigning, node *augn)
                        return;
                
                default:
-                       /* XXX fprintf(stderr, "node type %d\n", TYPE(n)); */
                        com_error(c, PyExc_SystemError,
                                  "com_assign: bad node");
                        return;
@@ -3155,7 +3150,7 @@ com_suite(struct compiling *c, node *n)
        }
        else {
                int i;
-               for (i = 0; i < NCH(n); i++) {
+               for (i = 0; i < NCH(n) && c->c_errors == 0; i++) {
                        node *ch = CHILD(n, i);
                        if (TYPE(ch) == stmt)
                                com_node(c, ch);
@@ -3353,6 +3348,8 @@ static void
 com_node(struct compiling *c, node *n)
 {
  loop:
+       if (c->c_errors)
+               return;
        switch (TYPE(n)) {
        
        /* Definition nodes */
@@ -3492,7 +3489,6 @@ com_node(struct compiling *c, node *n)
                break;
        
        default:
-               /* XXX fprintf(stderr, "node type %d\n", TYPE(n)); */
                com_error(c, PyExc_SystemError,
                          "com_node: unexpected node type");
        }
@@ -3775,7 +3771,6 @@ compile_node(struct compiling *c, node *n)
                break;
        
        default:
-               /* XXX fprintf(stderr, "node type %d\n", TYPE(n)); */
                com_error(c, PyExc_SystemError,
                          "compile_node: unexpected node type");
        }
@@ -3809,7 +3804,7 @@ PyNode_CompileSymtable(node *n, char *filename)
 {
        struct symtable *st;
 
-       st = symtable_init(1);
+       st = symtable_init();
        if (st == NULL)
                return NULL;
        assert(st->st_symbols != NULL);
@@ -3844,7 +3839,7 @@ jcompile(node *n, char *filename, struct compiling *base)
                sc.c_symtable = base->c_symtable;
                /* c_symtable still points to parent's symbols */
                if (base->c_nested 
-                   || (sc.c_symtable->st_cur_type == TYPE_FUNCTION))
+                   || (sc.c_symtable->st_cur->ste_type == TYPE_FUNCTION))
                        sc.c_nested = 1;
        } else {
                sc.c_private = NULL;
@@ -3854,8 +3849,10 @@ jcompile(node *n, char *filename, struct compiling *base)
                }
        }
        co = NULL;
-       if (symtable_load_symbols(&sc) < 0)
+       if (symtable_load_symbols(&sc) < 0) {
+               sc.c_errors++;
                goto exit;
+       }
        compile_node(&sc, n);
        com_done(&sc);
        if (sc.c_errors == 0) {
@@ -3947,10 +3944,12 @@ get_ref_type(struct compiling *c, char *name)
                }
        }
        {
-               char buf[250];
-               sprintf(buf, "unknown scope for %.100s in %.100s (%s)",
+               char buf[350];
+               sprintf(buf, 
+                       "unknown scope for %.100s in %.100s(%s) in %s",
                        name, c->c_name, 
-                       PyObject_REPR(c->c_symtable->st_cur_id));
+                       PyObject_REPR(c->c_symtable->st_cur->ste_id),
+                       c->c_filename);
                Py_FatalError(buf);
        }
        return -1; /* can't get here */
@@ -3959,7 +3958,7 @@ get_ref_type(struct compiling *c, char *name)
 static int
 symtable_build(struct compiling *c, node *n)
 {
-       if ((c->c_symtable = symtable_init(0)) == NULL)
+       if ((c->c_symtable = symtable_init()) == NULL)
                return -1;
        c->c_symtable->st_filename = c->c_filename;
        symtable_enter_scope(c->c_symtable, TOP, TYPE(n), n->n_lineno);
@@ -3979,9 +3978,10 @@ symtable_load_symbols(struct compiling *c)
 {
        static PyObject *implicit = NULL;
        PyObject *name, *varnames, *v;
-       int i, info, pos;
-       int nlocals, nfrees, ncells;
+       int i, flags, pos;
+       int nlocals, nfrees, ncells, nimplicit;
        struct symtable *st = c->c_symtable;
+       PySymtableEntryObject *ste = st->st_cur;
 
        if (implicit == NULL) {
                implicit = PyInt_FromLong(1);
@@ -3990,11 +3990,13 @@ symtable_load_symbols(struct compiling *c)
        }
        v = NULL;
 
-       varnames = PyDict_GetItem(st->st_varnames, st->st_cur_id);
+       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;
@@ -4013,6 +4015,7 @@ symtable_load_symbols(struct compiling *c)
        c->c_argcount = nlocals;
        nfrees = 0;
        ncells = 0;
+       nimplicit = 0;
        for (i = 0; i < nlocals; ++i) {
                v = PyInt_FromLong(i);
                if (PyDict_SetItem(c->c_locals, 
@@ -4024,13 +4027,12 @@ symtable_load_symbols(struct compiling *c)
        /* XXX The cases below define the rules for whether a name is
           local or global.  The logic could probably be clearer. */
        pos = 0;
-       while (PyDict_Next(st->st_cur, &pos, &name, &v)) {
-               info = PyInt_AS_LONG(v);
+       while (PyDict_Next(ste->ste_symbols, &pos, &name, &v)) {
+               flags = PyInt_AS_LONG(v);
 
-               if (info & DEF_FREE_GLOBAL)
+               if (flags & DEF_FREE_GLOBAL)
                    /* undo the original DEF_FREE */
-                   info &= ~(DEF_FREE | DEF_FREE_CLASS);
-
+                   flags &= ~(DEF_FREE | DEF_FREE_CLASS);
 
                /* Seperate logic for DEF_FREE.  If it occurs in a
                   function, it indicates a local that we must
@@ -4039,10 +4041,10 @@ symtable_load_symbols(struct compiling *c)
                   variable with the same name.
                */
 
-               if ((info & (DEF_FREE | DEF_FREE_CLASS))
-                   && (info & (DEF_LOCAL | DEF_PARAM))) {
+               if ((flags & (DEF_FREE | DEF_FREE_CLASS))
+                   && (flags & (DEF_LOCAL | DEF_PARAM))) {
                        PyObject *dict;
-                       if (st->st_cur_type == TYPE_FUNCTION) {
+                       if (ste->ste_type == TYPE_FUNCTION) {
                                v = PyInt_FromLong(ncells++);
                                dict = c->c_cellvars;
                        } else {
@@ -4056,49 +4058,50 @@ symtable_load_symbols(struct compiling *c)
                        Py_DECREF(v);
                }
 
-               if (info & DEF_STAR) {
+               if (flags & DEF_STAR) {
                        c->c_argcount--;
                        c->c_flags |= CO_VARARGS;
-               } else if (info & DEF_DOUBLESTAR) {
+               } else if (flags & DEF_DOUBLESTAR) {
                        c->c_argcount--;
                        c->c_flags |= CO_VARKEYWORDS;
-               } else if (info & DEF_INTUPLE) 
+               } else if (flags & DEF_INTUPLE) 
                        c->c_argcount--;
-               else if (info & DEF_GLOBAL) {
-                       if ((info & DEF_PARAM) 
+               else if (flags & DEF_GLOBAL) {
+                       if ((flags & DEF_PARAM) 
                            && (PyString_AS_STRING(name)[0] != '.')){
                                PyErr_Format(PyExc_SyntaxError,
                                     "name '%.400s' is local and global",
                                             PyString_AS_STRING(name));
                                set_error_location(st->st_filename,
-                                                  st->st_cur_lineno);
+                                                  ste->ste_lineno);
                                goto fail;
                        }
                        if (PyDict_SetItem(c->c_globals, name, Py_None) < 0)
                                goto fail;
-               } else if (info & DEF_FREE_GLOBAL) {
+               } else if (flags & DEF_FREE_GLOBAL) {
+                       nimplicit++;
                        if (PyDict_SetItem(c->c_globals, name, implicit) < 0)
                                goto fail;
-               } else if ((info & DEF_LOCAL) && !(info & DEF_PARAM)) {
+               } else if ((flags & DEF_LOCAL) && !(flags & DEF_PARAM)) {
                        v = PyInt_FromLong(nlocals++);
                        if (v == NULL)
                                goto fail;
                        if (PyDict_SetItem(c->c_locals, name, v) < 0)
                                goto fail;
                        Py_DECREF(v);
-                       if (st->st_cur_type != TYPE_CLASS) 
+                       if (ste->ste_type != TYPE_CLASS) 
                                if (PyList_Append(c->c_varnames, name) < 0)
                                        goto fail;
-               } else if (is_free(info)) {
-                       if (st->st_nested) {
+               } else if (is_free(flags)) {
+                       if (ste->ste_nested) {
                                v = PyInt_FromLong(nfrees++);
                                if (v == NULL)
                                        goto fail;
-                               if (PyDict_SetItem(c->c_freevars,
-                                                  name, v) < 0)
+                               if (PyDict_SetItem(c->c_freevars, name, v) < 0)
                                        goto fail;
                                Py_DECREF(v);
                        } else {
+                               nimplicit++;
                                if (PyDict_SetItem(c->c_globals, name,
                                                   implicit) < 0)
                                        goto fail;
@@ -4120,24 +4123,24 @@ symtable_load_symbols(struct compiling *c)
                Py_DECREF(o);
        }
 
-       if (st->st_cur_type == TYPE_FUNCTION)
+       if (ste->ste_type == TYPE_FUNCTION)
                c->c_nlocals = nlocals;
 
-       if (st->st_cur_type != TYPE_MODULE)
+       if (ste->ste_type != TYPE_MODULE)
                c->c_flags |= CO_NEWLOCALS;
-       if (st->st_cur_type == TYPE_FUNCTION) {
-               if (PyDict_GetItemString(st->st_cur, NOOPT) == NULL)
+       if (ste->ste_type == TYPE_FUNCTION) {
+               if (ste->ste_optimized)
                        c->c_flags |= CO_OPTIMIZED;
-               else if (ncells || nfrees) {
-                       PyErr_Format(PyExc_SyntaxError,
-                               "function %.100s: may not use lexical scoping"
-                               " and 'import *' or exec in same function",
-                               PyString_AS_STRING(st->st_cur_name));
-                       set_error_location(st->st_filename,
-                                          st->st_cur_lineno);
+               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;
 
  fail:
@@ -4147,43 +4150,20 @@ symtable_load_symbols(struct compiling *c)
 }
 
 static struct symtable *
-symtable_init(int keep)
+symtable_init()
 {
        struct symtable *st;
-       PyObject *d;
 
        st = (struct symtable *)PyMem_Malloc(sizeof(struct symtable));
        if (st == NULL)
                return NULL;
        st->st_pass = 1;
-       st->st_keep = keep;
        st->st_filename = NULL;
        if ((st->st_stack = PyList_New(0)) == NULL)
                goto fail;
        if ((st->st_symbols = PyDict_New()) == NULL)
                goto fail; 
-       if ((st->st_children = PyDict_New()) == NULL)
-               goto fail; 
-       if ((st->st_varnames = PyDict_New()) == NULL)
-               goto fail; 
-       if ((d = PyDict_New()) == NULL) 
-               goto fail;
-       if (PyDict_SetItemString(st->st_symbols, TOP, d) < 0)
-               goto fail;
-       st->st_global = d;
-       Py_DECREF(d);
-       if (keep) {
-               if ((d = PyDict_New()) == NULL)
-                       goto fail;
-               st->st_scopes = d;
-       } else 
-               st->st_scopes = NULL;
        st->st_cur = NULL;
-       st->st_cur_id = NULL;
-       st->st_cur_name = NULL;
-       st->st_cur_children = NULL;
-       st->st_cur_type = 0;
-       st->st_nested = 0;
        st->st_nscopes = 0;
        st->st_errors = 0;
        st->st_tmpname = 0;
@@ -4198,51 +4178,10 @@ void
 PySymtable_Free(struct symtable *st)
 {
        Py_XDECREF(st->st_symbols);
-       Py_XDECREF(st->st_varnames);
-       Py_XDECREF(st->st_children);
        Py_XDECREF(st->st_stack);
-       Py_XDECREF(st->st_scopes);
-       Py_XDECREF(st->st_cur_id);
-       Py_XDECREF(st->st_cur_name);
        PyMem_Free((void *)st);
 }
 
-static PyObject *
-make_scope_info(PyObject *id, PyObject *name, int nested, int type,
-               int lineno)
-{
-       PyObject *t, *i1 = NULL, *i2 = NULL, *i3 = NULL;
-
-       t = PyTuple_New(5);
-       if (t == NULL)
-               return NULL;
-       i1 = PyInt_FromLong(nested);
-       if (i1 == NULL)
-               goto fail;
-       i2 = PyInt_FromLong(type);
-       if (i2 == NULL)
-               goto fail;
-       i3 = PyInt_FromLong(lineno);
-       if (i3 == NULL)
-               goto fail;
-
-       Py_INCREF(name);
-       Py_INCREF(id);
-       PyTuple_SET_ITEM(t, 0, name);
-       PyTuple_SET_ITEM(t, 1, id);
-       /* i1 & i2 alloced here; don't need incref */
-       PyTuple_SET_ITEM(t, 2, i1);
-       PyTuple_SET_ITEM(t, 3, i2);
-       PyTuple_SET_ITEM(t, 4, i3);
-       return t;
- fail:
-       Py_XDECREF(t);
-       Py_XDECREF(i1);
-       Py_XDECREF(i2);
-       Py_XDECREF(i3);
-       return NULL;
-}
-
 /* 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.
@@ -4250,7 +4189,7 @@ make_scope_info(PyObject *id, PyObject *name, int nested, int type,
    Variables that are free in children and defined in the current
    scope are cellvars.
 
-   If the scope being exited is defined at the top-level (st_nested is
+   If the scope being exited is defined at the top-level (ste_nested is
    false), free variables in children that are not defined here are
    implicit globals.
 
@@ -4259,30 +4198,30 @@ make_scope_info(PyObject *id, PyObject *name, int nested, int type,
 static int
 symtable_update_free_vars(struct symtable *st)
 {
-       PyObject *dict, *o, *child, *name;
+       PyObject *o, *name;
        int i, def;
+       PySymtableEntryObject *child, *ste = st->st_cur;
 
-       if (st->st_cur_type == TYPE_CLASS)
+       if (ste->ste_type == TYPE_CLASS)
                def = DEF_FREE_CLASS;
        else
                def = DEF_FREE;
-       for (i = 0; i < PyList_GET_SIZE(st->st_cur_children); ++i) {
+       for (i = 0; i < PyList_GET_SIZE(ste->ste_children); ++i) {
                int pos = 0;
 
-               child = PyList_GET_ITEM(st->st_cur_children, i);
-               dict = PyDict_GetItem(st->st_symbols, child);
-               if (dict == NULL)
-                       return -1;
-               while (PyDict_Next(dict, &pos, &name, &o)) {
+               child = (PySymtableEntryObject *)\
+                       PyList_GET_ITEM(ste->ste_children, i);
+               while (PyDict_Next(child->ste_symbols, &pos, &name, &o)) {
                        int v = PyInt_AS_LONG(o);
                        if (!(is_free(v)))
                                continue; /* avoids indentation */
-                       if (st->st_nested) {
-                               if (symtable_add_def_o(st, st->st_cur,  
+                       ste->ste_child_free = 1;
+                       if (ste->ste_nested) {
+                               if (symtable_add_def_o(st, ste->ste_symbols,
                                                       name, def) < 0)
                                                return -1;
                        } else {
-                               if (symtable_check_global(st, child, 
+                               if (symtable_check_global(st, child->ste_id
                                                          name) < 0)
                                                return -1;
                        }
@@ -4302,17 +4241,19 @@ symtable_check_global(struct symtable *st, PyObject *child, PyObject *name)
 {
        PyObject *o;
        int v;
+       PySymtableEntryObject *ste = st->st_cur;
 
-       if (st->st_cur_type == TYPE_CLASS)
+       if (ste->ste_type == TYPE_CLASS)
                return symtable_undo_free(st, child, name);
-       o = PyDict_GetItem(st->st_cur, name);
+       o = PyDict_GetItem(ste->ste_symbols, name);
        if (o == NULL)
                return symtable_undo_free(st, child, name);
        v = PyInt_AS_LONG(o);
        if (is_free(v) || (v & DEF_GLOBAL)) 
                return symtable_undo_free(st, child, name);
        else
-               return symtable_add_def_o(st, st->st_cur, name, DEF_FREE);
+               return symtable_add_def_o(st, ste->ste_symbols,
+                                         name, DEF_FREE);
 }
 
 static int
@@ -4320,17 +4261,18 @@ symtable_undo_free(struct symtable *st, PyObject *id,
                      PyObject *name)
 {
        int i, v, x;
-       PyObject *dict, *children, *info;
+       PyObject *info;
+       PySymtableEntryObject *ste;
 
-       dict = PyDict_GetItem(st->st_symbols, id);
-       if (dict == NULL)
+       ste = (PySymtableEntryObject *)PyDict_GetItem(st->st_symbols, id);
+       if (ste == NULL)
                return -1;
-       info = PyDict_GetItem(dict, name);
+       info = PyDict_GetItem(ste->ste_symbols, name);
        if (info == NULL)
                return 0;
        v = PyInt_AS_LONG(info);
        if (is_free(v)) {
-               if (symtable_add_def_o(st, dict, name,
+               if (symtable_add_def_o(st, ste->ste_symbols, name,
                                       DEF_FREE_GLOBAL) < 0)
                        return -1;
        } else
@@ -4338,10 +4280,11 @@ symtable_undo_free(struct symtable *st, PyObject *id,
                   then the recursion stops. */
                return 0;
        
-       children = PyDict_GetItem(st->st_children, id);
-       for (i = 0; i < PyList_GET_SIZE(children); ++i) {
-               x = symtable_undo_free(st, PyList_GET_ITEM(children, i),
-                                         name);
+       for (i = 0; i < PyList_GET_SIZE(ste->ste_children); ++i) {
+               PySymtableEntryObject *child;
+               child = (PySymtableEntryObject *) \
+                       PyList_GET_ITEM(ste->ste_children, i);
+               x = symtable_undo_free(st, child->ste_id, name);
                if (x < 0)
                        return x;
        }
@@ -4351,141 +4294,41 @@ symtable_undo_free(struct symtable *st, PyObject *id,
 static int
 symtable_exit_scope(struct symtable *st)
 {
-       PyObject *o;
        int end;
 
        if (st->st_pass == 1)
                symtable_update_free_vars(st);
-       if (st->st_cur_name) {
-               Py_XDECREF(st->st_cur_name);
-               Py_XDECREF(st->st_cur_id);
-       }
+       Py_DECREF(st->st_cur);
        end = PyList_GET_SIZE(st->st_stack) - 1;
-       o = PyList_GET_ITEM(st->st_stack, end);
-       st->st_cur_name = PyTuple_GET_ITEM(o, 0);
-       st->st_cur_id = PyTuple_GET_ITEM(o, 1);
-       st->st_nested = PyInt_AS_LONG(PyTuple_GET_ITEM(o, 2));
-       st->st_cur_type = PyInt_AS_LONG(PyTuple_GET_ITEM(o, 3));
+       st->st_cur = (PySymtableEntryObject *)PyList_GET_ITEM(st->st_stack, 
+                                                             end);
        if (PySequence_DelItem(st->st_stack, end) < 0)
                return -1;
-       return symtable_update_cur(st);
+       return 0;
 }
 
 static void
 symtable_enter_scope(struct symtable *st, char *name, int type,
                     int lineno)
 {
-       PyObject *o;
+       PySymtableEntryObject *prev = NULL;
 
        if (st->st_cur) {
-               /* push current scope info on stack */
-               o = make_scope_info(st->st_cur_id, st->st_cur_name, 
-                                   st->st_nested, st->st_cur_type,
-                                   st->st_cur_lineno);
-               if (o == NULL) {
+               prev = st->st_cur;
+               if (PyList_Append(st->st_stack, (PyObject *)st->st_cur) < 0) {
+                       Py_DECREF(st->st_cur);
                        st->st_errors++;
                        return;
                }
-               if (PyList_Append(st->st_stack, o) < 0) {
-                       Py_DECREF(o);
-                       st->st_errors++;
-                       return;
-               }
-               if (st->st_keep) {
-                       if (PyDict_SetItem(st->st_scopes,
-                                          st->st_cur_id, o) < 0) {
-                               Py_DECREF(o);
-                               st->st_errors++;
-                               return;
-                       }
-               }
-               Py_DECREF(o);
        }
-       st->st_cur_name = PyString_FromString(name);
-       if (st->st_nested || st->st_cur_type == TYPE_FUNCTION)
-               st->st_nested = 1;
-       st->st_cur_lineno = lineno;
-       switch (type) {
-       case funcdef:
-       case lambdef:
-               st->st_cur_type = TYPE_FUNCTION;
-               break;
-       case classdef:
-               st->st_cur_type = TYPE_CLASS;
-               break;
-       case single_input:
-       case eval_input:
-       case file_input:
-               st->st_cur_type = TYPE_MODULE;
-               break;
-       default:
-               fprintf(stderr, "invalid symtable scope: %d\n", type);
-               st->st_errors++;
-               return;
-       }
-       /* update st_cur_id and parent's st_cur_children */
-       o = PyInt_FromLong(st->st_nscopes++);
-       if (o == NULL) {
-               st->st_errors++;
-               return;
-       }
-       if (st->st_cur_children) {
-               if (PyList_Append(st->st_cur_children, o) < 0) {
-                       Py_DECREF(o);
+       st->st_cur = (PySymtableEntryObject *)\
+               PySymtableEntry_New(st, name, type, lineno);
+       if (strcmp(name, TOP) == 0)
+               st->st_global = st->st_cur->ste_symbols;
+       if (prev)
+               if (PyList_Append(prev->ste_children, 
+                                 (PyObject *)st->st_cur) < 0)
                        st->st_errors++;
-                       return;
-               }
-       }
-       st->st_cur_id = o;
-       /* create st_cur_children list */
-       o = PyList_New(0);
-       if (o == NULL) {
-               st->st_errors++;
-               return;
-       }
-       if (PyDict_SetItem(st->st_children, st->st_cur_id, o) < 0) {
-               Py_DECREF(o);
-               st->st_errors++;
-               return;
-       }
-       Py_DECREF(o);
-
-       symtable_update_cur(st);
-}
-
-static int
-symtable_update_cur(struct symtable *st)
-{
-       PyObject *s, *d, *l;
-
-       s = st->st_cur_id;
-       d = PyDict_GetItem(st->st_symbols, s);
-       if (d == NULL) {
-               if ((d = PyDict_New()) == NULL)
-                       return -1;
-               if (PyObject_SetItem(st->st_symbols, s, d) < 0) {
-                       Py_DECREF(d);
-                       return -1;
-               }
-               Py_DECREF(d);
-               if (st->st_cur_type == TYPE_FUNCTION) {
-                       if ((l = PyList_New(0)) == NULL)
-                               return -1;
-                       if (PyDict_SetItem(st->st_varnames, s, l) < 0) {
-                               Py_DECREF(l);
-                               return -1;
-                       }
-                       Py_DECREF(l);
-               }
-       }
-       
-       st->st_cur = d;
-
-       d = PyDict_GetItem(st->st_children, s);
-       if (d == NULL)
-               return -1;
-       st->st_cur_children = d;
-       return 0;
 }
 
 static int
@@ -4498,7 +4341,7 @@ symtable_add_def(struct symtable *st, char *name, int flag)
                name = buffer;
        if ((s = PyString_InternFromString(name)) == NULL)
                return -1;
-       return symtable_add_def_o(st, st->st_cur, s, flag);
+       return symtable_add_def_o(st, st->st_cur->ste_symbols, s, flag);
 }
 
 /* Must only be called with mangled names */
@@ -4516,7 +4359,7 @@ symtable_add_def_o(struct symtable *st, PyObject *dict,
                    PyErr_Format(PyExc_SyntaxError, DUPLICATE_ARGUMENT,
                                 PyString_AsString(name));
                    set_error_location(st->st_filename,
-                                      st->st_cur_lineno);
+                                      st->st_cur->ste_lineno);
                    return -1;
            }
            val |= flag;
@@ -4530,11 +4373,7 @@ symtable_add_def_o(struct symtable *st, PyObject *dict,
        Py_DECREF(o);
 
        if (flag & DEF_PARAM) {
-               PyObject *l = PyDict_GetItem(st->st_varnames, 
-                                            st->st_cur_id);
-               if (l == NULL)
-                       return -1;
-               if (PyList_Append(l, name) < 0) 
+               if (PyList_Append(st->st_cur->ste_varnames, name) < 0) 
                        return -1;
        } else  if (flag & DEF_GLOBAL) {
                /* XXX need to update DEF_GLOBAL for other flags too;
@@ -4614,15 +4453,7 @@ symtable_node(struct symtable *st, node *n)
                symtable_import(st, n);
                break;
        case exec_stmt: {
-               PyObject *zero = PyInt_FromLong(0);
-               if (zero == NULL)
-                       st->st_errors++;
-               else {
-                       if (PyDict_SetItemString(st->st_cur, NOOPT,
-                                                zero) < 0)   
-                               st->st_errors++;
-                       Py_DECREF(zero);
-               }
+               st->st_cur->ste_optimized = 0;
                symtable_node(st, CHILD(n, 1));
                if (NCH(n) > 2)
                        symtable_node(st, CHILD(n, 3));
@@ -4852,23 +4683,7 @@ symtable_import(struct symtable *st, node *n)
 
        if (STR(CHILD(n, 0))[0] == 'f') {  /* from */
                if (TYPE(CHILD(n, 3)) == STAR) {
-                       PyObject *zero = PyInt_FromLong(0);
-                       if (st->st_cur_type != TYPE_MODULE) {
-                               PyErr_SetString(PyExc_SyntaxError,
-                                               ILLEGAL_IMPORT_STAR);
-                               set_error_location(st->st_filename,
-                                                  n->n_lineno);
-                               st->st_errors++;
-                               return;
-                       }
-                       if (zero == NULL)
-                               st->st_errors++;
-                       else {
-                               if (PyDict_SetItemString(st->st_cur, NOOPT,
-                                                        zero) < 0)
-                                       st->st_errors++;
-                               Py_DECREF(zero);
-                       }
+                       st->st_cur->ste_optimized = 0;
                } else {
                        for (i = 3; i < NCH(n); i += 2) {
                                node *c = CHILD(n, i);
diff --git a/Python/symtable.c b/Python/symtable.c
new file mode 100644 (file)
index 0000000..5dc0272
--- /dev/null
@@ -0,0 +1,147 @@
+#include "Python.h"
+#include "symtable.h"
+#include "graminit.h"
+#include "structmember.h"
+
+PyObject *
+PySymtableEntry_New(struct symtable *st, char *name, int type, int lineno)
+{
+       PySymtableEntryObject *ste = NULL;
+       PyObject *k, *v;
+
+       k = PyInt_FromLong(st->st_nscopes++);
+       if (k == NULL)
+               goto fail;
+       v = PyDict_GetItem(st->st_symbols, k);
+       if (v) /* XXX could check that name, type, lineno match */
+           return v;
+       
+       ste = (PySymtableEntryObject *)PyObject_New(PySymtableEntryObject,
+                                                   &PySymtableEntry_Type);
+       ste->ste_table = st;
+       ste->ste_id = k;
+
+       v = PyString_FromString(name);
+       if (v == NULL)
+               goto fail;
+       ste->ste_name = v;
+       
+       v = PyDict_New();
+       if (v == NULL)
+           goto fail;
+       ste->ste_symbols = v;
+
+       v = PyList_New(0);
+       if (v == NULL)
+           goto fail;
+       ste->ste_varnames = v;
+
+       v = PyList_New(0);
+       if (v == NULL)
+           goto fail;
+       ste->ste_children = v;
+
+       ste->ste_optimized = 1;
+       ste->ste_lineno = lineno;
+       switch (type) {
+       case funcdef:
+       case lambdef:
+               ste->ste_type = TYPE_FUNCTION;
+               break;
+       case classdef:
+               ste->ste_type = TYPE_CLASS;
+               break;
+       case single_input:
+       case eval_input:
+       case file_input:
+               ste->ste_type = TYPE_MODULE;
+               break;
+       }
+
+       if (st->st_cur == NULL)
+               ste->ste_nested = 0;
+       else if (st->st_cur->ste_nested 
+                || st->st_cur->ste_type == TYPE_FUNCTION)
+               ste->ste_nested = 1;
+       else
+               ste->ste_nested = 0;
+       ste->ste_child_free = 0;
+
+       if (PyDict_SetItem(st->st_symbols, ste->ste_id, (PyObject *)ste) < 0)
+           goto fail;
+
+       return (PyObject *)ste;
+ fail:
+       Py_XDECREF(ste);
+       return NULL;
+}
+
+static PyObject *
+ste_repr(PySymtableEntryObject *ste)
+{
+       char buf[256];
+
+       sprintf(buf, "<symtable entry %.100s(%ld), line %d>",
+               PyString_AS_STRING(ste->ste_name),
+               PyInt_AS_LONG(ste->ste_id),
+               ste->ste_lineno);
+       return PyString_FromString(buf);
+}
+
+static void
+ste_dealloc(PySymtableEntryObject *ste)
+{
+       ste->ste_table = NULL;
+       Py_XDECREF(ste->ste_id);
+       Py_XDECREF(ste->ste_name);
+       Py_XDECREF(ste->ste_symbols);
+       Py_XDECREF(ste->ste_varnames);
+       Py_XDECREF(ste->ste_children);
+       PyObject_Del(ste);
+}
+
+#define OFF(x) offsetof(PySymtableEntryObject, x)
+
+static struct memberlist ste_memberlist[] = {
+       {"id",       T_OBJECT, OFF(ste_id), READONLY},
+       {"name",     T_OBJECT, OFF(ste_name), READONLY},
+       {"symbols",  T_OBJECT, OFF(ste_symbols), READONLY},
+       {"varnames", T_OBJECT, OFF(ste_varnames), READONLY},
+       {"children", T_OBJECT, OFF(ste_children), READONLY},
+       {"type",     T_INT,    OFF(ste_type), READONLY},
+       {"lineno",   T_INT,    OFF(ste_lineno), READONLY},
+       {"optimized",T_INT,    OFF(ste_optimized), READONLY},
+       {"nested",   T_INT,    OFF(ste_nested), READONLY},
+       {NULL}
+};
+
+static PyObject *
+ste_getattr(PySymtableEntryObject *ste, char *name)
+{
+       return PyMember_Get((char *)ste, ste_memberlist, name);
+}
+
+PyTypeObject PySymtableEntry_Type = {
+       PyObject_HEAD_INIT(&PyType_Type)
+       0,
+       "symtable entry",
+       sizeof(PySymtableEntryObject),
+       0,
+       (destructor)ste_dealloc,                /* tp_dealloc */
+       0,                                      /* tp_print */
+       (getattrfunc)ste_getattr,               /* tp_getattr */
+       0,                                      /* tp_setattr */
+       0,                                      /* tp_compare */
+       (reprfunc)ste_repr,                     /* tp_repr */
+       0,                                      /* tp_as_number */
+       0,                                      /* tp_as_sequence */
+       0,                                      /* tp_as_mapping */
+       0,                                      /* tp_hash */
+       0,                                      /* tp_call */
+       0,                                      /* tp_str */
+       0,                                      /* tp_getattro */
+       0,                                      /* tp_setattro */
+       0,                                      /* tp_as_buffer */
+       Py_TPFLAGS_DEFAULT,                     /* tp_flags */
+       0,                                      /* tp_doc */
+};