Commit e641b20d authored by Jeremy Hylton's avatar Jeremy Hylton

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.
parent 24811994
......@@ -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 */
......
......@@ -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 \
......
......@@ -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;
}
......
......@@ -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) {
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);
prev = st->st_cur;
if (PyList_Append(st->st_stack, (PyObject *)st->st_cur) < 0) {
Py_DECREF(st->st_cur);
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);
......
#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 */
};
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment