[Python-checkins] CVS: python/dist/src/Objects abstract.c,2.60.2.1,2.60.2.2 classobject.c,2.127.2.1,2.127.2.2 funcobject.c,2.37,2.37.4.1 methodobject.c,2.33.8.3,2.33.8.4 object.c,2.124.4.6,2.124.4.7

Guido van Rossum gvanrossum@users.sourceforge.net
Sat, 05 May 2001 04:37:31 -0700


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

Modified Files:
      Tag: descr-branch
	abstract.c classobject.c funcobject.c methodobject.c object.c 
Log Message:
Reorganization of object calling.

The call_object() function, originally in ceval.c, begins a new life
as the official API PyObject_Call().  It is also much simplified: all
it does is call the tp_call slot, or raise an exception if that's
NULL.

The subsidiary functions (call_eval_code2(), call_cfunction(),
call_instance(), and call_method()) have all been moved to the file
implementing their particular object type, renamed according to the
local convention, and added to the type's tp_call slot.  Note that
call_eval_code2() became function_call(); the tp_slot for class
objects now simply points to PyInstance_New(), which already has the
correct signature.

Because of these moves, there are some more new APIs that expose
helpers in ceval.c that are now needed outside: PyEval_GetFuncName(),
PyEval_GetFuncDesc(), PyEval_EvalCodeEx() (formerly get_func_name(),
get_func_desc(), and eval_code2().



Index: abstract.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/abstract.c,v
retrieving revision 2.60.2.1
retrieving revision 2.60.2.2
diff -C2 -r2.60.2.1 -r2.60.2.2
*** abstract.c	2001/05/04 16:52:44	2.60.2.1
--- abstract.c	2001/05/05 11:37:29	2.60.2.2
***************
*** 1537,1540 ****
--- 1537,1558 ----
  
  PyObject *
+ PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw)
+ {
+         ternaryfunc call;
+ 
+ 	if ((call = func->ob_type->tp_call) != NULL) {
+ 		PyObject *result = (*call)(func, arg, kw);
+ 		if (result == NULL && !PyErr_Occurred())
+ 			PyErr_SetString(
+ 				PyExc_SystemError,
+ 				"NULL result without error in PyObject_Call");
+ 		return result;
+ 	}
+ 	PyErr_Format(PyExc_TypeError, "object is not callable: %s",
+ 		     PyString_AS_STRING(PyObject_Repr(func)));
+ 	return NULL;
+ }
+ 
+ PyObject *
  PyObject_CallFunction(PyObject *callable, char *format, ...)
  {

Index: classobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/classobject.c,v
retrieving revision 2.127.2.1
retrieving revision 2.127.2.2
diff -C2 -r2.127.2.1 -r2.127.2.2
*** classobject.c	2001/04/30 14:37:19	2.127.2.1
--- classobject.c	2001/05/05 11:37:29	2.127.2.2
***************
*** 397,401 ****
  	0,					/* tp_as_mapping */
  	0,					/* tp_hash */
! 	0,					/* tp_call */
  	(reprfunc)class_str,			/* tp_str */
  	(getattrofunc)class_getattr,		/* tp_getattro */
--- 397,401 ----
  	0,					/* tp_as_mapping */
  	0,					/* tp_hash */
! 	PyInstance_New,				/* tp_call */
  	(reprfunc)class_str,			/* tp_str */
  	(getattrofunc)class_getattr,		/* tp_getattro */
***************
*** 1792,1795 ****
--- 1792,1812 ----
  }
  
