/* Abstract Object Interface (many thanks to Jim Fulton) */ #include "Python.h"#include <ctype.h>#include "structmember.h" /* we need the offsetof() macro from there */#include "longintrepr.h" #define NEW_STYLE_NUMBER(o) PyType_HasFeature((o)->ob_type, \ Py_TPFLAGS_CHECKTYPES) /* Shorthands to return certain errors */ static PyObject *type_error(const char *msg, PyObject *obj){ PyErr_Format(PyExc_TypeError, msg, obj->ob_type->tp_name); return NULL;} static PyObject *null_error(void){ if (!PyErr_Occurred()) PyErr_SetString(PyExc_SystemError, "null argument to internal routine"); return NULL;} /* Operations on any object */ intPyObject_Cmp(PyObject *o1, PyObject *o2, int *result){ int r; if (o1 == NULL || o2 == NULL) { null_error(); return -1; } r = PyObject_Compare(o1, o2); if (PyErr_Occurred()) return -1; *result = r; return 0;} PyObject *PyObject_Type(PyObject *o){ PyObject *v; if (o == NULL) return null_error(); v = (PyObject *)o->ob_type; Py_INCREF(v); return v;} Py_ssize_tPyObject_Size(PyObject *o){ PySequenceMethods *m; if (o == NULL) { null_error(); return -1; } m = o->ob_type->tp_as_sequence; if (m && m->sq_length) return m->sq_length(o); return PyMapping_Size(o);} #undef PyObject_LengthPy_ssize_tPyObject_Length(PyObject *o){ return PyObject_Size(o);}#define PyObject_Length PyObject_Size Py_ssize_t_PyObject_LengthHint(PyObject *o){ Py_ssize_t rv = PyObject_Size(o); if (rv != -1) return rv; if (PyErr_ExceptionMatches(PyExc_TypeError) || PyErr_ExceptionMatches(PyExc_AttributeError)) { PyObject *err_type, *err_value, *err_tb, *ro; PyErr_Fetch(&err_type, &err_value, &err_tb); ro = PyObject_CallMethod(o, "__length_hint__", NULL); if (ro != NULL) { rv = PyInt_AsLong(ro); Py_DECREF(ro); Py_XDECREF(err_type); Py_XDECREF(err_value); Py_XDECREF(err_tb); return rv; } PyErr_Restore(err_type, err_value, err_tb); } return -1;} PyObject *PyObject_GetItem(PyObject *o, PyObject *key){ PyMappingMethods *m; if (o == NULL || key == NULL) return null_error(); m = o->ob_type->tp_as_mapping; if (m && m->mp_subscript) return m->mp_subscript(o, key); if (o->ob_type->tp_as_sequence) { if (PyIndex_Check(key)) { Py_ssize_t key_value; key_value = PyNumber_AsSsize_t(key, PyExc_IndexError); if (key_value == -1 && PyErr_Occurred()) return NULL; return PySequence_GetItem(o, key_value); } else if (o->ob_type->tp_as_sequence->sq_item) return type_error("sequence index must " "be integer, not '%.200s'", key); } return type_error("'%.200s' object is unsubscriptable", o);} intPyObject_SetItem(PyObject *o, PyObject *key, PyObject *value){ PyMappingMethods *m; if (o == NULL || key == NULL || value == NULL) { null_error(); return -1; } m = o->ob_type->tp_as_mapping; if (m && m->mp_ass_subscript) return m->mp_ass_subscript(o, key, value); if (o->ob_type->tp_as_sequence) { if (PyIndex_Check(key)) { Py_ssize_t key_value; key_value = PyNumber_AsSsize_t(key, PyExc_IndexError); if (key_value == -1 && PyErr_Occurred()) return -1; return PySequence_SetItem(o, key_value, value); } else if (o->ob_type->tp_as_sequence->sq_ass_item) { type_error("sequence index must be " "integer, not '%.200s'", key); return -1; } } type_error("'%.200s' object does not support item assignment", o); return -1;} intPyObject_DelItem(PyObject *o, PyObject *key){ PyMappingMethods *m; if (o == NULL || key == NULL) { null_error(); return -1; } m = o->ob_type->tp_as_mapping; if (m && m->mp_ass_subscript) return m->mp_ass_subscript(o, key, (PyObject*)NULL); if (o->ob_type->tp_as_sequence) { if (PyIndex_Check(key)) { Py_ssize_t key_value; key_value = PyNumber_AsSsize_t(key, PyExc_IndexError); if (key_value == -1 && PyErr_Occurred()) return -1; return PySequence_DelItem(o, key_value); } else if (o->ob_type->tp_as_sequence->sq_ass_item) { type_error("sequence index must be " "integer, not '%.200s'", key); return -1; } } type_error("'%.200s' object does not support item deletion", o); return -1;} intPyObject_DelItemString(PyObject *o, char *key){ PyObject *okey; int ret; if (o == NULL || key == NULL) { null_error(); return -1; } okey = PyString_FromString(key); if (okey == NULL) return -1; ret = PyObject_DelItem(o, okey); Py_DECREF(okey); return ret;} intPyObject_AsCharBuffer(PyObject *obj, const char **buffer, Py_ssize_t *buffer_len){ PyBufferProcs *pb; char *pp; Py_ssize_t len; if (obj == NULL || buffer == NULL || buffer_len == NULL) { null_error(); return -1; } pb = obj->ob_type->tp_as_buffer; if (pb == NULL || pb->bf_getcharbuffer == NULL || pb->bf_getsegcount == NULL) { PyErr_SetString(PyExc_TypeError, "expected a character buffer object"); return -1; } if ((*pb->bf_getsegcount)(obj,NULL) != 1) { PyErr_SetString(PyExc_TypeError, "expected a single-segment buffer object"); return -1; } len = (*pb->bf_getcharbuffer)(obj, 0, &pp); if (len < 0) return -1; *buffer = pp; *buffer_len = len; return 0;} intPyObject_CheckReadBuffer(PyObject *obj){ PyBufferProcs *pb = obj->ob_type->tp_as_buffer; if (pb == NULL || pb->bf_getreadbuffer == NULL || pb->bf_getsegcount == NULL || (*pb->bf_getsegcount)(obj, NULL) != 1) return 0; return 1;} int PyObject_AsReadBuffer(PyObject *obj, const void **buffer, Py_ssize_t *buffer_len){ PyBufferProcs *pb; void *pp; Py_ssize_t len; if (obj == NULL || buffer == NULL || buffer_len == NULL) { null_error(); return -1; } pb = obj->ob_type->tp_as_buffer; if (pb == NULL || pb->bf_getreadbuffer == NULL || pb->bf_getsegcount == NULL) { PyErr_SetString(PyExc_TypeError, "expected a readable buffer object"); return -1; } if ((*pb->bf_getsegcount)(obj, NULL) != 1) { PyErr_SetString(PyExc_TypeError, "expected a single-segment buffer object"); return -1; } len = (*pb->bf_getreadbuffer)(obj, 0, &pp); if (len < 0) return -1; *buffer = pp; *buffer_len = len; return 0;} int PyObject_AsWriteBuffer(PyObject *obj, void **buffer, Py_ssize_t *buffer_len){ PyBufferProcs *pb; void*pp; Py_ssize_t len; if (obj == NULL || buffer == NULL || buffer_len == NULL) { null_error(); return -1; } pb = obj->ob_type->tp_as_buffer; if (pb == NULL || pb->bf_getwritebuffer == NULL || pb->bf_getsegcount == NULL) { PyErr_SetString(PyExc_TypeError, "expected a writeable buffer object"); return -1; } if ((*pb->bf_getsegcount)(obj, NULL) != 1) { PyErr_SetString(PyExc_TypeError, "expected a single-segment buffer object"); return -1; } len = (*pb->bf_getwritebuffer)(obj,0,&pp); if (len < 0) return -1; *buffer = pp; *buffer_len = len; return 0;} /* Operations on numbers */ intPyNumber_Check(PyObject *o){ return o && o->ob_type->tp_as_number && (o->ob_type->tp_as_number->nb_int || o->ob_type->tp_as_number->nb_float);} /* Binary operators */ /* New style number protocol support */ #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])) /* Calling scheme used for binary operations: v w Action ------------------------------------------------------------------- new new w.op(v,w)[*], 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) [*] only when v->ob_type != w->ob_type && w->ob_type is a subclass of v->ob_type 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){ PyObject *x; binaryfunc slotv = NULL; binaryfunc slotw = NULL; if (v->ob_type->tp_as_number != NULL && NEW_STYLE_NUMBER(v)) slotv = NB_BINOP(v->ob_type->tp_as_number, op_slot); if (w->ob_type != v->ob_type && w->ob_type->tp_as_number != NULL && NEW_STYLE_NUMBER(w)) { slotw = NB_BINOP(w->ob_type->tp_as_number, op_slot); if (slotw == slotv) slotw = NULL; } if (slotv) { if (slotw && PyType_IsSubtype(w->ob_type, v->ob_type)) { x = slotw(v, w); if (x != Py_NotImplemented) return x; Py_DECREF(x); /* can't do it */ slotw = NULL; } x = slotv(v, w); if (x != Py_NotImplemented) return x; Py_DECREF(x); /* can't do it */ } if (slotw) { x = slotw(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 (err == 0) { PyNumberMethods *mv = v->ob_type->tp_as_number; if (mv) { binaryfunc slot; slot = NB_BINOP(mv, op_slot); if (slot) { x = slot(v, w); Py_DECREF(v); Py_DECREF(w); return x; } } /* CoerceEx incremented the reference counts */ Py_DECREF(v); Py_DECREF(w); } } Py_INCREF(Py_NotImplemented); return Py_NotImplemented;} static PyObject *binop_type_error(PyObject *v, PyObject *w, const char *op_name){ PyErr_Format(PyExc_TypeError, "unsupported operand type(s) for %.100s: " "'%.100s' and '%.100s'", op_name, v->ob_type->tp_name, w->ob_type->tp_name); return NULL;} static PyObject *binary_op(PyObject *v, PyObject *w, const int op_slot, const char *op_name){ PyObject *result = binary_op1(v, w, op_slot); if (result == Py_NotImplemented) { Py_DECREF(result); return binop_type_error(v, w, op_name); } return result;} /* Calling scheme used for ternary operations: *** In some cases, w.op is called before v.op; see binary_op1. *** 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) 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. */ static PyObject *ternary_op(PyObject *v, PyObject *w, PyObject *z, const int op_slot, const char *op_name){ PyNumberMethods *mv, *mw, *mz; PyObject *x = NULL; ternaryfunc slotv = NULL; ternaryfunc slotw = NULL; ternaryfunc slotz = NULL; mv = v->ob_type->tp_as_number;Lines 1–500 of 2381. Load more
/* Abstract Object Interface (many thanks to Jim Fulton) */ #include "Python.h" #include <ctype.h> #include "structmember.h" /* we need the offsetof() macro from there */ #include "longintrepr.h" #define NEW_STYLE_NUMBER(o) PyType_HasFeature((o)->ob_type, \ Py_TPFLAGS_CHECKTYPES) /* Shorthands to return certain errors */ static PyObject * type_error(const char *msg, PyObject *obj) { PyErr_Format(PyExc_TypeError, msg, obj->ob_type->tp_name); return NULL; } static PyObject * null_error(void) { if (!PyErr_Occurred()) PyErr_SetString(PyExc_SystemError, "null argument to internal routine"); return NULL; } /* Operations on any object */ int PyObject_Cmp(PyObject *o1, PyObject *o2, int *result) { int r; if (o1 == NULL || o2 == NULL) { null_error(); return -1; } r = PyObject_Compare(o1, o2); if (PyErr_Occurred()) return -1; *result = r; return 0; } PyObject * PyObject_Type(PyObject *o) { PyObject *v; if (o == NULL) return null_error(); v = (PyObject *)o->ob_type; Py_INCREF(v); return v; } Py_ssize_t PyObject_Size(PyObject *o) { PySequenceMethods *m; if (o == NULL) { null_error(); return -1; } m = o->ob_type->tp_as_sequence; if (m && m->sq_length) return m->sq_length(o); return PyMapping_Size(o); } #undef PyObject_Length Py_ssize_t PyObject_Length(PyObject *o) { return PyObject_Size(o); } #define PyObject_Length PyObject_Size Py_ssize_t _PyObject_LengthHint(PyObject *o) { Py_ssize_t rv = PyObject_Size(o); if (rv != -1) return rv; if (PyErr_ExceptionMatches(PyExc_TypeError) || PyErr_ExceptionMatches(PyExc_AttributeError)) { PyObject *err_type, *err_value, *err_tb, *ro; PyErr_Fetch(&err_type, &err_value, &err_tb); ro = PyObject_CallMethod(o, "__length_hint__", NULL); if (ro != NULL) { rv = PyInt_AsLong(ro); Py_DECREF(ro); Py_XDECREF(err_type); Py_XDECREF(err_value); Py_XDECREF(err_tb); return rv; } PyErr_Restore(err_type, err_value, err_tb); } return -1; } PyObject * PyObject_GetItem(PyObject *o, PyObject *key) { PyMappingMethods *m; if (o == NULL || key == NULL) return null_error(); m = o->ob_type->tp_as_mapping; if (m && m->mp_subscript) return m->mp_subscript(o, key); if (o->ob_type->tp_as_sequence) { if (PyIndex_Check(key)) { Py_ssize_t key_value; key_value = PyNumber_AsSsize_t(key, PyExc_IndexError); if (key_value == -1 && PyErr_Occurred()) return NULL; return PySequence_GetItem(o, key_value); } else if (o->ob_type->tp_as_sequence->sq_item) return type_error("sequence index must " "be integer, not '%.200s'", key); } return type_error("'%.200s' object is unsubscriptable", o); } int PyObject_SetItem(PyObject *o, PyObject *key, PyObject *value) { PyMappingMethods *m; if (o == NULL || key == NULL || value == NULL) { null_error(); return -1; } m = o->ob_type->tp_as_mapping; if (m && m->mp_ass_subscript) return m->mp_ass_subscript(o, key, value); if (o->ob_type->tp_as_sequence) { if (PyIndex_Check(key)) { Py_ssize_t key_value; key_value = PyNumber_AsSsize_t(key, PyExc_IndexError); if (key_value == -1 && PyErr_Occurred()) return -1; return PySequence_SetItem(o, key_value, value); } else if (o->ob_type->tp_as_sequence->sq_ass_item) { type_error("sequence index must be " "integer, not '%.200s'", key); return -1; } } type_error("'%.200s' object does not support item assignment", o); return -1; } int PyObject_DelItem(PyObject *o, PyObject *key) { PyMappingMethods *m; if (o == NULL || key == NULL) { null_error(); return -1; } m = o->ob_type->tp_as_mapping; if (m && m->mp_ass_subscript) return m->mp_ass_subscript(o, key, (PyObject*)NULL); if (o->ob_type->tp_as_sequence) { if (PyIndex_Check(key)) { Py_ssize_t key_value; key_value = PyNumber_AsSsize_t(key, PyExc_IndexError); if (key_value == -1 && PyErr_Occurred()) return -1; return PySequence_DelItem(o, key_value); } else if (o->ob_type->tp_as_sequence->sq_ass_item) { type_error("sequence index must be " "integer, not '%.200s'", key); return -1; } } type_error("'%.200s' object does not support item deletion", o); return -1; } int PyObject_DelItemString(PyObject *o, char *key) { PyObject *okey; int ret; if (o == NULL || key == NULL) { null_error(); return -1; } okey = PyString_FromString(key); if (okey == NULL) return -1; ret = PyObject_DelItem(o, okey); Py_DECREF(okey); return ret; } int PyObject_AsCharBuffer(PyObject *obj, const char **buffer, Py_ssize_t *buffer_len) { PyBufferProcs *pb; char *pp; Py_ssize_t len; if (obj == NULL || buffer == NULL || buffer_len == NULL) { null_error(); return -1; } pb = obj->ob_type->tp_as_buffer; if (pb == NULL || pb->bf_getcharbuffer == NULL || pb->bf_getsegcount == NULL) { PyErr_SetString(PyExc_TypeError, "expected a character buffer object"); return -1; } if ((*pb->bf_getsegcount)(obj,NULL) != 1) { PyErr_SetString(PyExc_TypeError, "expected a single-segment buffer object"); return -1; } len = (*pb->bf_getcharbuffer)(obj, 0, &pp); if (len < 0) return -1; *buffer = pp; *buffer_len = len; return 0; } int PyObject_CheckReadBuffer(PyObject *obj) { PyBufferProcs *pb = obj->ob_type->tp_as_buffer; if (pb == NULL || pb->bf_getreadbuffer == NULL || pb->bf_getsegcount == NULL || (*pb->bf_getsegcount)(obj, NULL) != 1) return 0; return 1; } int PyObject_AsReadBuffer(PyObject *obj, const void **buffer, Py_ssize_t *buffer_len) { PyBufferProcs *pb; void *pp; Py_ssize_t len; if (obj == NULL || buffer == NULL || buffer_len == NULL) { null_error(); return -1; } pb = obj->ob_type->tp_as_buffer; if (pb == NULL || pb->bf_getreadbuffer == NULL || pb->bf_getsegcount == NULL) { PyErr_SetString(PyExc_TypeError, "expected a readable buffer object"); return -1; } if ((*pb->bf_getsegcount)(obj, NULL) != 1) { PyErr_SetString(PyExc_TypeError, "expected a single-segment buffer object"); return -1; } len = (*pb->bf_getreadbuffer)(obj, 0, &pp); if (len < 0) return -1; *buffer = pp; *buffer_len = len; return 0; } int PyObject_AsWriteBuffer(PyObject *obj, void **buffer, Py_ssize_t *buffer_len) { PyBufferProcs *pb; void*pp; Py_ssize_t len; if (obj == NULL || buffer == NULL || buffer_len == NULL) { null_error(); return -1; } pb = obj->ob_type->tp_as_buffer; if (pb == NULL || pb->bf_getwritebuffer == NULL || pb->bf_getsegcount == NULL) { PyErr_SetString(PyExc_TypeError, "expected a writeable buffer object"); return -1; } if ((*pb->bf_getsegcount)(obj, NULL) != 1) { PyErr_SetString(PyExc_TypeError, "expected a single-segment buffer object"); return -1; } len = (*pb->bf_getwritebuffer)(obj,0,&pp); if (len < 0) return -1; *buffer = pp; *buffer_len = len; return 0; } /* Operations on numbers */ int PyNumber_Check(PyObject *o) { return o && o->ob_type->tp_as_number && (o->ob_type->tp_as_number->nb_int || o->ob_type->tp_as_number->nb_float); } /* Binary operators */ /* New style number protocol support */ #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])) /* Calling scheme used for binary operations: v w Action ------------------------------------------------------------------- new new w.op(v,w)[*], 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) [*] only when v->ob_type != w->ob_type && w->ob_type is a subclass of v->ob_type 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) { PyObject *x; binaryfunc slotv = NULL; binaryfunc slotw = NULL; if (v->ob_type->tp_as_number != NULL && NEW_STYLE_NUMBER(v)) slotv = NB_BINOP(v->ob_type->tp_as_number, op_slot); if (w->ob_type != v->ob_type && w->ob_type->tp_as_number != NULL && NEW_STYLE_NUMBER(w)) { slotw = NB_BINOP(w->ob_type->tp_as_number, op_slot); if (slotw == slotv) slotw = NULL; } if (slotv) { if (slotw && PyType_IsSubtype(w->ob_type, v->ob_type)) { x = slotw(v, w); if (x != Py_NotImplemented) return x; Py_DECREF(x); /* can't do it */ slotw = NULL; } x = slotv(v, w); if (x != Py_NotImplemented) return x; Py_DECREF(x); /* can't do it */ } if (slotw) { x = slotw(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 (err == 0) { PyNumberMethods *mv = v->ob_type->tp_as_number; if (mv) { binaryfunc slot; slot = NB_BINOP(mv, op_slot); if (slot) { x = slot(v, w); Py_DECREF(v); Py_DECREF(w); return x; } } /* CoerceEx incremented the reference counts */ Py_DECREF(v); Py_DECREF(w); } } Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } static PyObject * binop_type_error(PyObject *v, PyObject *w, const char *op_name) { PyErr_Format(PyExc_TypeError, "unsupported operand type(s) for %.100s: " "'%.100s' and '%.100s'", op_name, v->ob_type->tp_name, w->ob_type->tp_name); return NULL; } static PyObject * binary_op(PyObject *v, PyObject *w, const int op_slot, const char *op_name) { PyObject *result = binary_op1(v, w, op_slot); if (result == Py_NotImplemented) { Py_DECREF(result); return binop_type_error(v, w, op_name); } return result; } /* Calling scheme used for ternary operations: *** In some cases, w.op is called before v.op; see binary_op1. *** 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) 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. */ static PyObject * ternary_op(PyObject *v, PyObject *w, PyObject *z, const int op_slot, const char *op_name) { PyNumberMethods *mv, *mw, *mz; PyObject *x = NULL; ternaryfunc slotv = NULL; ternaryfunc slotw = NULL; ternaryfunc slotz = NULL; mv = v->ob_type->tp_as_number;