mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 05:31:20 +00:00 
			
		
		
		
	Changes so that user-defined classes can implement operations invoked
by special syntax: you can now define your own numbers, sequences and mappings.
This commit is contained in:
		
							parent
							
								
									423d6c6bca
								
							
						
					
					
						commit
						04691fc1c1
					
				
					 5 changed files with 609 additions and 42 deletions
				
			
		|  | @ -77,13 +77,13 @@ void flushline PROTO((void)); | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
| extern void init_save_thread PROTO((void)); | extern void init_save_thread PROTO((void)); | ||||||
| extern void *save_thread PROTO((void)); | extern object *save_thread PROTO((void)); | ||||||
| extern void restore_thread PROTO((void *)); | extern void restore_thread PROTO((object *)); | ||||||
| 
 | 
 | ||||||
| #ifdef USE_THREAD | #ifdef USE_THREAD | ||||||
| 
 | 
 | ||||||
| #define BGN_SAVE { \ | #define BGN_SAVE { \ | ||||||
| 			void *_save; \ | 			object *_save; \ | ||||||
| 			_save = save_thread(); | 			_save = save_thread(); | ||||||
| #define RET_SAVE	restore_thread(_save); | #define RET_SAVE	restore_thread(_save); | ||||||
| #define RES_SAVE	_save = save_thread(); | #define RES_SAVE	_save = save_thread(); | ||||||
|  |  | ||||||
|  | @ -42,3 +42,6 @@ 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 *)); | ||||||
|  |  | ||||||
|  | @ -25,8 +25,12 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||||||
| /* Class object implementation */ | /* Class object implementation */ | ||||||
| 
 | 
 | ||||||
| #include "allobjects.h" | #include "allobjects.h" | ||||||
| 
 | #include "modsupport.h" | ||||||
| #include "structmember.h" | #include "structmember.h" | ||||||
|  | #include "ceval.h" | ||||||
|  | 
 | ||||||