+ static PyObject *
+ instance_call(PyObject *func, PyObject *arg, PyObject *kw)
+ {
+ 	PyObject *res, *call = PyObject_GetAttrString(func, "__call__");
+ 	if (call == NULL) {
+ 		PyInstanceObject *inst = (PyInstanceObject*) func;
+ 		PyErr_Clear();
+ 		PyErr_Format(PyExc_AttributeError,
+ 			     "%.200s instance has no __call__ method",
+ 			     PyString_AsString(inst->in_class->cl_name));
+ 		return NULL;
+ 	}
+ 	res = PyObject_Call(call, arg, kw);
+ 	Py_DECREF(call);
+ 	return res;
+ }
+ 
  
  static PyNumberMethods instance_as_number = {
***************
*** 1846,1850 ****
  	&instance_as_mapping,			/* tp_as_mapping */
  	(hashfunc)instance_hash,		/* tp_hash */
! 	0,					/* tp_call */
  	(reprfunc)instance_str,			/* tp_str */
  	(getattrofunc)instance_getattr,		/* tp_getattro */
--- 1863,1867 ----
  	&instance_as_mapping,			/* tp_as_mapping */
  	(hashfunc)instance_hash,		/* tp_hash */
! 	instance_call,				/* tp_call */
  	(reprfunc)instance_str,			/* tp_str */
  	(getattrofunc)instance_getattr,		/* tp_getattro */
***************
*** 2083,2086 ****
--- 2100,2154 ----
  }
  
+ static PyObject *
+ instancemethod_call(PyObject *func, PyObject *arg, PyObject *kw)
+ {
+ 	PyObject *self = PyMethod_GET_SELF(func);
+ 	PyObject *class = PyMethod_GET_CLASS(func);
+ 	PyObject *result;
+ 
+ 	func = PyMethod_GET_FUNCTION(func);
+ 	if (self == NULL) {
+ 		/* Unbound methods must be called with an instance of
+ 		   the class (or a derived class) as first argument */
+ 		int ok;
+ 		if (PyTuple_Size(arg) >= 1)
+ 			self = PyTuple_GET_ITEM(arg, 0);
+ 		if (self == NULL)
+ 			ok = 0;
+ 		else {
+ 			ok = PyObject_IsInstance(self, class);
+ 			if (ok < 0)
+ 				return NULL;
+ 		}
+ 		if (!ok) {
+ 			PyErr_Format(PyExc_TypeError,
+ 				     "unbound method %s%s must be "
+ 				     "called with instance as first argument",
+ 				     PyEval_GetFuncName(func),
+ 				     PyEval_GetFuncDesc(func));
+ 			return NULL;
+ 		}
+ 		Py_INCREF(arg);
+ 	}
+ 	else {
+ 		int argcount = PyTuple_Size(arg);
+ 		PyObject *newarg = PyTuple_New(argcount + 1);
+ 		int i;
+ 		if (newarg == NULL)
+ 			return NULL;
+ 		Py_INCREF(self);
+ 		PyTuple_SET_ITEM(newarg, 0, self);
+ 		for (i = 0; i < argcount; i++) {
+ 			PyObject *v = PyTuple_GET_ITEM(arg, i);
+ 			Py_XINCREF(v);
+ 			PyTuple_SET_ITEM(newarg, i+1, v);
+ 		}
+ 		arg = newarg;
+ 	}
+ 	result = PyObject_Call((PyObject *)func, arg, kw);
+ 	Py_DECREF(arg);
+ 	return result;
+ }
+ 
  PyTypeObject PyMethod_Type = {
  	PyObject_HEAD_INIT(&PyType_Type)
***************
*** 2099,2108 ****
  	0,					/* tp_as_mapping */
  	(hashfunc)instancemethod_hash,		/* tp_hash */
! 	0,					/* tp_call */
  	0,					/* tp_str */
  	(getattrofunc)instancemethod_getattro,	/* tp_getattro */
  	(setattrofunc)instancemethod_setattro,	/* tp_setattro */
  	0,					/* tp_as_buffer */
! 	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC | Py_TPFLAGS_HAVE_WEAKREFS,
  	0,					/* tp_doc */
  	(traverseproc)instancemethod_traverse,	/* tp_traverse */
--- 2167,2176 ----
  	0,					/* tp_as_mapping */
  	(hashfunc)instancemethod_hash,		/* tp_hash */
! 	instancemethod_call,			/* tp_call */
  	0,					/* tp_str */
  	(getattrofunc)instancemethod_getattro,	/* tp_getattro */
  	(setattrofunc)instancemethod_setattro,	/* tp_setattro */
  	0,					/* tp_as_buffer */
! 	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC,
  	0,					/* tp_doc */
  	(traverseproc)instancemethod_traverse,	/* tp_traverse */

Index: funcobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/funcobject.c,v
retrieving revision 2.37
retrieving revision 2.37.4.1
diff -C2 -r2.37 -r2.37.4.1
*** funcobject.c	2001/03/23 04:19:27	2.37
--- funcobject.c	2001/05/05 11:37:29	2.37.4.1
***************
*** 4,7 ****
--- 4,8 ----
  #include "Python.h"
  #include "compile.h"
+ #include "eval.h"
  #include "structmember.h"
  
***************
*** 315,318 ****
--- 316,370 ----
  }
  
