summaryrefslogtreecommitdiffstats
path: root/Objects/classobject.c
diff options
context:
space:
mode:
authorNeil Schemenauer <nascheme@enme.ucalgary.ca>2001-01-04 01:43:46 (GMT)
committerNeil Schemenauer <nascheme@enme.ucalgary.ca>2001-01-04 01:43:46 (GMT)
commit29bfc071838d8aa02272af70ae88aaf7ea90db27 (patch)
treead362881e8780fe855eb9908b2ab5b7cdacdc590 /Objects/classobject.c
parent5a1f015bee85ca271316b1600ae67dae387d3dd8 (diff)
downloadcpython-29bfc071838d8aa02272af70ae88aaf7ea90db27.zip
cpython-29bfc071838d8aa02272af70ae88aaf7ea90db27.tar.gz
cpython-29bfc071838d8aa02272af70ae88aaf7ea90db27.tar.bz2
Make instances a new style number type. See PEP 208 for details. Instance
types no longer get special treatment from abstract.c so more number number methods have to be implemented.
Diffstat (limited to 'Objects/classobject.c')
-rw-r--r--Objects/classobject.c452
1 files changed, 268 insertions, 184 deletions
diff --git a/Objects/classobject.c b/Objects/classobject.c
index 1c9cd7e..f7fd30c 100644
--- a/Objects/classobject.c
+++ b/Objects/classobject.c
@@ -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 */
};