|  | extern typeobject MappingInstancetype; | ||||||
|  | extern typeobject SequenceInstancetype; | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
| 	OB_HEAD | 	OB_HEAD | ||||||
|  | @ -166,6 +170,7 @@ newinstanceobject(class) | ||||||
| 	register object *class; | 	register object *class; | ||||||
| { | { | ||||||
| 	register instanceobject *inst; | 	register instanceobject *inst; | ||||||
|  | 	object *v; | ||||||
| 	if (!is_classobject(class)) { | 	if (!is_classobject(class)) { | ||||||
| 		err_badcall(); | 		err_badcall(); | ||||||
| 		return NULL; | 		return NULL; | ||||||
|  | @ -246,6 +251,428 @@ instance_setattr(inst, name, v) | ||||||
| 		return dictinsert(inst->in_attr, name, v); | 		return dictinsert(inst->in_attr, name, v); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | int | ||||||
|  | instance_print(inst, fp, flags) | ||||||
|  | 	instanceobject *inst; | ||||||
|  | 	FILE *fp; | ||||||
|  | 	int flags; | ||||||
|  | { | ||||||
|  | 	object *func, *repr; | ||||||
|  | 	int ret; | ||||||
|  | 
 | ||||||
|  | 	func = instance_getattr(inst, "__repr__"); | ||||||
|  | 	if (func == NULL) { | ||||||
|  | 		err_clear(); | ||||||
|  | 		fprintf(fp, "<instance object at %lx>", (long)inst); | ||||||
|  | 		return 0; | ||||||
|  | 	} | ||||||
|  | 	repr = call_object(func, (object *)NULL); | ||||||
|  | 	DECREF(func); | ||||||
|  | 	if (repr == NULL) | ||||||
|  | 		return -1; | ||||||
|  | 	ret = printobject(repr, fp, flags | PRINT_RAW); | ||||||
|  | 	DECREF(repr); | ||||||
|  | 	return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | object * | ||||||
|  | instance_repr(inst) | ||||||
|  | 	instanceobject *inst; | ||||||
|  | { | ||||||
|  | 	object *func; | ||||||
|  | 	object *res; | ||||||
|  | 
 | ||||||
|  | 	func = instance_getattr(inst, "__repr__"); | ||||||
|  | 	if (func == NULL) { | ||||||
|  | 		char buf[80]; | ||||||
|  | 		err_clear(); | ||||||
|  | 		sprintf(buf, "<instance object at %lx>", (long)inst); | ||||||
|  | 		return newstringobject(buf); | ||||||
|  | 	} | ||||||
|  | 	res = call_object(func, (object *)NULL); | ||||||
|  | 	DECREF(func); | ||||||
|  | 	return res; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int | ||||||
|  | instance_compare(inst, other) | ||||||
|  | 	instanceobject *inst, *other; | ||||||
|  | { | ||||||
|  | 	object *func; | ||||||
|  | 	object *res; | ||||||
|  | 	int outcome; | ||||||
|  | 
 | ||||||
|  | 	func = instance_getattr(inst, "__cmp__"); | ||||||
|  | 	if (func == NULL) { | ||||||
|  | 		err_clear(); | ||||||
|  | 		if (inst < other) | ||||||
|  | 			return -1; | ||||||
|  | 		if (inst > other) | ||||||
|  | 			return 1; | ||||||
|  | 		return 0; | ||||||
|  | 	} | ||||||
|  | 	res = call_object(func, (object *)other); | ||||||
|  | 	DECREF(func); | ||||||
|  | 	if (res == NULL) { | ||||||
|  | 		err_clear(); /* XXX Should report the error, bot how...??? */ | ||||||
|  | 		return 0; | ||||||
|  | 	} | ||||||
|  | 	if (is_intobject(res)) | ||||||
|  | 		outcome = getintvalue(res); | ||||||
|  | 	else | ||||||
|  | 		outcome = 0; /* XXX Should report the error, bot how...??? */ | ||||||
|  | 	DECREF(res); | ||||||
|  | 	return outcome; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int | ||||||
|  | instance_length(inst) | ||||||
|  | 	instanceobject *inst; | ||||||
|  | { | ||||||
|  | 	object *func; | ||||||
|  | 	object *res; | ||||||
|  | 	int outcome; | ||||||
|  | 
 | ||||||
|  | 	func = instance_getattr(inst, "__len__"); | ||||||
|  | 	if (func == NULL) | ||||||
|  | 		return -1; | ||||||
|  | 	res = call_object(func, (object *)NULL); | ||||||
|  | 	DECREF(func); | ||||||
|  | 	if (is_intobject(res)) { | ||||||
|  | 		outcome = getintvalue(res); | ||||||
|  | 		if (outcome < 0) | ||||||
|  | 			err_setstr(ValueError, "__len__() should return >= 0"); | ||||||
|  | 	} | ||||||
|  | 	else { | ||||||
|  | 		err_setstr(TypeError, "__len__() should return an int"); | ||||||
|  | 		outcome = -1; | ||||||
|  | 	} | ||||||
|  | 	DECREF(res); | ||||||
|  | 	return outcome; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | object * | ||||||
|  | instance_subscript(inst, key) | ||||||
|  | 	instanceobject *inst; | ||||||
|  | 	object *key; | ||||||
|  | { | ||||||
|  | 	object *func; | ||||||
|  | 	object *arg; | ||||||
|  | 	object *res; | ||||||
|  | 
 | ||||||
|  | 	func = instance_getattr(inst, "__getitem__"); | ||||||
|  | 	if (func == NULL) | ||||||
|  | 		return NULL; | ||||||
|  | 	arg = mkvalue("(O)", key); | ||||||
|  | 	if (arg == NULL) { | ||||||
|  | 		DECREF(func); | ||||||
|  | 		return NULL; | ||||||
|  | 	} | ||||||
|  | 	res = call_object(func, arg); | ||||||
|  | 	DECREF(func); | ||||||
|  | 	DECREF(arg); | ||||||
|  | 	return res; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int | ||||||
|  | instance_ass_subscript(inst, key, value) | ||||||
|  | 	instanceobject*inst; | ||||||
|  | 	object *key; | ||||||
|  | 	object *value; | ||||||
|  | { | ||||||
|  | 	object *func; | ||||||
|  | 	object *arg; | ||||||
|  | 	object *res; | ||||||
|  | 
 | ||||||
|  | 	if (value == NULL) | ||||||
|  | 		func = instance_getattr(inst, "__delitem__"); | ||||||
|  | 	else | ||||||
|  | 		func = instance_getattr(inst, "__setitem__"); | ||||||
|  | 	if (func == NULL) | ||||||
|  | 		return -1; | ||||||
|  | 	if (value == NULL) | ||||||
|  | 		arg = mkvalue("(O)", key); | ||||||
|  | 	else | ||||||
|  | 		arg = mkvalue("(OO)", key, value); | ||||||
|  | 	if (arg == NULL) { | ||||||
|  | 		DECREF(func); | ||||||
|  | 		return NULL; | ||||||
|  | 	} | ||||||
|  | 	res = call_object(func, arg); | ||||||
|  | 	DECREF(func); | ||||||
|  | 	DECREF(arg); | ||||||
|  | 	if (res == NULL) | ||||||
|  | 		return -1; | ||||||
|  | 	DECREF(res); | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | mapping_methods instance_as_mapping = { | ||||||
|  | 	instance_length,	/*mp_length*/ | ||||||
|  | 	instance_subscript,	/*mp_subscript*/ | ||||||
|  | 	instance_ass_subscript,	/*mp_ass_subscript*/ | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static object * | ||||||
|  | instance_concat(inst, other) | ||||||
|  | 	instanceobject *inst, *other; | ||||||
|  | { | ||||||
|  | 	object *func, *res; | ||||||
|  | 
 | ||||||
|  | 	func = instance_getattr(inst, "__add__"); | ||||||
|  | 	if (func == NULL) | ||||||
|  | 		return NULL; | ||||||
|  | 	res = call_object(func, (object *)other); | ||||||
|  | 	DECREF(func); | ||||||
|  | 	return res; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static object * | ||||||
|  | instance_repeat(inst, count) | ||||||
|  | 	instanceobject *inst; | ||||||
|  | 	int count; | ||||||
|  | { | ||||||
|  | 	object *func, *arg, *res; | ||||||
|  | 
 | ||||||
|  | 	func = instance_getattr(inst, "__mul__"); | ||||||
|  | 	if (func == NULL) | ||||||
|  | 		return NULL; | ||||||
|  | 	arg = newintobject((long)count); | ||||||
|  | 	if (arg == NULL) { | ||||||
|  | 		DECREF(func); | ||||||
|  | 		return NULL; | ||||||
|  | 	} | ||||||
|  | 	res = call_object(func, arg); | ||||||
|  | 	DECREF(func); | ||||||
|  | 	DECREF(arg); | ||||||
|  | 	return res; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static object * | ||||||
|  | instance_item(inst, i) | ||||||
|  | 	instanceobject *inst; | ||||||
|  | 	int i; | ||||||
|  | { | ||||||
|  | 	object *func, *arg, *res; | ||||||
|  | 
 | ||||||
|  | 	func = instance_getattr(inst, "__getitem__"); | ||||||
|  | 	if (func == NULL) | ||||||
|  | 		return NULL; | ||||||
|  | 	arg = newintobject((long)i); | ||||||
|  | 	if (arg == NULL) { | ||||||
|  | 		DECREF(func); | ||||||
|  | 		return NULL; | ||||||
|  | 	} | ||||||
|  | 	res = call_object(func, arg); | ||||||
|  | 	DECREF(func); | ||||||
|  | 	DECREF(arg); | ||||||
|  | 	return res; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static object * | ||||||
|  | instance_slice(inst, i, j) | ||||||
|  | 	instanceobject *inst; | ||||||
|  | 	int i, j; | ||||||
|  | { | ||||||
|  | 	object *func, *arg, *res; | ||||||
|  | 
 | ||||||
|  | 	func = instance_getattr(inst, "__getslice__"); | ||||||
|  | 	if (func == NULL) | ||||||
|  | 		return NULL; | ||||||
|  | 	arg = mkvalue("(ii)", i, j); | ||||||
|  | 	if (arg == NULL) { | ||||||
|  | 		DECREF(func); | ||||||
|  | 		return NULL; | ||||||
|  | 	} | ||||||
|  | 	res = call_object(func, arg); | ||||||
|  | 	DECREF(func); | ||||||
|  | 	DECREF(arg); | ||||||
|  | 	return res; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int | ||||||
|  | instance_ass_item(inst, i, item) | ||||||
|  | 	instanceobject *inst; | ||||||
|  | 	int i; | ||||||
|  | 	object *item; | ||||||
|  | { | ||||||
|  | 	object *func, *arg, *res; | ||||||
|  | 
 | ||||||
|  | 	if (item == NULL) | ||||||
|  | 		func = instance_getattr(inst, "__delitem__"); | ||||||
|  | 	else | ||||||
|  | 		func = instance_getattr(inst, "__setitem__"); | ||||||
|  | 	if (func == NULL) | ||||||
|  | 		return NULL; | ||||||
|  | 	if (item == NULL) | ||||||
|  | 		arg = mkvalue("i", i); | ||||||
|  | 	else | ||||||
|  | 		arg = mkvalue("(iO)", i, item); | ||||||
|  | 	if (arg == NULL) { | ||||||
|  | 		DECREF(func); | ||||||
|  | 		return NULL; | ||||||
|  | 	} | ||||||
|  | 	res = call_object(func, arg); | ||||||
|  | 	DECREF(func); | ||||||
|  | 	DECREF(arg); | ||||||
|  | 	if (res == NULL) | ||||||
|  | 		return -1; | ||||||
|  | 	DECREF(res); | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int | ||||||
|  | instance_ass_slice(inst, i, j, value) | ||||||
|  | 	instanceobject *inst; | ||||||
|  | 	int i, j; | ||||||
|  | 	object *value; | ||||||
|  | { | ||||||
|  | 	object *func, *arg, *res; | ||||||
|  | 
 | ||||||
|  | 	if (value == NULL) | ||||||
|  | 		func = instance_getattr(inst, "__delslice__"); | ||||||
|  | 	else | ||||||
|  | 		func = instance_getattr(inst, "__setslice__"); | ||||||
|  | 	if (func == NULL) | ||||||
|  | 		return NULL; | ||||||
|  | 	if (value == NULL) | ||||||
|  | 		arg = mkvalue("(ii)", i, j); | ||||||
|  | 	else | ||||||
|  | 		arg = mkvalue("(iiO)", i, j, value); | ||||||
|  | 	if (arg == NULL) { | ||||||
|  | 		DECREF(func); | ||||||
|  | 		return NULL; | ||||||
|  | 	} | ||||||
|  | 	res = call_object(func, arg); | ||||||
|  | 	DECREF(func); | ||||||
|  | 	DECREF(arg); | ||||||
|  | 	if (res == NULL) | ||||||
|  | 		return -1; | ||||||
|  | 	DECREF(res); | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static sequence_methods instance_as_sequence = { | ||||||
|  | 	instance_length,	/*sq_length*/ | ||||||
|  | 	instance_concat,	/*sq_concat*/ | ||||||
|  | 	instance_repeat,	/*sq_repeat*/ | ||||||
|  | 	instance_item,		/*sq_item*/ | ||||||
|  | 	instance_slice,		/*sq_slice*/ | ||||||
|  | 	instance_ass_item,	/*sq_ass_item*/ | ||||||
|  | 	instance_ass_slice,	/*sq_ass_slice*/ | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static object * | ||||||
|  | generic_binary_op(self, other, methodname) | ||||||
|  | 	instanceobject *self; | ||||||
|  | 	object *other; | ||||||
|  | 	char *methodname; | ||||||
|  | { | ||||||
|  | 	object *func, *res; | ||||||
|  | 
 | ||||||
|  | 	if ((func = instance_getattr(self, methodname)) == NULL) | ||||||
|  | 		return NULL; | ||||||
|  | 	res = call_object(func, other); | ||||||
|  | 	DECREF(func); | ||||||
|  | 	return res; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static object * | ||||||
|  | generic_unary_op(self, methodname) | ||||||
|  | 	instanceobject *self; | ||||||
|  | 	char *methodname; | ||||||
|  | { | ||||||
|  | 	object *func, *res; | ||||||
|  | 
 | ||||||
|  | 	if ((func = instance_getattr(self, methodname)) == NULL) | ||||||
|  | 		return NULL; | ||||||
|  | 	res = call_object(func, (object *)NULL); | ||||||
|  | 	DECREF(func); | ||||||
|  | 	return res; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #define BINARY(funcname, methodname) \ | ||||||
|  | static object * funcname(self, other) instanceobject *self; object *other; { \ | ||||||
|  | 	return generic_binary_op(self, other, methodname); \ | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #define UNARY(funcname, methodname) \ | ||||||
|  | static object *funcname(self) instanceobject *self; { \ | ||||||
|  | 	return generic_unary_op(self, methodname); \ | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | BINARY(instance_add, "__add__") | ||||||
|  | BINARY(instance_sub, "__sub__") | ||||||
|  | BINARY(instance_mul, "__mul__") | ||||||
|  | BINARY(instance_div, "__div__") | ||||||
|  | BINARY(instance_mod, "__mod__") | ||||||
|  | BINARY(instance_divmod, "__divmod__") | ||||||
|  | BINARY(instance_pow, "__pow__") | ||||||
|  | UNARY(instance_neg, "__neg__") | ||||||
|  | UNARY(instance_pos, "__pos__") | ||||||
|  | UNARY(instance_abs, "__abs__") | ||||||
|  | 
 | ||||||
|  | int | ||||||
|  | instance_nonzero(self) | ||||||
|  | 	instanceobject *self; | ||||||
|  | { | ||||||
|  | 	object *func, *res; | ||||||
|  | 	long outcome; | ||||||
|  | 
 | ||||||
|  | 	if ((func = instance_getattr(self, "__len__")) == NULL) { | ||||||
|  | 		err_clear(); | ||||||
|  | 		if ((func = instance_getattr(self, "__nonzero__")) == NULL) { | ||||||
|  | 			err_clear(); | ||||||
|  | 			/* Fall back to the default behavior:
 | ||||||
|  | 			   all instances are nonzero */ | ||||||
|  | 			return 1; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	res = call_object(func, (object *)NULL); | ||||||
|  | 	DECREF(func); | ||||||
|  | 	if (res == NULL) | ||||||
|  | 		return -1; | ||||||
|  | 	if (!is_intobject(res)) { | ||||||
|  | 		DECREF(res); | ||||||
|  | 		err_setstr(TypeError, "__nonzero__ should return an int"); | ||||||
|  | 		return -1; | ||||||
|  | 	} | ||||||
|  | 	outcome = getintvalue(res); | ||||||
|  | 	DECREF(res); | ||||||
|  | 	if (outcome < 0) { | ||||||
|  | 		err_setstr(ValueError, "__nonzero__ should return >= 0"); | ||||||
|  | 		return -1; | ||||||
|  | 	} | ||||||
|  | 	return outcome > 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | UNARY(instance_invert, "__invert__") | ||||||
|  | BINARY(instance_lshift, "__lshift__") | ||||||
|  | BINARY(instance_rshift, "__rshift__") | ||||||
|  | BINARY(instance_and, "__and__") | ||||||
|  | BINARY(instance_xor, "__xor__") | ||||||
|  | BINARY(instance_or, "__or__") | ||||||
|  | 
 | ||||||
|  | static number_methods instance_as_number = { | ||||||
|  | 	instance_add,		/*nb_add*/ | ||||||
|  | 	instance_sub,		/*nb_subtract*/ | ||||||
|  | 	instance_mul,		/*nb_multiply*/ | ||||||
|  | 	instance_div,		/*nb_divide*/ | ||||||
|  | 	instance_mod,		/*nb_remainder*/ | ||||||
|  | 	instance_divmod,	/*nb_divmod*/ | ||||||
|  | 	instance_pow,		/*nb_power*/ | ||||||
|  | 	instance_neg,		/*nb_negative*/ | ||||||
|  | 	instance_pos,		/*nb_positive*/ | ||||||
|  | 	instance_abs,		/*nb_absolute*/ | ||||||
|  | 	instance_nonzero,	/*nb_nonzero*/ | ||||||
|  | 	instance_invert,	/*nb_invert*/ | ||||||
|  | 	instance_lshift,	/*nb_lshift*/ | ||||||
|  | 	instance_rshift,	/*nb_rshift*/ | ||||||
|  | 	instance_and,		/*nb_and*/ | ||||||
|  | 	instance_xor,		/*nb_xor*/ | ||||||
|  | 	instance_or,		/*nb_or*/ | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| typeobject Instancetype = { | typeobject Instancetype = { | ||||||
| 	OB_HEAD_INIT(&Typetype) | 	OB_HEAD_INIT(&Typetype) | ||||||
| 	0, | 	0, | ||||||
|  | @ -253,16 +680,76 @@ typeobject Instancetype = { | ||||||
| 	sizeof(instanceobject), | 	sizeof(instanceobject), | ||||||
| 	0, | 	0, | ||||||
| 	instance_dealloc,	/*tp_dealloc*/ | 	instance_dealloc,	/*tp_dealloc*/ | ||||||
| 	0,			/*tp_print*/ | 	instance_print,		/*tp_print*/ | ||||||
| 	instance_getattr,	/*tp_getattr*/ | 	instance_getattr,	/*tp_getattr*/ | ||||||
| 	instance_setattr,	/*tp_setattr*/ | 	instance_setattr,	/*tp_setattr*/ | ||||||
| 	0,			/*tp_compare*/ | 	instance_compare,	/*tp_compare*/ | ||||||
| 	0,			/*tp_repr*/ | 	instance_repr,		/*tp_repr*/ | ||||||
| 	0,			/*tp_as_number*/ | 	&instance_as_number,	/*tp_as_number*/ | ||||||
| 	0,			/*tp_as_sequence*/ | 	&instance_as_sequence,	/*tp_as_sequence*/ | ||||||
| 	0,			/*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 * | ||||||
|  | instance_convert(inst, methodname) | ||||||
|  | 	object *inst; | ||||||
|  | 	char *methodname; | ||||||
|  | { | ||||||
|  | 	return generic_unary_op((instanceobject *)inst, methodname); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| /* And finally, here are instance method objects */ | /* And finally, here are instance method objects */ | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -84,6 +84,24 @@ builtin_chr(self, v) | ||||||
| 	return newsizedstringobject(s, 1); | 	return newsizedstringobject(s, 1); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static object * | ||||||
|  | builtin_coerce(self, args) | ||||||
|  | 	object *self; | ||||||
|  | 	object *args; | ||||||
|  | { | ||||||
|  | 	object *v, *w; | ||||||
|  | 	object *res; | ||||||
|  | 
 | ||||||
|  | 	if (!getargs(args, "(OO)", &v, &w)) | ||||||
|  | 		return NULL; | ||||||
|  | 	if (coerce(&v, &w) < 0) | ||||||
|  | 		return NULL; | ||||||
|  | 	res = mkvalue("(OO)", v, w); | ||||||
|  | 	DECREF(v); | ||||||
|  | 	DECREF(w); | ||||||
|  | 	return res; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static object * | static object * | ||||||
| builtin_dir(self, v) | builtin_dir(self, v) | ||||||
| 	object *self; | 	object *self; | ||||||
|  | @ -250,6 +268,9 @@ builtin_float(self, v) | ||||||
| 		INCREF(v); | 		INCREF(v); | ||||||
| 		return v; | 		return v; | ||||||
| 	} | 	} | ||||||
|  | 	else if (is_instanceobject(v)) { | ||||||
|  | 		return instance_convert(v, "__float__"); | ||||||
|  | 	} | ||||||
| 	err_setstr(TypeError, "float() argument must be int, long or float"); | 	err_setstr(TypeError, "float() argument must be int, long or float"); | ||||||
| 	return NULL; | 	return NULL; | ||||||
| } | } | ||||||
|  | @ -359,6 +380,9 @@ builtin_int(self, v) | ||||||
| 		/* XXX should check for overflow */ | 		/* XXX should check for overflow */ | ||||||
| 		return newintobject((long)x); | 		return newintobject((long)x); | ||||||
| 	} | 	} | ||||||
|  | 	else if (is_instanceobject(v)) { | ||||||
|  | 		return instance_convert(v, "__int__"); | ||||||
|  | 	} | ||||||
| 	err_setstr(TypeError, "int() argument must be int, long or float"); | 	err_setstr(TypeError, "int() argument must be int, long or float"); | ||||||
| 	return NULL; | 	return NULL; | ||||||
| } | } | ||||||
|  | @ -385,7 +409,10 @@ builtin_len(self, v) | ||||||
| 		err_setstr(TypeError, "len() of unsized object"); | 		err_setstr(TypeError, "len() of unsized object"); | ||||||
| 		return NULL; | 		return NULL; | ||||||
| 	} | 	} | ||||||
| 	return newintobject(len); | 	if (len < 0) | ||||||
|  | 		return NULL; | ||||||
|  | 	else | ||||||
|  | 		return newintobject(len); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static object * | static object * | ||||||
|  | @ -407,6 +434,9 @@ builtin_long(self, v) | ||||||
| 		double x = getfloatvalue(v); | 		double x = getfloatvalue(v); | ||||||
| 		return dnewlongobject(x); | 		return dnewlongobject(x); | ||||||
| 	} | 	} | ||||||
|  | 	else if (is_instanceobject(v)) { | ||||||
|  | 		return instance_convert(v, "__long__"); | ||||||
|  | 	} | ||||||
| 	err_setstr(TypeError, "long() argument must be int, long or float"); | 	err_setstr(TypeError, "long() argument must be int, long or float"); | ||||||
| 	return NULL; | 	return NULL; | ||||||
| } | } | ||||||
|  | @ -648,6 +678,7 @@ static struct methodlist builtin_methods[] = { | ||||||
| 	{"abs",		builtin_abs}, | 	{"abs",		builtin_abs}, | ||||||
| 	{"apply",	builtin_apply}, | 	{"apply",	builtin_apply}, | ||||||
| 	{"chr",		builtin_chr}, | 	{"chr",		builtin_chr}, | ||||||
|  | 	{"coerce",	builtin_coerce}, | ||||||
| 	{"dir",		builtin_dir}, | 	{"dir",		builtin_dir}, | ||||||
| 	{"divmod",	builtin_divmod}, | 	{"divmod",	builtin_divmod}, | ||||||
| 	{"eval",	builtin_eval}, | 	{"eval",	builtin_eval}, | ||||||
|  | @ -766,6 +797,8 @@ coerce(pv, pw) | ||||||
| 		INCREF(w); | 		INCREF(w); | ||||||
| 		return 0; | 		return 0; | ||||||
| 	} | 	} | ||||||
|  | 	if (is_instanceobject(v) || is_instanceobject(w)) | ||||||
|  | 		return instance_coerce(pv, pw); | ||||||
| 	if (v->ob_type->tp_as_number == NULL || | 	if (v->ob_type->tp_as_number == NULL || | ||||||
| 					w->ob_type->tp_as_number == NULL) { | 					w->ob_type->tp_as_number == NULL) { | ||||||
| 		err_setstr(TypeError, "mixing number and non-number"); | 		err_setstr(TypeError, "mixing number and non-number"); | ||||||
|  |  | ||||||
							
								
								
									
										106
									
								
								Python/ceval.c
									
										
									
									
									
								
							
							
						
						
									
										106
									
								
								Python/ceval.c
									
										
									
									
									
								
							|  | @ -36,6 +36,9 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||||||
| #include "bltinmodule.h" | #include "bltinmodule.h" | ||||||
| #include "traceback.h" | #include "traceback.h" | ||||||
| 
 | 
 | ||||||
|  | /* Turn this on if your compiler chokes on the big switch: */ | ||||||
|  | /* #define CASE_TOO_BIG 1 /**/ | ||||||
|  | 
 | ||||||
| #ifndef NDEBUG | #ifndef NDEBUG | ||||||
| /* For debugging the interpreter: */ | /* For debugging the interpreter: */ | ||||||
| #define LLTRACE  1	/* Low-level trace feature */ | #define LLTRACE  1	/* Low-level trace feature */ | ||||||
|  | @ -106,13 +109,13 @@ init_save_thread() | ||||||
|    dynamically loaded modules needn't be compiled separately for use |    dynamically loaded modules needn't be compiled separately for use | ||||||
|    with and without threads: */ |    with and without threads: */ | ||||||
| 
 | 
 | ||||||
| void * | object * | ||||||
| save_thread() | save_thread() | ||||||
| { | { | ||||||
| #ifdef USE_THREAD | #ifdef USE_THREAD | ||||||
| 	if (interpreter_lock) { | 	if (interpreter_lock) { | ||||||
| 		void *res; | 		object *res; | ||||||
| 		res = (void *)current_frame; | 		res = (object *)current_frame; | ||||||
| 		current_frame = NULL; | 		current_frame = NULL; | ||||||
| 		release_lock(interpreter_lock); | 		release_lock(interpreter_lock); | ||||||
| 		return res; | 		return res; | ||||||
|  | @ -124,7 +127,7 @@ save_thread() | ||||||
| 
 | 
 | ||||||
| void | void | ||||||
| restore_thread(x) | restore_thread(x) | ||||||
| 	void *x; | 	object *x; | ||||||
| { | { | ||||||
| #ifdef USE_THREAD | #ifdef USE_THREAD | ||||||
| 	if (interpreter_lock) { | 	if (interpreter_lock) { | ||||||
|  | @ -722,6 +725,10 @@ eval_code(co, globals, locals, arg) | ||||||
| 			if ((err = dict2remove(f->f_locals, w)) != 0) | 			if ((err = dict2remove(f->f_locals, w)) != 0) | ||||||
| 				err_setstr(NameError, getstringvalue(w)); | 				err_setstr(NameError, getstringvalue(w)); | ||||||
| 			break; | 			break; | ||||||
|  | 
 | ||||||
|  | #ifdef CASE_TOO_BIG | ||||||
|  | 		default: switch (opcode) { | ||||||
|  | #endif | ||||||
| 		 | 		 | ||||||
| 		case UNPACK_VARARG: | 		case UNPACK_VARARG: | ||||||
| 			if (EMPTY()) { | 			if (EMPTY()) { | ||||||
|  | @ -1023,13 +1030,19 @@ eval_code(co, globals, locals, arg) | ||||||
| 			break; | 			break; | ||||||
| 		 | 		 | ||||||
| 		case JUMP_IF_FALSE: | 		case JUMP_IF_FALSE: | ||||||
| 			if (!testbool(TOP())) | 			err = testbool(TOP()); | ||||||
|  | 			if (err > 0) | ||||||
|  | 				err = 0; | ||||||
|  | 			else if (err == 0) | ||||||
| 				JUMPBY(oparg); | 				JUMPBY(oparg); | ||||||
| 			break; | 			break; | ||||||
| 		 | 		 | ||||||
| 		case JUMP_IF_TRUE: | 		case JUMP_IF_TRUE: | ||||||
| 			if (testbool(TOP())) | 			err = testbool(TOP()); | ||||||
|  | 			if (err > 0) { | ||||||
|  | 				err = 0; | ||||||
| 				JUMPBY(oparg); | 				JUMPBY(oparg); | ||||||
|  | 			} | ||||||
| 			break; | 			break; | ||||||
| 		 | 		 | ||||||
| 		case JUMP_ABSOLUTE: | 		case JUMP_ABSOLUTE: | ||||||
|  | @ -1092,7 +1105,11 @@ eval_code(co, globals, locals, arg) | ||||||
| 			err_setstr(SystemError, "eval_code: unknown opcode"); | 			err_setstr(SystemError, "eval_code: unknown opcode"); | ||||||
| 			why = WHY_EXCEPTION; | 			why = WHY_EXCEPTION; | ||||||
| 			break; | 			break; | ||||||
| 		 | 
 | ||||||
|  | #ifdef CASE_TOO_BIG | ||||||
|  | 		} | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| 		} /* switch */ | 		} /* switch */ | ||||||
| 
 | 
 | ||||||
| 	    on_error: | 	    on_error: | ||||||
|  | @ -1388,22 +1405,27 @@ flushline() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| /* Test a value used as condition, e.g., in a for or if statement */ | /* Test a value used as condition, e.g., in a for or if statement.
 | ||||||
|  |    Return -1 if an error occurred */ | ||||||
| 
 | 
 | ||||||
| static int | static int | ||||||
| testbool(v) | testbool(v) | ||||||
| 	object *v; | 	object *v; | ||||||
| { | { | ||||||
|  | 	int res; | ||||||
| 	if (v == None) | 	if (v == None) | ||||||
| 		return 0; | 		res = 0; | ||||||
| 	if (v->ob_type->tp_as_number != NULL) | 	else if (v->ob_type->tp_as_number != NULL) | ||||||
| 		return (*v->ob_type->tp_as_number->nb_nonzero)(v); | 		res = (*v->ob_type->tp_as_number->nb_nonzero)(v); | ||||||
| 	if (v->ob_type->tp_as_sequence != NULL) | 	else if (v->ob_type->tp_as_mapping != NULL) | ||||||
| 		return (*v->ob_type->tp_as_sequence->sq_length)(v) != 0; | 		res = (*v->ob_type->tp_as_mapping->mp_length)(v); | ||||||
| 	if (v->ob_type->tp_as_mapping != NULL) | 	else if (v->ob_type->tp_as_sequence != NULL) | ||||||
| 		return (*v->ob_type->tp_as_mapping->mp_length)(v) != 0; | 		res = (*v->ob_type->tp_as_sequence->sq_length)(v); | ||||||
| 	/* All other objects are 'true' */ | 	else | ||||||
| 	return 1; | 		res = 0; | ||||||
|  | 	if (res > 0) | ||||||
|  | 		res = 1; | ||||||
|  | 	return res; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static object * | static object * | ||||||
|  | @ -1649,7 +1671,13 @@ not(v) | ||||||
| 	object *v; | 	object *v; | ||||||
| { | { | ||||||
| 	int outcome = testbool(v); | 	int outcome = testbool(v); | ||||||
| 	object *w = outcome == 0 ? True : False; | 	object *w; | ||||||
|  | 	if (outcome < 0) | ||||||
|  | 		return NULL; | ||||||
|  | 	if (outcome == 0) | ||||||
|  | 		w = True; | ||||||
|  | 	else | ||||||
|  | 		w = False; | ||||||
| 	INCREF(w); | 	INCREF(w); | ||||||
| 	return w; | 	return w; | ||||||
| } | } | ||||||
|  | @ -1780,18 +1808,24 @@ apply_subscript(v, w) | ||||||
| 		err_setstr(TypeError, "unsubscriptable object"); | 		err_setstr(TypeError, "unsubscriptable object"); | ||||||
| 		return NULL; | 		return NULL; | ||||||
| 	} | 	} | ||||||
| 	if (tp->tp_as_sequence != NULL) { | 	if (tp->tp_as_mapping != NULL) { | ||||||
|  | 		return (*tp->tp_as_mapping->mp_subscript)(v, w); | ||||||
|  | 	} | ||||||
|  | 	else { | ||||||
| 		int i; | 		int i; | ||||||
| 		if (!is_intobject(w)) { | 		if (!is_intobject(w)) { | ||||||
| 			err_setstr(TypeError, "sequence subscript not int"); | 			err_setstr(TypeError, "sequence subscript not int"); | ||||||
| 			return NULL; | 			return NULL; | ||||||
| 		} | 		} | ||||||
| 		i = getintvalue(w); | 		i = getintvalue(w); | ||||||
| 		if (i < 0) | 		if (i < 0) { | ||||||
| 			i += (*tp->tp_as_sequence->sq_length)(v); | 			int len = (*tp->tp_as_sequence->sq_length)(v); | ||||||
|  | 			if (len < 0) | ||||||
|  | 				return NULL; | ||||||
|  | 			i += len; | ||||||
|  | 		} | ||||||
| 		return (*tp->tp_as_sequence->sq_item)(v, i); | 		return (*tp->tp_as_sequence->sq_item)(v, i); | ||||||
| 	} | 	} | ||||||
| 	return (*tp->tp_as_mapping->mp_subscript)(v, w); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static object * | static object * | ||||||
|  | @ -1841,6 +1875,8 @@ apply_slice(u, v, w) /* return u[v:w] */ | ||||||
| 	} | 	} | ||||||
| 	ilow = 0; | 	ilow = 0; | ||||||
| 	isize = ihigh = (*tp->tp_as_sequence->sq_length)(u); | 	isize = ihigh = (*tp->tp_as_sequence->sq_length)(u); | ||||||
|  | 	if (isize < 0) | ||||||
|  | 		return NULL; | ||||||
| 	if (slice_index(v, isize, &ilow) != 0) | 	if (slice_index(v, isize, &ilow) != 0) | ||||||
| 		return NULL; | 		return NULL; | ||||||
| 	if (slice_index(w, isize, &ihigh) != 0) | 	if (slice_index(w, isize, &ihigh) != 0) | ||||||
|  | @ -1858,7 +1894,11 @@ assign_subscript(w, key, v) /* w[key] = v */ | ||||||
| 	sequence_methods *sq; | 	sequence_methods *sq; | ||||||
| 	mapping_methods *mp; | 	mapping_methods *mp; | ||||||
| 	int (*func)(); | 	int (*func)(); | ||||||
| 	if ((sq = tp->tp_as_sequence) != NULL && | 	if ((mp = tp->tp_as_mapping) != NULL && | ||||||
|  | 			(func = mp->mp_ass_subscript) != NULL) { | ||||||
|  | 		return (*func)(w, key, v); | ||||||
|  | 	} | ||||||
|  | 	else if ((sq = tp->tp_as_sequence) != NULL && | ||||||
| 			(func = sq->sq_ass_item) != NULL) { | 			(func = sq->sq_ass_item) != NULL) { | ||||||
| 		if (!is_intobject(key)) { | 		if (!is_intobject(key)) { | ||||||
| 			err_setstr(TypeError, | 			err_setstr(TypeError, | ||||||
|  | @ -1867,15 +1907,15 @@ assign_subscript(w, key, v) /* w[key] = v */ | ||||||
| 		} | 		} | ||||||
| 		else { | 		else { | ||||||
| 			int i = getintvalue(key); | 			int i = getintvalue(key); | ||||||
| 			if (i < 0) | 			if (i < 0) { | ||||||
| 				i += (*sq->sq_length)(w); | 				int len = (*sq->sq_length)(w); | ||||||
|  | 				if (len < 0) | ||||||
|  | 					return -1; | ||||||
|  | 				i += len; | ||||||
|  | 			} | ||||||
| 			return (*func)(w, i, v); | 			return (*func)(w, i, v); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	else if ((mp = tp->tp_as_mapping) != NULL && |  | ||||||
| 			(func = mp->mp_ass_subscript) != NULL) { |  | ||||||
| 		return (*func)(w, key, v); |  | ||||||
| 	} |  | ||||||
| 	else { | 	else { | ||||||
| 		err_setstr(TypeError, | 		err_setstr(TypeError, | ||||||
| 				"can't assign to this subscripted object"); | 				"can't assign to this subscripted object"); | ||||||
|  | @ -1899,6 +1939,8 @@ assign_slice(u, v, w, x) /* u[v:w] = x */ | ||||||
| 	} | 	} | ||||||
| 	ilow = 0; | 	ilow = 0; | ||||||
| 	isize = ihigh = (*sq->sq_length)(u); | 	isize = ihigh = (*sq->sq_length)(u); | ||||||
|  | 	if (isize < 0) | ||||||
|  | 		return -1; | ||||||
| 	if (slice_index(v, isize, &ilow) != 0) | 	if (slice_index(v, isize, &ilow) != 0) | ||||||
| 		return -1; | 		return -1; | ||||||
| 	if (slice_index(w, isize, &ihigh) != 0) | 	if (slice_index(w, isize, &ihigh) != 0) | ||||||
|  | @ -1955,6 +1997,8 @@ cmp_member(v, w) | ||||||
| 		return -1; | 		return -1; | ||||||
| 	} | 	} | ||||||
| 	n = (*sq->sq_length)(w); | 	n = (*sq->sq_length)(w); | ||||||
|  | 	if (n < 0) | ||||||
|  | 		return -1; | ||||||
| 	for (i = 0; i < n; i++) { | 	for (i = 0; i < n; i++) { | ||||||
| 		x = (*sq->sq_item)(w, i); | 		x = (*sq->sq_item)(w, i); | ||||||
| 		cmp = cmpobject(v, x); | 		cmp = cmpobject(v, x); | ||||||
|  | @ -1977,7 +2021,7 @@ cmp_outcome(op, v, w) | ||||||
| 	case IS: | 	case IS: | ||||||
| 	case IS_NOT: | 	case IS_NOT: | ||||||
| 		res = (v == w); | 		res = (v == w); | ||||||
| 		if (op == IS_NOT) | 		if (op == (int) IS_NOT) | ||||||
| 			res = !res; | 			res = !res; | ||||||
| 		break; | 		break; | ||||||
| 	case IN: | 	case IN: | ||||||
|  | @ -1985,7 +2029,7 @@ cmp_outcome(op, v, w) | ||||||
| 		res = cmp_member(v, w); | 		res = cmp_member(v, w); | ||||||
| 		if (res < 0) | 		if (res < 0) | ||||||
| 			return NULL; | 			return NULL; | ||||||
| 		if (op == NOT_IN) | 		if (op == (int) NOT_IN) | ||||||
| 			res = !res; | 			res = !res; | ||||||
| 		break; | 		break; | ||||||
| 	case EXC_MATCH: | 	case EXC_MATCH: | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Guido van Rossum
						Guido van Rossum