/* the 'cimpl_xxx()' functions are called at run-time, to do things we give up to write at the meta-level in the PsycoXxx() functions. */ static PyObject* cimpl_oldstyle_binary_op1(PyObject* v, PyObject* w, const int op_slot) { 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) { PyObject *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; }
/* Try a 3-way comparison, returning an int. Return: -2 for an exception; -1 if v < w; 0 if v == w; 1 if v > w; 2 if this particular 3-way comparison is not implemented or undefined. */ static int try_3way_compare(PyObject *v, PyObject *w) { int c; cmpfunc f; /* Comparisons involving instances are given to instance_compare, which has the same return conventions as this function. */ f = v->ob_type->tp_compare; if (PyInstance_Check(v)) return (*f)(v, w); if (PyInstance_Check(w)) return (*w->ob_type->tp_compare)(v, w); /* If both have the same (non-NULL) tp_compare, use it. */ if (f != NULL && f == w->ob_type->tp_compare) { c = (*f)(v, w); if (c < 0 && PyErr_Occurred()) return -1; return c < 0 ? -1 : c > 0 ? 1 : 0; } /* If either tp_compare is _PyObject_SlotCompare, that's safe. */ if (f == _PyObject_SlotCompare || w->ob_type->tp_compare == _PyObject_SlotCompare) return _PyObject_SlotCompare(v, w); /* Try coercion; if it fails, give up */ c = PyNumber_CoerceEx(&v, &w); if (c < 0) return -2; if (c > 0) return 2; /* Try v's comparison, if defined */ if ((f = v->ob_type->tp_compare) != NULL) { c = (*f)(v, w); Py_DECREF(v); Py_DECREF(w); if (c < 0 && PyErr_Occurred()) return -2; return c < 0 ? -1 : c > 0 ? 1 : 0; } /* Try w's comparison, if defined */ if ((f = w->ob_type->tp_compare) != NULL) { c = (*f)(w, v); /* swapped! */ Py_DECREF(v); Py_DECREF(w); if (c < 0 && PyErr_Occurred()) return -2; return c < 0 ? 1 : c > 0 ? -1 : 0; /* negated! */ } /* No comparison defined */ Py_DECREF(v); Py_DECREF(w); return 2; }
/* Coerce two numeric types to the "larger" one. Increment the reference count on each argument. Return -1 and raise an exception if no coercion is possible (and then no reference count is incremented). */ int PyNumber_Coerce(PyObject **pv, PyObject **pw) { int err = PyNumber_CoerceEx(pv, pw); if (err <= 0) return err; PyErr_SetString(PyExc_TypeError, "number coercion failed"); return -1; }
/* Try a 3-way comparison, returning an int. Return: -2 for an exception; -1 if v < w; 0 if v == w; 1 if v > w; 2 if this particular 3-way comparison is not implemented or undefined. */ static int try_3way_compare(PyObject *v, PyObject *w) { int c; cmpfunc f; /* Comparisons involving instances are given to instance_compare, which has the same return conventions as this function. */ f = v->ob_type->tp_compare; if (PyInstance_Check(v)) return (*f)(v, w); if (PyInstance_Check(w)) return (*w->ob_type->tp_compare)(v, w); /* If both have the same (non-NULL) tp_compare, use it. */ if (f != NULL && f == w->ob_type->tp_compare) { c = (*f)(v, w); return adjust_tp_compare(c); } /* If either tp_compare is _PyObject_SlotCompare, that's safe. */ if (f == _PyObject_SlotCompare || w->ob_type->tp_compare == _PyObject_SlotCompare) return _PyObject_SlotCompare(v, w); /* If we're here, v and w, a) are not instances; b) have different types or a type without tp_compare; and c) don't have a user-defined tp_compare. tp_compare implementations in C assume that both arguments have their type, so we give up if the coercion fails or if it yields types which are still incompatible (which can happen with a user-defined nb_coerce). */ c = PyNumber_CoerceEx(&v, &w); if (c < 0) return -2; if (c > 0) return 2; f = v->ob_type->tp_compare; if (f != NULL && f == w->ob_type->tp_compare) { c = (*f)(v, w); Py_DECREF(v); Py_DECREF(w); return adjust_tp_compare(c); } /* No comparison defined */ Py_DECREF(v); Py_DECREF(w); return 2; }
static PyObject * complex_richcompare(PyObject *v, PyObject *w, int op) { int c; Py_complex i, j; PyObject *res; c = PyNumber_CoerceEx(&v, &w); if (c < 0) return NULL; if (c > 0) { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } /* Make sure both arguments are complex. */ if (!(PyComplex_Check(v) && PyComplex_Check(w))) { Py_DECREF(v); Py_DECREF(w); Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } i = ((PyComplexObject *)v)->cval; j = ((PyComplexObject *)w)->cval; Py_DECREF(v); Py_DECREF(w); if (op != Py_EQ && op != Py_NE) { PyErr_SetString(PyExc_TypeError, "no ordering relation is defined for complex numbers"); return NULL; } if ((i.real == j.real && i.imag == j.imag) == (op == Py_EQ)) res = Py_True; else res = Py_False; Py_INCREF(res); return res; }
static int wrap_coerce(PyObject **p_self, PyObject **p_other) { PyObject *self = *p_self; PyObject *other = *p_other; PyObject *object; PyObject *left; PyObject *right; int r; assert(Proxy_Check(self)); object = Proxy_GET_OBJECT(self); left = object; right = other; r = PyNumber_CoerceEx(&left, &right); if (r != 0) return r; /* Now left and right have been INCREF'ed. Any new value that comes out is proxied; any unchanged value is left unchanged. */ if (left == object) { /* Keep the old proxy */ Py_INCREF(self); Py_DECREF(left); left = self; } #if 0 else { /* ??? create proxy for left? */ } if (right != other) { /* ??? create proxy for right? */ } #endif *p_self = left; *p_other = right; return 0; }
NUITKA_MAY_BE_UNUSED static PyObject *BINARY_OPERATION_REMAINDER( PyObject *operand1, PyObject *operand2 ) { CHECK_OBJECT( operand1 ); CHECK_OBJECT( operand2 ); binaryfunc slot1 = NULL; binaryfunc slot2 = NULL; PyTypeObject *type1 = Py_TYPE( operand1 ); PyTypeObject *type2 = Py_TYPE( operand2 ); if ( type1->tp_as_number != NULL && NEW_STYLE_NUMBER( operand1 ) ) { slot1 = type1->tp_as_number->nb_remainder; } if ( type1 != type2 ) { if ( type2->tp_as_number != NULL && NEW_STYLE_NUMBER( operand2 ) ) { slot2 = type2->tp_as_number->nb_remainder; if ( slot1 == slot2 ) { slot2 = NULL; } } } if ( slot1 != NULL ) { if ( slot2 && PyType_IsSubtype( type2, type1 ) ) { PyObject *x = slot2( operand1, operand2 ); if ( x != Py_NotImplemented ) { if (unlikely( x == NULL )) { return NULL; } return x; } Py_DECREF( x ); slot2 = NULL; } PyObject *x = slot1( operand1, operand2 ); if ( x != Py_NotImplemented ) { if (unlikely( x == NULL )) { return NULL; } return x; } Py_DECREF( x ); } if ( slot2 != NULL ) { PyObject *x = slot2( operand1, operand2 ); if ( x != Py_NotImplemented ) { if (unlikely( x == NULL )) { return NULL; } return x; } Py_DECREF( x ); } #if PYTHON_VERSION < 300 if ( !NEW_STYLE_NUMBER( operand1 ) || !NEW_STYLE_NUMBER( operand2 ) ) { int err = PyNumber_CoerceEx( &operand1, &operand2 ); if ( err < 0 ) { return NULL; } if ( err == 0 ) { PyNumberMethods *mv = Py_TYPE( operand1 )->tp_as_number; if ( mv ) { binaryfunc slot = mv->nb_remainder; if ( slot != NULL ) { PyObject *x = slot( operand1, operand2 ); Py_DECREF( operand1 ); Py_DECREF( operand2 ); if (unlikely( x == NULL )) { return NULL; } return x; } } // CoerceEx did that Py_DECREF( operand1 ); Py_DECREF( operand2 ); } } #endif PyErr_Format( PyExc_TypeError, "unsupported operand type(s) for %%: '%s' and '%s'", type1->tp_name, type2->tp_name ); return NULL; }
NUITKA_MAY_BE_UNUSED static PyObject *BINARY_OPERATION_ADD( PyObject *operand1, PyObject *operand2 ) { CHECK_OBJECT( operand1 ); CHECK_OBJECT( operand2 ); #if PYTHON_VERSION < 300 // Something similar for Python3 should exist too. if ( PyInt_CheckExact( operand1 ) && PyInt_CheckExact( operand2 ) ) { long a, b, i; a = PyInt_AS_LONG( operand1 ); b = PyInt_AS_LONG( operand2 ); i = a + b; // Detect overflow, in which case, a "long" object would have to be // created, which we won't handle here. if (likely(!( (i^a) < 0 && (i^b) < 0 ) )) { return PyInt_FromLong( i ); } } #endif binaryfunc slot1 = NULL; binaryfunc slot2 = NULL; PyTypeObject *type1 = Py_TYPE( operand1 ); PyTypeObject *type2 = Py_TYPE( operand2 ); if ( type1->tp_as_number != NULL && NEW_STYLE_NUMBER( operand1 ) ) { slot1 = type1->tp_as_number->nb_add; } if ( type1 != type2 ) { if ( type2->tp_as_number != NULL && NEW_STYLE_NUMBER( operand2 ) ) { slot2 = type2->tp_as_number->nb_add; if ( slot1 == slot2 ) { slot2 = NULL; } } } if ( slot1 != NULL ) { if ( slot2 && PyType_IsSubtype( type2, type1 ) ) { PyObject *x = slot2( operand1, operand2 ); if ( x != Py_NotImplemented ) { if (unlikely( x == NULL )) { return NULL; } return x; } Py_DECREF( x ); slot2 = NULL; } PyObject *x = slot1( operand1, operand2 ); if ( x != Py_NotImplemented ) { if (unlikely( x == NULL )) { return NULL; } return x; } Py_DECREF( x ); } if ( slot2 != NULL ) { PyObject *x = slot2( operand1, operand2 ); if ( x != Py_NotImplemented ) { if (unlikely( x == NULL )) { return NULL; } return x; } Py_DECREF( x ); } #if PYTHON_VERSION < 300 if ( !NEW_STYLE_NUMBER( operand1 ) || !NEW_STYLE_NUMBER( operand2 ) ) { int err = PyNumber_CoerceEx( &operand1, &operand2 ); if ( err < 0 ) { return NULL; } if ( err == 0 ) { PyNumberMethods *mv = Py_TYPE( operand1 )->tp_as_number; if ( mv ) { binaryfunc slot = mv->nb_add; if ( slot != NULL ) { PyObject *x = slot( operand1, operand2 ); Py_DECREF( operand1 ); Py_DECREF( operand2 ); if (unlikely( x == NULL )) { return NULL; } return x; } } // CoerceEx did that Py_DECREF( operand1 ); Py_DECREF( operand2 ); } } #endif // Special case for "+", also works as sequence concat. PySequenceMethods *seq_methods = Py_TYPE( operand1 )->tp_as_sequence; if ( seq_methods && seq_methods->sq_concat ) { PyObject *result = (*seq_methods->sq_concat)( operand1, operand2 ); if (unlikely( result == NULL )) { return NULL; } return result; } PyErr_Format( PyExc_TypeError, "unsupported operand type(s) for +: '%s' and '%s'", type1->tp_name, type2->tp_name ); return NULL; }
NUITKA_MAY_BE_UNUSED static PyObject *BINARY_OPERATION_MUL( PyObject *operand1, PyObject *operand2 ) { CHECK_OBJECT( operand1 ); CHECK_OBJECT( operand2 ); binaryfunc slot1 = NULL; binaryfunc slot2 = NULL; PyTypeObject *type1 = Py_TYPE( operand1 ); PyTypeObject *type2 = Py_TYPE( operand2 ); if ( type1->tp_as_number != NULL && NEW_STYLE_NUMBER( operand1 ) ) { slot1 = type1->tp_as_number->nb_multiply; } if ( type1 != type2 ) { if ( type2->tp_as_number != NULL && NEW_STYLE_NUMBER( operand2 ) ) { slot2 = type2->tp_as_number->nb_multiply; if ( slot1 == slot2 ) { slot2 = NULL; } } } if ( slot1 != NULL ) { if ( slot2 && PyType_IsSubtype( type2, type1 ) ) { PyObject *x = slot2( operand1, operand2 ); if ( x != Py_NotImplemented ) { if (unlikely( x == NULL )) { return NULL; } return x; } Py_DECREF( x ); slot2 = NULL; } PyObject *x = slot1( operand1, operand2 ); if ( x != Py_NotImplemented ) { if (unlikely( x == NULL )) { return NULL; } return x; } Py_DECREF( x ); } if ( slot2 != NULL ) { PyObject *x = slot2( operand1, operand2 ); if ( x != Py_NotImplemented ) { if (unlikely( x == NULL )) { return NULL; } return x; } Py_DECREF( x ); } #if PYTHON_VERSION < 300 if ( !NEW_STYLE_NUMBER( operand1 ) || !NEW_STYLE_NUMBER( operand2 ) ) { int err = PyNumber_CoerceEx( &operand1, &operand2 ); if ( err < 0 ) { return NULL; } if ( err == 0 ) { PyNumberMethods *mv = Py_TYPE( operand1 )->tp_as_number; if ( mv ) { binaryfunc slot = mv->nb_multiply; if ( slot != NULL ) { PyObject *x = slot( operand1, operand2 ); Py_DECREF( operand1 ); Py_DECREF( operand2 ); if (unlikely( x == NULL )) { return NULL; } return x; } } // CoerceEx did that Py_DECREF( operand1 ); Py_DECREF( operand2 ); } } #endif // Special case for "+", also works as sequence concat. PySequenceMethods *seq_methods1 = Py_TYPE( operand1 )->tp_as_sequence; PySequenceMethods *seq_methods2 = Py_TYPE( operand2 )->tp_as_sequence; if ( seq_methods1 != NULL && seq_methods1->sq_repeat ) { return SEQUENCE_REPEAT( seq_methods1->sq_repeat, operand1, operand2 ); } if ( seq_methods2 != NULL && seq_methods2->sq_repeat ) { return SEQUENCE_REPEAT( seq_methods2->sq_repeat, operand2, operand1 ); } PyErr_Format( PyExc_TypeError, "unsupported operand type(s) for *: '%s' and '%s'", type1->tp_name, type2->tp_name ); return NULL; }