summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeremy Hylton <jeremy@alum.mit.edu>2001-02-09 22:22:18 (GMT)
committerJeremy Hylton <jeremy@alum.mit.edu>2001-02-09 22:22:18 (GMT)
commitcb17ae8b19c35cc63e7daec871c025d903c49105 (patch)
tree763b5b42fc1a889f7445f77263aab2c5c3dd13a3
parent670fa52698e90b5025dc2434310eada42fcfdd4a (diff)
downloadcpython-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.h64
-rw-r--r--Makefile.pre.in1
-rw-r--r--Modules/symtablemodule.c2
-rw-r--r--Python/compile.c409
-rw-r--r--Python/symtable.c147
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 */
+};