Index: Grammar/Grammar
===================================================================
RCS file: /cvsroot/python/python/dist/src/Grammar/Grammar,v
retrieving revision 1.42
diff -u -r1.42 Grammar
--- Grammar/Grammar	2001/02/27 18:36:14	1.42
+++ Grammar/Grammar	2001/03/17 01:41:27
@@ -43,10 +43,11 @@
 print_stmt: 'print' ( [ test (',' test)* [','] ] | '>>' test [ (',' test)+ [','] ] )
 del_stmt: 'del' exprlist
 pass_stmt: 'pass'
-flow_stmt: break_stmt | continue_stmt | return_stmt | raise_stmt
+flow_stmt: break_stmt | continue_stmt | return_stmt | suspend_stmt | raise_stmt
 break_stmt: 'break'
 continue_stmt: 'continue'
 return_stmt: 'return' [testlist]
+suspend_stmt: 'suspend' [testlist]
 raise_stmt: 'raise' [test [',' test [',' test]]]
 import_stmt: 'import' dotted_as_name (',' dotted_as_name)* | 'from' dotted_name 'import' ('*' | import_as_name (',' import_as_name)*)
 import_as_name: NAME [NAME NAME]
Index: Include/ceval.h
===================================================================
RCS file: /cvsroot/python/python/dist/src/Include/ceval.h,v
retrieving revision 2.40
diff -u -r2.40 ceval.h
--- Include/ceval.h	2000/09/15 18:19:27	2.40
+++ Include/ceval.h	2001/03/17 01:41:27
@@ -10,6 +10,10 @@
 DL_IMPORT(PyObject *) PyEval_CallObjectWithKeywords
 	(PyObject *, PyObject *, PyObject *);
 
+struct _frame;
+
+DL_IMPORT(PyObject *) PyEval_EvalFrame(struct _frame *);
+
 /* DLL-level Backwards compatibility: */
 #undef PyEval_CallObject
 DL_IMPORT(PyObject *) PyEval_CallObject(PyObject *, PyObject *);
Index: Include/frameobject.h
===================================================================
RCS file: /cvsroot/python/python/dist/src/Include/frameobject.h,v
retrieving revision 2.31
diff -u -r2.31 frameobject.h
--- Include/frameobject.h	2001/03/13 01:58:21	2.31
+++ Include/frameobject.h	2001/03/17 01:41:27
@@ -21,6 +21,7 @@
     PyObject *f_globals;	/* global symbol table (PyDictObject) */
     PyObject *f_locals;		/* local symbol table (PyDictObject) */
     PyObject **f_valuestack;	/* points after the last local */
+    PyObject **f_stackbottom;	/* points to the last item on the stack */
     PyObject *f_trace;		/* Trace function */
     PyObject *f_exc_type, *f_exc_value, *f_exc_traceback;
     PyThreadState *f_tstate;
Index: Include/opcode.h
===================================================================
RCS file: /cvsroot/python/python/dist/src/Include/opcode.h,v
retrieving revision 2.34
diff -u -r2.34 opcode.h
--- Include/opcode.h	2001/02/01 22:48:12	2.34
+++ Include/opcode.h	2001/03/17 01:41:27
@@ -70,6 +70,7 @@
 #define RETURN_VALUE	83
 #define IMPORT_STAR	84
 #define EXEC_STMT	85
+#define SUSPEND		86
 
 #define POP_BLOCK	87
 #define END_FINALLY	88
Index: Objects/frameobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/frameobject.c,v
retrieving revision 2.46
diff -u -r2.46 frameobject.c
--- Objects/frameobject.c	2001/03/13 01:58:21	2.46
+++ Objects/frameobject.c	2001/03/17 01:41:27
@@ -27,11 +27,42 @@
 };
 
 static PyObject *
