[Python-checkins] python/dist/src/Python newcompile.c, 1.1.2.64, 1.1.2.65

nnorwitz at projects.sourceforge.net nnorwitz at projects.sourceforge.net
Tue Jan 27 14:05:46 EST 2004


Update of /cvsroot/python/python/dist/src/Python
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv26950/Python

Modified Files:
      Tag: ast-branch
	newcompile.c 
Log Message:
Start implementing closures

Index: newcompile.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Python/Attic/newcompile.c,v
retrieving revision 1.1.2.64
retrieving revision 1.1.2.65
diff -C2 -d -r1.1.2.64 -r1.1.2.65
*** newcompile.c	26 Jan 2004 14:38:58 -0000	1.1.2.64
--- newcompile.c	27 Jan 2004 19:05:43 -0000	1.1.2.65
***************
*** 78,81 ****
--- 78,83 ----
  	PyObject *u_names;     /* all names */
  	PyObject *u_varnames;  /* local variables */
+ 	PyObject *u_cellvars;  /* cell variables */
+ 	PyObject *u_freevars;  /* free variables */
  
  	int u_argcount;    /* number of arguments for block */ 
***************
*** 275,278 ****
--- 277,311 ----
  }
  
+ static PyObject *
+ dictbytype(PyObject *src, int scope_type)
+ {
+ 	int pos = 0, i = 0, scope;
+ 	PyObject *k, *v, *dest = PyDict_New();
+ 
+         if (dest == NULL)
+             return NULL;
+ 
+ 	while (PyDict_Next(src, &pos, &k, &v)) {
+             /* XXX this should probably be a macro in symtable.h */
+             assert(PyInt_Check(v));
+             scope = (PyInt_AS_LONG(v) >> SCOPE_OFF) & SCOPE_MASK;
+ 
+             if (scope == scope_type) {
+                 PyObject *item = PyInt_FromLong(i);
+                 if (item == NULL) {
+ 			Py_DECREF(dest);
+ 			return NULL;
+ 		}
+ 		if (PyDict_SetItem(dest, k, item) < 0) {
+ 			Py_DECREF(item);
+ 			Py_DECREF(dest);
+ 			return NULL;
+ 		}
+ 		Py_DECREF(item);
+             }
+ 	}
+ 	return dest;
+ }
+ 
  static void
  compiler_display_symbols(PyObject *name, PyObject *symbols)
***************
*** 324,328 ****
  	u->u_name = name;
  	u->u_varnames = list2dict(u->u_ste->ste_varnames);
! 	Py_INCREF(u->u_varnames);
  	u->u_nblocks = 0;
  	u->u_nalloc = DEFAULT_BLOCKS;
--- 357,362 ----
  	u->u_name = name;
  	u->u_varnames = list2dict(u->u_ste->ste_varnames);
! 	u->u_cellvars = dictbytype(u->u_ste->ste_symbols, CELL);
! 	u->u_freevars = dictbytype(u->u_ste->ste_symbols, FREE);
  	u->u_nblocks = 0;
  	u->u_nalloc = DEFAULT_BLOCKS;
***************
*** 334,338 ****
  	u->u_nfblocks = 0;
  	u->u_lineno = 0;
! 	u->u_lineno_set = true;
  	memset(u->u_blocks, 0, sizeof(struct basicblock *) * DEFAULT_BLOCKS);
  	u->u_consts = PyDict_New();
--- 368,372 ----
  	u->u_nfblocks = 0;
  	u->u_lineno = 0;
! 	u->u_lineno_set = false;
  	memset(u->u_blocks, 0, sizeof(struct basicblock *) * DEFAULT_BLOCKS);
  	u->u_consts = PyDict_New();
***************
*** 393,396 ****
--- 427,432 ----
  	Py_XDECREF(u->u_names);
  	Py_XDECREF(u->u_varnames);
+ 	Py_XDECREF(u->u_freevars);
+ 	Py_XDECREF(u->u_cellvars);
  	PyObject_Free(u);
  }
***************
*** 732,735 ****
--- 768,852 ----
  }
  
