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" { ...@@ -14,61 +14,51 @@ extern "C" {
block; the integer values are used to store several flags, block; the integer values are used to store several flags,
e.g. DEF_PARAM indicates that a variable is a parameter to a e.g. DEF_PARAM indicates that a variable is a parameter to a
function. 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 { struct symtable {
int st_pass; /* pass == 1 or 2 */ int st_pass; /* pass == 1 or 2 */
int st_keep; /* true if symtable will be returned */
char *st_filename; /* name of file being compiled */ char *st_filename; /* name of file being compiled */
PyObject *st_symbols; /* dictionary of symbol tables */ struct _symtable_entry *st_cur; /* current symbol table entry */
PyObject *st_varnames; /* dictionary of parameter lists */ PyObject *st_symbols; /* dictionary of symbol table entries */
PyObject *st_stack; /* stack of namespace info */ 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 */ PyObject *st_global; /* borrowed ref to MODULE in st_symbols */
int st_nscopes; /* number of scopes */ int st_nscopes; /* number of scopes */
int st_errors; /* number of errors */ int st_errors; /* number of errors */
char *st_private; /* name of current class or NULL */ char *st_private; /* name of current class or NULL */
int st_tmpname; /* temporary name counter */ 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(struct symtable *) PyNode_CompileSymtable(struct _node *, char *);
DL_IMPORT(void) PySymtable_Free(struct symtable *); DL_IMPORT(void) PySymtable_Free(struct symtable *);
#define TOP "global" #define TOP "global"
#define NOOPT ".noopt"
/* Flags for def-use information */ /* Flags for def-use information */
......
...@@ -228,6 +228,7 @@ PYTHON_OBJS= \ ...@@ -228,6 +228,7 @@ PYTHON_OBJS= \
Python/pystate.o \ Python/pystate.o \
Python/pythonrun.o \ Python/pythonrun.o \
Python/structmember.o \ Python/structmember.o \
Python/symtable.o \
Python/sysmodule.o \ Python/sysmodule.o \
Python/traceback.o \ Python/traceback.o \
Python/getopt.o \ Python/getopt.o \
......
...@@ -31,7 +31,7 @@ symtable_symtable(PyObject *self, PyObject *args) ...@@ -31,7 +31,7 @@ symtable_symtable(PyObject *self, PyObject *args)
st = Py_SymtableString(str, filename, start); st = Py_SymtableString(str, filename, start);
if (st == NULL) if (st == NULL)
return NULL; return NULL;
t = Py_BuildValue("OO", st->st_symbols, st->st_scopes); t = Py_BuildValue("O", st->st_symbols);
PySymtable_Free(st); PySymtable_Free(st);
return t; return t;
} }
......
...@@ -52,8 +52,8 @@ int Py_OptimizeFlag = 0; ...@@ -52,8 +52,8 @@ int Py_OptimizeFlag = 0;
#define DUPLICATE_ARGUMENT \ #define DUPLICATE_ARGUMENT \
"duplicate argument '%s' in function definition" "duplicate argument '%s' in function definition"
#define ILLEGAL_IMPORT_STAR \ #define ILLEGAL_DYNAMIC_SCOPE \
"'from ... import *' may only occur in a module scope" "%.100s: exec or 'import *' makes names ambiguous in nested scope"
#define MANGLE_LEN 256 #define MANGLE_LEN 256
...@@ -484,10 +484,9 @@ static int get_ref_type(struct compiling *, char *); ...@@ -484,10 +484,9 @@ static int get_ref_type(struct compiling *, char *);
/* symtable operations */ /* symtable operations */
static int symtable_build(struct compiling *, node *); static int symtable_build(struct compiling *, node *);
static int symtable_load_symbols(struct compiling *); 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 void symtable_enter_scope(struct symtable *, char *, int, int);
static int symtable_exit_scope(struct symtable *); 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(struct symtable *, char *, int);
static int symtable_add_def_o(struct symtable *, PyObject *, PyObject *, int); static int symtable_add_def_o(struct symtable *, PyObject *, PyObject *, int);
...@@ -638,10 +637,6 @@ com_addbyte(struct compiling *c, int byte) ...@@ -638,10 +637,6 @@ com_addbyte(struct compiling *c, int byte)
/*fprintf(stderr, "%3d: %3d\n", c->c_nexti, byte);*/ /*fprintf(stderr, "%3d: %3d\n", c->c_nexti, byte);*/
assert(byte >= 0 && byte <= 255); assert(byte >= 0 && byte <= 255);
if (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_error(c, PyExc_SystemError,
"com_addbyte: byte out of range"); "com_addbyte: byte out of range");
} }
...@@ -838,7 +833,6 @@ mangle(char *p, char *name, char *buffer, size_t maxlen) ...@@ -838,7 +833,6 @@ mangle(char *p, char *name, char *buffer, size_t maxlen)
buffer[0] = '_'; buffer[0] = '_';
strncpy(buffer+1, p, plen); strncpy(buffer+1, p, plen);
strcpy(buffer+1+plen, name); strcpy(buffer+1+plen, name);
/* fprintf(stderr, "mangle %s -> %s\n", name, buffer); */
return 1; return 1;
} }
...@@ -897,7 +891,7 @@ com_addop_varname(struct compiling *c, int kind, char *name) ...@@ -897,7 +891,7 @@ com_addop_varname(struct compiling *c, int kind, char *name)
reftype = get_ref_type(c, name); reftype = get_ref_type(c, name);
switch (reftype) { switch (reftype) {
case LOCAL: case LOCAL:
if (c->c_symtable->st_cur_type == TYPE_FUNCTION) if (c->c_symtable->st_cur->ste_type == TYPE_FUNCTION)
scope = NAME_LOCAL; scope = NAME_LOCAL;
break; break;
case GLOBAL_EXPLICIT: case GLOBAL_EXPLICIT:
...@@ -982,7 +976,6 @@ com_addop_varname(struct compiling *c, int kind, char *name) ...@@ -982,7 +976,6 @@ com_addop_varname(struct compiling *c, int kind, char *name)
break; break;
} }
done: done:
/* fprintf(stderr, " addoparg(op=%d, arg=%d)\n", op, i);*/
com_addoparg(c, op, i); com_addoparg(c, op, i);
} }
...@@ -1426,7 +1419,6 @@ com_atom(struct compiling *c, node *n) ...@@ -1426,7 +1419,6 @@ com_atom(struct compiling *c, node *n)
com_push(c, 1); com_push(c, 1);
break; break;
default: default:
/* XXX fprintf(stderr, "node type %d\n", TYPE(ch)); */
com_error(c, PyExc_SystemError, com_error(c, PyExc_SystemError,
"com_atom: unexpected node type"); "com_atom: unexpected node type");
} }
...@@ -2150,6 +2142,10 @@ com_test(struct compiling *c, node *n) ...@@ -2150,6 +2142,10 @@ com_test(struct compiling *c, node *n)
symtable_enter_scope(c->c_symtable, "lambda", lambdef, symtable_enter_scope(c->c_symtable, "lambda", lambdef,
n->n_lineno); n->n_lineno);
co = (PyObject *) icompile(CHILD(n, 0), c); co = (PyObject *) icompile(CHILD(n, 0), c);
if (co == NULL) {
c->c_errors++;
return;
}
symtable_exit_scope(c->c_symtable); symtable_exit_scope(c->c_symtable);
if (co == NULL) { if (co == NULL) {
c->c_errors++; c->c_errors++;
...@@ -2326,8 +2322,8 @@ com_assign(struct compiling *c, node *n, int assigning, node *augn) ...@@ -2326,8 +2322,8 @@ com_assign(struct compiling *c, node *n, int assigning, node *augn)
n = CHILD(n, 0); n = CHILD(n, 0);
break; break;
case power: /* atom trailer* ('**' power)* */ case power: /* atom trailer* ('**' power)*
/* ('+'|'-'|'~') factor | atom trailer* */ ('+'|'-'|'~') factor | atom trailer* */
if (TYPE(CHILD(n, 0)) != atom) { if (TYPE(CHILD(n, 0)) != atom) {
com_error(c, PyExc_SyntaxError, com_error(c, PyExc_SyntaxError,
"can't assign to operator"); "can't assign to operator");
...@@ -2408,7 +2404,6 @@ com_assign(struct compiling *c, node *n, int assigning, node *augn) ...@@ -2408,7 +2404,6 @@ com_assign(struct compiling *c, node *n, int assigning, node *augn)
return; return;
default: default:
/* XXX fprintf(stderr, "node type %d\n", TYPE(n)); */
com_error(c, PyExc_SystemError, com_error(c, PyExc_SystemError,
"com_assign: bad node"); "com_assign: bad node");
return; return;
...@@ -3155,7 +3150,7 @@ com_suite(struct compiling *c, node *n) ...@@ -3155,7 +3150,7 @@ com_suite(struct compiling *c, node *n)
} }
else { else {
int i; 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); node *ch = CHILD(n, i);
if (TYPE(ch) == stmt) if (TYPE(ch) == stmt)
com_node(c, ch); com_node(c, ch);
...@@ -3353,6 +3348,8 @@ static void ...@@ -3353,6 +3348,8 @@ static void
com_node(struct compiling *c, node *n) com_node(struct compiling *c, node *n)
{ {
loop: loop:
if (c->c_errors)
return;
switch (TYPE(n)) { switch (TYPE(n)) {
/* Definition nodes */ /* Definition nodes */
...@@ -3492,7 +3489,6 @@ com_node(struct compiling *c, node *n) ...@@ -3492,7 +3489,6 @@ com_node(struct compiling *c, node *n)
break; break;
default: default:
/* XXX fprintf(stderr, "node type %d\n", TYPE(n)); */
com_error(c, PyExc_SystemError, com_error(c, PyExc_SystemError,
"com_node: unexpected node type"); "com_node: unexpected node type");
} }
...@@ -3775,7 +3771,6 @@ compile_node(struct compiling *c, node *n) ...@@ -3775,7 +3771,6 @@ compile_node(struct compiling *c, node *n)
break; break;
default: default:
/* XXX fprintf(stderr, "node type %d\n", TYPE(n)); */
com_error(c, PyExc_SystemError, com_error(c, PyExc_SystemError,
"compile_node: unexpected node type"); "compile_node: unexpected node type");
} }
...@@ -3809,7 +3804,7 @@ PyNode_CompileSymtable(node *n, char *filename) ...@@ -3809,7 +3804,7 @@ PyNode_CompileSymtable(node *n, char *filename)
{ {
struct symtable *st; struct symtable *st;
st = symtable_init(1); st = symtable_init();
if (st == NULL) if (st == NULL)
return NULL; return NULL;
assert(st->st_symbols != NULL); assert(st->st_symbols != NULL);
...@@ -3844,7 +3839,7 @@ jcompile(node *n, char *filename, struct compiling *base) ...@@ -3844,7 +3839,7 @@ jcompile(node *n, char *filename, struct compiling *base)
sc.c_symtable = base->c_symtable; sc.c_symtable = base->c_symtable;
/* c_symtable still points to parent's symbols */ /* c_symtable still points to parent's symbols */
if (base->c_nested 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; sc.c_nested = 1;
} else { } else {
sc.c_private = NULL; sc.c_private = NULL;
...@@ -3854,8 +3849,10 @@ jcompile(node *n, char *filename, struct compiling *base) ...@@ -3854,8 +3849,10 @@ jcompile(node *n, char *filename, struct compiling *base)
} }
} }
co = NULL; co = NULL;
if (symtable_load_symbols(&sc) < 0) if (symtable_load_symbols(&sc) < 0) {
sc.c_errors++;
goto exit; goto exit;
}
compile_node(&sc, n); compile_node(&sc, n);
com_done(&sc); com_done(&sc);
if (sc.c_errors == 0) { if (sc.c_errors == 0) {
...@@ -3947,10 +3944,12 @@ get_ref_type(struct compiling *c, char *name) ...@@ -3947,10 +3944,12 @@ get_ref_type(struct compiling *c, char *name)
} }
} }
{ {
char buf[250]; char buf[350];
sprintf(buf, "unknown scope for %.100s in %.100s (%s)", sprintf(buf,
"unknown scope for %.100s in %.100s(%s) in %s",
name, c->c_name, 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); Py_FatalError(buf);
} }
return -1; /* can't get here */ return -1; /* can't get here */
...@@ -3959,7 +3958,7 @@ get_ref_type(struct compiling *c, char *name) ...@@ -3959,7 +3958,7 @@ get_ref_type(struct compiling *c, char *name)
static int static int
symtable_build(struct compiling *c, node *n) symtable_build(struct compiling *c, node *n)
{ {
if ((c->c_symtable = symtable_init(0)) == NULL) if ((c->c_symtable = symtable_init()) == NULL)
return -1; return -1;
c->c_symtable->st_filename = c->c_filename; c->c_symtable->st_filename = c->c_filename;
symtable_enter_scope(c->c_symtable, TOP, TYPE(n), n->n_lineno); symtable_enter_scope(c->c_symtable, TOP, TYPE(n), n->n_lineno);
...@@ -3979,9 +3978,10 @@ symtable_load_symbols(struct compiling *c) ...@@ -3979,9 +3978,10 @@ symtable_load_symbols(struct compiling *c)
{ {
static PyObject *implicit = NULL; static PyObject *implicit = NULL;
PyObject *name, *varnames, *v; PyObject *name, *varnames, *v;
int i, info, pos; int i, flags, pos;
int nlocals, nfrees, ncells; int nlocals, nfrees, ncells, nimplicit;
struct symtable *st = c->c_symtable; struct symtable *st = c->c_symtable;
PySymtableEntryObject *ste = st->st_cur;
if (implicit == NULL) { if (implicit == NULL) {
implicit = PyInt_FromLong(1); implicit = PyInt_FromLong(1);
...@@ -3990,11 +3990,13 @@ symtable_load_symbols(struct compiling *c) ...@@ -3990,11 +3990,13 @@ symtable_load_symbols(struct compiling *c)
} }
v = NULL; v = NULL;
varnames = PyDict_GetItem(st->st_varnames, st->st_cur_id); varnames = st->st_cur->ste_varnames;
if (varnames == NULL) { if (varnames == NULL) {
varnames = PyList_New(0); varnames = PyList_New(0);
if (varnames == NULL) if (varnames == NULL)
return -1; return -1;
ste->ste_varnames = varnames;
Py_INCREF(varnames);
} else } else
Py_INCREF(varnames); Py_INCREF(varnames);
c->c_varnames = varnames; c->c_varnames = varnames;
...@@ -4013,6 +4015,7 @@ symtable_load_symbols(struct compiling *c) ...@@ -4013,6 +4015,7 @@ symtable_load_symbols(struct compiling *c)
c->c_argcount = nlocals; c->c_argcount = nlocals;
nfrees = 0; nfrees = 0;
ncells = 0; ncells = 0;
nimplicit = 0;
for (i = 0; i < nlocals; ++i) { for (i = 0; i < nlocals; ++i) {
v = PyInt_FromLong(i); v = PyInt_FromLong(i);
if (PyDict_SetItem(c->c_locals, if (PyDict_SetItem(c->c_locals,
...@@ -4024,13 +4027,12 @@ symtable_load_symbols(struct compiling *c) ...@@ -4024,13 +4027,12 @@ symtable_load_symbols(struct compiling *c)
/* XXX The cases below define the rules for whether a name is /* XXX The cases below define the rules for whether a name is
local or global. The logic could probably be clearer. */ local or global. The logic could probably be clearer. */
pos = 0; pos = 0;
while (PyDict_Next(st->st_cur, &pos, &name, &v)) { while (PyDict_Next(ste->ste_symbols, &pos, &name, &v)) {
info = PyInt_AS_LONG(v); flags = PyInt_AS_LONG(v);
if (info & DEF_FREE_GLOBAL) if (flags & DEF_FREE_GLOBAL)
/* undo the original DEF_FREE */ /* 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 /* Seperate logic for DEF_FREE. If it occurs in a
function, it indicates a local that we must function, it indicates a local that we must
...@@ -4039,10 +4041,10 @@ symtable_load_symbols(struct compiling *c) ...@@ -4039,10 +4041,10 @@ symtable_load_symbols(struct compiling *c)
variable with the same name. variable with the same name.
*/ */
if ((info & (DEF_FREE | DEF_FREE_CLASS)) if ((flags & (DEF_FREE | DEF_FREE_CLASS))
&& (info & (DEF_LOCAL | DEF_PARAM))) { && (flags & (DEF_LOCAL | DEF_PARAM))) {
PyObject *dict; PyObject *dict;
if (st->st_cur_type == TYPE_FUNCTION) { if (ste->ste_type == TYPE_FUNCTION) {
v = PyInt_FromLong(ncells++); v = PyInt_FromLong(ncells++);
dict = c->c_cellvars; dict = c->c_cellvars;
} else { } else {
...@@ -4056,49 +4058,50 @@ symtable_load_symbols(struct compiling *c) ...@@ -4056,49 +4058,50 @@ symtable_load_symbols(struct compiling *c)
Py_DECREF(v); Py_DECREF(v);
} }
if (info & DEF_STAR) { if (flags & DEF_STAR) {
c->c_argcount--; c->c_argcount--;
c->c_flags |= CO_VARARGS; c->c_flags |= CO_VARARGS;
} else if (info & DEF_DOUBLESTAR) { } else if (flags & DEF_DOUBLESTAR) {
c->c_argcount--; c->c_argcount--;
c->c_flags |= CO_VARKEYWORDS; c->c_flags |= CO_VARKEYWORDS;
} else if (info & DEF_INTUPLE) } else if (flags & DEF_INTUPLE)
c->c_argcount--; c->c_argcount--;
else if (info & DEF_GLOBAL) { else if (flags & DEF_GLOBAL) {
if ((info & DEF_PARAM) if ((flags & DEF_PARAM)
&& (PyString_AS_STRING(name)[0] != '.')){ && (PyString_AS_STRING(name)[0] != '.')){
PyErr_Format(PyExc_SyntaxError, PyErr_Format(PyExc_SyntaxError,
"name '%.400s' is local and global", "name '%.400s' is local and global",
PyString_AS_STRING(name)); PyString_AS_STRING(name));
set_error_location(st->st_filename, set_error_location(st->st_filename,
st->st_cur_lineno); ste->ste_lineno);
goto fail; goto fail;
} }
if (PyDict_SetItem(c->c_globals, name, Py_None) < 0) if (PyDict_SetItem(c->c_globals, name, Py_None) < 0)
goto fail; goto fail;
} else if (info & DEF_FREE_GLOBAL) { } else if (flags & DEF_FREE_GLOBAL) {
nimplicit++;
if (PyDict_SetItem(c->c_globals, name, implicit) < 0) if (PyDict_SetItem(c->c_globals, name, implicit) < 0)
goto fail; goto fail;
} else if ((info & DEF_LOCAL) && !(info & DEF_PARAM)) { } else if ((flags & DEF_LOCAL) && !(flags & DEF_PARAM)) {
v = PyInt_FromLong(nlocals++); v = PyInt_FromLong(nlocals++);
if (v == NULL) if (v == NULL)
goto fail; goto fail;
if (PyDict_SetItem(c->c_locals, name, v) < 0) if (PyDict_SetItem(c->c_locals, name, v) < 0)
goto fail; goto fail;
Py_DECREF(v); Py_DECREF(v);
if (st->st_cur_type != TYPE_CLASS) if (ste->ste_type != TYPE_CLASS)
if (PyList_Append(c->c_varnames, name) < 0) if (PyList_Append(c->c_varnames, name) < 0)
goto fail; goto fail;
} else if (is_free(info)) { } else if (is_free(flags)) {
if (st->st_nested) { if (ste->ste_nested) {
v = PyInt_FromLong(nfrees++); v = PyInt_FromLong(nfrees++);
if (v == NULL) if (v == NULL)
goto fail; goto fail;
if (PyDict_SetItem(c->c_freevars, if (PyDict_SetItem(c->c_freevars, name, v) < 0)
name, v) < 0)
goto fail; goto fail;
Py_DECREF(v); Py_DECREF(v);
} else { } else {
nimplicit++;
if (PyDict_SetItem(c->c_globals, name, if (PyDict_SetItem(c->c_globals, name,
implicit) < 0) implicit) < 0)
goto fail; goto fail;
...@@ -4120,24 +4123,24 @@ symtable_load_symbols(struct compiling *c) ...@@ -4120,24 +4123,24 @@ symtable_load_symbols(struct compiling *c)
Py_DECREF(o); Py_DECREF(o);
} }
if (st->st_cur_type == TYPE_FUNCTION) if (ste->ste_type == TYPE_FUNCTION)
c->c_nlocals = nlocals; c->c_nlocals = nlocals;
if (st->st_cur_type != TYPE_MODULE) if (ste->ste_type != TYPE_MODULE)
c->c_flags |= CO_NEWLOCALS; c->c_flags |= CO_NEWLOCALS;
if (st->st_cur_type == TYPE_FUNCTION) { if (ste->ste_type == TYPE_FUNCTION) {
if (PyDict_GetItemString(st->st_cur, NOOPT) == NULL) if (ste->ste_optimized)
c->c_flags |= CO_OPTIMIZED; c->c_flags |= CO_OPTIMIZED;
else if (ncells || nfrees) { else if (ncells || nfrees
PyErr_Format(PyExc_SyntaxError, || (ste->ste_nested && nimplicit)
"function %.100s: may not use lexical scoping" || ste->ste_child_free) {
" and 'import *' or exec in same function", PyErr_Format(PyExc_SyntaxError, ILLEGAL_DYNAMIC_SCOPE,
PyString_AS_STRING(st->st_cur_name)); PyString_AS_STRING(ste->ste_name));
set_error_location(st->st_filename, set_error_location(st->st_filename, ste->ste_lineno);
st->st_cur_lineno);
return -1; return -1;
} }
} }
return 0; return 0;
fail: fail:
...@@ -4147,43 +4150,20 @@ symtable_load_symbols(struct compiling *c) ...@@ -4147,43 +4150,20 @@ symtable_load_symbols(struct compiling *c)
} }
static struct symtable * static struct symtable *
symtable_init(int keep) symtable_init()
{ {
struct symtable *st; struct symtable *st;
PyObject *d;
st = (struct symtable *)PyMem_Malloc(sizeof(struct symtable)); st = (struct symtable *)PyMem_Malloc(sizeof(struct symtable));
if (st == NULL) if (st == NULL)
return NULL; return NULL;
st->st_pass = 1; st->st_pass = 1;
st->st_keep = keep;
st->st_filename = NULL; st->st_filename = NULL;
if ((st->st_stack = PyList_New(0)) == NULL) if ((st->st_stack = PyList_New(0)) == NULL)
goto fail; goto fail;
if ((st->st_symbols = PyDict_New()) == NULL) if ((st->st_symbols = PyDict_New()) == NULL)
goto fail; 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 = 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_nscopes = 0;
st->st_errors = 0; st->st_errors = 0;
st->st_tmpname = 0; st->st_tmpname = 0;
...@@ -4198,51 +4178,10 @@ void ...@@ -4198,51 +4178,10 @@ void
PySymtable_Free(struct symtable *st) PySymtable_Free(struct symtable *st)
{ {
Py_XDECREF(st->st_symbols); Py_XDECREF(st->st_symbols);
Py_XDECREF(st->st_varnames);
Py_XDECREF(st->st_children);
Py_XDECREF(st->st_stack); 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); 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 /* When the compiler exits a scope, it must should update the scope's
free variable information with the list of free variables in its free variable information with the list of free variables in its
children. children.
...@@ -4250,7 +4189,7 @@ make_scope_info(PyObject *id, PyObject *name, int nested, int type, ...@@ -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 Variables that are free in children and defined in the current
scope are cellvars. 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 false), free variables in children that are not defined here are
implicit globals. implicit globals.
...@@ -4259,30 +4198,30 @@ make_scope_info(PyObject *id, PyObject *name, int nested, int type, ...@@ -4259,30 +4198,30 @@ make_scope_info(PyObject *id, PyObject *name, int nested, int type,
static int static int
symtable_update_free_vars(struct symtable *st) symtable_update_free_vars(struct symtable *st)
{ {
PyObject *dict, *o, *child, *name; PyObject *o, *name;
int i, def; 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; def = DEF_FREE_CLASS;
else else
def = DEF_FREE; 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; int pos = 0;
child = PyList_GET_ITEM(st->st_cur_children, i); child = (PySymtableEntryObject *)\
dict = PyDict_GetItem(st->st_symbols, child); PyList_GET_ITEM(ste->ste_children, i);
if (dict == NULL) while (PyDict_Next(child->ste_symbols, &pos, &name, &o)) {
return -1;
while (PyDict_Next(dict, &pos, &name, &o)) {
int v = PyInt_AS_LONG(o); int v = PyInt_AS_LONG(o);
if (!(is_free(v))) if (!(is_free(v)))
continue; /* avoids indentation */ continue; /* avoids indentation */
if (st->st_nested) { ste->ste_child_free = 1;
if (symtable_add_def_o(st, st->st_cur, if (ste->ste_nested) {
if (symtable_add_def_o(st, ste->ste_symbols,
name, def) < 0) name, def) < 0)
return -1; return -1;
} else { } else {
if (symtable_check_global(st, child, if (symtable_check_global(st, child->ste_id,
name) < 0) name) < 0)
return -1; return -1;
} }
...@@ -4302,17 +4241,19 @@ symtable_check_global(struct symtable *st, PyObject *child, PyObject *name) ...@@ -4302,17 +4241,19 @@ symtable_check_global(struct symtable *st, PyObject *child, PyObject *name)
{ {
PyObject *o; PyObject *o;
int v; 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); return symtable_undo_free(st, child, name);
o = PyDict_GetItem(st->st_cur, name); o = PyDict_GetItem(ste->ste_symbols, name);
if (o == NULL) if (o == NULL)
return symtable_undo_free(st, child, name); return symtable_undo_free(st, child, name);
v = PyInt_AS_LONG(o); v = PyInt_AS_LONG(o);
if (is_free(v) || (v & DEF_GLOBAL)) if (is_free(v) || (v & DEF_GLOBAL))
return symtable_undo_free(st, child, name); return symtable_undo_free(st, child, name);
else 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 static int
...@@ -4320,17 +4261,18 @@ symtable_undo_free(struct symtable *st, PyObject *id, ...@@ -4320,17 +4261,18 @@ symtable_undo_free(struct symtable *st, PyObject *id,
PyObject *name) PyObject *name)
{ {
int i, v, x; int i, v, x;
PyObject *dict, *children, *info; PyObject *info;
PySymtableEntryObject *ste;
dict = PyDict_GetItem(st->st_symbols, id); ste = (PySymtableEntryObject *)PyDict_GetItem(st->st_symbols, id);
if (dict == NULL) if (ste == NULL)
return -1; return -1;
info = PyDict_GetItem(dict, name); info = PyDict_GetItem(ste->ste_symbols, name);
if (info == NULL) if (info == NULL)
return 0; return 0;
v = PyInt_AS_LONG(info); v = PyInt_AS_LONG(info);
if (is_free(v)) { 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) DEF_FREE_GLOBAL) < 0)
return -1; return -1;
} else } else
...@@ -4338,10 +4280,11 @@ symtable_undo_free(struct symtable *st, PyObject *id, ...@@ -4338,10 +4280,11 @@ symtable_undo_free(struct symtable *st, PyObject *id,
then the recursion stops. */ then the recursion stops. */
return 0; return 0;
children = PyDict_GetItem(st->st_children, id); for (i = 0; i < PyList_GET_SIZE(ste->ste_children); ++i) {
for (i = 0; i < PyList_GET_SIZE(children); ++i) { PySymtableEntryObject *child;
x = symtable_undo_free(st, PyList_GET_ITEM(children, i), child = (PySymtableEntryObject *) \
name); PyList_GET_ITEM(ste->ste_children, i);
x = symtable_undo_free(st, child->ste_id, name);
if (x < 0) if (x < 0)
return x; return x;
} }
...@@ -4351,141 +4294,41 @@ symtable_undo_free(struct symtable *st, PyObject *id, ...@@ -4351,141 +4294,41 @@ symtable_undo_free(struct symtable *st, PyObject *id,
static int static int
symtable_exit_scope(struct symtable *st) symtable_exit_scope(struct symtable *st)
{ {
PyObject *o;
int end; int end;
if (st->st_pass == 1) if (st->st_pass == 1)
symtable_update_free_vars(st); symtable_update_free_vars(st);
if (st->st_cur_name) { Py_DECREF(st->st_cur);
Py_XDECREF(st->st_cur_name);
Py_XDECREF(st->st_cur_id);
}
end = PyList_GET_SIZE(st->st_stack) - 1; end = PyList_GET_SIZE(st->st_stack) - 1;
o = PyList_GET_ITEM(st->st_stack, end); st->st_cur = (PySymtableEntryObject *)PyList_GET_ITEM(st->st_stack,
st->st_cur_name = PyTuple_GET_ITEM(o, 0); end);
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));
if (PySequence_DelItem(st->st_stack, end) < 0) if (PySequence_DelItem(st->st_stack, end) < 0)
return -1; return -1;
return symtable_update_cur(st); return 0;
} }
static void static void
symtable_enter_scope(struct symtable *st, char *name, int type, symtable_enter_scope(struct symtable *st, char *name, int type,
int lineno) int lineno)
{ {
PyObject *o; PySymtableEntryObject *prev = NULL;
if (st->st_cur) { if (st->st_cur) {
/* push current scope info on stack */ prev = st->st_cur;
o = make_scope_info(st->st_cur_id, st->st_cur_name, if (PyList_Append(st->st_stack, (PyObject *)st->st_cur) < 0) {
st->st_nested, st->st_cur_type, Py_DECREF(st->st_cur);
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);
st->st_errors++; st->st_errors++;
return; 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) { st->st_cur = (PySymtableEntryObject *)\
if (PyList_Append(st->st_cur_children, o) < 0) { PySymtableEntry_New(st, name, type, lineno);
Py_DECREF(o); 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++; 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 static int
...@@ -4498,7 +4341,7 @@ symtable_add_def(struct symtable *st, char *name, int flag) ...@@ -4498,7 +4341,7 @@ symtable_add_def(struct symtable *st, char *name, int flag)
name = buffer; name = buffer;
if ((s = PyString_InternFromString(name)) == NULL) if ((s = PyString_InternFromString(name)) == NULL)
return -1; 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 */ /* Must only be called with mangled names */
...@@ -4516,7 +4359,7 @@ symtable_add_def_o(struct symtable *st, PyObject *dict, ...@@ -4516,7 +4359,7 @@ symtable_add_def_o(struct symtable *st, PyObject *dict,
PyErr_Format(PyExc_SyntaxError, DUPLICATE_ARGUMENT, PyErr_Format(PyExc_SyntaxError, DUPLICATE_ARGUMENT,
PyString_AsString(name)); PyString_AsString(name));
set_error_location(st->st_filename, set_error_location(st->st_filename,
st->st_cur_lineno); st->st_cur->ste_lineno);
return -1; return -1;
} }
val |= flag; val |= flag;
...@@ -4530,11 +4373,7 @@ symtable_add_def_o(struct symtable *st, PyObject *dict, ...@@ -4530,11 +4373,7 @@ symtable_add_def_o(struct symtable *st, PyObject *dict,
Py_DECREF(o); Py_DECREF(o);
if (flag & DEF_PARAM) { if (flag & DEF_PARAM) {
PyObject *l = PyDict_GetItem(st->st_varnames, if (PyList_Append(st->st_cur->ste_varnames, name) < 0)
st->st_cur_id);
if (l == NULL)
return -1;
if (PyList_Append(l, name) < 0)
return -1; return -1;
} else if (flag & DEF_GLOBAL) { } else if (flag & DEF_GLOBAL) {
/* XXX need to update DEF_GLOBAL for other flags too; /* XXX need to update DEF_GLOBAL for other flags too;
...@@ -4614,15 +4453,7 @@ symtable_node(struct symtable *st, node *n) ...@@ -4614,15 +4453,7 @@ symtable_node(struct symtable *st, node *n)
symtable_import(st, n); symtable_import(st, n);
break; break;
case exec_stmt: { case exec_stmt: {
PyObject *zero = PyInt_FromLong(0); st->st_cur->ste_optimized = 0;
if (zero == NULL)
st->st_errors++;
else {
if (PyDict_SetItemString(st->st_cur, NOOPT,
zero) < 0)
st->st_errors++;
Py_DECREF(zero);
}
symtable_node(st, CHILD(n, 1)); symtable_node(st, CHILD(n, 1));
if (NCH(n) > 2) if (NCH(n) > 2)
symtable_node(st, CHILD(n, 3)); symtable_node(st, CHILD(n, 3));
...@@ -4852,23 +4683,7 @@ symtable_import(struct symtable *st, node *n) ...@@ -4852,23 +4683,7 @@ symtable_import(struct symtable *st, node *n)
if (STR(CHILD(n, 0))[0] == 'f') { /* from */ if (STR(CHILD(n, 0))[0] == 'f') { /* from */
if (TYPE(CHILD(n, 3)) == STAR) { if (TYPE(CHILD(n, 3)) == STAR) {
PyObject *zero = PyInt_FromLong(0); st->st_cur->ste_optimized = 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);
}
} else { } else {
for (i = 3; i < NCH(n); i += 2) { for (i = 3; i < NCH(n); i += 2) {
node *c = CHILD(n, i); 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