+frame_resume(PyFrameObject *f, PyObject *args)
+{
+	PyThreadState *tstate = PyThreadState_GET();
+	if (!PyArg_ParseTuple(args, ":resume"))
+		return NULL;
+	if (f->f_stackbottom == NULL) {
+		PyErr_SetString(PyExc_ValueError, "frame not suspended");
+		return NULL;
+	}
+	f->f_back = tstate->frame;
+	/* don't run off the end of the code */
+	if (f->f_lasti >= PySequence_Size(f->f_code->co_code)) {
+		Py_INCREF(Py_None);
+		return Py_None;
+	}
+	Py_INCREF(f);
+	return PyEval_EvalFrame(f);
+}
+
+
+static struct PyMethodDef frame_methods[] = {
+	{"resume",	(PyCFunction)frame_resume, METH_VARARGS},
+	{NULL, 		NULL}	/* Sentinel */
+};
+
+static PyObject *
 frame_getattr(PyFrameObject *f, char *name)
 {
+	PyObject *res;
 	if (strcmp(name, "f_locals") == 0)
 		PyFrame_FastToLocals(f);
-	return PyMember_Get((char *)f, frame_memberlist, name);
+	res = PyMember_Get((char *)f, frame_memberlist, name);
+	if (res != NULL)
+		return res;
+	PyErr_Clear();
+	return Py_FindMethod(frame_methods, (PyObject *)f, name);
 }
 
 static int
@@ -67,6 +98,7 @@
 {
 	int i, slots;
 	PyObject **fastlocals;
+	PyObject **p;
 
 	Py_TRASHCAN_SAFE_BEGIN(f)
 	/* Kill all local variables */
@@ -75,7 +107,16 @@
 	for (i = slots; --i >= 0; ++fastlocals) {
 		Py_XDECREF(*fastlocals);
 	}
-
+	/* Free stack */
+	for (p = f->f_valuestack; p < f->f_stackbottom; p++) {
+		Py_XDECREF(*p);
+	}
+	/* Free blocks */
+	/*
+	while (f->f_iblock > 0) {
+		PyTryBlock *b = PyFrame_BlockPop(f);
+	}
+	*/
 	Py_XDECREF(f->f_back);
 	Py_XDECREF(f->f_code);
 	Py_XDECREF(f->f_builtins);
@@ -85,8 +126,10 @@
 	Py_XDECREF(f->f_exc_type);
 	Py_XDECREF(f->f_exc_value);
 	Py_XDECREF(f->f_exc_traceback);
+	/*
 	f->f_back = free_list;
 	free_list = f;
+	*/
 	Py_TRASHCAN_SAFE_END(f)
 }
 
@@ -221,6 +264,7 @@
 		f->f_localsplus[extras] = NULL;
 
 	f->f_valuestack = f->f_localsplus + (f->f_nlocals + ncells + nfrees);
+	f->f_stackbottom = f->f_valuestack;
 
 	return f;
 }
@@ -341,3 +385,4 @@
 		PyObject_DEL(f);
 	}
 }
+
Index: Python/ceval.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Python/ceval.c,v
retrieving revision 2.231
diff -u -r2.231 ceval.c
--- Python/ceval.c	2001/03/13 01:58:21	2.231
+++ Python/ceval.c	2001/03/17 01:41:28
@@ -322,6 +322,7 @@
 		WHY_EXCEPTION,	/* Exception occurred */
 		WHY_RERAISE,	/* Exception re-raised by 'finally' */
 		WHY_RETURN,	/* 'return' statement */
+		WHY_SUSPEND,	/* 'suspend' statement */
 		WHY_BREAK,	/* 'break' statement */
 		WHY_CONTINUE	/* 'continue' statement */
 };
@@ -341,13 +342,8 @@
 			  NULL);
 }
 
