summaryrefslogtreecommitdiffstats
path: root/Objects/funcobject.c
diff options
context:
space:
mode:
authorTim Peters <tim.peters@gmail.com>2001-08-02 04:15:00 (GMT)
committerTim Peters <tim.peters@gmail.com>2001-08-02 04:15:00 (GMT)
commit6d6c1a35e08b95a83dbe47dbd9e6474daff00354 (patch)
tree542089077b9c2650dcf5c52d6bfcef1baf12d176 /Objects/funcobject.c
parent52d55a392600011d3edfe85c694744ec550ad1fe (diff)
downloadcpython-6d6c1a35e08b95a83dbe47dbd9e6474daff00354.zip
cpython-6d6c1a35e08b95a83dbe47dbd9e6474daff00354.tar.gz
cpython-6d6c1a35e08b95a83dbe47dbd9e6474daff00354.tar.bz2
Merge of descr-branch back into trunk.
Diffstat (limited to 'Objects/funcobject.c')
-rw-r--r--Objects/funcobject.c380
1 files changed, 318 insertions, 62 deletions
diff --git a/Objects/funcobject.c b/Objects/funcobject.c
index 09c6cb8..311bcde 100644
--- a/Objects/funcobject.c
+++ b/Objects/funcobject.c
@@ -3,6 +3,7 @@
#include "Python.h"
#include "compile.h"
+#include "eval.h"
#include "structmember.h"
PyObject *
@@ -141,9 +142,8 @@ static struct memberlist func_memberlist[] = {
};
static PyObject *
-func_getattro(PyFunctionObject *op, PyObject *name)
+func_getattro(PyObject *op, PyObject *name)
{
- PyObject *rtn;
char *sname = PyString_AsString(name);
if (sname[0] != '_' && PyEval_GetRestricted()) {
@@ -152,25 +152,12 @@ func_getattro(PyFunctionObject *op, PyObject *name)
return NULL;
}
- /* no API for PyMember_HasAttr() */
- rtn = PyMember_Get((char *)op, func_memberlist, sname);
-
- if (rtn == NULL && PyErr_ExceptionMatches(PyExc_AttributeError)) {
- PyErr_Clear();
- if (op->func_dict != NULL) {
- rtn = PyDict_GetItem(op->func_dict, name);
- Py_XINCREF(rtn);
- }
- if (rtn == NULL)
- PyErr_SetObject(PyExc_AttributeError, name);
- }
- return rtn;
+ return PyObject_GenericGetAttr(op, name);
}
static int
-func_setattro(PyFunctionObject *op, PyObject *name, PyObject *value)
+func_setattro(PyObject *op, PyObject *name, PyObject *value)
{
- int rtn;
char *sname = PyString_AsString(name);
if (PyEval_GetRestricted()) {
@@ -216,31 +203,7 @@ func_setattro(PyFunctionObject *op, PyObject *name, PyObject *value)
}
}
- rtn = PyMember_Set((char *)op, func_memberlist, sname, value);
- if (rtn < 0 && PyErr_ExceptionMatches(PyExc_AttributeError)) {
- PyErr_Clear();
- if (op->func_dict == NULL) {
- /* don't create the dict if we're deleting an
- * attribute. In that case, we know we'll get an
- * AttributeError.
- */
- if (value == NULL) {
- PyErr_SetString(PyExc_AttributeError, sname);
- return -1;
- }
- op->func_dict = PyDict_New();
- if (op->func_dict == NULL)
- return -1;
- }
- if (value == NULL)
- rtn = PyDict_DelItem(op->func_dict, name);
- else
- rtn = PyDict_SetItem(op->func_dict, name, value);
- /* transform KeyError into AttributeError */
- if (rtn < 0 && PyErr_ExceptionMatches(PyExc_KeyError))
- PyErr_SetString(PyExc_AttributeError, sname);
- }
- return rtn;
+ return PyObject_GenericSetAttr(op, name, value);
}
static void
@@ -314,31 +277,324 @@ func_traverse(PyFunctionObject *f, visitproc visit, void *arg)
return 0;
}
+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;
+}
+
+/* Bind a function to an object */
+static PyObject *
+func_descr_get(PyObject *func, PyObject *obj, PyObject *type)
+{
+ if (obj == Py_None)
+ obj = NULL;
+ return PyMethod_New(func, obj, type);
+}
+
PyTypeObject PyFunction_Type = {
PyObject_HEAD_INIT(&PyType_Type)
0,
"function",
sizeof(PyFunctionObject) + PyGC_HEAD_SIZE,
0,
- (destructor)func_dealloc, /* tp_dealloc */
- 0, /* tp_print */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_compare */
- (reprfunc)func_repr, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 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, /* tp_flags */
- 0, /* tp_doc */
- (traverseproc)func_traverse, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
+ (destructor)func_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ (reprfunc)func_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ function_call, /* tp_call */
+ 0, /* tp_str */
+ func_getattro, /* tp_getattro */
+ func_setattro, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
+ 0, /* tp_doc */
+ (traverseproc)func_traverse, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
offsetof(PyFunctionObject, func_weakreflist), /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ func_memberlist, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ func_descr_get, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ offsetof(PyFunctionObject, func_dict), /* tp_dictoffset */
+};
+
+
+/* Class method object */
+
+/* A class method receives the class as implicit first argument,
+ just like an instance method receives the instance.
+ To declare a class method, use this idiom:
+
+ class C:
+ def f(cls, arg1, arg2, ...): ...
+ f = classmethod(f)
+
+ It can be called either on the class (e.g. C.f()) or on an instance
+ (e.g. C().f()); the instance is ignored except for its class.
+ If a class method is called for a derived class, the derived class
+ object is passed as the implied first argument.
+
+ Class methods are different than C++ or Java static methods.
+ If you want those, see static methods below.
+*/
+
+typedef struct {
+ PyObject_HEAD
+ PyObject *cm_callable;
+} classmethod;
+
+static void
+cm_dealloc(classmethod *cm)
+{
+ Py_XDECREF(cm->cm_callable);
+ PyObject_DEL(cm);
+}
+
+static PyObject *
+cm_descr_get(PyObject *self, PyObject *obj, PyObject *type)
+{
+ classmethod *cm = (classmethod *)self;
+
+ if (cm->cm_callable == NULL) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "uninitialized classmethod object");
+ return NULL;
+ }
+ return PyMethod_New(cm->cm_callable,
+ type, (PyObject *)(type->ob_type));
+}
+
+static int
+cm_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ classmethod *cm = (classmethod *)self;
+ PyObject *callable;
+
+ if (!PyArg_ParseTuple(args, "O:callable", &callable))
+ return -1;
+ Py_INCREF(callable);
+ cm->cm_callable = callable;
+ return 0;
+}
+
+PyTypeObject PyClassMethod_Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "classmethod",
+ sizeof(classmethod),
+ 0,
+ (destructor)cm_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ PyObject_GenericGetAttr, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ 0, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ cm_descr_get, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ cm_init, /* tp_init */
+ PyType_GenericAlloc, /* tp_alloc */
+ PyType_GenericNew, /* tp_new */
+};
+
+PyObject *
+PyClassMethod_New(PyObject *callable)
+{
+ classmethod *cm = (classmethod *)
+ PyType_GenericAlloc(&PyClassMethod_Type, 0);
+ if (cm != NULL) {
+ Py_INCREF(callable);
+ cm->cm_callable = callable;
+ }
+ return (PyObject *)cm;
+}
+
+
+/* Static method object */
+
+/* A static method does not receive an implicit first argument.
+ To declare a static method, use this idiom:
+
+ class C:
+ def f(arg1, arg2, ...): ...
+ f = staticmethod(f)
+
+ It can be called either on the class (e.g. C.f()) or on an instance
+ (e.g. C().f()); the instance is ignored except for its class.
+
+ Static methods in Python are similar to those found in Java or C++.
+ For a more advanced concept, see class methods above.
+*/
+
+typedef struct {
+ PyObject_HEAD
+ PyObject *sm_callable;
+} staticmethod;
+
+static void
+sm_dealloc(staticmethod *sm)
+{
+ Py_XDECREF(sm->sm_callable);
+ PyObject_DEL(sm);
+}
+
+static PyObject *
+sm_descr_get(PyObject *self, PyObject *obj, PyObject *type)
+{
+ staticmethod *sm = (staticmethod *)self;
+
+ if (sm->sm_callable == NULL) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "uninitialized staticmethod object");
+ return NULL;
+ }
+ Py_INCREF(sm->sm_callable);
+ return sm->sm_callable;
+}
+
+static int
+sm_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ staticmethod *sm = (staticmethod *)self;
+ PyObject *callable;
+
+ if (!PyArg_ParseTuple(args, "O:callable", &callable))
+ return -1;
+ Py_INCREF(callable);
+ sm->sm_callable = callable;
+ return 0;
+}
+
+PyTypeObject PyStaticMethod_Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "staticmethod",
+ sizeof(staticmethod),
+ 0,
+ (destructor)sm_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ PyObject_GenericGetAttr, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ 0, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ sm_descr_get, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ sm_init, /* tp_init */
+ PyType_GenericAlloc, /* tp_alloc */
+ PyType_GenericNew, /* tp_new */
};
+
+PyObject *
+PyStaticMethod_New(PyObject *callable)
+{
+ staticmethod *sm = (staticmethod *)
+ PyType_GenericAlloc(&PyStaticMethod_Type, 0);
+ if (sm != NULL) {
+ Py_INCREF(callable);
+ sm->sm_callable = callable;
+ }
+ return (PyObject *)sm;
+}