[Python-checkins] CVS: python/dist/src/Python symtable.c,NONE,2.1 compile.c,2.160,2.161

Jeremy Hylton jhylton@users.sourceforge.net
Fri, 09 Feb 2001 14:22:20 -0800


Update of /cvsroot/python/python/dist/src/Python
In directory usw-pr-cvs1:/tmp/cvs-serv13672/Python

Modified Files:
	compile.c 
Added Files:
	symtable.c 
Log Message:
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.



--- NEW FILE: symtable.c ---
#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 */
};

Index: compile.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Python/compile.c,v
retrieving revision 2.160
retrieving revision 2.161
diff -C2 -r2.160 -r2.161
*** compile.c	2001/02/09 15:06:42	2.160
--- compile.c	2001/02/09 22:22:18	2.161
***************
*** 53,58 ****
  "duplicate argument '%s' in function definition"
  
! #define ILLEGAL_IMPORT_STAR \
! "'from ... import *' may only occur in a module scope"
  
  #define MANGLE_LEN 256
--- 53,58 ----
  "duplicate argument '%s' in function definition"
  
! #define ILLEGAL_DYNAMIC_SCOPE \
[...985 lines suppressed...]
! 						   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 {
  			for (i = 3; i < NCH(n); i += 2) {
--- 4684,4688 ----
  	if (STR(CHILD(n, 0))[0] == 'f') {  /* from */
  		if (TYPE(CHILD(n, 3)) == STAR) {
! 			st->st_cur->ste_optimized = 0;
  		} else {
  			for (i = 3; i < NCH(n); i += 2) {