-
-/* Interpreter main loop */
-
-static PyObject *
-eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
-	   PyObject **args, int argcount, PyObject **kws, int kwcount,
-	   PyObject **defs, int defcount, PyObject *closure)
+PyObject *
+PyEval_EvalFrame(PyFrameObject *f)
 {
 #ifdef DXPAIRS
 	int lastopcode = 0;
@@ -364,10 +360,10 @@
 	register PyObject *u;
 	register PyObject *t;
 	register PyObject *stream = NULL;    /* for PRINT opcodes */
-	register PyFrameObject *f; /* Current frame */
 	register PyObject **fastlocals, **freevars;
 	PyObject *retval = NULL;	/* Return value */
-	PyThreadState *tstate = PyThreadState_GET();
+	PyThreadState *tstate = f->f_tstate;
+	PyCodeObject *co = f->f_code;
 	unsigned char *first_instr;
 #ifdef LLTRACE
 	int lltrace;
@@ -410,225 +406,17 @@
 #define SETLOCAL(i, value)	do { Py_XDECREF(GETLOCAL(i)); \
 				     GETLOCAL(i) = value; } while (0)
 
-/* Start of code */
-
-#ifdef USE_STACKCHECK
-	if (tstate->recursion_depth%10 == 0 && PyOS_CheckStack()) {
-		PyErr_SetString(PyExc_MemoryError, "Stack overflow");
-		return NULL;
-	}
-#endif
-
-	if (globals == NULL) {
-		PyErr_SetString(PyExc_SystemError, "eval_code2: NULL globals");
-		return NULL;
-	}
-
 #ifdef LLTRACE
-	lltrace = PyDict_GetItemString(globals, "__lltrace__") != NULL;
+	lltrace = PyDict_GetItemString(f->f_globals, "__lltrace__") != NULL;
 #endif
 
-	f = PyFrame_New(tstate,			/*back*/
-			co,			/*code*/
-			globals, locals);
-	if (f == NULL)
-		return NULL;
-
+	_PyCode_GETCODEPTR(co, &first_instr);
+	next_instr = first_instr + f->f_lasti;
+	stack_pointer = f->f_stackbottom;
 	tstate->frame = f;
 	fastlocals = f->f_localsplus;
 	freevars = f->f_localsplus + f->f_nlocals;
 