+ /* The test for LOCAL must come before the test for FREE in order to
+    handle classes where name is both local and free.  The local var is
+    a method and the free var is a free var referenced within a method.
+ */
+ 
+ static int
+ get_ref_type(struct compiler *c, PyObject *name)
+ {
+ 	int scope = PyST_GetScope(c->u->u_ste, name);
+         if (scope == 0) {
+             char buf[350];
+             PyOS_snprintf(buf, sizeof(buf),
+                           "unknown scope for %.100s in %.100s(%s) in %s\n"
+                           "symbols: %s\nlocals: %s\nglobals: %s\n",
+                           PyString_AS_STRING(name), 
+                           PyString_AS_STRING(c->u->u_name), 
+                           PyObject_REPR(c->c_st->st_cur->ste_id),
+                           c->c_filename,
+                           PyObject_REPR(c->c_st->st_cur->ste_symbols),
+                           PyObject_REPR(c->u->u_varnames),
+                           PyObject_REPR(c->u->u_names)
+ 		);
+             Py_FatalError(buf);
+         }
+ 
+         return scope;
+ }
+ 
+ static int
+ compiler_lookup_arg(PyObject *dict, PyObject *name)
+ {
+     PyObject *v = PyDict_GetItem(dict, name);
+     if (v == NULL)
+         return -1;
+     return PyInt_AS_LONG(v);
+ }
+ 
+ static int
+ compiler_make_closure(struct compiler *c, PyCodeObject *co, int args)
+ {
+ 	int i, free = PyCode_GetNumFree(co);
+ 	if (free == 0) {
+             ADDOP_O(c, LOAD_CONST, (PyObject*)co, consts);
+             ADDOP_I(c, MAKE_FUNCTION, args);
+             return 1;
+         }
+ 	for (i = 0; i < free; ++i) {
+ 		/* Bypass com_addop_varname because it will generate
+ 		   LOAD_DEREF but LOAD_CLOSURE is needed. 
+ 		*/
+ 		PyObject *name = PyTuple_GET_ITEM(co->co_freevars, i);
+ 		int arg, reftype;
+ 
+ 		/* Special case: If a class contains a method with a
+ 		   free variable that has the same name as a method,
+ 		   the name will be considered free *and* local in the
+ 		   class.  It should be handled by the closure, as
+ 		   well as by the normal name loookup logic.
+ 		*/
+ 		reftype = get_ref_type(c, name);
+ 		if (reftype == CELL)
+ 			arg = compiler_lookup_arg(c->u->u_cellvars, name);
+ 		else /* (reftype == FREE) */
+ 			arg = compiler_lookup_arg(c->u->u_freevars, name);
+ 		if (arg == -1) {
+ 			fprintf(stderr, "lookup %s in %s %d %d\n"
+ 				"freevars of %s: %s\n",
+ 				PyObject_REPR(name), 
+ 				PyString_AS_STRING(c->u->u_name), 
+ 				reftype, arg,
+ 				PyString_AS_STRING(co->co_name),
+ 				PyObject_REPR(co->co_freevars));
+ 			Py_FatalError("compiler_make_closure()");
+ 		}
+ 		ADDOP_I(c, LOAD_CLOSURE, arg);
+ 	}
+ 	ADDOP_O(c, LOAD_CONST, (PyObject*)co, consts);
+         ADDOP_I(c, MAKE_CLOSURE, args);
+         return 1;
+ }
+ 
  static int
  compiler_function(struct compiler *c, stmt_ty s)
***************
*** 769,775 ****
  	compiler_exit_scope(c);
  
! 	/* XXX closure */
! 	ADDOP_O(c, LOAD_CONST, (PyObject *)co, consts);
! 	ADDOP_I(c, MAKE_FUNCTION, asdl_seq_LEN(args->defaults));
  	if (!compiler_nameop(c, s->v.FunctionDef.name, Store))
  		return 0;
--- 886,890 ----
  	compiler_exit_scope(c);
  
!         compiler_make_closure(c, co, asdl_seq_LEN(args->defaults));
  	if (!compiler_nameop(c, s->v.FunctionDef.name, Store))
  		return 0;
