]> granicus.if.org Git - python/commitdiff
Make instances a new style number type. See PEP 208 for details. Instance
authorNeil Schemenauer <nascheme@enme.ucalgary.ca>
Thu, 4 Jan 2001 01:43:46 +0000 (01:43 +0000)
committerNeil Schemenauer <nascheme@enme.ucalgary.ca>
Thu, 4 Jan 2001 01:43:46 +0000 (01:43 +0000)
types no longer get special treatment from abstract.c so more number number
methods have to be implemented.

Objects/classobject.c

index 1c9cd7ee3f75d434b88e92899c0f109f85088e40..f7fd30c773457daa9786e5f10a37212521ca86d2 100644 (file)
@@ -4,6 +4,7 @@
 #include "Python.h"
 #include "structmember.h"
 
+
 /* Forward */
 static PyObject *class_lookup(PyClassObject *, PyObject *,
                              PyClassObject **);
@@ -755,36 +756,6 @@ instance_repr(PyInstanceObject *inst)
        return res;
 }
 
-static PyObject *
-instance_compare1(PyObject *inst, PyObject *other)
-{
-       return PyInstance_DoBinOp(inst, other, "__cmp__", "__rcmp__",
-                            instance_compare1);
-}
-
-static int
-instance_compare(PyObject *inst, PyObject *other)
-{
-       PyObject *result;
-       long outcome;
-       result = instance_compare1(inst, other);
-       if (result == NULL)
-               return -1;
-       if (!PyInt_Check(result)) {
-               Py_DECREF(result);
-               PyErr_SetString(PyExc_TypeError,
-                               "comparison did not return an int");
-               return -1;
-       }
-       outcome = PyInt_AsLong(result);
-       Py_DECREF(result);
-       if (outcome < 0)
-               return -1;
-       else if (outcome > 0)
-               return 1;
-       return 0;
-}
-
 static long
 instance_hash(PyInstanceObject *inst)
 {
@@ -1185,117 +1156,119 @@ generic_unary_op(PyInstanceObject *self, PyObject *methodname)
        return res;
 }
 
-
-/* Implement a binary operator involving at least one class instance. */
-
-PyObject *
-PyInstance_DoBinOp(PyObject *v, PyObject *w, char *opname, char *ropname,
-                   PyObject * (*thisfunc)(PyObject *, PyObject *))
+static PyObject *
+generic_binary_op(PyObject *v, PyObject *w, char *opname)
 {
-       char buf[256];
-       PyObject *result = NULL;
-
-       if (PyInstance_HalfBinOp(v, w, opname, &result, thisfunc, 0) <= 0)
-               return result;
-       if (PyInstance_HalfBinOp(w, v, ropname, &result, thisfunc, 1) <= 0)
-               return result;
-       /* Sigh -- special case for comparisons */
-       if (strcmp(opname, "__cmp__") == 0) {
-               Py_uintptr_t iv = (Py_uintptr_t)v;
-               Py_uintptr_t iw = (Py_uintptr_t)w;
-               long c = (iv < iw) ? -1 : (iv > iw) ? 1 : 0;
-               return PyInt_FromLong(c);
-       }
-       sprintf(buf, "%s nor %s defined for these operands", opname, ropname);
-       PyErr_SetString(PyExc_TypeError, buf);
-       return NULL;
+       PyObject *result;
+       PyObject *args;
+       PyObject *func = PyObject_GetAttrString(v, opname);
+       if (func == NULL) {
+               if (!PyErr_ExceptionMatches(PyExc_AttributeError))
+                       return NULL;
+               PyErr_Clear();
+               Py_INCREF(Py_NotImplemented);
+               return Py_NotImplemented;
+       }
+       args = Py_BuildValue("(O)", w);
+       if (args == NULL) {
+               Py_DECREF(func);
+               return NULL;
+       }
+       result = PyEval_CallObject(func, args);
+       Py_DECREF(args);
+       Py_DECREF(func);
+       return result;
 }
 
 
-/* Try one half of a binary operator involving a class instance.
-   Return value:
-   -1 if an exception is to be reported right away
-   0  if we have a valid result
-   1  if we could try another operation
-*/
-
 static PyObject *coerce_obj;
 
