Commit 29bfc071 authored by Neil Schemenauer's avatar Neil Schemenauer

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.
parent 5a1f015b
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "Python.h" #include "Python.h"
#include "structmember.h" #include "structmember.h"
/* Forward */ /* Forward */
static PyObject *class_lookup(PyClassObject *, PyObject *, static PyObject *class_lookup(PyClassObject *, PyObject *,
PyClassObject **); PyClassObject **);
...@@ -755,36 +756,6 @@ instance_repr(PyInstanceObject *inst) ...@@ -755,36 +756,6 @@ instance_repr(PyInstanceObject *inst)
return res; 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 static long
instance_hash(PyInstanceObject *inst) instance_hash(PyInstanceObject *inst)
{ {
...@@ -1185,117 +1156,119 @@ generic_unary_op(PyInstanceObject *self, PyObject *methodname) ...@@ -1185,117 +1156,119 @@ generic_unary_op(PyInstanceObject *self, PyObject *methodname)
return res; return res;
} }
static PyObject *
/* Implement a binary operator involving at least one class instance. */ generic_binary_op(PyObject *v, PyObject *w, char *opname)
PyObject *
PyInstance_DoBinOp(PyObject *v, PyObject *w, char *opname, char *ropname,
PyObject * (*thisfunc)(PyObject *, PyObject *))
{ {
char buf[256]; PyObject *result;
PyObject *result = NULL; PyObject *args;
PyObject *func = PyObject_GetAttrString(v, opname);
if (PyInstance_HalfBinOp(v, w, opname, &result, thisfunc, 0) <= 0) if (func == NULL) {
return result; if (!PyErr_ExceptionMatches(PyExc_AttributeError))
if (PyInstance_HalfBinOp(w, v, ropname, &result, thisfunc, 1) <= 0) return NULL;
return result; PyErr_Clear();
/* Sigh -- special case for comparisons */ Py_INCREF(Py_NotImplemented);
if (strcmp(opname, "__cmp__") == 0) { return Py_NotImplemented;
Py_uintptr_t iv = (Py_uintptr_t)v; }
Py_uintptr_t iw = (Py_uintptr_t)w; args = Py_BuildValue("(O)", w);
long c = (iv < iw) ? -1 : (iv > iw) ? 1 : 0; if (args == NULL) {
return PyInt_FromLong(c); Py_DECREF(func);
} return NULL;
sprintf(buf, "%s nor %s defined for these operands", opname, ropname); }
PyErr_SetString(PyExc_TypeError, buf); result = PyEval_CallObject(func, args);
return NULL; 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; static PyObject *coerce_obj;
int /* Try one half of a binary operator involving a class instance. */
PyInstance_HalfBinOp(PyObject *v, PyObject *w, char *opname, PyObject **r_result, static PyObject *
PyObject * (*thisfunc)(PyObject *, PyObject *), int swapped) half_binop(PyObject *v, PyObject *w, char *opname, binaryfunc thisfunc,
int swapped)
{ {
PyObject *func;
PyObject *args; PyObject *args;
PyObject *coercefunc; PyObject *coercefunc;
PyObject *coerced = NULL; PyObject *coerced = NULL;
PyObject *v1; PyObject *v1;
PyObject *result;
if (!PyInstance_Check(v)) if (!PyInstance_Check(v)) {
return 1; Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}
if (coerce_obj == NULL) { if (coerce_obj == NULL) {
coerce_obj = PyString_InternFromString("__coerce__"); coerce_obj = PyString_InternFromString("__coerce__");
if (coerce_obj == NULL) if (coerce_obj == NULL)
return -1; return NULL;
} }
coercefunc = PyObject_GetAttr(v, coerce_obj); coercefunc = PyObject_GetAttr(v, coerce_obj);
if (coercefunc == NULL) { if (coercefunc == NULL) {
PyErr_Clear(); 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); args = Py_BuildValue("(O)", w);
if (args == NULL) { if (args == NULL) {
Py_DECREF(func); return NULL;
Py_XDECREF(coerced);
return -1;
} }
*r_result = PyEval_CallObject(func, args); coerced = PyEval_CallObject(coercefunc, args);
Py_DECREF(args); Py_DECREF(args);
Py_DECREF(func); Py_DECREF(coercefunc);
Py_XDECREF(coerced); if (coerced == NULL) {
return *r_result == NULL ? -1 : 0; 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 static int
...@@ -1314,11 +1287,11 @@ instance_coerce(PyObject **pv, PyObject **pw) ...@@ -1314,11 +1287,11 @@ instance_coerce(PyObject **pv, PyObject **pw)
} }
coercefunc = PyObject_GetAttr(v, coerce_obj); coercefunc = PyObject_GetAttr(v, coerce_obj);
if (coercefunc == NULL) { if (coercefunc == NULL) {
/* No __coerce__ method: always OK */ /* No __coerce__ method */
PyErr_Clear(); PyErr_Clear();
Py_INCREF(v); Py_INCREF(v);
Py_INCREF(w); Py_INCREF(w);
return 0; return 1;
} }
/* Has __coerce__ method: call it */ /* Has __coerce__ method: call it */
args = Py_BuildValue("(O)", w); args = Py_BuildValue("(O)", w);
...@@ -1332,7 +1305,7 @@ instance_coerce(PyObject **pv, PyObject **pw) ...@@ -1332,7 +1305,7 @@ instance_coerce(PyObject **pv, PyObject **pw)
/* __coerce__ call raised an exception */ /* __coerce__ call raised an exception */
return -1; return -1;
} }
if (coerced == Py_None) { if (coerced == Py_None || coerced == Py_NotImplemented) {
/* __coerce__ says "I can't do it" */ /* __coerce__ says "I can't do it" */
Py_DECREF(coerced); Py_DECREF(coerced);
return 1; return 1;
...@@ -1353,7 +1326,6 @@ instance_coerce(PyObject **pv, PyObject **pw) ...@@ -1353,7 +1326,6 @@ instance_coerce(PyObject **pv, PyObject **pw)
return 0; return 0;
} }
#define UNARY(funcname, methodname) \ #define UNARY(funcname, methodname) \
static PyObject *funcname(PyInstanceObject *self) { \ static PyObject *funcname(PyInstanceObject *self) { \
static PyObject *o; \ static PyObject *o; \
...@@ -1361,10 +1333,102 @@ static PyObject *funcname(PyInstanceObject *self) { \ ...@@ -1361,10 +1333,102 @@ static PyObject *funcname(PyInstanceObject *self) { \
return generic_unary_op(self, o); \ 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_neg, "__neg__")
UNARY(instance_pos, "__pos__") UNARY(instance_pos, "__pos__")
UNARY(instance_abs, "__abs__") 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 static int
instance_nonzero(PyInstanceObject *self) instance_nonzero(PyInstanceObject *self)
{ {
...@@ -1412,97 +1476,117 @@ UNARY(instance_float, "__float__") ...@@ -1412,97 +1476,117 @@ UNARY(instance_float, "__float__")
UNARY(instance_oct, "__oct__") UNARY(instance_oct, "__oct__")
UNARY(instance_hex, "__hex__") 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) */ /* This version is for ternary calls only (z != None) */
static PyObject * static PyObject *
instance_pow(PyObject *v, PyObject *w, PyObject *z) instance_pow(PyObject *v, PyObject *w, PyObject *z)
{ {
/* XXX Doesn't do coercions... */ if (z == Py_None) {
PyObject *func; return do_binop(v, w, "__pow__", "__rpow__", bin_power);
PyObject *args; }
PyObject *result; else {
static PyObject *powstr; PyObject *func;
PyObject *args;
PyObject *result;
if (powstr == NULL) /* XXX Doesn't do coercions... */
powstr = PyString_InternFromString("__pow__"); func = PyObject_GetAttrString(v, "__pow__");
func = PyObject_GetAttr(v, powstr); if (func == NULL)
if (func == NULL) return NULL;
return NULL; args = Py_BuildValue("(OO)", w, z);
args = Py_BuildValue("(OO)", w, z); if (args == NULL) {
if (args == NULL) { Py_DECREF(func);
return NULL;
}
result = PyEval_CallObject(func, args);
Py_DECREF(func); 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 * static PyObject *
instance_inplace_pow(PyObject *v, PyObject *w, PyObject *z) bin_inplace_power(PyObject *v, PyObject *w)
{ {
/* XXX Doesn't do coercions... */ return PyNumber_InPlacePower(v, w, Py_None);
PyObject *func; }
PyObject *args;
PyObject *result;
static PyObject *ipowstr;
if (ipowstr == NULL)
ipowstr = PyString_InternFromString("__ipow__"); static PyObject *
func = PyObject_GetAttr(v, ipowstr); instance_ipow(PyObject *v, PyObject *w, PyObject *z)
if (func == NULL) { {
if (!PyErr_ExceptionMatches(PyExc_AttributeError)) if (z == Py_None) {
return NULL; return do_binop_inplace(v, w, "__ipow__", "__pow__",
PyErr_Clear(); "__rpow__", bin_inplace_power);
return instance_pow(v, w, z);
} }
args = Py_BuildValue("(OO)", w, z); else {
if (args == NULL) { /* 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); 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 = { static PyNumberMethods instance_as_number = {
0, /*nb_add*/ (binaryfunc)instance_add, /*nb_add*/
0, /*nb_subtract*/ (binaryfunc)instance_sub, /*nb_subtract*/
0, /*nb_multiply*/ (binaryfunc)instance_mul, /*nb_multiply*/
0, /*nb_divide*/ (binaryfunc)instance_div, /*nb_divide*/
0, /*nb_remainder*/ (binaryfunc)instance_mod, /*nb_remainder*/
0, /*nb_divmod*/ (binaryfunc)instance_divmod, /*nb_divmod*/
(ternaryfunc)instance_pow, /*nb_power*/ (ternaryfunc)instance_pow, /*nb_power*/
(unaryfunc)instance_neg, /*nb_negative*/ (unaryfunc)instance_neg, /*nb_negative*/
(unaryfunc)instance_pos, /*nb_positive*/ (unaryfunc)instance_pos, /*nb_positive*/
(unaryfunc)instance_abs, /*nb_absolute*/ (unaryfunc)instance_abs, /*nb_absolute*/
(inquiry)instance_nonzero, /*nb_nonzero*/ (inquiry)instance_nonzero, /*nb_nonzero*/
(unaryfunc)instance_invert, /*nb_invert*/ (unaryfunc)instance_invert, /*nb_invert*/
0, /*nb_lshift*/ (binaryfunc)instance_lshift, /*nb_lshift*/
0, /*nb_rshift*/ (binaryfunc)instance_rshift, /*nb_rshift*/
0, /*nb_and*/ (binaryfunc)instance_and, /*nb_and*/
0, /*nb_xor*/ (binaryfunc)instance_xor, /*nb_xor*/
0, /*nb_or*/ (binaryfunc)instance_or, /*nb_or*/
(coercion)instance_coerce, /*nb_coerce*/ (coercion)instance_coerce, /*nb_coerce*/
(unaryfunc)instance_int, /*nb_int*/ (unaryfunc)instance_int, /*nb_int*/
(unaryfunc)instance_long, /*nb_long*/ (unaryfunc)instance_long, /*nb_long*/
(unaryfunc)instance_float, /*nb_float*/ (unaryfunc)instance_float, /*nb_float*/
(unaryfunc)instance_oct, /*nb_oct*/ (unaryfunc)instance_oct, /*nb_oct*/
(unaryfunc)instance_hex, /*nb_hex*/ (unaryfunc)instance_hex, /*nb_hex*/
0, /*nb_inplace_add*/ (binaryfunc)instance_iadd, /*nb_inplace_add*/
0, /*nb_inplace_subtract*/ (binaryfunc)instance_isub, /*nb_inplace_subtract*/
0, /*nb_inplace_multiply*/ (binaryfunc)instance_imul, /*nb_inplace_multiply*/
0, /*nb_inplace_divide*/ (binaryfunc)instance_idiv, /*nb_inplace_divide*/
0, /*nb_inplace_remainder*/ (binaryfunc)instance_imod, /*nb_inplace_remainder*/
(ternaryfunc)instance_inplace_pow, /*nb_inplace_power*/ (ternaryfunc)instance_ipow, /*nb_inplace_power*/
0, /*nb_inplace_lshift*/ (binaryfunc)instance_ilshift, /*nb_inplace_lshift*/
0, /*nb_inplace_rshift*/ (binaryfunc)instance_irshift, /*nb_inplace_rshift*/
0, /*nb_inplace_and*/ (binaryfunc)instance_iand, /*nb_inplace_and*/
0, /*nb_inplace_xor*/ (binaryfunc)instance_ixor, /*nb_inplace_xor*/
0, /*nb_inplace_or*/ (binaryfunc)instance_ior, /*nb_inplace_or*/
(binaryfunc)instance_cmp, /*nb_cmp*/
}; };
PyTypeObject PyInstance_Type = { PyTypeObject PyInstance_Type = {
...@@ -1525,8 +1609,8 @@ PyTypeObject PyInstance_Type = { ...@@ -1525,8 +1609,8 @@ PyTypeObject PyInstance_Type = {
0, /*tp_str*/ 0, /*tp_str*/
(getattrofunc)instance_getattr, /*tp_getattro*/ (getattrofunc)instance_getattr, /*tp_getattro*/
(setattrofunc)instance_setattr, /*tp_setattro*/ (setattrofunc)instance_setattr, /*tp_setattro*/
0, /* tp_as_buffer */ 0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /*tp_flags*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC | Py_TPFLAGS_NEWSTYLENUMBER, /*tp_flags*/
0, /* tp_doc */ 0, /* tp_doc */
(traverseproc)instance_traverse, /* tp_traverse */ (traverseproc)instance_traverse, /* tp_traverse */
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment