From e6eefc22313e7f2da5918ecd608fbb0b7a7a1610 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Fri, 14 Aug 1992 12:06:52 +0000 Subject: * 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. --- Include/classobject.h | 1 - Include/object.h | 1 + Objects/classobject.c | 112 +++++++++++++++++++++++++------------------------- Objects/floatobject.c | 20 +++++++++ Objects/longobject.c | 15 +++++++ Python/bltinmodule.c | 42 ++++++------------- Python/ceval.c | 25 +++++++---- 7 files changed, 123 insertions(+), 93 deletions(-) diff --git a/Include/classobject.h b/Include/classobject.h index 1d24a7c..b33cacc 100644 --- a/Include/classobject.h +++ b/Include/classobject.h @@ -43,5 +43,4 @@ extern object *newinstancemethodobject PROTO((object *, object *)); extern object *instancemethodgetfunc PROTO((object *)); extern object *instancemethodgetself PROTO((object *)); -extern int instance_coerce PROTO((object **, object **)); extern object *instance_convert PROTO((object *, char *)); diff --git a/Include/object.h b/Include/object.h index d987efb..a66629c 100644 --- a/Include/object.h +++ b/Include/object.h @@ -142,6 +142,7 @@ typedef struct { object *(*nb_and) FPROTO((object *, object *)); object *(*nb_xor) FPROTO((object *, object *)); object *(*nb_or) FPROTO((object *, object *)); + int (*nb_coerce) FPROTO((object **, object **)); } number_methods; typedef struct { diff --git a/Objects/classobject.c b/Objects/classobject.c index 40fe0c9..8164ced 100644 --- a/Objects/classobject.c +++ b/Objects/classobject.c @@ -417,13 +417,19 @@ static object * instance_concat(inst, other) instanceobject *inst, *other; { - object *func, *res; + object *func, *arg, *res; func = instance_getattr(inst, "__add__"); if (func == 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(arg); return res; } @@ -568,12 +574,18 @@ generic_binary_op(self, other, methodname) object *other; char *methodname; { - object *func, *res; + object *func, *arg, *res; if ((func = instance_getattr(self, methodname)) == 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(arg); return res; } @@ -653,6 +665,45 @@ BINARY(instance_and, "__and__") BINARY(instance_xor, "__xor__") 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 = { instance_add, /*nb_add*/ instance_sub, /*nb_subtract*/ @@ -671,6 +722,7 @@ static number_methods instance_as_number = { instance_and, /*nb_and*/ instance_xor, /*nb_xor*/ instance_or, /*nb_or*/ + instance_coerce, /*nb_coerce*/ }; typeobject Instancetype = { @@ -690,58 +742,6 @@ typeobject Instancetype = { &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 * instance_convert(inst, methodname) object *inst; diff --git a/Objects/floatobject.c b/Objects/floatobject.c index d154cab..5ce6202 100644 --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -299,6 +299,25 @@ float_nonzero(v) 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 = { float_add, /*nb_add*/ float_sub, /*nb_subtract*/ @@ -317,6 +336,7 @@ static number_methods float_as_number = { 0, /*nb_and*/ 0, /*nb_xor*/ 0, /*nb_or*/ + float_coerce, /*nb_coerce*/ }; typeobject Floattype = { diff --git a/Objects/longobject.c b/Objects/longobject.c index bf62c1f..f9e3765 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -1253,6 +1253,19 @@ long_or(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 BF (object* (*) FPROTO((object *, object *))) /* Binary 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_xor, /*nb_xor*/ BF long_or, /*nb_or*/ + (int (*) FPROTO((object **, object **))) + long_coerce, /*nb_coerce*/ }; typeobject Longtype = { diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index cce19e1..86deac3 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -781,10 +781,7 @@ initbuiltin() 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). - 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 coerce(pv, pw) @@ -792,36 +789,23 @@ coerce(pv, pw) { register object *v = *pv; register object *w = *pw; + int res; + if (v->ob_type == w->ob_type) { INCREF(v); INCREF(w); return 0; } - if (is_instanceobject(v) || is_instanceobject(w)) - return instance_coerce(pv, pw); - if (v->ob_type->tp_as_number == NULL || - w->ob_type->tp_as_number == NULL) { - err_setstr(TypeError, "mixing number and non-number"); - return -1; - } - if (is_floatobject(v) || is_floatobject(w)) { - v = builtin_float((object *)0, v); - w = builtin_float((object *)0, w); - } - else if (is_longobject(v) || is_longobject(w)) { - v = builtin_long((object *)0, v); - w = builtin_long((object *)0, w); - } - else { - err_setstr(TypeError, "can't coerce numeric types?!?!?"); - return -1; + if (v->ob_type->tp_as_number && v->ob_type->tp_as_number->nb_coerce) { + res = (*v->ob_type->tp_as_number->nb_coerce)(pv, pw); + if (res <= 0) + return res; } - if (v == NULL || w == NULL) { - XDECREF(v); - XDECREF(w); - return -1; + if (w->ob_type->tp_as_number && w->ob_type->tp_as_number->nb_coerce) { + res = (*w->ob_type->tp_as_number->nb_coerce)(pw, pv); + if (res <= 0) + return res; } - *pv = v; - *pw = w; - return 0; + err_setstr(TypeError, "number coercion failed"); + return -1; } diff --git a/Python/ceval.c b/Python/ceval.c index ad679a6..5b72d8e 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1532,7 +1532,9 @@ static object * add(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; if (coerce(&v, &w) != 0) return NULL; @@ -1541,8 +1543,6 @@ add(v, w) DECREF(w); return x; } - else if (v->ob_type->tp_as_sequence != NULL) - return (*v->ob_type->tp_as_sequence->sq_concat)(v, w); else { err_setstr(TypeError, "+ not supported by operands"); return NULL; @@ -1571,16 +1571,27 @@ mul(v, w) object *v, *w; { typeobject *tp; - if (is_intobject(v) && w->ob_type->tp_as_sequence != NULL) { - /* int*sequence -- swap v and w */ + tp = v->ob_type; + 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; v = w; w = tmp; + tp = v->ob_type; } - tp = v->ob_type; if (tp->tp_as_number != NULL) { 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; x = (*v->ob_type->tp_as_number->nb_multiply)(v, w); DECREF(v); -- cgit v0.12