* 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:
Guido van Rossum 1992-08-14 12:06:52 +00:00
parent 70d7a310a9
commit e6eefc2231
7 changed files with 123 additions and 93 deletions

View File

@ -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 *));

View File

@ -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 {

View File

@ -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;

View File

@ -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 = {

View File

@ -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 = {

View File

@ -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;
} }

View File

@ -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);