summaryrefslogtreecommitdiffstats
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
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.
-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 */
};