***************
*** 816,822 ****
  	compiler_exit_scope(c);
  
! 	/* XXX closure */
! 	ADDOP_O(c, LOAD_CONST, (PyObject *)co, consts);
! 	ADDOP_I(c, MAKE_FUNCTION, 0);
  	ADDOP_I(c, CALL_FUNCTION, 0);
  	ADDOP(c, BUILD_CLASS);
--- 931,935 ----
  	compiler_exit_scope(c);
  
!         compiler_make_closure(c, co, 0);
  	ADDOP_I(c, CALL_FUNCTION, 0);
  	ADDOP(c, BUILD_CLASS);
***************
*** 842,846 ****
  	if (!compiler_enter_scope(c, name, (void *)e))
  		return 0;
! 	c->u->u_argcount = asdl_seq_LEN(e->v.Lambda.args->args);
  	VISIT(c, expr, e->v.Lambda.body);
  	ADDOP(c, RETURN_VALUE);
--- 955,959 ----
  	if (!compiler_enter_scope(c, name, (void *)e))
  		return 0;
! 	c->u->u_argcount = asdl_seq_LEN(args->args);
  	VISIT(c, expr, e->v.Lambda.body);
  	ADDOP(c, RETURN_VALUE);
***************
*** 850,857 ****
  	compiler_exit_scope(c);
  
! 	/* XXX closure */
! 	ADDOP_O(c, LOAD_CONST, (PyObject *)co, consts);
! 	ADDOP_I(c, MAKE_FUNCTION, asdl_seq_LEN(args->defaults));
! 
  	Py_DECREF(name);
  
--- 963,967 ----
  	compiler_exit_scope(c);
  
!         compiler_make_closure(c, co, asdl_seq_LEN(args->defaults));
  	Py_DECREF(name);
  
***************
*** 2522,2526 ****
  	PyObject *filename = NULL;
  	PyObject *name = NULL;
! 	PyObject *nil = PyTuple_New(0);
  	int nlocals;
  
--- 2632,2637 ----
  	PyObject *filename = NULL;
  	PyObject *name = NULL;
! 	PyObject *freevars = NULL;
! 	PyObject *cellvars = NULL;
  	int nlocals;
  
***************
*** 2532,2546 ****
  		goto error;
  	varnames = PySequence_Tuple(c->u->u_ste->ste_varnames);
! 	if (!varnames)
! 		goto error;
  	filename = PyString_FromString(c->c_filename);
  	if (!filename)
  		goto error;
  
! 	nlocals = PyList_GET_SIZE(c->u->u_varnames);
  	co = PyCode_New(c->u->u_argcount, nlocals, stackdepth(c),
  			compute_code_flags(c),
  			a->a_bytecode, consts, names, varnames,
! 			nil, nil,
  			filename, c->u->u_name,
  			a->a_firstlineno,
--- 2643,2660 ----
  		goto error;
  	varnames = PySequence_Tuple(c->u->u_ste->ste_varnames);
!         freevars = PySequence_Tuple(c->u->u_freevars);
!         cellvars = PySequence_Tuple(c->u->u_cellvars);
!         if (!varnames || !freevars || !cellvars)
!             goto error;
! 
  	filename = PyString_FromString(c->c_filename);
  	if (!filename)
  		goto error;
  
!         nlocals = PyDict_Size(c->u->u_varnames);
  	co = PyCode_New(c->u->u_argcount, nlocals, stackdepth(c),
  			compute_code_flags(c),
  			a->a_bytecode, consts, names, varnames,
! 			freevars, cellvars,
  			filename, c->u->u_name,
  			a->a_firstlineno,
***************
*** 2552,2557 ****
  	Py_XDECREF(filename);
  	Py_XDECREF(name);
  	return co;
- 
  }
  
--- 2666,2672 ----
  	Py_XDECREF(filename);
  	Py_XDECREF(name);
+ 	Py_XDECREF(freevars);
+ 	Py_XDECREF(cellvars);
  	return co;
  }
  




More information about the Python-checkins mailing list