-int
-PyInstance_HalfBinOp(PyObject *v, PyObject *w, char *opname, PyObject **r_result,
-                    PyObject * (*thisfunc)(PyObject *, PyObject *), int swapped)
+/* Try one half of a binary operator involving a class instance. */
+static PyObject *
+half_binop(PyObject *v, PyObject *w, char *opname, binaryfunc thisfunc, 
+               int swapped)
 {
-       PyObject *func;
        PyObject *args;
        PyObject *coercefunc;
        PyObject *coerced = NULL;
        PyObject *v1;
+       PyObject *result;
        
-       if (!PyInstance_Check(v))
-               return 1;
+       if (!PyInstance_Check(v)) {
+               Py_INCREF(Py_NotImplemented);
+               return Py_NotImplemented;
+       }
+
        if (coerce_obj == NULL) {
                coerce_obj = PyString_InternFromString("__coerce__");
                if (coerce_obj == NULL)
-                       return -1;
+                       return NULL;
        }
        coercefunc = PyObject_GetAttr(v, coerce_obj);
        if (coercefunc == NULL) {
                PyErr_Clear();
+               return generic_binary_op(v, w, opname);
        }
-       else {
-               args = Py_BuildValue("(O)", w);
-               if (args == NULL) {
-                       return -1;
-               }
-               coerced = PyEval_CallObject(coercefunc, args);
-               Py_DECREF(args);
-               Py_DECREF(coercefunc);
-               if (coerced == NULL) {
-                       return -1;
-               }
-               if (coerced == Py_None) {
-                       Py_DECREF(coerced);
-                       return 1;
-               }
-               if (!PyTuple_Check(coerced) || PyTuple_Size(coerced) != 2) {
-                       Py_DECREF(coerced);
-                       PyErr_SetString(PyExc_TypeError,
-                                  "coercion should return None or 2-tuple");
-                       return -1;
-               }
-               v1 = PyTuple_GetItem(coerced, 0);
-               w = PyTuple_GetItem(coerced, 1);
-               if (v1 != v) {
-                       v = v1;
-                       if (!PyInstance_Check(v) && !PyInstance_Check(w)) {
-                               if (swapped)
-                                       *r_result = (*thisfunc)(w, v);
-                               else
-                                       *r_result = (*thisfunc)(v, w);
-                               Py_DECREF(coerced);
-                               return *r_result == NULL ? -1 : 0;
-                       }
-               }
-       }
-       func = PyObject_GetAttrString(v, opname);
-       if (func == NULL) {
-               Py_XDECREF(coerced);
-               if (!PyErr_ExceptionMatches(PyExc_AttributeError))
-                       return -1;
-               PyErr_Clear();
-               return 1;
-       }
+
        args = Py_BuildValue("(O)", w);
        if (args == NULL) {
-               Py_DECREF(func);
-               Py_XDECREF(coerced);
-               return -1;
+               return NULL;
        }
-       *r_result = PyEval_CallObject(func, args);
+       coerced = PyEval_CallObject(coercefunc, args);
        Py_DECREF(args);
-       Py_DECREF(func);
-       Py_XDECREF(coerced);
-       return *r_result == NULL ? -1 : 0;
+       Py_DECREF(coercefunc);
+       if (coerced == NULL) {
+               return NULL;
+       }
+       if (coerced == Py_None || coerced == Py_NotImplemented) {
+               Py_DECREF(coerced);
+               return generic_binary_op(v, w, opname);
+       }
+       if (!PyTuple_Check(coerced) || PyTuple_Size(coerced) != 2) {
+               Py_DECREF(coerced);
+               PyErr_SetString(PyExc_TypeError,
+                               "coercion should return None or 2-tuple");
+               return NULL;
+       }
+       v1 = PyTuple_GetItem(coerced, 0);
+       w = PyTuple_GetItem(coerced, 1);
+       if (v1 == v) {
+               /* prevent recursion if __coerce__ returns self as the first
+                * argument */
+               result = generic_binary_op(v, w, opname);
+       } else {
+               if (swapped)
+                       result = (thisfunc)(w, v1);
+               else
+                       result = (thisfunc)(v1, w);
+       }
+       Py_DECREF(coerced);
+       return result;
+}
+
+/* Implement a binary operator involving at least one class instance. */
+static PyObject *
+do_binop(PyObject *v, PyObject *w, char *opname, char *ropname,
+                   binaryfunc thisfunc)
+{
+       PyObject *result = half_binop(v, w, opname, thisfunc, 0);
+       if (result == Py_NotImplemented) {
+               Py_DECREF(Py_NotImplemented);
+               result = half_binop(w, v, ropname, thisfunc, 1);
+       }
+       return result;
+}
+
+static PyObject *
+do_binop_inplace(PyObject *v, PyObject *w, char *iopname, char *opname,
+                       char *ropname, binaryfunc thisfunc)
+{
+       PyObject *result = half_binop(v, w, iopname, thisfunc, 0);
+       if (result == Py_NotImplemented) {
+               Py_DECREF(Py_NotImplemented);
+               result = do_binop(v, w, opname, ropname, thisfunc);
+       }
+       return result;
 }
 
 static int
