mirror of https://github.com/python/cpython
* classobject.[ch], {float,long,int}object.c, bltinmodule.c:
coercion is now completely generic. * ceval.c: for instances, don't coerce for + and *; * reverses arguments if left one is non-instance numeric and right one sequence.
This commit is contained in:
parent
70d7a310a9
commit
e6eefc2231
|
@ -43,5 +43,4 @@ extern object *newinstancemethodobject PROTO((object *, object *));
|
||||||
extern object *instancemethodgetfunc PROTO((object *));
|
extern object *instancemethodgetfunc PROTO((object *));
|
||||||
extern object *instancemethodgetself PROTO((object *));
|
extern object *instancemethodgetself PROTO((object *));
|
||||||
|
|
||||||
extern int instance_coerce PROTO((object **, object **));
|
|
||||||
extern object *instance_convert PROTO((object *, char *));
|
extern object *instance_convert PROTO((object *, char *));
|
||||||
|
|
|
@ -142,6 +142,7 @@ typedef struct {
|
||||||
object *(*nb_and) FPROTO((object *, object *));
|
object *(*nb_and) FPROTO((object *, object *));
|
||||||
object *(*nb_xor) FPROTO((object *, object *));
|
object *(*nb_xor) FPROTO((object *, object *));
|
||||||
object *(*nb_or) FPROTO((object *, object *));
|
object *(*nb_or) FPROTO((object *, object *));
|
||||||
|
int (*nb_coerce) FPROTO((object **, object **));
|
||||||
} number_methods;
|
} number_methods;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
|
@ -417,13 +417,19 @@ static object *
|
||||||
instance_concat(inst, other)
|
instance_concat(inst, other)
|
||||||
instanceobject *inst, *other;
|
instanceobject *inst, *other;
|
||||||
{
|
{
|
||||||
object *func, *res;
|
object *func, *arg, *res;
|
||||||
|
|
||||||
func = instance_getattr(inst, "__add__");
|
func = instance_getattr(inst, "__add__");
|
||||||
if (func == NULL)
|
if (func == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
res = call_object(func, (object *)other);
|
arg = mkvalue("(O)", other);
|
||||||
|
if (arg == NULL) {
|
||||||
|
DECREF(func);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
res = call_object(func, arg);
|
||||||
DECREF(func);
|
DECREF(func);
|
||||||
|
DECREF(arg);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -568,12 +574,18 @@ generic_binary_op(self, other, methodname)
|
||||||
object *other;
|
object *other;
|
||||||
char *methodname;
|
char *methodname;
|
||||||
{
|
{
|
||||||
object *func, *res;
|
object *func, *arg, *res;
|
||||||
|
|
||||||
if ((func = instance_getattr(self, methodname)) == NULL)
|
if ((func = instance_getattr(self, methodname)) == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
res = call_object(func, other);
|
arg = mkvalue("O", other);
|
||||||
|
if (arg == NULL) {
|
||||||
|
DECREF(func);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
res = call_object(func, arg);
|
||||||
DECREF(func);
|
DECREF(func);
|
||||||
|
DECREF(arg);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -653,6 +665,45 @@ BINARY(instance_and, "__and__")
|
||||||
BINARY(instance_xor, "__xor__")
|
BINARY(instance_xor, "__xor__")
|
||||||
BINARY(instance_or, "__or__")
|
BINARY(instance_or, "__or__")
|
||||||
|
|
||||||
|
static int
|
||||||
|
instance_coerce(pv, pw)
|
||||||
|
object **pv, **pw;
|
||||||
|
{
|
||||||
|
object *v = *pv;
|
||||||
|
object *w = *pw;
|
||||||
|
object *func;
|
||||||
|
object *res;
|
||||||
|
int outcome;
|
||||||
|
|
||||||
|
if (!is_instanceobject(v))
|
||||||
|
return 1; /* XXX shouldn't be possible */
|
||||||
|
func = instance_getattr((instanceobject *)v, "__coerce__");
|
||||||
|
if (func == NULL) {
|
||||||
|
err_clear();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
res = call_object(func, w);
|
||||||
|
if (res == NULL)
|
||||||
|
return -1;
|
||||||
|
if (res == None) {
|
||||||
|
DECREF(res);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
outcome = getargs(res, "(OO)", &v, &w);
|
||||||
|
if (!outcome || v->ob_type != w->ob_type ||
|
||||||
|
v->ob_type->tp_as_number == NULL) {
|
||||||
|
DECREF(res);
|
||||||
|
err_setstr(TypeError, "bad __coerce__ result");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
INCREF(v);
|
||||||
|
INCREF(w);
|
||||||
|
DECREF(res);
|
||||||
|
*pv = v;
|
||||||
|
*pw = w;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static number_methods instance_as_number = {
|
static number_methods instance_as_number = {
|
||||||
instance_add, /*nb_add*/
|
instance_add, /*nb_add*/
|
||||||
instance_sub, /*nb_subtract*/
|
instance_sub, /*nb_subtract*/
|
||||||
|
@ -671,6 +722,7 @@ static number_methods instance_as_number = {
|
||||||
instance_and, /*nb_and*/
|
instance_and, /*nb_and*/
|
||||||
instance_xor, /*nb_xor*/
|
instance_xor, /*nb_xor*/
|
||||||
instance_or, /*nb_or*/
|
instance_or, /*nb_or*/
|
||||||
|
instance_coerce, /*nb_coerce*/
|
||||||
};
|
};
|
||||||
|
|
||||||
typeobject Instancetype = {
|
typeobject Instancetype = {
|
||||||
|
@ -690,58 +742,6 @@ typeobject Instancetype = {
|
||||||
&instance_as_mapping, /*tp_as_mapping*/
|
&instance_as_mapping, /*tp_as_mapping*/
|
||||||
};
|
};
|
||||||
|
|
||||||
static int
|
|
||||||
one_coerce(pv, pw)
|
|
||||||
object **pv, **pw;
|
|
||||||
{
|
|
||||||
object *v = *pv;
|
|
||||||
object *w = *pw;
|
|
||||||
object *func;
|
|
||||||
|
|
||||||
if (!is_instanceobject(v))
|
|
||||||
return 1;
|
|
||||||
func = instance_getattr((instanceobject *)v, "__coerce__");
|
|
||||||
if (func == NULL) {
|
|
||||||
err_clear();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (func != NULL) {
|
|
||||||
object *res = call_object(func, w);
|
|
||||||
int outcome;
|
|
||||||
if (res == NULL)
|
|
||||||
return -1;
|
|
||||||
outcome = getargs(res, "(OO)", &v, &w);
|
|
||||||
if (!outcome || v->ob_type != w->ob_type ||
|
|
||||||
v->ob_type->tp_as_number == NULL) {
|
|
||||||
DECREF(res);
|
|
||||||
err_setstr(TypeError, "bad __coerce__ result");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
INCREF(v);
|
|
||||||
INCREF(w);
|
|
||||||
DECREF(res);
|
|
||||||
*pv = v;
|
|
||||||
*pw = w;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
instance_coerce(pv, pw)
|
|
||||||
object **pv, **pw;
|
|
||||||
{
|
|
||||||
int outcome;
|
|
||||||
outcome = one_coerce(pv, pw);
|
|
||||||
if (outcome > 0) {
|
|
||||||
outcome = one_coerce(pw, pv);
|
|
||||||
if (outcome > 0) {
|
|
||||||
err_setstr(TypeError, "uncoerceable instance");
|
|
||||||
outcome = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return outcome;
|
|
||||||
}
|
|
||||||
|
|
||||||
object *
|
object *
|
||||||
instance_convert(inst, methodname)
|
instance_convert(inst, methodname)
|
||||||
object *inst;
|
object *inst;
|
||||||
|
|
|
@ -299,6 +299,25 @@ float_nonzero(v)
|
||||||
return v->ob_fval != 0.0;
|
return v->ob_fval != 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
float_coerce(pv, pw)
|
||||||
|
object **pv;
|
||||||
|
object **pw;
|
||||||
|
{
|
||||||
|
if (is_intobject(*pw)) {
|
||||||
|
long x = getintvalue(*pw);
|
||||||
|
*pw = newfloatobject((double)x);
|
||||||
|
INCREF(*pv);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if (is_longobject(*pw)) {
|
||||||
|
*pw = newfloatobject(dgetlongvalue(*pw));
|
||||||
|
INCREF(*pv);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1; /* Can't do it */
|
||||||
|
}
|
||||||
|
|
||||||
static number_methods float_as_number = {
|
static number_methods float_as_number = {
|
||||||
float_add, /*nb_add*/
|
float_add, /*nb_add*/
|
||||||
float_sub, /*nb_subtract*/
|
float_sub, /*nb_subtract*/
|
||||||
|
@ -317,6 +336,7 @@ static number_methods float_as_number = {
|
||||||
0, /*nb_and*/
|
0, /*nb_and*/
|
||||||
0, /*nb_xor*/
|
0, /*nb_xor*/
|
||||||
0, /*nb_or*/
|
0, /*nb_or*/
|
||||||
|
float_coerce, /*nb_coerce*/
|
||||||
};
|
};
|
||||||
|
|
||||||
typeobject Floattype = {
|
typeobject Floattype = {
|
||||||
|
|
|
@ -1253,6 +1253,19 @@ long_or(a, b)
|
||||||
return long_bitwise(a, '|', b);
|
return long_bitwise(a, '|', b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
long_coerce(pv, pw)
|
||||||
|
object **pv;
|
||||||
|
object **pw;
|
||||||
|
{
|
||||||
|
if (is_intobject(*pw)) {
|
||||||
|
*pw = newlongobject(getintvalue(*pw));
|
||||||
|
INCREF(*pv);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1; /* Can't do it */
|
||||||
|
}
|
||||||
|
|
||||||
#define UF (object* (*) FPROTO((object *))) /* Unary function */
|
#define UF (object* (*) FPROTO((object *))) /* Unary function */
|
||||||
#define BF (object* (*) FPROTO((object *, object *))) /* Binary function */
|
#define BF (object* (*) FPROTO((object *, object *))) /* Binary function */
|
||||||
#define IF (int (*) FPROTO((object *))) /* Int function */
|
#define IF (int (*) FPROTO((object *))) /* Int function */
|
||||||
|
@ -1275,6 +1288,8 @@ static number_methods long_as_number = {
|
||||||
BF long_and, /*nb_and*/
|
BF long_and, /*nb_and*/
|
||||||
BF long_xor, /*nb_xor*/
|
BF long_xor, /*nb_xor*/
|
||||||
BF long_or, /*nb_or*/
|
BF long_or, /*nb_or*/
|
||||||
|
(int (*) FPROTO((object **, object **)))
|
||||||
|
long_coerce, /*nb_coerce*/
|
||||||
};
|
};
|
||||||
|
|
||||||
typeobject Longtype = {
|
typeobject Longtype = {
|
||||||
|
|
|
@ -781,10 +781,7 @@ initbuiltin()
|
||||||
Increment the reference count on each argument.
|
Increment the reference count on each argument.
|
||||||
Return -1 and raise an exception if no coercion is possible
|
Return -1 and raise an exception if no coercion is possible
|
||||||
(and then no reference count is incremented).
|
(and then no reference count is incremented).
|
||||||
XXX This should be distributed over the various numeric types,
|
*/
|
||||||
XXX but for now I don't see how to implement that.
|
|
||||||
XXX So, for now, if you add a new numeric type,
|
|
||||||
XXX you must add to this function as well. */
|
|
||||||
|
|
||||||
int
|
int
|
||||||
coerce(pv, pw)
|
coerce(pv, pw)
|
||||||
|
@ -792,36 +789,23 @@ coerce(pv, pw)
|
||||||
{
|
{
|
||||||
register object *v = *pv;
|
register object *v = *pv;
|
||||||
register object *w = *pw;
|
register object *w = *pw;
|
||||||
|
int res;
|
||||||
|
|
||||||
if (v->ob_type == w->ob_type) {
|
if (v->ob_type == w->ob_type) {
|
||||||
INCREF(v);
|
INCREF(v);
|
||||||
INCREF(w);
|
INCREF(w);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (is_instanceobject(v) || is_instanceobject(w))
|
if (v->ob_type->tp_as_number && v->ob_type->tp_as_number->nb_coerce) {
|
||||||
return instance_coerce(pv, pw);
|
res = (*v->ob_type->tp_as_number->nb_coerce)(pv, pw);
|
||||||
if (v->ob_type->tp_as_number == NULL ||
|
if (res <= 0)
|
||||||
w->ob_type->tp_as_number == NULL) {
|
return res;
|
||||||
err_setstr(TypeError, "mixing number and non-number");
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
if (is_floatobject(v) || is_floatobject(w)) {
|
if (w->ob_type->tp_as_number && w->ob_type->tp_as_number->nb_coerce) {
|
||||||
v = builtin_float((object *)0, v);
|
res = (*w->ob_type->tp_as_number->nb_coerce)(pw, pv);
|
||||||
w = builtin_float((object *)0, w);
|
if (res <= 0)
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
else if (is_longobject(v) || is_longobject(w)) {
|
err_setstr(TypeError, "number coercion failed");
|
||||||
v = builtin_long((object *)0, v);
|
return -1;
|
||||||
w = builtin_long((object *)0, w);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
err_setstr(TypeError, "can't coerce numeric types?!?!?");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (v == NULL || w == NULL) {
|
|
||||||
XDECREF(v);
|
|
||||||
XDECREF(w);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
*pv = v;
|
|
||||||
*pw = w;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1532,7 +1532,9 @@ static object *
|
||||||
add(v, w)
|
add(v, w)
|
||||||
object *v, *w;
|
object *v, *w;
|
||||||
{
|
{
|
||||||
if (v->ob_type->tp_as_number != NULL) {
|
if (v->ob_type->tp_as_sequence != NULL)
|
||||||
|
return (*v->ob_type->tp_as_sequence->sq_concat)(v, w);
|
||||||
|
else if (v->ob_type->tp_as_number != NULL) {
|
||||||
object *x;
|
object *x;
|
||||||
if (coerce(&v, &w) != 0)
|
if (coerce(&v, &w) != 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -1541,8 +1543,6 @@ add(v, w)
|
||||||
DECREF(w);
|
DECREF(w);
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
else if (v->ob_type->tp_as_sequence != NULL)
|
|
||||||
return (*v->ob_type->tp_as_sequence->sq_concat)(v, w);
|
|
||||||
else {
|
else {
|
||||||
err_setstr(TypeError, "+ not supported by operands");
|
err_setstr(TypeError, "+ not supported by operands");
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -1571,16 +1571,27 @@ mul(v, w)
|
||||||
object *v, *w;
|
object *v, *w;
|
||||||
{
|
{
|
||||||
typeobject *tp;
|
typeobject *tp;
|
||||||
if (is_intobject(v) && w->ob_type->tp_as_sequence != NULL) {
|
tp = v->ob_type;
|
||||||
/* int*sequence -- swap v and w */
|
if (tp->tp_as_number != NULL &&
|
||||||
|
w->ob_type->tp_as_sequence != NULL &&
|
||||||
|
!is_instanceobject(v)) {
|
||||||
|
/* number*sequence -- swap v and w */
|
||||||
object *tmp = v;
|
object *tmp = v;
|
||||||
v = w;
|
v = w;
|
||||||
w = tmp;
|
w = tmp;
|
||||||
|
tp = v->ob_type;
|
||||||
}
|
}
|
||||||
tp = v->ob_type;
|
|
||||||
if (tp->tp_as_number != NULL) {
|
if (tp->tp_as_number != NULL) {
|
||||||
object *x;
|
object *x;
|
||||||
if (coerce(&v, &w) != 0)
|
if (is_instanceobject(v)) {
|
||||||
|
/* Instances of user-defined classes get their
|
||||||
|
other argument uncoerced, so they may
|
||||||
|
implement sequence*number as well as
|
||||||
|
number*number. */
|
||||||
|
INCREF(v);
|
||||||
|
INCREF(w);
|
||||||
|
}
|
||||||
|
else if (coerce(&v, &w) != 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
x = (*v->ob_type->tp_as_number->nb_multiply)(v, w);
|
x = (*v->ob_type->tp_as_number->nb_multiply)(v, w);
|
||||||
DECREF(v);
|
DECREF(v);
|
||||||
|
|
Loading…
Reference in New Issue