Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e6eefc2

Browse files
committed
* 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.
1 parent 70d7a31 commit e6eefc2

7 files changed

Lines changed: 123 additions & 93 deletions

File tree

Include/classobject.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,5 +43,4 @@ extern object *newinstancemethodobject PROTO((object *, object *));
4343
extern object *instancemethodgetfunc PROTO((object *));
4444
extern object *instancemethodgetself PROTO((object *));
4545

46-
extern int instance_coerce PROTO((object **, object **));
4746
extern object *instance_convert PROTO((object *, char *));

Include/object.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ typedef struct {
142142
object *(*nb_and) FPROTO((object *, object *));
143143
object *(*nb_xor) FPROTO((object *, object *));
144144
object *(*nb_or) FPROTO((object *, object *));
145+
int (*nb_coerce) FPROTO((object **, object **));
145146
} number_methods;
146147

147148
typedef struct {

Objects/classobject.c

Lines changed: 56 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -417,13 +417,19 @@ static object *
417417
instance_concat(inst, other)
418418
instanceobject *inst, *other;
419419
{
420-
object *func, *res;
420+
object *func, *arg, *res;
421421

422422
func = instance_getattr(inst, "__add__");
423423
if (func == NULL)
424424
return NULL;
425-
res = call_object(func, (object *)other);
425+
arg = mkvalue("(O)", other);
426+
if (arg == NULL) {
427+
DECREF(func);
428+
return NULL;
429+
}
430+
res = call_object(func, arg);
426431
DECREF(func);
432+
DECREF(arg);
427433
return res;
428434
}
429435

@@ -568,12 +574,18 @@ generic_binary_op(self, other, methodname)
568574
object *other;
569575
char *methodname;
570576
{
571-
object *func, *res;
577+
object *func, *arg, *res;
572578

573579
if ((func = instance_getattr(self, methodname)) == NULL)
574580
return NULL;
575-
res = call_object(func, other);
581+
arg = mkvalue("O", other);
582+
if (arg == NULL) {
583+
DECREF(func);
584+
return NULL;
585+
}
586+
res = call_object(func, arg);
576587
DECREF(func);
588+
DECREF(arg);
577589
return res;
578590
}
579591

@@ -653,6 +665,45 @@ BINARY(instance_and, "__and__")
653665
BINARY(instance_xor, "__xor__")
654666
BINARY(instance_or, "__or__")
655667

668+
static int
669+
instance_coerce(pv, pw)
670+
object **pv, **pw;
671+
{
672+
object *v = *pv;
673+
object *w = *pw;
674+
object *func;
675+
object *res;
676+
int outcome;
677+
678+
if (!is_instanceobject(v))
679+
return 1; /* XXX shouldn't be possible */
680+
func = instance_getattr((instanceobject *)v, "__coerce__");
681+
if (func == NULL) {
682+
err_clear();
683+
return 1;
684+
}
685+
res = call_object(func, w);
686+
if (res == NULL)
687+
return -1;
688+
if (res == None) {
689+
DECREF(res);
690+
return 1;
691+
}
692+
outcome = getargs(res, "(OO)", &v, &w);
693+
if (!outcome || v->ob_type != w->ob_type ||
694+
v->ob_type->tp_as_number == NULL) {
695+
DECREF(res);
696+
err_setstr(TypeError, "bad __coerce__ result");
697+
return -1;
698+
}
699+
INCREF(v);
700+
INCREF(w);
701+
DECREF(res);
702+
*pv = v;
703+
*pw = w;
704+
return 0;
705+
}
706+
656707
static number_methods instance_as_number = {
657708
instance_add, /*nb_add*/
658709
instance_sub, /*nb_subtract*/
@@ -671,6 +722,7 @@ static number_methods instance_as_number = {
671722
instance_and, /*nb_and*/
672723
instance_xor, /*nb_xor*/
673724
instance_or, /*nb_or*/
725+
instance_coerce, /*nb_coerce*/
674726
};
675727

676728
typeobject Instancetype = {
@@ -690,58 +742,6 @@ typeobject Instancetype = {
690742
&instance_as_mapping, /*tp_as_mapping*/
691743
};
692744

693-
static int
694-
one_coerce(pv, pw)
695-
object **pv, **pw;
696-
{
697-
object *v = *pv;
698-
object *w = *pw;
699-
object *func;
700-
701-
if (!is_instanceobject(v))
702-
return 1;
703-
func = instance_getattr((instanceobject *)v, "__coerce__");
704-
if (func == NULL) {
705-
err_clear();
706-
return 1;
707-
}
708-
if (func != NULL) {
709-
object *res = call_object(func, w);
710-
int outcome;
711-
if (res == NULL)
712-
return -1;
713-
outcome = getargs(res, "(OO)", &v, &w);
714-
if (!outcome || v->ob_type != w->ob_type ||
715-
v->ob_type->tp_as_number == NULL) {
716-
DECREF(res);
717-
err_setstr(TypeError, "bad __coerce__ result");
718-
return -1;
719-
}
720-
INCREF(v);
721-
INCREF(w);
722-
DECREF(res);
723-
*pv = v;
724-
*pw = w;
725-
return 0;
726-
}
727-
}
728-
729-
int
730-
instance_coerce(pv, pw)
731-
object **pv, **pw;
732-
{
733-
int outcome;
734-
outcome = one_coerce(pv, pw);
735-
if (outcome > 0) {
736-
outcome = one_coerce(pw, pv);
737-
if (outcome > 0) {
738-
err_setstr(TypeError, "uncoerceable instance");
739-
outcome = -1;
740-
}
741-
}
742-
return outcome;
743-
}
744-
745745
object *
746746
instance_convert(inst, methodname)
747747
object *inst;

Objects/floatobject.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,25 @@ float_nonzero(v)
299299
return v->ob_fval != 0.0;
300300
}
301301

302+
int
303+
float_coerce(pv, pw)
304+
object **pv;
305+
object **pw;
306+
{
307+
if (is_intobject(*pw)) {
308+
long x = getintvalue(*pw);
309+
*pw = newfloatobject((double)x);
310+
INCREF(*pv);
311+
return 0;
312+
}
313+
else if (is_longobject(*pw)) {
314+
*pw = newfloatobject(dgetlongvalue(*pw));
315+
INCREF(*pv);
316+
return 0;
317+
}
318+
return 1; /* Can't do it */
319+
}
320+
302321
static number_methods float_as_number = {
303322
float_add, /*nb_add*/
304323
float_sub, /*nb_subtract*/
@@ -317,6 +336,7 @@ static number_methods float_as_number = {
317336
0, /*nb_and*/
318337
0, /*nb_xor*/
319338
0, /*nb_or*/
339+
float_coerce, /*nb_coerce*/
320340
};
321341

322342
typeobject Floattype = {

Objects/longobject.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1253,6 +1253,19 @@ long_or(a, b)
12531253
return long_bitwise(a, '|', b);
12541254
}
12551255

1256+
int
1257+
long_coerce(pv, pw)
1258+
object **pv;
1259+
object **pw;
1260+
{
1261+
if (is_intobject(*pw)) {
1262+
*pw = newlongobject(getintvalue(*pw));
1263+
INCREF(*pv);
1264+
return 0;
1265+
}
1266+
return 1; /* Can't do it */
1267+
}
1268+
12561269
#define UF (object* (*) FPROTO((object *))) /* Unary function */
12571270
#define BF (object* (*) FPROTO((object *, object *))) /* Binary function */
12581271
#define IF (int (*) FPROTO((object *))) /* Int function */
@@ -1275,6 +1288,8 @@ static number_methods long_as_number = {
12751288
BF long_and, /*nb_and*/
12761289
BF long_xor, /*nb_xor*/
12771290
BF long_or, /*nb_or*/
1291+
(int (*) FPROTO((object **, object **)))
1292+
long_coerce, /*nb_coerce*/
12781293
};
12791294

12801295
typeobject Longtype = {

Python/bltinmodule.c

Lines changed: 13 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -781,47 +781,31 @@ initbuiltin()
781781
Increment the reference count on each argument.
782782
Return -1 and raise an exception if no coercion is possible
783783
(and then no reference count is incremented).
784-
XXX This should be distributed over the various numeric types,
785-
XXX but for now I don't see how to implement that.
786-
XXX So, for now, if you add a new numeric type,
787-
XXX you must add to this function as well. */
784+
*/
788785

789786
int
790787
coerce(pv, pw)
791788
object **pv, **pw;
792789
{
793790
register object *v = *pv;
794791
register object *w = *pw;
792+
int res;
793+
795794
if (v->ob_type == w->ob_type) {
796795
INCREF(v);
797796
INCREF(w);
798797
return 0;
799798
}
800-
if (is_instanceobject(v) || is_instanceobject(w))
801-
return instance_coerce(pv, pw);
802-
if (v->ob_type->tp_as_number == NULL ||
803-
w->ob_type->tp_as_number == NULL) {
804-
err_setstr(TypeError, "mixing number and non-number");
805-
return -1;
806-
}
807-
if (is_floatobject(v) || is_floatobject(w)) {
808-
v = builtin_float((object *)0, v);
809-
w = builtin_float((object *)0, w);
810-
}
811-
else if (is_longobject(v) || is_longobject(w)) {
812-
v = builtin_long((object *)0, v);
813-
w = builtin_long((object *)0, w);
814-
}
815-
else {
816-
err_setstr(TypeError, "can't coerce numeric types?!?!?");
817-
return -1;
799+
if (v->ob_type->tp_as_number && v->ob_type->tp_as_number->nb_coerce) {
800+
res = (*v->ob_type->tp_as_number->nb_coerce)(pv, pw);
801+
if (res <= 0)
802+
return res;
818803
}
819-
if (v == NULL || w == NULL) {
820-
XDECREF(v);
821-
XDECREF(w);
822-
return -1;
804+
if (w->ob_type->tp_as_number && w->ob_type->tp_as_number->nb_coerce) {
805+
res = (*w->ob_type->tp_as_number->nb_coerce)(pw, pv);
806+
if (res <= 0)
807+
return res;
823808
}
824-
*pv = v;
825-
*pw = w;
826-
return 0;
809+
err_setstr(TypeError, "number coercion failed");
810+
return -1;
827811
}

Python/ceval.c

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1532,7 +1532,9 @@ static object *
15321532
add(v, w)
15331533
object *v, *w;
15341534
{
1535-
if (v->ob_type->tp_as_number != NULL) {
1535+
if (v->ob_type->tp_as_sequence != NULL)
1536+
return (*v->ob_type->tp_as_sequence->sq_concat)(v, w);
1537+
else if (v->ob_type->tp_as_number != NULL) {
15361538
object *x;
15371539
if (coerce(&v, &w) != 0)
15381540
return NULL;
@@ -1541,8 +1543,6 @@ add(v, w)
15411543
DECREF(w);
15421544
return x;
15431545
}
1544-
else if (v->ob_type->tp_as_sequence != NULL)
1545-
return (*v->ob_type->tp_as_sequence->sq_concat)(v, w);
15461546
else {
15471547
err_setstr(TypeError, "+ not supported by operands");
15481548
return NULL;
@@ -1571,16 +1571,27 @@ mul(v, w)
15711571
object *v, *w;
15721572
{
15731573
typeobject *tp;
1574-
if (is_intobject(v) && w->ob_type->tp_as_sequence != NULL) {
1575-
/* int*sequence -- swap v and w */
1574+
tp = v->ob_type;
1575+
if (tp->tp_as_number != NULL &&
1576+
w->ob_type->tp_as_sequence != NULL &&
1577+
!is_instanceobject(v)) {
1578+
/* number*sequence -- swap v and w */
15761579
object *tmp = v;
15771580
v = w;
15781581
w = tmp;
1582+
tp = v->ob_type;
15791583
}
1580-
tp = v->ob_type;
15811584
if (tp->tp_as_number != NULL) {
15821585
object *x;
1583-
if (coerce(&v, &w) != 0)
1586+
if (is_instanceobject(v)) {
1587+
/* Instances of user-defined classes get their
1588+
other argument uncoerced, so they may
1589+
implement sequence*number as well as
1590+
number*number. */
1591+
INCREF(v);
1592+
INCREF(w);
1593+
}
1594+
else if (coerce(&v, &w) != 0)
15841595
return NULL;
15851596
x = (*v->ob_type->tp_as_number->nb_multiply)(v, w);
15861597
DECREF(v);

0 commit comments

Comments
 (0)