diff options
author | Jeremy Hylton <jeremy@alum.mit.edu> | 2001-02-09 22:22:18 (GMT) |
---|---|---|
committer | Jeremy Hylton <jeremy@alum.mit.edu> | 2001-02-09 22:22:18 (GMT) |
commit | cb17ae8b19c35cc63e7daec871c025d903c49105 (patch) | |
tree | 763b5b42fc1a889f7445f77263aab2c5c3dd13a3 | |
parent | 670fa52698e90b5025dc2434310eada42fcfdd4a (diff) | |
download | cpython-cb17ae8b19c35cc63e7daec871c025d903c49105.zip cpython-cb17ae8b19c35cc63e7daec871c025d903c49105.tar.gz cpython-cb17ae8b19c35cc63e7daec871c025d903c49105.tar.bz2 |
Relax the rules for using 'from ... import *' and exec in the presence
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.
-rw-r--r-- | Include/symtable.h | 64 | ||||
-rw-r--r-- | Makefile.pre.in | 1 | ||||
-rw-r--r-- | Modules/symtablemodule.c | 2 | ||||
-rw-r--r-- | Python/compile.c | 409 | ||||
-rw-r--r-- | Python/symtable.c | 147 |
5 files changed, 288 insertions, 335 deletions
diff --git a/Include/symtable.h b/Include/symtable.h index beea9f5..f96ed0c 100644 --- a/Include/symtable.h +++ b/Include/symtable.h @@ -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 */ diff --git a/Makefile.pre.in b/Makefile.pre.in index 43d1dad..f6dabe6 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -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 \ diff --git a/Modules/symtablemodule.c b/Modules/symtablemodule.c index ccf4aba..ce1f206 100644 --- a/Modules/symtablemodule.c +++ b/Modules/symtablemodule.c @@ -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; } diff --git a/Python/compile.c b/Python/compile.c index 2a93a57..eb2ba90 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -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 index 0000000..5dc0272 --- /dev/null +++ b/Python/symtable.c @@ -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 */ +}; |