Commit 8d7ee810 authored by Neil Schemenauer's avatar Neil Schemenauer

Massive changes as per PEP 208. Read it for details.

parent 7f2458c3
/* Abstract Object Interface (many thanks to Jim Fulton) */ /* Abstract Object Interface (many thanks to Jim Fulton) */
#include "Python.h" #include "Python.h"
#include <ctype.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 */ /* Shorthands to return certain errors */
...@@ -281,328 +286,230 @@ PyNumber_Check(PyObject *o) ...@@ -281,328 +286,230 @@ PyNumber_Check(PyObject *o)
/* Binary operators */ /* Binary operators */
#define BINOP(v, w, opname, ropname, thisfunc) \ /* New style number protocol support */
if (PyInstance_Check(v) || PyInstance_Check(w)) \
return PyInstance_DoBinOp(v, w, opname, ropname, thisfunc)
PyObject * #define NB_SLOT(x) offsetof(PyNumberMethods, x)
PyNumber_Or(PyObject *v, PyObject *w) #define NB_BINOP(nb_methods, slot) \
((binaryfunc*)(& ((char*)nb_methods)[slot] ))
#define NB_TERNOP(nb_methods, slot) \
((ternaryfunc*)(& ((char*)nb_methods)[slot] ))
/*
Calling scheme used for binary operations:
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)
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, "__or__", "__ror__", PyNumber_Or); PyObject *x;
if (v->ob_type->tp_as_number != NULL) { binaryfunc *slot;
PyObject *x = NULL; if (v->ob_type->tp_as_number != NULL && NEW_STYLE_NUMBER(v)) {
PyObject * (*f)(PyObject *, PyObject *) = NULL; slot = NB_BINOP(v->ob_type->tp_as_number, op_slot);
if (PyNumber_Coerce(&v, &w) != 0) if (*slot) {
return NULL; x = (*slot)(v, w);
if (v->ob_type->tp_as_number != NULL && if (x != Py_NotImplemented) {
(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 x;
} }
return type_error("bad operand type(s) for |"); Py_DECREF(x); /* can't do it */
} }
if (v->ob_type == w->ob_type) {
PyObject * goto binop_error;
PyNumber_Xor(PyObject *v, PyObject *w) }
{ }
BINOP(v, w, "__xor__", "__rxor__", PyNumber_Xor); if (w->ob_type->tp_as_number != NULL && NEW_STYLE_NUMBER(w)) {
if (v->ob_type->tp_as_number != NULL) { slot = NB_BINOP(w->ob_type->tp_as_number, op_slot);
PyObject *x = NULL; if (*slot) {
PyObject * (*f)(PyObject *, PyObject *) = NULL; x = (*slot)(v, w);
if (PyNumber_Coerce(&v, &w) != 0) if (x != Py_NotImplemented) {
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 x;
} }
return type_error("bad operand type(s) for ^"); Py_DECREF(x); /* can't do it */
} }
}
PyObject * if (!NEW_STYLE_NUMBER(v) || !NEW_STYLE_NUMBER(w)) {
PyNumber_And(PyObject *v, PyObject *w) int err = PyNumber_CoerceEx(&v, &w);
{ if (err < 0) {
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; return NULL;
if (v->ob_type->tp_as_number != NULL && }
(f = v->ob_type->tp_as_number->nb_and) != NULL) if (err == 0) {
x = (*f)(v, w); 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(v);
Py_DECREF(w); Py_DECREF(w);
if (f != NULL)
return x; return x;
} }
return type_error("bad operand type(s) for &"); }
} /* CoerceEx incremented the reference counts */
PyObject *
PyNumber_Lshift(PyObject *v, PyObject *w)
{
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)
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(v);
Py_DECREF(w); Py_DECREF(w);
if (f != NULL)
return x;
} }
return type_error("bad operand type(s) for <<"); }
binop_error:
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
} }
PyObject * static PyObject *
PyNumber_Rshift(PyObject *v, PyObject *w) binary_op(PyObject *v, PyObject *w, const int op_slot, const char *op_name)
{ {
BINOP(v, w, "__rshift__", "__rrshift__", PyNumber_Rshift); PyObject *result = binary_op1(v, w, op_slot);
if (v->ob_type->tp_as_number != NULL) { if (result == Py_NotImplemented) {
PyObject *x = NULL; Py_DECREF(Py_NotImplemented);
PyObject * (*f)(PyObject *, PyObject *) = NULL; PyErr_Format(PyExc_TypeError,
if (PyNumber_Coerce(&v, &w) != 0) "unsupported operand type(s) for %s", op_name);
return NULL; 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;
} }
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; Calling scheme used for ternary operations:
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 +");
}
PyObject * v w z Action
PyNumber_Subtract(PyObject *v, PyObject *w) -------------------------------------------------------------------
{ new new new v.op(v,w,z), w.op(v,w,z), z.op(v,w,z)
BINOP(v, w, "__sub__", "__rsub__", PyNumber_Subtract); new old new v.op(v,w,z), z.op(v,w,z), coerce(v,w,z), v.op(v,w,z)
if (v->ob_type->tp_as_number != NULL) { old new new w.op(v,w,z), z.op(v,w,z), coerce(v,w,z), v.op(v,w,z)
PyObject *x = NULL; old old new z.op(v,w,z), coerce(v,w,z), v.op(v,w,z)
PyObject * (*f)(PyObject *, PyObject *) = NULL; new new old v.op(v,w,z), w.op(v,w,z), coerce(v,w,z), v.op(v,w,z)
if (PyNumber_Coerce(&v, &w) != 0) new old old v.op(v,w,z), coerce(v,w,z), v.op(v,w,z)
return NULL; old new old w.op(v,w,z), coerce(v,w,z), v.op(v,w,z)
if (v->ob_type->tp_as_number != NULL && old old old coerce(v,w,z), v.op(v,w,z)
(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 -");
}
PyObject * Legend:
PyNumber_Multiply(PyObject *v, PyObject *w) -------
{ * new == new style number
PyTypeObject *tp = v->ob_type; * old == old style number
PySequenceMethods *m; * 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) { static PyObject *
/* number*sequence -- swap v and w */ ternary_op(PyObject *v,
PyObject *tmp = v; PyObject *w,
v = w; PyObject *z,
w = tmp; const int op_slot,
tp = v->ob_type; const char *op_name)
} {
if (tp->tp_as_number != NULL) { PyNumberMethods *mv, *mw, *mz;
PyObject *x = NULL; register PyObject *x = NULL;
PyObject * (*f)(PyObject *, PyObject *) = NULL; register ternaryfunc *slot;
if (PyNumber_Coerce(&v, &w) != 0)
return NULL; mv = v->ob_type->tp_as_number;
if (v->ob_type->tp_as_number != NULL && if (mv != NULL && NEW_STYLE_NUMBER(v)) {
(f = v->ob_type->tp_as_number->nb_multiply) != NULL) /* try v.op(v,w,z) */
x = (*f)(v, w); slot = NB_TERNOP(mv, op_slot);
Py_DECREF(v); if (*slot) {
Py_DECREF(w); x = (*slot)(v, w, z);
if (f != NULL) if (x != Py_NotImplemented)
return x; return x;
/* Can't do it... fall through */
Py_DECREF(x);
} }
m = tp->tp_as_sequence; if (v->ob_type == w->ob_type &&
if (m && m->sq_repeat) { (z == Py_None || z->ob_type == v->ob_type)) {
long mul_value; goto ternary_error;
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;
} }
else { mw = w->ob_type->tp_as_number;
return type_error( if (mw != NULL && NEW_STYLE_NUMBER(w)) {
"can't multiply sequence with non-int"); /* 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);
} }
return (*m->sq_repeat)(v, (int)mul_value); if (NEW_STYLE_NUMBER(v) &&
(z == Py_None || z->ob_type == v->ob_type)) {
goto ternary_error;
} }
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;
} }
return type_error("bad operand type(s) for /"); mz = z->ob_type->tp_as_number;
} if (mz != NULL && NEW_STYLE_NUMBER(z)) {
/* try: z.op(v,w,z) */
PyObject * slot = NB_TERNOP(mz, op_slot);
PyNumber_Remainder(PyObject *v, PyObject *w) if (*slot) {
{ x = (*slot)(v, w, z);
if (PyString_Check(v)) if (x != Py_NotImplemented)
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);
Py_DECREF(v);
Py_DECREF(w);
if (f != NULL)
return x; return x;
/* Can't do it... fall through */
Py_DECREF(x);
} }
return type_error("bad operand type(s) for %");
}
PyObject *
PyNumber_Divmod(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;
} }
return type_error("bad operand type(s) for divmod()");
}
/* Power (binary or ternary) */ 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;
static PyObject * c = PyNumber_Coerce(&v, &w);
do_pow(PyObject *v, PyObject *w) if (c != 0)
{ goto error3;
PyObject *res;
PyObject * (*f)(PyObject *, PyObject *, PyObject *); /* Special case: if the third argument is None, it is
BINOP(v, w, "__pow__", "__rpow__", do_pow); treated as absent argument and not coerced. */
if (v->ob_type->tp_as_number == NULL || if (z == Py_None) {
w->ob_type->tp_as_number == NULL) { if (v->ob_type->tp_as_number) {
PyErr_SetString(PyExc_TypeError, slot = NB_TERNOP(v->ob_type->tp_as_number,
"pow(x, y) requires numeric arguments"); op_slot);
return NULL; if (*slot)
x = (*slot)(v, w, z);
else
c = -1;
} }
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 else
res = type_error("pow(x, y) not defined for these operands"); c = -1;
Py_DECREF(v); goto error2;
Py_DECREF(w); }
return res;
}
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; v1 = v;
z1 = z; z1 = z;
if (PyNumber_Coerce(&v1, &z1) != 0) c = PyNumber_Coerce(&v1, &z1);
if (c != 0)
goto error2; goto error2;
w2 = w; w2 = w;
z2 = z1; z2 = z1;
if (PyNumber_Coerce(&w2, &z2) != 0) c = PyNumber_Coerce(&w2, &z2);
if (c != 0)
goto error1; goto error1;
if (v->ob_type->tp_as_number != NULL &&
(f = v1->ob_type->tp_as_number->nb_power) != NULL) if (v1->ob_type->tp_as_number != NULL) {
res = (*f)(v1, w2, z2); slot = NB_TERNOP(v1->ob_type->tp_as_number,
op_slot);
if (*slot)
x = (*slot)(v1, w2, z2);
else else
res = type_error( c = -1;
"pow(x, y, z) not defined for these operands"); }
else
c = -1;
Py_DECREF(w2); Py_DECREF(w2);
Py_DECREF(z2); Py_DECREF(z2);
error1: error1:
...@@ -611,500 +518,183 @@ PyNumber_Power(PyObject *v, PyObject *w, PyObject *z) ...@@ -611,500 +518,183 @@ PyNumber_Power(PyObject *v, PyObject *w, PyObject *z)
error2: error2:
Py_DECREF(v); Py_DECREF(v);
Py_DECREF(w); Py_DECREF(w);
return res; error3:
} if (c >= 0)
/* 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:
- If either object is an instance, let PyInstance_DoBinOp() handle it.
- 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.
*/
#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; 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); ternary_error:
PyErr_Format(PyExc_TypeError, "unsupported operand type(s) for %s",
if (v->ob_type->tp_as_number != NULL) { op_name);
if (PyNumber_Coerce(&v, &w) != 0)
return NULL; return NULL;
if (v->ob_type->tp_as_number != NULL && }
(f = v->ob_type->tp_as_number->nb_or) != NULL)
x = (*f)(v, w); #define BINARY_FUNC(func, op, op_name) \
Py_DECREF(v); PyObject * \
Py_DECREF(w); func(PyObject *v, PyObject *w) { \
if (f != NULL) return binary_op(v, w, NB_SLOT(op), op_name); \
return x;
} }
return type_error("bad operand type(s) for |="); 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 * PyObject *
PyNumber_InPlaceXor(PyObject *v, PyObject *w) PyNumber_Add(PyObject *v, PyObject *w)
{ {
PyObject * (*f)(PyObject *, PyObject *) = NULL; PyObject *result = binary_op1(v, w, NB_SLOT(nb_add));
PyObject *x = NULL; if (result == Py_NotImplemented) {
PySequenceMethods *m = v->ob_type->tp_as_sequence;
if (PyInstance_Check(v)) { Py_DECREF(Py_NotImplemented);
if (PyInstance_HalfBinOp(v, w, "__ixor__", &x, if (m && m->sq_concat) {
PyNumber_Xor, 0) <= 0) result = (*m->sq_concat)(v, w);
return x;
} }
else if (v->ob_type->tp_as_number != NULL && HASINPLACE(v) && else {
(f = v->ob_type->tp_as_number->nb_inplace_xor) != NULL) PyErr_SetString(PyExc_TypeError,
return (*f)(v, w); "unsupported operand types for +");
result = NULL;
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 ^="); return result;
} }
PyObject * PyObject *
PyNumber_InPlaceAnd(PyObject *v, PyObject *w) PyNumber_Remainder(PyObject *v, PyObject *w)
{ {
PyObject * (*f)(PyObject *, PyObject *) = NULL; if (PyString_Check(v))
PyObject *x = NULL; return PyString_Format(v, w);
else if (PyUnicode_Check(v))
if (PyInstance_Check(v)) { return PyUnicode_Format(v, w);
if (PyInstance_HalfBinOp(v, w, "__iand__", &x, return binary_op(v, w, NB_SLOT(nb_remainder), "%");
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 * PyObject *
PyNumber_InPlaceLshift(PyObject *v, PyObject *w) PyNumber_Power(PyObject *v, PyObject *w, PyObject *z)
{ {
PyObject * (*f)(PyObject *, PyObject *) = NULL; return ternary_op(v, w, z, NB_SLOT(nb_power), "** or pow()");
PyObject *x = NULL; }
if (PyInstance_Check(v)) { /* Binary in-place operators */
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); /* 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.
if (v->ob_type->tp_as_number != NULL) { - If the left hand object has the appropriate struct members, and
if (PyNumber_Coerce(&v, &w) != 0) they are filled, call the appropriate function and return the
return NULL; result. No coercion is done on the arguments; the left-hand object
if (v->ob_type->tp_as_number != NULL && is the one the operation is performed on, and it's up to the
(f = v->ob_type->tp_as_number->nb_lshift) != NULL) function to deal with the right-hand object.
x = (*f)(v, w);
Py_DECREF(v);
Py_DECREF(w);
if (f != NULL)
return x;
}
return type_error("bad operand type(s) for <<="); - Otherwise, in-place modification is not supported. Handle it exactly as
} a non in-place operation of the same kind.
PyObject * */
PyNumber_InPlaceRshift(PyObject *v, PyObject *w)
{ #define HASINPLACE(t) PyType_HasFeature((t)->ob_type, Py_TPFLAGS_HAVE_INPLACEOPS)
PyObject * (*f)(PyObject *, PyObject *) = NULL;
PyObject *x = NULL;
if (PyInstance_Check(v)) { static PyObject *
if (PyInstance_HalfBinOp(v, w, "__irshift__", &x, binary_iop(PyObject *v, PyObject *w, const int iop_slot, const int op_slot,
PyNumber_Rshift, 0) <= 0) 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; return x;
} }
else if (v->ob_type->tp_as_number != NULL && HASINPLACE(v) && Py_DECREF(x);
(f = v->ob_type->tp_as_number->nb_inplace_rshift) != NULL) }
return (*f)(v, w); }
return binary_op(v, w, op_slot, op_name);
BINOP(v, w, "__rshift__", "__rrshift__", PyNumber_Rshift); }
if (v->ob_type->tp_as_number != NULL) { #define INPLACE_BINOP(func, iop, op, op_name) \
if (PyNumber_Coerce(&v, &w) != 0) PyObject * \
return NULL; func(PyObject *v, PyObject *w) { \
if (v->ob_type->tp_as_number != NULL && return binary_iop(v, w, NB_SLOT(iop), NB_SLOT(op), op_name); \
(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;
} }
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 * PyObject *
PyNumber_InPlaceAdd(PyObject *v, PyObject *w) PyNumber_InPlaceAdd(PyObject *v, PyObject *w)
{ {
PyObject * (*f)(PyObject *, PyObject *) = NULL; binaryfunc f = 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);
if (v->ob_type->tp_as_sequence != NULL) { if (v->ob_type->tp_as_sequence != NULL) {
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; f = v->ob_type->tp_as_sequence->sq_concat;
if (f != NULL) if (f != NULL)
return (*f)(v, w); return (*f)(v, w);
} }
if (v->ob_type->tp_as_number != NULL) { return binary_iop(v, w, NB_SLOT(nb_inplace_add), NB_SLOT(nb_add), "+=");
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 -=");
} }
PyObject * PyObject *
PyNumber_InPlaceMultiply(PyObject *v, PyObject *w) PyNumber_InPlaceMultiply(PyObject *v, PyObject *w)
{ {
PyObject * (*f)(PyObject *, PyObject *) = NULL;
PyObject * (*g)(PyObject *, int) = NULL; PyObject * (*g)(PyObject *, int) = NULL;
PyObject *x = NULL; if (HASINPLACE(v) && v->ob_type->tp_as_sequence &&
(g = v->ob_type->tp_as_sequence->sq_inplace_repeat)) {
if (PyInstance_Check(v)) { long n;
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 (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;
}
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)) { if (PyInt_Check(w)) {
mul_value = PyInt_AsLong(w); n = PyInt_AsLong(w);
} }
else if (PyLong_Check(w)) { else if (PyLong_Check(w)) {
mul_value = PyLong_AsLong(w); n = PyLong_AsLong(w);
if (mul_value == -1 && PyErr_Occurred()) if (n == -1 && PyErr_Occurred())
return NULL; return NULL;
} }
else { else {
return type_error( return type_error("can't multiply sequence to non-int");
"can't multiply sequence with 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 * PyObject *
PyNumber_InPlaceRemainder(PyObject *v, PyObject *w) 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)) if (PyString_Check(v))
return PyString_Format(v, w); return PyString_Format(v, w);
else if (PyUnicode_Check(v)) else if (PyUnicode_Check(v))
return PyUnicode_Format(v, w); 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 else
x = type_error("bad operand type(s) for **="); return binary_iop(v, w, NB_SLOT(nb_inplace_remainder),
Py_DECREF(v); NB_SLOT(nb_remainder), "%=");
Py_DECREF(w);
return x;
} }
PyObject * PyObject *
PyNumber_InPlacePower(PyObject *v, PyObject *w, PyObject *z) PyNumber_InPlacePower(PyObject *v, PyObject *w, PyObject *z)
{ {
PyObject *res; if (HASINPLACE(v) && v->ob_type->tp_as_number &&
PyObject *v1, *z1, *w2, *z2, *oldv; v->ob_type->tp_as_number->nb_inplace_power != NULL) {
PyObject * (*f)(PyObject *, PyObject *, PyObject *); return ternary_op(v, w, z, NB_SLOT(nb_inplace_power), "**=");
}
if (z == Py_None) else {
return do_inplace_pow(v, w); return ternary_op(v, w, z, NB_SLOT(nb_power), "**=");
/* 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;
} }
......
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