-	if (co->co_argcount > 0 ||
-	    co->co_flags & (CO_VARARGS | CO_VARKEYWORDS)) {
-		int i;
-		int n = argcount;
-		PyObject *kwdict = NULL;
-		if (co->co_flags & CO_VARKEYWORDS) {
-			kwdict = PyDict_New();
-			if (kwdict == NULL)
-				goto fail;
-			i = co->co_argcount;
-			if (co->co_flags & CO_VARARGS)
-				i++;
-			SETLOCAL(i, kwdict);
-		}
-		if (argcount > co->co_argcount) {
-			if (!(co->co_flags & CO_VARARGS)) {
-				PyErr_Format(PyExc_TypeError,
-				    "%.200s() takes %s %d "
-				    "%sargument%s (%d given)",
-				    PyString_AsString(co->co_name),
-				    defcount ? "at most" : "exactly",
-				    co->co_argcount,
-				    kwcount ? "non-keyword " : "",
-				    co->co_argcount == 1 ? "" : "s",
-				    argcount);
-				goto fail;
-			}
-			n = co->co_argcount;
-		}
-		for (i = 0; i < n; i++) {
-			x = args[i];
-			Py_INCREF(x);
-			SETLOCAL(i, x);
-		}
-		if (co->co_flags & CO_VARARGS) {
-			u = PyTuple_New(argcount - n);
-			if (u == NULL)
-				goto fail;
-			SETLOCAL(co->co_argcount, u);
-			for (i = n; i < argcount; i++) {
-				x = args[i];
-				Py_INCREF(x);
-				PyTuple_SET_ITEM(u, i-n, x);
-			}
-		}
-		for (i = 0; i < kwcount; i++) {
-			PyObject *keyword = kws[2*i];
-			PyObject *value = kws[2*i + 1];
-			int j;
-			if (keyword == NULL || !PyString_Check(keyword)) {
-				PyErr_Format(PyExc_TypeError,
-				    "%.200s() keywords must be strings",
-				    PyString_AsString(co->co_name));
-				goto fail;
-			}
-			/* XXX slow -- speed up using dictionary? */
-			for (j = 0; j < co->co_argcount; j++) {
-				PyObject *nm = PyTuple_GET_ITEM(
-					co->co_varnames, j);
-				int cmp = PyObject_RichCompareBool(
-					keyword, nm, Py_EQ);
-				if (cmp > 0)
-					break;
-				else if (cmp < 0)
-					goto fail;
-			}
-			/* Check errors from Compare */
-			if (PyErr_Occurred())
-				goto fail;
-			if (j >= co->co_argcount) {
-				if (kwdict == NULL) {
-					PyErr_Format(PyExc_TypeError,
-					    "%.200s() got an unexpected "
-					    "keyword argument '%.400s'",
-					    PyString_AsString(co->co_name),
-					    PyString_AsString(keyword));
-					goto fail;
-				}
-				PyDict_SetItem(kwdict, keyword, value);
-			}
-			else {
-				if (GETLOCAL(j) != NULL) {
-					PyErr_Format(PyExc_TypeError,
-					     "%.200s() got multiple "
-					     "values for keyword "
-					     "argument '%.400s'",
-					     PyString_AsString(co->co_name),
-					     PyString_AsString(keyword));
-					goto fail;
-				}
-				Py_INCREF(value);
-				SETLOCAL(j, value);
-			}
-		}
-		if (argcount < co->co_argcount) {
-			int m = co->co_argcount - defcount;
-			for (i = argcount; i < m; i++) {
-				if (GETLOCAL(i) == NULL) {
-					PyErr_Format(PyExc_TypeError,
-					    "%.200s() takes %s %d "
-					    "%sargument%s (%d given)",
-					    PyString_AsString(co->co_name),
-					    ((co->co_flags & CO_VARARGS) ||
-					     defcount) ? "at least"
-						       : "exactly",
-					    m, kwcount ? "non-keyword " : "",
-					    m == 1 ? "" : "s", i);
-					goto fail;
-				}
-			}
-			if (n > m)
-				i = n - m;
-			else
-				i = 0;
-			for (; i < defcount; i++) {
-				if (GETLOCAL(m+i) == NULL) {
-					PyObject *def = defs[i];
-					Py_INCREF(def);
-					SETLOCAL(m+i, def);
-				}
-			}
-		}
-	}
-	else {
-		if (argcount > 0 || kwcount > 0) {
-			PyErr_Format(PyExc_TypeError,
-				     "%.200s() takes no arguments (%d given)",
-				     PyString_AsString(co->co_name),
-				     argcount + kwcount);
-			goto fail;
-		}
-	}
-	/* Allocate storage for cell vars and copy free vars into frame */ 
-	if (f->f_ncells) {
-		int i;
-		for (i = 0; i < f->f_ncells; ++i)
-			freevars[i] = PyCell_New(NULL);
-	}
-	if (f->f_nfreevars) {
-		int i;
-		for (i = 0; i < f->f_nfreevars; ++i) {
-			PyObject *o = PyTuple_GET_ITEM(closure, i);
-			Py_INCREF(o);
-			freevars[f->f_ncells + i] = o;
-		}
-	}
-
-	if (tstate->sys_tracefunc != NULL) {
-		/* tstate->sys_tracefunc, if defined, is a function that
-		   will be called  on *every* entry to a code block.
-		   Its return value, if not None, is a function that
-		   will be called at the start of each executed line
-		   of code.  (Actually, the function must return
-		   itself in order to continue tracing.)
-		   The trace functions are called with three arguments:
-		   a pointer to the current frame, a string indicating
-		   why the function is called, and an argument which
-		   depends on the situation.  The global trace function
-		   (sys.trace) is also called whenever an exception
-		   is detected. */
-		if (call_trace(&tstate->sys_tracefunc,
-			       &f->f_trace, f, "call",
-			       Py_None/*XXX how to compute arguments now?*/)) {
-			/* Trace function raised an error */
-			goto fail;
-		}
-	}
-
-	if (tstate->sys_profilefunc != NULL) {
-		/* Similar for sys_profilefunc, except it needn't return
-		   itself and isn't called for "line" events */
-		if (call_trace(&tstate->sys_profilefunc,
-			       (PyObject**)0, f, "call",
-			       Py_None/*XXX*/)) {
-			goto fail;
-		}
-	}
-
-	if (++tstate->recursion_depth > recursion_limit) {
-		--tstate->recursion_depth;
-		PyErr_SetString(PyExc_RuntimeError,
-				"maximum recursion depth exceeded");
-		tstate->frame = f->f_back;
-		Py_DECREF(f);
-		return NULL;
-	}
-
-	_PyCode_GETCODEPTR(co, &first_instr);
-	next_instr = first_instr;
-	stack_pointer = f->f_valuestack;
-
 	why = WHY_NOT;
 	err = 0;
 	x = Py_None;	/* Not a reference, just anything non-NULL */
