summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
authorNeil Schemenauer <nascheme@enme.ucalgary.ca>2001-01-04 01:39:06 (GMT)
committerNeil Schemenauer <nascheme@enme.ucalgary.ca>2001-01-04 01:39:06 (GMT)
commit5a1f015bee85ca271316b1600ae67dae387d3dd8 (patch)
treea7844c67d0d720aa54fb0b6dc86f5a42b045ffe5 /Objects
parent0ee7d8233f1dc1f5b720cc242cd999a7d129371f (diff)
downloadcpython-5a1f015bee85ca271316b1600ae67dae387d3dd8.zip
cpython-5a1f015bee85ca271316b1600ae67dae387d3dd8.tar.gz
cpython-5a1f015bee85ca271316b1600ae67dae387d3dd8.tar.bz2
Massive changes as per PEP 208. Read it for details.
Diffstat (limited to 'Objects')
-rw-r--r--Objects/abstract.c1046
1 files changed, 318 insertions, 728 deletions
diff --git a/Objects/abstract.c b/Objects/abstract.c
index dfdfc43..9050a4c 100644
--- a/Objects/abstract.c
+++ b/Objects/abstract.c
@@ -1,7 +1,12 @@
/* Abstract Object Interface (many thanks to Jim Fulton) */
+
#include "Python.h"
#include <ctype.h>
+#include "structmember.h" /* we need the offsetof() macro from there */
+
+#define NEW_STYLE_NUMBER(o) PyType_HasFeature((o)->ob_type, \
+ Py_TPFLAGS_NEWSTYLENUMBER)
/* Shorthands to return certain errors */
@@ -281,830 +286,415 @@ PyNumber_Check(PyObject *o)
/* Binary operators */
-#define BINOP(v, w, opname, ropname, thisfunc) \
- if (PyInstance_Check(v) || PyInstance_Check(w)) \
- return PyInstance_DoBinOp(v, w, opname, ropname, thisfunc)
+/* New style number protocol support */
-PyObject *
-PyNumber_Or(PyObject *v, PyObject *w)
-{
- BINOP(v, w, "__or__", "__ror__", PyNumber_Or);
- if (v->ob_type->tp_as_number != NULL) {
- PyObject *x = NULL;
- PyObject * (*f)(PyObject *, PyObject *) = NULL;
- if (PyNumber_Coerce(&v, &w) != 0)
- return NULL;
- if (v->ob_type->tp_as_number != NULL &&
- (f = v->ob_type->tp_as_number->nb_or) != NULL)
- x = (*f)(v, w);
- Py_DECREF(v);
- Py_DECREF(w);
- if (f != NULL)
- return x;
- }
- return type_error("bad operand type(s) for |");
-}
+#define NB_SLOT(x) offsetof(PyNumberMethods, x)
+#define NB_BINOP(nb_methods, slot) \
+ ((binaryfunc*)(& ((char*)nb_methods)[slot] ))
+#define NB_TERNOP(nb_methods, slot) \
+ ((ternaryfunc*)(& ((char*)nb_methods)[slot] ))
-PyObject *
-PyNumber_Xor(PyObject *v, PyObject *w)
-{
- BINOP(v, w, "__xor__", "__rxor__", PyNumber_Xor);
- if (v->ob_type->tp_as_number != NULL) {
- PyObject *x = NULL;
- PyObject * (*f)(PyObject *, PyObject *) = NULL;
- if (PyNumber_Coerce(&v, &w) != 0)
- return NULL;
- if (v->ob_type->tp_as_number != NULL &&
- (f = v->ob_type->tp_as_number->nb_xor) != NULL)
- x = (*f)(v, w);
- Py_DECREF(v);
- Py_DECREF(w);
- if (f != NULL)
- return x;
- }
- return type_error("bad operand type(s) for ^");
-}
+/*
+ Calling scheme used for binary operations:
-PyObject *
-PyNumber_And(PyObject *v, PyObject *w)
-{
- BINOP(v, w, "__and__", "__rand__", PyNumber_And);
- if (v->ob_type->tp_as_number != NULL) {
- PyObject *x = NULL;
- PyObject * (*f)(PyObject *, PyObject *) = NULL;
- if (PyNumber_Coerce(&v, &w) != 0)
- return NULL;
- if (v->ob_type->tp_as_number != NULL &&
- (f = v->ob_type->tp_as_number->nb_and) != NULL)
- x = (*f)(v, w);
- Py_DECREF(v);
- Py_DECREF(w);
- if (f != NULL)
- return x;
- }
- return type_error("bad operand type(s) for &");
-}
+ v w Action
+ -------------------------------------------------------------------
+ new new v.op(v,w), w.op(v,w)
+ new old v.op(v,w), coerce(v,w), v.op(v,w)
+ old new w.op(v,w), coerce(v,w), v.op(v,w)
+ old old coerce(v,w), v.op(v,w)
-PyObject *
-PyNumber_Lshift(PyObject *v, PyObject *w)
+ Legend:
+ -------
+ * new == new style number
+ * old == old style number
+ * Action indicates the order in which operations are tried until either
+ a valid result is produced or an error occurs.
+
+ */
+
+static PyObject *
+binary_op1(PyObject *v, PyObject *w, const int op_slot)
{
- BINOP(v, w, "__lshift__", "__rlshift__", PyNumber_Lshift);
- if (v->ob_type->tp_as_number != NULL) {
- PyObject *x = NULL;
- PyObject * (*f)(PyObject *, PyObject *) = NULL;
- if (PyNumber_Coerce(&v, &w) != 0)
+ PyObject *x;
+ binaryfunc *slot;
+ if (v->ob_type->tp_as_number != NULL && NEW_STYLE_NUMBER(v)) {
+ slot = NB_BINOP(v->ob_type->tp_as_number, op_slot);
+ if (*slot) {
+ x = (*slot)(v, w);
+ if (x != Py_NotImplemented) {
+ return x;
+ }
+ Py_DECREF(x); /* can't do it */
+ }
+ if (v->ob_type == w->ob_type) {
+ goto binop_error;
+ }
+ }
+ if (w->ob_type->tp_as_number != NULL && NEW_STYLE_NUMBER(w)) {
+ slot = NB_BINOP(w->ob_type->tp_as_number, op_slot);
+ if (*slot) {
+ x = (*slot)(v, w);
+ if (x != Py_NotImplemented) {
+ return x;
+ }
+ Py_DECREF(x); /* can't do it */
+ }
+ }
+ if (!NEW_STYLE_NUMBER(v) || !NEW_STYLE_NUMBER(w)) {
+ int err = PyNumber_CoerceEx(&v, &w);
+ if (err < 0) {
return NULL;
- if (v->ob_type->tp_as_number != NULL &&
- (f = v->ob_type->tp_as_number->nb_lshift) != NULL)
- x = (*f)(v, w);
- Py_DECREF(v);
- Py_DECREF(w);
- if (f != NULL)
- return x;
+ }
+ if (err == 0) {
+ PyNumberMethods *mv = v->ob_type->tp_as_number;
+ if (mv) {
+ slot = NB_BINOP(mv, op_slot);
+ if (*slot) {
+ PyObject *x = (*slot)(v, w);
+ Py_DECREF(v);
+ Py_DECREF(w);
+ return x;
+ }
+ }
+ /* CoerceEx incremented the reference counts */
+ Py_DECREF(v);
+ Py_DECREF(w);
+ }
}
- return type_error("bad operand type(s) for <<");
+binop_error:
+ Py_INCREF(Py_NotImplemented);
+ return Py_NotImplemented;
}
-
-PyObject *
-PyNumber_Rshift(PyObject *v, PyObject *w)
+
+static PyObject *
+binary_op(PyObject *v, PyObject *w, const int op_slot, const char *op_name)
{
- BINOP(v, w, "__rshift__", "__rrshift__", PyNumber_Rshift);
- if (v->ob_type->tp_as_number != NULL) {
- PyObject *x = NULL;
- PyObject * (*f)(PyObject *, PyObject *) = NULL;
- if (PyNumber_Coerce(&v, &w) != 0)
- return NULL;
- if (v->ob_type->tp_as_number != NULL &&
- (f = v->ob_type->tp_as_number->nb_rshift) != NULL)
- x = (*f)(v, w);
- Py_DECREF(v);
- Py_DECREF(w);
- if (f != NULL)
- return x;
+ PyObject *result = binary_op1(v, w, op_slot);
+ if (result == Py_NotImplemented) {
+ Py_DECREF(Py_NotImplemented);
+ PyErr_Format(PyExc_TypeError,
+ "unsupported operand type(s) for %s", op_name);
+ return NULL;
}
- return type_error("bad operand type(s) for >>");
+ return result;
}
-PyObject *
-PyNumber_Add(PyObject *v, PyObject *w)
-{
- PySequenceMethods *m;
- BINOP(v, w, "__add__", "__radd__", PyNumber_Add);
- m = v->ob_type->tp_as_sequence;
- if (m && m->sq_concat)
- return (*m->sq_concat)(v, w);
- else if (v->ob_type->tp_as_number != NULL) {
- PyObject *x = NULL;
- PyObject * (*f)(PyObject *, PyObject *) = NULL;
- if (PyNumber_Coerce(&v, &w) != 0)
- return NULL;
- if (v->ob_type->tp_as_number != NULL &&
- (f = v->ob_type->tp_as_number->nb_add) != NULL)
- x = (*f)(v, w);
- Py_DECREF(v);
- Py_DECREF(w);
- if (f != NULL)
- return x;
- }
- return type_error("bad operand type(s) for +");
-}
+/*
+ Calling scheme used for ternary operations:
-PyObject *
-PyNumber_Subtract(PyObject *v, PyObject *w)
-{
- BINOP(v, w, "__sub__", "__rsub__", PyNumber_Subtract);
- if (v->ob_type->tp_as_number != NULL) {
- PyObject *x = NULL;
- PyObject * (*f)(PyObject *, PyObject *) = NULL;
- if (PyNumber_Coerce(&v, &w) != 0)
- return NULL;
- if (v->ob_type->tp_as_number != NULL &&
- (f = v->ob_type->tp_as_number->nb_subtract) != NULL)
- x = (*f)(v, w);
- Py_DECREF(v);
- Py_DECREF(w);
- if (f != NULL)
- return x;
- }
- return type_error("bad operand type(s) for -");
-}
+ v w z Action
+ -------------------------------------------------------------------
+ new new new v.op(v,w,z), w.op(v,w,z), z.op(v,w,z)
+ new old new v.op(v,w,z), z.op(v,w,z), coerce(v,w,z), v.op(v,w,z)
+ old new new w.op(v,w,z), z.op(v,w,z), coerce(v,w,z), v.op(v,w,z)
+ old old new z.op(v,w,z), coerce(v,w,z), v.op(v,w,z)
+ new new old v.op(v,w,z), w.op(v,w,z), coerce(v,w,z), v.op(v,w,z)
+ new old old v.op(v,w,z), coerce(v,w,z), v.op(v,w,z)
+ old new old w.op(v,w,z), coerce(v,w,z), v.op(v,w,z)
+ old old old coerce(v,w,z), v.op(v,w,z)
-PyObject *
-PyNumber_Multiply(PyObject *v, PyObject *w)
-{
- PyTypeObject *tp = v->ob_type;
- PySequenceMethods *m;
+ Legend:
+ -------
+ * new == new style number
+ * old == old style number
+ * Action indicates the order in which operations are tried until either
+ a valid result is produced or an error occurs.
+ * coerce(v,w,z) actually does: coerce(v,w), coerce(v,z), coerce(w,z) and
+ only if z != Py_None; if z == Py_None, then it is treated as absent
+ variable and only coerce(v,w) is tried.
- BINOP(v, w, "__mul__", "__rmul__", PyNumber_Multiply);
- if (tp->tp_as_number != NULL &&
- w->ob_type->tp_as_sequence != NULL) {
- /* number*sequence -- swap v and w */
- PyObject *tmp = v;
- v = w;
- w = tmp;
- tp = v->ob_type;
- }
- if (tp->tp_as_number != NULL) {
- PyObject *x = NULL;
- PyObject * (*f)(PyObject *, PyObject *) = NULL;
- if (PyNumber_Coerce(&v, &w) != 0)
- return NULL;
- if (v->ob_type->tp_as_number != NULL &&
- (f = v->ob_type->tp_as_number->nb_multiply) != NULL)
- x = (*f)(v, w);
- Py_DECREF(v);
- Py_DECREF(w);
- if (f != NULL)
- return x;
- }
- m = tp->tp_as_sequence;
- if (m && m->sq_repeat) {
- long mul_value;
+ */
- if (PyInt_Check(w)) {
- mul_value = PyInt_AsLong(w);
+static PyObject *
+ternary_op(PyObject *v,
+ PyObject *w,
+ PyObject *z,
+ const int op_slot,
+ const char *op_name)
+{
+ PyNumberMethods *mv, *mw, *mz;
+ register PyObject *x = NULL;
+ register ternaryfunc *slot;
+
+ mv = v->ob_type->tp_as_number;
+ if (mv != NULL && NEW_STYLE_NUMBER(v)) {
+ /* try v.op(v,w,z) */
+ slot = NB_TERNOP(mv, op_slot);
+ if (*slot) {
+ x = (*slot)(v, w, z);
+ if (x != Py_NotImplemented)
+ return x;
+ /* Can't do it... fall through */
+ Py_DECREF(x);
}
- else if (PyLong_Check(w)) {
- mul_value = PyLong_AsLong(w);
- if (mul_value == -1 && PyErr_Occurred())
- return NULL;
+ if (v->ob_type == w->ob_type &&
+ (z == Py_None || z->ob_type == v->ob_type)) {
+ goto ternary_error;
}
- else {
- return type_error(
- "can't multiply sequence with non-int");
+ }
+ mw = w->ob_type->tp_as_number;
+ if (mw != NULL && NEW_STYLE_NUMBER(w)) {
+ /* try w.op(v,w,z) */
+ slot = NB_TERNOP(mw,op_slot);
+ if (*slot) {
+ x = (*slot)(v, w, z);
+ if (x != Py_NotImplemented)
+ return x;
+ /* Can't do it... fall through */
+ Py_DECREF(x);
+ }
+ if (NEW_STYLE_NUMBER(v) &&
+ (z == Py_None || z->ob_type == v->ob_type)) {
+ goto ternary_error;
}
- return (*m->sq_repeat)(v, (int)mul_value);
}
- return type_error("bad operand type(s) for *");
-}
-
-PyObject *
-PyNumber_Divide(PyObject *v, PyObject *w)
-{
- BINOP(v, w, "__div__", "__rdiv__", PyNumber_Divide);
- if (v->ob_type->tp_as_number != NULL) {
- PyObject *x = NULL;
- PyObject * (*f)(PyObject *, PyObject *) = NULL;
- if (PyNumber_Coerce(&v, &w) != 0)
- return NULL;
- if (v->ob_type->tp_as_number != NULL &&
- (f = v->ob_type->tp_as_number->nb_divide) != NULL)
- x = (*f)(v, w);
- Py_DECREF(v);
- Py_DECREF(w);
- if (f != NULL)
- return x;
+ mz = z->ob_type->tp_as_number;
+ if (mz != NULL && NEW_STYLE_NUMBER(z)) {
+ /* try: z.op(v,w,z) */
+ slot = NB_TERNOP(mz, op_slot);
+ if (*slot) {
+ x = (*slot)(v, w, z);
+ if (x != Py_NotImplemented)
+ return x;
+ /* Can't do it... fall through */
+ Py_DECREF(x);
+ }
}
- return type_error("bad operand type(s) for /");
-}
-PyObject *
-PyNumber_Remainder(PyObject *v, PyObject *w)
-{
- if (PyString_Check(v))
- return PyString_Format(v, w);
- else if (PyUnicode_Check(v))
- return PyUnicode_Format(v, w);
- BINOP(v, w, "__mod__", "__rmod__", PyNumber_Remainder);
- if (v->ob_type->tp_as_number != NULL) {
- PyObject *x = NULL;
- PyObject * (*f)(PyObject *, PyObject *) = NULL;
- if (PyNumber_Coerce(&v, &w) != 0)
- return NULL;
- if (v->ob_type->tp_as_number != NULL &&
- (f = v->ob_type->tp_as_number->nb_remainder) != NULL)
- x = (*f)(v, w);
+ if (!NEW_STYLE_NUMBER(v) || !NEW_STYLE_NUMBER(w) ||
+ (z != Py_None && !NEW_STYLE_NUMBER(z))) {
+ /* we have an old style operand, coerce */
+ PyObject *v1, *z1, *w2, *z2;
+ int c;
+
+ c = PyNumber_Coerce(&v, &w);
+ if (c != 0)
+ goto error3;
+
+ /* Special case: if the third argument is None, it is
+ treated as absent argument and not coerced. */
+ if (z == Py_None) {
+ if (v->ob_type->tp_as_number) {
+ slot = NB_TERNOP(v->ob_type->tp_as_number,
+ op_slot);
+ if (*slot)
+ x = (*slot)(v, w, z);
+ else
+ c = -1;
+ }
+ else
+ c = -1;
+ goto error2;
+ }
+ v1 = v;
+ z1 = z;
+ c = PyNumber_Coerce(&v1, &z1);
+ if (c != 0)
+ goto error2;
+ w2 = w;
+ z2 = z1;
+ c = PyNumber_Coerce(&w2, &z2);
+ if (c != 0)
+ goto error1;
+
+ if (v1->ob_type->tp_as_number != NULL) {
+ slot = NB_TERNOP(v1->ob_type->tp_as_number,
+ op_slot);
+ if (*slot)
+ x = (*slot)(v1, w2, z2);
+ else
+ c = -1;
+ }
+ else
+ c = -1;
+
+ Py_DECREF(w2);
+ Py_DECREF(z2);
+ error1:
+ Py_DECREF(v1);
+ Py_DECREF(z1);
+ error2:
Py_DECREF(v);
Py_DECREF(w);
- if (f != NULL)
+ error3:
+ if (c >= 0)
return x;
}
- return type_error("bad operand type(s) for %");
+
+ternary_error:
+ PyErr_Format(PyExc_TypeError, "unsupported operand type(s) for %s",
+ op_name);
+ return NULL;
}
+#define BINARY_FUNC(func, op, op_name) \
+ PyObject * \
+ func(PyObject *v, PyObject *w) { \
+ return binary_op(v, w, NB_SLOT(op), op_name); \
+ }
+
+BINARY_FUNC(PyNumber_Or, nb_or, "|")
+BINARY_FUNC(PyNumber_Xor, nb_xor, "^")
+BINARY_FUNC(PyNumber_And, nb_and, "&")
+BINARY_FUNC(PyNumber_Lshift, nb_lshift, "<<")
+BINARY_FUNC(PyNumber_Rshift, nb_rshift, ">>")
+BINARY_FUNC(PyNumber_Subtract, nb_subtract, "-")
+BINARY_FUNC(PyNumber_Multiply, nb_multiply, "*")
+BINARY_FUNC(PyNumber_Divide, nb_divide, "/")
+BINARY_FUNC(PyNumber_Divmod, nb_divmod, "divmod()")
+
PyObject *
-PyNumber_Divmod(PyObject *v, PyObject *w)
+PyNumber_Add(PyObject *v, PyObject *w)
{
- BINOP(v, w, "__divmod__", "__rdivmod__", PyNumber_Divmod);
- if (v->ob_type->tp_as_number != NULL) {
- PyObject *x = NULL;
- PyObject * (*f)(PyObject *, PyObject *) = NULL;
- if (PyNumber_Coerce(&v, &w) != 0)
- return NULL;
- if (v->ob_type->tp_as_number != NULL &&
- (f = v->ob_type->tp_as_number->nb_divmod) != NULL)
- x = (*f)(v, w);
- Py_DECREF(v);
- Py_DECREF(w);
- if (f != NULL)
- return x;
+ PyObject *result = binary_op1(v, w, NB_SLOT(nb_add));
+ if (result == Py_NotImplemented) {
+ PySequenceMethods *m = v->ob_type->tp_as_sequence;
+ Py_DECREF(Py_NotImplemented);
+ if (m && m->sq_concat) {
+ result = (*m->sq_concat)(v, w);
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError,
+ "unsupported operand types for +");
+ result = NULL;
+ }
}
- return type_error("bad operand type(s) for divmod()");
+ return result;
}
-/* Power (binary or ternary) */
-
-static PyObject *
-do_pow(PyObject *v, PyObject *w)
+PyObject *
+PyNumber_Remainder(PyObject *v, PyObject *w)
{
- PyObject *res;
- PyObject * (*f)(PyObject *, PyObject *, PyObject *);
- BINOP(v, w, "__pow__", "__rpow__", do_pow);
- if (v->ob_type->tp_as_number == NULL ||
- w->ob_type->tp_as_number == NULL) {
- PyErr_SetString(PyExc_TypeError,
- "pow(x, y) requires numeric arguments");
- return NULL;
- }
- if (PyNumber_Coerce(&v, &w) != 0)
- return NULL;
- if (v->ob_type->tp_as_number != NULL &&
- (f = v->ob_type->tp_as_number->nb_power) != NULL)
- res = (*f)(v, w, Py_None);
- else
- res = type_error("pow(x, y) not defined for these operands");
- Py_DECREF(v);
- Py_DECREF(w);
- return res;
+ if (PyString_Check(v))
+ return PyString_Format(v, w);
+ else if (PyUnicode_Check(v))
+ return PyUnicode_Format(v, w);
+ return binary_op(v, w, NB_SLOT(nb_remainder), "%");
}
PyObject *
PyNumber_Power(PyObject *v, PyObject *w, PyObject *z)
{
- PyObject *res;
- PyObject *v1, *z1, *w2, *z2;
- PyObject * (*f)(PyObject *, PyObject *, PyObject *);
-
- if (z == Py_None)
- return do_pow(v, w);
- /* XXX The ternary version doesn't do class instance coercions */
- if (PyInstance_Check(v))
- return v->ob_type->tp_as_number->nb_power(v, w, z);
- if (v->ob_type->tp_as_number == NULL ||
- z->ob_type->tp_as_number == NULL ||
- w->ob_type->tp_as_number == NULL) {
- return type_error("pow(x, y, z) requires numeric arguments");
- }
- if (PyNumber_Coerce(&v, &w) != 0)
- return NULL;
- res = NULL;
- v1 = v;
- z1 = z;
- if (PyNumber_Coerce(&v1, &z1) != 0)
- goto error2;
- w2 = w;
- z2 = z1;
- if (PyNumber_Coerce(&w2, &z2) != 0)
- goto error1;
- if (v->ob_type->tp_as_number != NULL &&
- (f = v1->ob_type->tp_as_number->nb_power) != NULL)
- res = (*f)(v1, w2, z2);
- else
- res = type_error(
- "pow(x, y, z) not defined for these operands");
- Py_DECREF(w2);
- Py_DECREF(z2);
- error1:
- Py_DECREF(v1);
- Py_DECREF(z1);
- error2:
- Py_DECREF(v);
- Py_DECREF(w);
- return res;
+ return ternary_op(v, w, z, NB_SLOT(nb_power), "** or pow()");
}
/* Binary in-place operators */
/* The in-place operators are defined to fall back to the 'normal',
- non in-place operations, if the in-place methods are not in place, and to
- take class instances into account. This is how it is supposed to work:
-
- - If the left-hand-side object (the first argument) is an
- instance object, try to let PyInstance_HalfBinOp() handle it. Pass the
- non in-place variant of the function as callback, because it will only
- be used if the left-hand object is changed by coercion.
-
- - Otherwise, if the left hand object is not an instance object, it has
- the appropriate struct members, and they are filled, call the
- appropriate function and return the result. No coercion is done on the
- arguments; the left-hand object is the one the operation is performed
- on, and it's up to the function to deal with the right-hand object.
-
- - Otherwise, in-place modification is not supported. Handle it exactly as
- a non in-place operation of the same kind:
+ non in-place operations, if the in-place methods are not in place.
- - If either object is an instance, let PyInstance_DoBinOp() handle it.
+ - If the left hand object has the appropriate struct members, and
+ they are filled, call the appropriate function and return the
+ result. No coercion is done on the arguments; the left-hand object
+ is the one the operation is performed on, and it's up to the
+ function to deal with the right-hand object.
- - Otherwise, both arguments are C types. If the left-hand object has
- the appropriate struct members filled, coerce, call the
- appropriate function, and return the result.
-
- - Otherwise, we are out of options: raise a type error specific to
- augmented assignment.
+ - Otherwise, in-place modification is not supported. Handle it exactly as
+ a non in-place operation of the same kind.
*/
#define HASINPLACE(t) PyType_HasFeature((t)->ob_type, Py_TPFLAGS_HAVE_INPLACEOPS)
-PyObject *
-PyNumber_InPlaceOr(PyObject *v, PyObject *w)
-{
- PyObject * (*f)(PyObject *, PyObject *) = NULL;
- PyObject *x = NULL;
-
- if (PyInstance_Check(v)) {
- if (PyInstance_HalfBinOp(v, w, "__ior__", &x,
- PyNumber_Or, 0) <= 0)
- return x;
- }
- else if (v->ob_type->tp_as_number != NULL && HASINPLACE(v) &&
- (f = v->ob_type->tp_as_number->nb_inplace_or) != NULL)
- return (*f)(v, w);
-
- BINOP(v, w, "__or__", "__ror__", PyNumber_Or);
-
- if (v->ob_type->tp_as_number != NULL) {
- if (PyNumber_Coerce(&v, &w) != 0)
- return NULL;
- if (v->ob_type->tp_as_number != NULL &&
- (f = v->ob_type->tp_as_number->nb_or) != NULL)
- x = (*f)(v, w);
- Py_DECREF(v);
- Py_DECREF(w);
- if (f != NULL)
- return x;
- }
-
- return type_error("bad operand type(s) for |=");
-}
-
-PyObject *
-PyNumber_InPlaceXor(PyObject *v, PyObject *w)
-{
- PyObject * (*f)(PyObject *, PyObject *) = NULL;
- PyObject *x = NULL;
-
- if (PyInstance_Check(v)) {
- if (PyInstance_HalfBinOp(v, w, "__ixor__", &x,
- PyNumber_Xor, 0) <= 0)
- return x;
- }
- else if (v->ob_type->tp_as_number != NULL && HASINPLACE(v) &&
- (f = v->ob_type->tp_as_number->nb_inplace_xor) != NULL)
- return (*f)(v, w);
-
- BINOP(v, w, "__xor__", "__rxor__", PyNumber_Xor);
-
- if (v->ob_type->tp_as_number != NULL) {
- if (PyNumber_Coerce(&v, &w) != 0)
- return NULL;
- if (v->ob_type->tp_as_number != NULL &&
- (f = v->ob_type->tp_as_number->nb_xor) != NULL)
- x = (*f)(v, w);
- Py_DECREF(v);
- Py_DECREF(w);
- if (f != NULL)
- return x;
- }
-
- return type_error("bad operand type(s) for ^=");
-}
-
-PyObject *
-PyNumber_InPlaceAnd(PyObject *v, PyObject *w)
-{
- PyObject * (*f)(PyObject *, PyObject *) = NULL;
- PyObject *x = NULL;
-
- if (PyInstance_Check(v)) {
- if (PyInstance_HalfBinOp(v, w, "__iand__", &x,
- PyNumber_And, 0) <= 0)
- return x;
- }
- else if (v->ob_type->tp_as_number != NULL && HASINPLACE(v) &&
- (f = v->ob_type->tp_as_number->nb_inplace_and) != NULL)
- return (*f)(v, w);
-
- BINOP(v, w, "__and__", "__rand__", PyNumber_And);
-
- if (v->ob_type->tp_as_number != NULL) {
- if (PyNumber_Coerce(&v, &w) != 0)
- return NULL;
- if (v->ob_type->tp_as_number != NULL &&
- (f = v->ob_type->tp_as_number->nb_and) != NULL)
- x = (*f)(v, w);
- Py_DECREF(v);
- Py_DECREF(w);
- if (f != NULL)
- return x;
- }
-
- return type_error("bad operand type(s) for &=");
-}
-
-PyObject *
-PyNumber_InPlaceLshift(PyObject *v, PyObject *w)
-{
- PyObject * (*f)(PyObject *, PyObject *) = NULL;
- PyObject *x = NULL;
-
- if (PyInstance_Check(v)) {
- if (PyInstance_HalfBinOp(v, w, "__ilshift__", &x,
- PyNumber_Lshift, 0) <= 0)
- return x;
- }
- else if (v->ob_type->tp_as_number != NULL && HASINPLACE(v) &&
- (f = v->ob_type->tp_as_number->nb_inplace_lshift) != NULL)
- return (*f)(v, w);
-
- BINOP(v, w, "__lshift__", "__rlshift__", PyNumber_Lshift);
-
- if (v->ob_type->tp_as_number != NULL) {
- if (PyNumber_Coerce(&v, &w) != 0)
- return NULL;
- if (v->ob_type->tp_as_number != NULL &&
- (f = v->ob_type->tp_as_number->nb_lshift) != NULL)
- x = (*f)(v, w);
- Py_DECREF(v);
- Py_DECREF(w);
- if (f != NULL)
- return x;
+static PyObject *
+binary_iop(PyObject *v, PyObject *w, const int iop_slot, const int op_slot,
+ const char *op_name)
+{
+ PyNumberMethods *mv = v->ob_type->tp_as_number;
+ if (mv != NULL && HASINPLACE(v)) {
+ binaryfunc *slot = NB_BINOP(mv, iop_slot);
+ if (*slot) {
+ PyObject *x = (*slot)(v, w);
+ if (x != Py_NotImplemented) {
+ return x;
+ }
+ Py_DECREF(x);
+ }
}
-
- return type_error("bad operand type(s) for <<=");
+ return binary_op(v, w, op_slot, op_name);
}
-PyObject *
-PyNumber_InPlaceRshift(PyObject *v, PyObject *w)
-{
- PyObject * (*f)(PyObject *, PyObject *) = NULL;
- PyObject *x = NULL;
-
- if (PyInstance_Check(v)) {
- if (PyInstance_HalfBinOp(v, w, "__irshift__", &x,
- PyNumber_Rshift, 0) <= 0)
- return x;
- }
- else if (v->ob_type->tp_as_number != NULL && HASINPLACE(v) &&
- (f = v->ob_type->tp_as_number->nb_inplace_rshift) != NULL)
- return (*f)(v, w);
-
- BINOP(v, w, "__rshift__", "__rrshift__", PyNumber_Rshift);
-
- if (v->ob_type->tp_as_number != NULL) {
- if (PyNumber_Coerce(&v, &w) != 0)
- return NULL;
- if (v->ob_type->tp_as_number != NULL &&
- (f = v->ob_type->tp_as_number->nb_rshift) != NULL)
- x = (*f)(v, w);
- Py_DECREF(v);
- Py_DECREF(w);
- if (f != NULL)
- return x;
+#define INPLACE_BINOP(func, iop, op, op_name) \
+ PyObject * \
+ func(PyObject *v, PyObject *w) { \
+ return binary_iop(v, w, NB_SLOT(iop), NB_SLOT(op), op_name); \
}
- return type_error("bad operand type(s) for >>=");
-}
+INPLACE_BINOP(PyNumber_InPlaceOr, nb_inplace_or, nb_or, "|=")
+INPLACE_BINOP(PyNumber_InPlaceXor, nb_inplace_xor, nb_xor, "^=")
+INPLACE_BINOP(PyNumber_InPlaceAnd, nb_inplace_and, nb_and, "&=")
+INPLACE_BINOP(PyNumber_InPlaceLshift, nb_inplace_lshift, nb_lshift, "<<=")
+INPLACE_BINOP(PyNumber_InPlaceRshift, nb_inplace_rshift, nb_rshift, ">>=")
+INPLACE_BINOP(PyNumber_InPlaceSubtract, nb_inplace_subtract, nb_subtract, "-=")
+INPLACE_BINOP(PyNumber_InPlaceDivide, nb_inplace_divide, nb_divide, "/=")
PyObject *
PyNumber_InPlaceAdd(PyObject *v, PyObject *w)
{
- PyObject * (*f)(PyObject *, PyObject *) = NULL;
- PyObject *x = NULL;
-
- if (PyInstance_Check(v)) {
- if (PyInstance_HalfBinOp(v, w, "__iadd__", &x,
- PyNumber_Add, 0) <= 0)
- return x;
- }
- else if (HASINPLACE(v)) {
- if (v->ob_type->tp_as_sequence != NULL)
- f = v->ob_type->tp_as_sequence->sq_inplace_concat;
- if (f == NULL && v->ob_type->tp_as_number != NULL)
- f = v->ob_type->tp_as_number->nb_inplace_add;
- if (f != NULL)
- return (*f)(v, w);
- }
-
- BINOP(v, w, "__add__", "__radd__", PyNumber_Add);
+ binaryfunc f = NULL;
if (v->ob_type->tp_as_sequence != NULL) {
- f = v->ob_type->tp_as_sequence->sq_concat;
+ if (HASINPLACE(v))
+ f = v->ob_type->tp_as_sequence->sq_inplace_concat;
+ if (f == NULL)
+ f = v->ob_type->tp_as_sequence->sq_concat;
if (f != NULL)
return (*f)(v, w);
}
- if (v->ob_type->tp_as_number != NULL) {
- if (PyNumber_Coerce(&v, &w) != 0)
- return NULL;
- if (v->ob_type->tp_as_number != NULL) {
- f = v->ob_type->tp_as_number->nb_add;
- if (f != NULL)
- x = (*f)(v, w);
- }
- Py_DECREF(v);
- Py_DECREF(w);
- if (f != NULL)
- return x;
- }
-
- return type_error("bad operand type(s) for +=");
-}
-
-PyObject *
-PyNumber_InPlaceSubtract(PyObject *v, PyObject *w)
-{
- PyObject * (*f)(PyObject *, PyObject *) = NULL;
- PyObject *x = NULL;
-
- if (PyInstance_Check(v)) {
- if (PyInstance_HalfBinOp(v, w, "__isub__", &x,
- PyNumber_Subtract, 0) <= 0)
- return x;
- }
- else if (v->ob_type->tp_as_number != NULL && HASINPLACE(v) &&
- (f = v->ob_type->tp_as_number->nb_inplace_subtract) != NULL)
- return (*f)(v, w);
-
- BINOP(v, w, "__sub__", "__rsub__", PyNumber_Subtract);
-
- if (v->ob_type->tp_as_number != NULL) {
- if (PyNumber_Coerce(&v, &w) != 0)
- return NULL;
- if (v->ob_type->tp_as_number != NULL &&
- (f = v->ob_type->tp_as_number->nb_subtract) != NULL)
- x = (*f)(v, w);
- Py_DECREF(v);
- Py_DECREF(w);
- if (f != NULL)
- return x;
- }
-
- return type_error("bad operand type(s) for -=");
+ return binary_iop(v, w, NB_SLOT(nb_inplace_add), NB_SLOT(nb_add), "+=");
}
PyObject *
PyNumber_InPlaceMultiply(PyObject *v, PyObject *w)
{
- PyObject * (*f)(PyObject *, PyObject *) = NULL;
PyObject * (*g)(PyObject *, int) = NULL;
- PyObject *x = NULL;
-
- if (PyInstance_Check(v)) {
- if (PyInstance_HalfBinOp(v, w, "__imul__", &x,
- PyNumber_Multiply, 0) <= 0)
- return x;
- }
- else if (v->ob_type->tp_as_number != NULL && HASINPLACE(v) &&
- (f = v->ob_type->tp_as_number->nb_inplace_multiply) != NULL)
- return (*f)(v, w);
- else if (v->ob_type->tp_as_sequence != NULL && HASINPLACE(v) &&
- (g = v->ob_type->tp_as_sequence->sq_inplace_repeat) != NULL) {
- long mul_value;
-
+ if (HASINPLACE(v) && v->ob_type->tp_as_sequence &&
+ (g = v->ob_type->tp_as_sequence->sq_inplace_repeat)) {
+ long n;
if (PyInt_Check(w)) {
- mul_value = PyInt_AsLong(w);
+ n = PyInt_AsLong(w);
}
else if (PyLong_Check(w)) {
- mul_value = PyLong_AsLong(w);
- if (mul_value == -1 && PyErr_Occurred())
- return NULL;
- }
- else {
- return type_error(
- "can't multiply sequence with non-int");
- }
- return (*g)(v, (int)mul_value);
- }
-
- BINOP(v, w, "__mul__", "__rmul__", PyNumber_Multiply);
-
- if (v->ob_type->tp_as_number != NULL) {
- if (PyNumber_Coerce(&v, &w) != 0)
- return NULL;
- if (v->ob_type->tp_as_number != NULL &&
- (f = v->ob_type->tp_as_number->nb_multiply) != NULL)
- x = (*f)(v, w);
- Py_DECREF(v);
- Py_DECREF(w);
- if (f != NULL)
- return x;
- }
- else if (v->ob_type->tp_as_sequence != NULL &&
- (g = v->ob_type->tp_as_sequence->sq_repeat) != NULL) {
- long mul_value;
-
- if (PyInt_Check(w)) {
- mul_value = PyInt_AsLong(w);
- }
- else if (PyLong_Check(w)) {
- mul_value = PyLong_AsLong(w);
- if (mul_value == -1 && PyErr_Occurred())
- return NULL;
+ n = PyLong_AsLong(w);
+ if (n == -1 && PyErr_Occurred())
+ return NULL;
}
else {
- return type_error(
- "can't multiply sequence with non-int");
+ return type_error("can't multiply sequence to non-int");
}
- return (*g)(v, (int)mul_value);
+ return (*g)(v, (int)n);
}
- return type_error("bad operand type(s) for *=");
+ return binary_iop(v, w, NB_SLOT(nb_inplace_multiply),
+ NB_SLOT(nb_multiply), "*=");
}
-PyObject *
-PyNumber_InPlaceDivide(PyObject *v, PyObject *w)
-{
- PyObject * (*f)(PyObject *, PyObject *) = NULL;
- PyObject *x = NULL;
-
- if (PyInstance_Check(v)) {
- if (PyInstance_HalfBinOp(v, w, "__idiv__", &x,
- PyNumber_Divide, 0) <= 0)
- return x;
- }
- else if (v->ob_type->tp_as_number != NULL && HASINPLACE(v) &&
- (f = v->ob_type->tp_as_number->nb_inplace_divide) != NULL)
- return (*f)(v, w);
- BINOP(v, w, "__div__", "__rdiv__", PyNumber_Divide);
-
- if (v->ob_type->tp_as_number != NULL) {
- if (PyNumber_Coerce(&v, &w) != 0)
- return NULL;
- if (v->ob_type->tp_as_number != NULL &&
- (f = v->ob_type->tp_as_number->nb_divide) != NULL)
- x = (*f)(v, w);
- Py_DECREF(v);
- Py_DECREF(w);
- if (f != NULL)
- return x;
- }
-
- return type_error("bad operand type(s) for /=");
-}
PyObject *
PyNumber_InPlaceRemainder(PyObject *v, PyObject *w)
{
- PyObject * (*f)(PyObject *, PyObject *) = NULL;
- PyObject *x = NULL;
-
- if (PyInstance_Check(v)) {
- if (PyInstance_HalfBinOp(v, w, "__imod__", &x,
- PyNumber_Remainder, 0) <= 0)
- return x;
- }
- else if (v->ob_type->tp_as_number != NULL && HASINPLACE(v) &&
- (f = v->ob_type->tp_as_number->nb_inplace_remainder) != NULL)
- return (*f)(v, w);
-
if (PyString_Check(v))
return PyString_Format(v, w);
else if (PyUnicode_Check(v))
return PyUnicode_Format(v, w);
-
- BINOP(v, w, "__mod__", "__rmod__", PyNumber_Remainder);
-
- if (v->ob_type->tp_as_number != NULL) {
- if (PyNumber_Coerce(&v, &w) != 0)
- return NULL;
- if ((f = v->ob_type->tp_as_number->nb_remainder) != NULL)
- x = (*f)(v, w);
- Py_DECREF(v);
- Py_DECREF(w);
- if (f != NULL)
- return x;
- }
-
- return type_error("bad operand type(s) for %=");
-}
-
-
-/* In-place Power (binary or ternary, for API consistency) */
-
-static PyObject *
-do_inplace_pow(PyObject *v, PyObject *w)
-{
- PyObject * (*f)(PyObject *, PyObject *, PyObject *) = NULL;
- PyObject *x = NULL;
-
- if (PyInstance_Check(v)) {
- if (PyInstance_HalfBinOp(v, w, "__ipow__", &x, do_pow, 0) <= 0)
- return x;
- }
- else if (v->ob_type->tp_as_number != NULL && HASINPLACE(v) &&
- (f = v->ob_type->tp_as_number->nb_inplace_power) != NULL)
- return (*f)(v, w, Py_None);
-
- BINOP(v, w, "__pow__", "__rpow__", do_pow);
-
- if (v->ob_type->tp_as_number == NULL ||
- w->ob_type->tp_as_number == NULL) {
- return type_error("bad operand type(s) for **=");
- }
- if (PyNumber_Coerce(&v, &w) != 0)
- return NULL;
- if ((f = v->ob_type->tp_as_number->nb_power) != NULL)
- x = (*f)(v, w, Py_None);
else
- x = type_error("bad operand type(s) for **=");
- Py_DECREF(v);
- Py_DECREF(w);
- return x;
+ return binary_iop(v, w, NB_SLOT(nb_inplace_remainder),
+ NB_SLOT(nb_remainder), "%=");
}
+
PyObject *
PyNumber_InPlacePower(PyObject *v, PyObject *w, PyObject *z)
{
- PyObject *res;
- PyObject *v1, *z1, *w2, *z2, *oldv;
- PyObject * (*f)(PyObject *, PyObject *, PyObject *);
-
- if (z == Py_None)
- return do_inplace_pow(v, w);
- /* XXX The ternary version doesn't do class instance coercions */
- if (PyInstance_Check(v))
- return v->ob_type->tp_as_number->nb_inplace_power(v, w, z);
- if (v->ob_type->tp_as_number == NULL ||
- z->ob_type->tp_as_number == NULL ||
- w->ob_type->tp_as_number == NULL) {
- return type_error(
- "(inplace) pow(x, y, z) requires numeric arguments");
- }
- oldv = v;
- Py_INCREF(oldv);
- res = NULL;
- if (PyNumber_Coerce(&v, &w) != 0)
- goto error3;
- v1 = v;
- z1 = z;
- if (PyNumber_Coerce(&v1, &z1) != 0)
- goto error2;
- w2 = w;
- z2 = z1;
- if (PyNumber_Coerce(&w2, &z2) != 0)
- goto error1;
- if (oldv == v1 && HASINPLACE(v1) &&
- v->ob_type->tp_as_number != NULL &&
- (f = v1->ob_type->tp_as_number->nb_inplace_power) != NULL)
- res = (*f)(v1, w2, z2);
- else if (v1->ob_type->tp_as_number != NULL &&
- (f = v1->ob_type->tp_as_number->nb_power) != NULL)
- res = (*f)(v1, w2, z2);
- else
- res = type_error(
- "(inplace) pow(x, y, z) not defined for these operands");
- Py_DECREF(w2);
- Py_DECREF(z2);
- error1:
- Py_DECREF(v1);
- Py_DECREF(z1);
- error2:
- Py_DECREF(v);
- Py_DECREF(w);
- error3:
- Py_DECREF(oldv);
- return res;
+ if (HASINPLACE(v) && v->ob_type->tp_as_number &&
+ v->ob_type->tp_as_number->nb_inplace_power != NULL) {
+ return ternary_op(v, w, z, NB_SLOT(nb_inplace_power), "**=");
+ }
+ else {
+ return ternary_op(v, w, z, NB_SLOT(nb_power), "**=");
+ }
}