+ static PyObject *
+ function_call(PyObject *func, PyObject *arg, PyObject *kw)
+ {
+ 	PyObject *result;
+ 	PyObject *argdefs;
+ 	PyObject **d, **k;
+ 	int nk, nd;
+ 
+ 	argdefs = PyFunction_GET_DEFAULTS(func);
+ 	if (argdefs != NULL && PyTuple_Check(argdefs)) {
+ 		d = &PyTuple_GET_ITEM((PyTupleObject *)argdefs, 0);
+ 		nd = PyTuple_Size(argdefs);
+ 	}
+ 	else {
+ 		d = NULL;
+ 		nd = 0;
+ 	}
+ 
+ 	if (kw != NULL && PyDict_Check(kw)) {
+ 		int pos, i;
+ 		nk = PyDict_Size(kw);
+ 		k = PyMem_NEW(PyObject *, 2*nk);
+ 		if (k == NULL) {
+ 			PyErr_NoMemory();
+ 			Py_DECREF(arg);
+ 			return NULL;
+ 		}
+ 		pos = i = 0;
+ 		while (PyDict_Next(kw, &pos, &k[i], &k[i+1]))
+ 			i += 2;
+ 		nk = i/2;
+ 		/* XXX This is broken if the caller deletes dict items! */
+ 	}
+ 	else {
+ 		k = NULL;
+ 		nk = 0;
+ 	}
+ 
+ 	result = PyEval_EvalCodeEx(
+ 		(PyCodeObject *)PyFunction_GET_CODE(func),
+ 		PyFunction_GET_GLOBALS(func), (PyObject *)NULL,
+ 		&PyTuple_GET_ITEM(arg, 0), PyTuple_Size(arg),
+ 		k, nk, d, nd,
+ 		PyFunction_GET_CLOSURE(func));
+ 
+ 	if (k != NULL)
+ 		PyMem_DEL(k);
+ 
+ 	return result;
+ }
+ 
  PyTypeObject PyFunction_Type = {
  	PyObject_HEAD_INIT(&PyType_Type)
***************
*** 331,340 ****
  	0,		/*tp_as_mapping*/
  	0,		/*tp_hash*/
! 	0,		/*tp_call*/
  	0,		/*tp_str*/
  	(getattrofunc)func_getattro,	     /*tp_getattro*/
  	(setattrofunc)func_setattro,	     /*tp_setattro*/
  	0,		/* tp_as_buffer */
! 	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC | Py_TPFLAGS_HAVE_WEAKREFS,
  	0,		/* tp_doc */
  	(traverseproc)func_traverse,	/* tp_traverse */
--- 383,392 ----
  	0,		/*tp_as_mapping*/
  	0,		/*tp_hash*/
! 	function_call,	/*tp_call*/
  	0,		/*tp_str*/
  	(getattrofunc)func_getattro,	     /*tp_getattro*/
  	(setattrofunc)func_setattro,	     /*tp_setattro*/
  	0,		/* tp_as_buffer */
! 	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC,
  	0,		/* tp_doc */
  	(traverseproc)func_traverse,	/* tp_traverse */

Index: methodobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/methodobject.c,v
retrieving revision 2.33.8.3
retrieving revision 2.33.8.4
diff -C2 -r2.33.8.3 -r2.33.8.4
*** methodobject.c	2001/04/27 18:04:51	2.33.8.3
--- methodobject.c	2001/05/05 11:37:29	2.33.8.4
***************
*** 153,156 ****
--- 153,191 ----
  }
  
+ static PyObject *
+ meth_call(PyObject *func, PyObject *arg, PyObject *kw)
+ {
+ 	PyCFunctionObject* f = (PyCFunctionObject*)func;
+ 	PyCFunction meth = PyCFunction_GET_FUNCTION(func);
+ 	PyObject *self = PyCFunction_GET_SELF(func);
+ 	int flags = PyCFunction_GET_FLAGS(func);
+ 
+ 	if (flags & METH_KEYWORDS) {
+ 		return (*(PyCFunctionWithKeywords)meth)(self, arg, kw);
+ 	}
+ 	if (kw != NULL && PyDict_Size(kw) != 0) {
+ 		PyErr_Format(PyExc_TypeError,
+ 			     "%.200s() takes no keyword arguments",
+ 			     f->m_ml->ml_name);
+ 		return NULL;
+ 	}
+ 	if (flags & METH_VARARGS) {
+ 		return (*meth)(self, arg);
+ 	}
+ 	if (!(flags & METH_VARARGS)) {
+ 		/* the really old style */
+ 		int size = PyTuple_GET_SIZE(arg);
+ 		if (size == 1)
+ 			arg = PyTuple_GET_ITEM(arg, 0);
+ 		else if (size == 0)
+ 			arg = NULL;
+ 		return (*meth)(self, arg);
+ 	}
+ 	/* should never get here ??? */
+ 	PyErr_BadInternalCall();
+ 	return NULL;
+ }
+ 
+ 
  PyTypeObject PyCFunction_Type = {
  	PyObject_HEAD_INIT(&PyType_Type)
***************
*** 169,173 ****
  	0,					/* tp_as_mapping */
  	(hashfunc)meth_hash,			/* tp_hash */
! 	0,					/* tp_call */
  	0,					/* tp_str */
  	PyGeneric_GetAttr,			/* tp_getattro */
--- 204,208 ----
  	0,					/* tp_as_mapping */
  	(hashfunc)meth_hash,			/* tp_hash */
! 	meth_call,				/* tp_call */
  	0,					/* tp_str */
  	PyGeneric_GetAttr,			/* tp_getattro */

Index: object.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/object.c,v
retrieving revision 2.124.4.6
retrieving revision 2.124.4.7
diff -C2 -r2.124.4.6 -r2.124.4.7
*** object.c	2001/05/04 16:50:22	2.124.4.6
--- object.c	2001/05/05 11:37:29	2.124.4.7
***************
*** 1209,1218 ****
  	if (x == NULL)
  		return 0;
- 	if (x->ob_type->tp_call != NULL ||
- 	    PyFunction_Check(x) ||
- 	    PyMethod_Check(x) ||
- 	    PyCFunction_Check(x) ||
- 	    PyClass_Check(x))
- 		return 1;
  	if (PyInstance_Check(x)) {
  		PyObject *call = PyObject_GetAttrString(x, "__call__");
--- 1209,1212 ----
***************
*** 1225,1230 ****
  		Py_DECREF(call);
  		return 1;
  	}
- 	return 0;
  }
  
--- 1219,1226 ----
  		Py_DECREF(call);
  		return 1;
+ 	}
+ 	else {
+ 		return x->ob_type->tp_call != NULL;
  	}
  }