@@ -1404,6 +1192,11 @@
 			why = WHY_RETURN;
 			break;
 
+		case SUSPEND:
+			retval = POP();
+			why = WHY_SUSPEND;
+			break;
+
 		case EXEC_STMT:
 			w = POP();
 			v = POP();
@@ -2134,7 +1927,7 @@
 
 		/* Unwind stacks if a (pseudo) exception occurred */
 
-		while (why != WHY_NOT && f->f_iblock > 0) {
+		while (why != WHY_NOT && why != WHY_SUSPEND && f->f_iblock > 0) {
 			PyTryBlock *b = PyFrame_BlockPop(f);
 
 			if (b->b_type == SETUP_LOOP && why == WHY_CONTINUE) {
@@ -2148,9 +1941,11 @@
 				break;
 			}
 
-			while (STACK_LEVEL() > b->b_level) {
-				v = POP();
-				Py_XDECREF(v);
+			if (why != WHY_RETURN) {
+				while (STACK_LEVEL() > b->b_level) {
+					v = POP();
+					Py_XDECREF(v);
+				}
 			}
 			if (b->b_type == SETUP_LOOP && why == WHY_BREAK) {
 				why = WHY_NOT;
@@ -2204,12 +1999,14 @@
 
 	/* Pop remaining stack entries */
 
+	/*
 	while (!EMPTY()) {
 		v = POP();
 		Py_XDECREF(v);
 	}
+	*/
 
-	if (why != WHY_RETURN)
+	if (why != WHY_RETURN && why != WHY_SUSPEND)
 		retval = NULL;
 
 	if (f->f_trace) {
@@ -2236,6 +2033,245 @@
 
 	--tstate->recursion_depth;
 
+	/* Restore previous frame and release the current one */
+
+	f->f_lasti = INSTR_OFFSET();
+	if (why == WHY_SUSPEND) {
+		/* make frame resumable */
+		f->f_stackbottom = stack_pointer;
+	} else {
+		f->f_stackbottom = NULL; 
+	}
+	tstate->frame = f->f_back;
+	Py_DECREF(f);
+
+	return retval;
+}
+
+/* Interpreter main loop */
+
+static PyObject *
+eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
+	   PyObject **args, int argcount, PyObject **kws, int kwcount,
+	   PyObject **defs, int defcount, PyObject *closure)
+{
+	register PyFrameObject *f; /* Current frame */
+	register PyObject **fastlocals, **freevars;
+	PyThreadState *tstate = PyThreadState_GET();
+	PyObject *x, *u;
+
+
+/* Start of code */
+
+#ifdef USE_STACKCHECK
+	if (tstate->recursion_depth%10 == 0 && PyOS_CheckStack()) {
+		PyErr_SetString(PyExc_MemoryError, "Stack overflow");
+		return NULL;
+	}
+#endif
+
+	if (globals == NULL) {
+		PyErr_SetString(PyExc_SystemError, "eval_code2: NULL globals");
+		return NULL;
+	}
+
+	f = PyFrame_New(tstate,			/*back*/
+			co,			/*code*/
+			globals, locals);
+	if (f == NULL)
+		return NULL;
+
+	fastlocals = f->f_localsplus;
+	freevars = f->f_localsplus + f->f_nlocals;
+
+	if (co->co_argcount > 0 ||
+	    co->co_flags & (CO_VARARGS | CO_VARKEYWORDS)) {
+		int i;
+		int n = argcount;
+		PyObject *kwdict = NULL;
+		if (co->co_flags & CO_VARKEYWORDS) {
+			kwdict = PyDict_New();
+			if (kwdict == NULL) {
+				goto fail;
+			}
+			i = co->co_argcount;
+			if (co->co_flags & CO_VARARGS)
+				i++;
+			SETLOCAL(i, kwdict);
+		}
+		if (argcount > co->co_argcount) {
+			if (!(co->co_flags & CO_VARARGS)) {
+				PyErr_Format(PyExc_TypeError,
+				    "%.200s() takes %s %d "
+				    "%sargument%s (%d given)",
+				    PyString_AsString(co->co_name),
+				    defcount ? "at most" : "exactly",
+				    co->co_argcount,
+				    kwcount ? "non-keyword " : "",
+				    co->co_argcount == 1 ? "" : "s",
+				    argcount);
+				goto fail;
+			}
+			n = co->co_argcount;
+		}
+		for (i = 0; i < n; i++) {
+			x = args[i];
+			Py_INCREF(x);
+			SETLOCAL(i, x);
+		}
+		if (co->co_flags & CO_VARARGS) {
+			u = PyTuple_New(argcount - n);
+			if (u == NULL)
+				goto fail;
+			SETLOCAL(co->co_argcount, u);
+			for (i = n; i < argcount; i++) {
+				x = args[i];
+				Py_INCREF(x);
+				PyTuple_SET_ITEM(u, i-n, x);
+			}
+		}
+		for (i = 0; i < kwcount; i++) {
+			PyObject *keyword = kws[2*i];
+			PyObject *value = kws[2*i + 1];
+			int j;
+			if (keyword == NULL || !PyString_Check(keyword)) {
+				PyErr_Format(PyExc_TypeError,
+				    "%.200s() keywords must be strings",
+				    PyString_AsString(co->co_name));
+				goto fail;
+			}
+			/* XXX slow -- speed up using dictionary? */
+			for (j = 0; j < co->co_argcount; j++) {
+				PyObject *nm = PyTuple_GET_ITEM(
+					co->co_varnames, j);
+				int cmp = PyObject_RichCompareBool(
+					keyword, nm, Py_EQ);
+				if (cmp > 0)
+					break;
+				else if (cmp < 0)
+					goto fail;
+			}
+			/* Check errors from Compare */
+			if (PyErr_Occurred())
+				goto fail;
+			if (j >= co->co_argcount) {
+				if (kwdict == NULL) {
+					PyErr_Format(PyExc_TypeError,
+					    "%.200s() got an unexpected "
+					    "keyword argument '%.400s'",
+					    PyString_AsString(co->co_name),
+					    PyString_AsString(keyword));
+					goto fail;
+				}
+				PyDict_SetItem(kwdict, keyword, value);
+			}
+			else {
+				if (GETLOCAL(j) != NULL) {
+					PyErr_Format(PyExc_TypeError,
+					     "%.200s() got multiple "
+					     "values for keyword "
+					     "argument '%.400s'",
+					     PyString_AsString(co->co_name),
+					     PyString_AsString(keyword));
+					goto fail;
+				}
+				Py_INCREF(value);
+				SETLOCAL(j, value);
+			}
+		}
+		if (argcount < co->co_argcount) {
+			int m = co->co_argcount - defcount;
+			for (i = argcount; i < m; i++) {
+				if (GETLOCAL(i) == NULL) {
+					PyErr_Format(PyExc_TypeError,
+					    "%.200s() takes %s %d "
+					    "%sargument%s (%d given)",
+					    PyString_AsString(co->co_name),
+					    ((co->co_flags & CO_VARARGS) ||
+					     defcount) ? "at least"
+						       : "exactly",
+					    m, kwcount ? "non-keyword " : "",
+					    m == 1 ? "" : "s", i);
+					goto fail;
+				}
+			}
+			if (n > m)
+				i = n - m;
+			else
+				i = 0;
+			for (; i < defcount; i++) {
+				if (GETLOCAL(m+i) == NULL) {
+					PyObject *def = defs[i];
+					Py_INCREF(def);
+					SETLOCAL(m+i, def);
+				}
+			}
+		}
+	}
+	else {
+		if (argcount > 0 || kwcount > 0) {
+			PyErr_Format(PyExc_TypeError,
+				     "%.200s() takes no arguments (%d given)",
+				     PyString_AsString(co->co_name),
+				     argcount + kwcount);
+			goto fail;
+		}
+	}
+	/* Allocate storage for cell vars and copy free vars into frame */ 
+	if (f->f_ncells) {
+		int i;
+		for (i = 0; i < f->f_ncells; ++i)
+			freevars[i] = PyCell_New(NULL);
+	}
+	if (f->f_nfreevars) {
+		int i;
+		for (i = 0; i < f->f_nfreevars; ++i) {
+			PyObject *o = PyTuple_GET_ITEM(closure, i);
+			Py_INCREF(o);
+			freevars[f->f_ncells + i] = o;
+		}
+	}
+
+	if (tstate->sys_tracefunc != NULL) {
+		/* tstate->sys_tracefunc, if defined, is a function that
+		   will be called  on *every* entry to a code block.
+		   Its return value, if not None, is a function that
+		   will be called at the start of each executed line
+		   of code.  (Actually, the function must return
+		   itself in order to continue tracing.)
+		   The trace functions are called with three arguments:
+		   a pointer to the current frame, a string indicating
+		   why the function is called, and an argument which
+		   depends on the situation.  The global trace function
+		   (sys.trace) is also called whenever an exception
+		   is detected. */
+		if (call_trace(&tstate->sys_tracefunc,
+			       &f->f_trace, f, "call",
+			       Py_None/*XXX how to compute arguments now?*/)) {
+			/* Trace function raised an error */
+			goto fail;
+		}
+	}
+
+	if (tstate->sys_profilefunc != NULL) {
+		/* Similar for sys_profilefunc, except it needn't return
+		   itself and isn't called for "line" events */
+		if (call_trace(&tstate->sys_profilefunc,
+			       (PyObject**)0, f, "call",
+			       Py_None/*XXX*/)) {
+			goto fail;
+		}
+	}
+
+	if (++tstate->recursion_depth > recursion_limit) {
+		--tstate->recursion_depth;
+		PyErr_SetString(PyExc_RuntimeError,
+				"maximum recursion depth exceeded");
+		goto fail;
+	}
+
+	return PyEval_EvalFrame(f);
+
   fail: /* Jump here from prelude on failure */
 
 	/* Restore previous frame and release the current one */
@@ -2243,7 +2279,7 @@
 	tstate->frame = f->f_back;
 	Py_DECREF(f);
 
-	return retval;
+	return NULL;
 }
 
 static void
Index: Python/compile.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Python/compile.c,v
retrieving revision 2.186
diff -u -r2.186 compile.c
--- Python/compile.c	2001/03/02 03:30:41	2.186
+++ Python/compile.c	2001/03/17 01:41:28
@@ -2604,6 +2604,23 @@
 }
 
 static void
+com_suspend_stmt(struct compiling *c, node *n)
+{
+	REQ(n, suspend_stmt); /* 'suspend' [testlist] */
+	if (!c->c_infunction) {
+		com_error(c, PyExc_SyntaxError, "'suspend' outside function");
+	}
+	if (NCH(n) < 2) {
+		com_addoparg(c, LOAD_CONST, com_addconst(c, Py_None));
+		com_push(c, 1);
+	}
+	else
+		com_node(c, CHILD(n, 1));
+	com_addbyte(c, SUSPEND);
+	com_pop(c, 1);
+}
+
+static void
 com_raise_stmt(struct compiling *c, node *n)
 {
 	int i;
@@ -3419,6 +3436,9 @@
 		break;
 	case return_stmt:
 		com_return_stmt(c, n);
+		break;
+	case suspend_stmt:
+		com_suspend_stmt(c, n);
 		break;
 	case raise_stmt:
 		com_raise_stmt(c, n);