@@ -1314,11 +1287,11 @@ instance_coerce(PyObject **pv, PyObject **pw)
        }
        coercefunc = PyObject_GetAttr(v, coerce_obj);
        if (coercefunc == NULL) {
-               /* No __coerce__ method: always OK */
+               /* No __coerce__ method */
                PyErr_Clear();
                Py_INCREF(v);
                Py_INCREF(w);
-               return 0;
+               return 1;
        }
        /* Has __coerce__ method: call it */
        args = Py_BuildValue("(O)", w);
@@ -1332,7 +1305,7 @@ instance_coerce(PyObject **pv, PyObject **pw)
                /* __coerce__ call raised an exception */
                return -1;
        }
-       if (coerced == Py_None) {
+       if (coerced == Py_None || coerced == Py_NotImplemented) {
                /* __coerce__ says "I can't do it" */
                Py_DECREF(coerced);
                return 1;
@@ -1353,7 +1326,6 @@ instance_coerce(PyObject **pv, PyObject **pw)
        return 0;
 }
 
-
 #define UNARY(funcname, methodname) \
 static PyObject *funcname(PyInstanceObject *self) { \
        static PyObject *o; \
@@ -1361,10 +1333,102 @@ static PyObject *funcname(PyInstanceObject *self) { \
        return generic_unary_op(self, o); \
 }
 
+#define BINARY(f, m, n) \
+static PyObject *f(PyObject *v, PyObject *w) { \
+       return do_binop(v, w, "__" m "__", "__r" m "__", n); \
+}
+
+#define BINARY_INPLACE(f, m, n) \
+static PyObject *f(PyObject *v, PyObject *w) { \
+       return do_binop_inplace(v, w, "__i" m "__", "__" m "__", \
+                       "__r" m "__", n); \
+}
+
 UNARY(instance_neg, "__neg__")
 UNARY(instance_pos, "__pos__")
 UNARY(instance_abs, "__abs__")
 
+BINARY(instance_or, "or", PyNumber_Or)
+BINARY(instance_and, "and", PyNumber_And)
+BINARY(instance_xor, "xor", PyNumber_Xor)
+BINARY(instance_lshift, "lshift", PyNumber_Lshift)
+BINARY(instance_rshift, "rshift", PyNumber_Rshift)
+BINARY(instance_add, "add", PyNumber_Add)
+BINARY(instance_sub, "sub", PyNumber_Subtract)
+BINARY(instance_mul, "mul", PyNumber_Multiply)
+BINARY(instance_div, "div", PyNumber_Divide)
+BINARY(instance_mod, "mod", PyNumber_Remainder)
+BINARY(instance_divmod, "divmod", PyNumber_Divmod)
+
+BINARY_INPLACE(instance_ior, "or", PyNumber_InPlaceOr)
+BINARY_INPLACE(instance_ixor, "xor", PyNumber_InPlaceXor)
+BINARY_INPLACE(instance_iand, "and", PyNumber_InPlaceAnd)
+BINARY_INPLACE(instance_ilshift, "lshift", PyNumber_InPlaceLshift)
+BINARY_INPLACE(instance_irshift, "rshift", PyNumber_InPlaceRshift)
+BINARY_INPLACE(instance_iadd, "add", PyNumber_InPlaceAdd)
+BINARY_INPLACE(instance_isub, "sub", PyNumber_InPlaceSubtract)
+BINARY_INPLACE(instance_imul, "mul", PyNumber_InPlaceMultiply)
+BINARY_INPLACE(instance_idiv, "div", PyNumber_InPlaceDivide)
+BINARY_INPLACE(instance_imod, "mod", PyNumber_InPlaceRemainder)
+
+static PyObject *
+do_cmp(PyObject *v, PyObject *w)
+{
+       int cmp = PyObject_Compare(v, w);
+       if (PyErr_Occurred()) {
+               return NULL;
+       }
+       return PyInt_FromLong(cmp);
+}
+
+static PyObject *
+instance_cmp(PyObject *v, PyObject *w)
+{
+       PyObject *result = half_binop(v, w, "__cmp__", do_cmp, 0);
+       if (result == Py_NotImplemented) {
+               Py_DECREF(Py_NotImplemented);
+                /* __rcmp__ is not called on instances, instead they
+                 * automaticly reverse the arguments and return the negative of
+                 * __cmp__ if it exists */
+               result = half_binop(w, v, "__cmp__", do_cmp, 0);
+                        
+                if (result != Py_NotImplemented && result != NULL) {
+                       PyObject *r = PyNumber_Negative(result);
+                       Py_DECREF(result);
+                       result = r;
+               }
+       }
+       return result;
+}
+
+static int
+instance_compare(PyObject *inst, PyObject *other)
+{
+       PyObject *result;
+       long outcome;
+       result = instance_cmp(inst, other);
+       if (result == NULL) {
+               return -1;
+       }
+       if (result == Py_NotImplemented) {
+               Py_DECREF(result);
+               return -1;
+       }
+       if (!PyInt_Check(result)) {
+               Py_DECREF(result);
+               PyErr_SetString(PyExc_TypeError,
+                               "comparison did not return an int");
+               return -1;
+       }
+       outcome = PyInt_AsLong(result);
+       Py_DECREF(result);
+       if (outcome < 0)
+               return -1;
+       else if (outcome > 0)
+               return 1;
+       return 0;
+}
+
 static int
 instance_nonzero(PyInstanceObject *self)
 {
@@ -1412,97 +1476,117 @@ UNARY(instance_float, "__float__")
 UNARY(instance_oct, "__oct__")
 UNARY(instance_hex, "__hex__")
 
+static PyObject *
+bin_power(PyObject *v, PyObject *w)
+{
+       return PyNumber_Power(v, w, Py_None);
+}
+
 /* This version is for ternary calls only (z != None) */
 static PyObject *
 instance_pow(PyObject *v, PyObject *w, PyObject *z)
-{
-       /* XXX Doesn't do coercions... */
-       PyObject *func;
-       PyObject *args;
-       PyObject *result;
-       static PyObject *powstr;
+{      
+       if (z == Py_None) {
+               return do_binop(v, w, "__pow__", "__rpow__", bin_power);
+       }
+       else {
+               PyObject *func;
+               PyObject *args;
+               PyObject *result;
 
-       if (powstr == NULL)
-               powstr = PyString_InternFromString("__pow__");
-       func = PyObject_GetAttr(v, powstr);
-       if (func == NULL)
-               return NULL;
-       args = Py_BuildValue("(OO)", w, z);
-       if (args == NULL) {
+               /* XXX Doesn't do coercions... */
+               func = PyObject_GetAttrString(v, "__pow__");
+               if (func == NULL)
+                       return NULL;
+               args = Py_BuildValue("(OO)", w, z);
+               if (args == NULL) {
+                       Py_DECREF(func);
+                       return NULL;
+               }
+               result = PyEval_CallObject(func, args);
                Py_DECREF(func);
-               return NULL;
+               Py_DECREF(args);
+               return result;
        }
-       result = PyEval_CallObject(func, args);
-       Py_DECREF(func);
-       Py_DECREF(args);
-       return result;
 }
 
 static PyObject *
-instance_inplace_pow(PyObject *v, PyObject *w, PyObject *z)
+bin_inplace_power(PyObject *v, PyObject *w)
 {
-       /* XXX Doesn't do coercions... */
-       PyObject *func;
-       PyObject *args;
-       PyObject *result;
-       static PyObject *ipowstr;
+       return PyNumber_InPlacePower(v, w, Py_None);
+}
 
-       if (ipowstr == NULL)
-               ipowstr = PyString_InternFromString("__ipow__");
-       func = PyObject_GetAttr(v, ipowstr);
-       if (func == NULL) {
-               if (!PyErr_ExceptionMatches(PyExc_AttributeError))
-                       return NULL;
-               PyErr_Clear();
-               return instance_pow(v, w, z);
+
+static PyObject *
+instance_ipow(PyObject *v, PyObject *w, PyObject *z)
+{
+       if (z == Py_None) {
+               return do_binop_inplace(v, w, "__ipow__", "__pow__",
+                       "__rpow__", bin_inplace_power);
        }
-       args = Py_BuildValue("(OO)", w, z);
-       if (args == NULL) {
+       else {
+               /* XXX Doesn't do coercions... */
+               PyObject *func;
+               PyObject *args;
+               PyObject *result;
+
+               func = PyObject_GetAttrString(v, "__ipow__");
+               if (func == NULL) {
+                       if (!PyErr_ExceptionMatches(PyExc_AttributeError))
+                               return NULL;
+                       PyErr_Clear();
+                       return instance_pow(v, w, z);
+               }
+               args = Py_BuildValue("(OO)", w, z);
+               if (args == NULL) {
+                       Py_DECREF(func);
+                       return NULL;
+               }
+               result = PyEval_CallObject(func, args);
                Py_DECREF(func);
-               return NULL;
+               Py_DECREF(args);
+               return result;
        }
-       result = PyEval_CallObject(func, args);
-       Py_DECREF(func);
-       Py_DECREF(args);
-       return result;
 }
 
 
+
 static PyNumberMethods instance_as_number = {
-       0, /*nb_add*/
-       0, /*nb_subtract*/
-       0, /*nb_multiply*/
-       0, /*nb_divide*/
-       0, /*nb_remainder*/
-       0, /*nb_divmod*/
+       (binaryfunc)instance_add, /*nb_add*/
+       (binaryfunc)instance_sub, /*nb_subtract*/
+       (binaryfunc)instance_mul, /*nb_multiply*/
+       (binaryfunc)instance_div, /*nb_divide*/
+       (binaryfunc)instance_mod, /*nb_remainder*/
+       (binaryfunc)instance_divmod, /*nb_divmod*/
        (ternaryfunc)instance_pow, /*nb_power*/
        (unaryfunc)instance_neg, /*nb_negative*/
        (unaryfunc)instance_pos, /*nb_positive*/
        (unaryfunc)instance_abs, /*nb_absolute*/
        (inquiry)instance_nonzero, /*nb_nonzero*/
        (unaryfunc)instance_invert, /*nb_invert*/
-       0, /*nb_lshift*/
-       0, /*nb_rshift*/
-       0, /*nb_and*/
-       0, /*nb_xor*/
-       0, /*nb_or*/
+       (binaryfunc)instance_lshift, /*nb_lshift*/
+       (binaryfunc)instance_rshift, /*nb_rshift*/
+       (binaryfunc)instance_and, /*nb_and*/
+       (binaryfunc)instance_xor, /*nb_xor*/
+       (binaryfunc)instance_or, /*nb_or*/
        (coercion)instance_coerce, /*nb_coerce*/
        (unaryfunc)instance_int, /*nb_int*/
        (unaryfunc)instance_long, /*nb_long*/
        (unaryfunc)instance_float, /*nb_float*/
        (unaryfunc)instance_oct, /*nb_oct*/
        (unaryfunc)instance_hex, /*nb_hex*/
-       0, /*nb_inplace_add*/
-       0, /*nb_inplace_subtract*/
-       0, /*nb_inplace_multiply*/
-       0, /*nb_inplace_divide*/
-       0, /*nb_inplace_remainder*/
-       (ternaryfunc)instance_inplace_pow, /*nb_inplace_power*/
-       0, /*nb_inplace_lshift*/
-       0, /*nb_inplace_rshift*/
-       0, /*nb_inplace_and*/
-       0, /*nb_inplace_xor*/
-       0, /*nb_inplace_or*/
+       (binaryfunc)instance_iadd, /*nb_inplace_add*/
+       (binaryfunc)instance_isub, /*nb_inplace_subtract*/
+       (binaryfunc)instance_imul, /*nb_inplace_multiply*/
+       (binaryfunc)instance_idiv, /*nb_inplace_divide*/
+       (binaryfunc)instance_imod, /*nb_inplace_remainder*/
+       (ternaryfunc)instance_ipow, /*nb_inplace_power*/
+       (binaryfunc)instance_ilshift, /*nb_inplace_lshift*/
+       (binaryfunc)instance_irshift, /*nb_inplace_rshift*/
+       (binaryfunc)instance_iand, /*nb_inplace_and*/
+       (binaryfunc)instance_ixor, /*nb_inplace_xor*/
+       (binaryfunc)instance_ior, /*nb_inplace_or*/
+       (binaryfunc)instance_cmp, /*nb_cmp*/
 };
 
 PyTypeObject PyInstance_Type = {
@@ -1525,8 +1609,8 @@ PyTypeObject PyInstance_Type = {
        0,                      /*tp_str*/
        (getattrofunc)instance_getattr, /*tp_getattro*/
        (setattrofunc)instance_setattr, /*tp_setattro*/
-        0, /* tp_as_buffer */
-       Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /*tp_flags*/
+       0, /* tp_as_buffer */
+       Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC | Py_TPFLAGS_NEWSTYLENUMBER, /*tp_flags*/
        0,              /* tp_doc */
        (traverseproc)instance_traverse,        /* tp_traverse */
 };