maybe support __eq__?

This commit is contained in:
K. Lange 2021-01-05 17:41:32 +09:00
parent 181e378628
commit 2f78ae8770
4 changed files with 55 additions and 26 deletions

View File

@ -96,6 +96,7 @@ typedef struct KrkClass {
KrkObj * _tostr;
KrkObj * _call;
KrkObj * _init;
KrkObj * _eq;
} KrkClass;
typedef struct {

76
value.c
View File

@ -96,32 +96,56 @@ void krk_printValueSafe(FILE * f, KrkValue printable) {
}
int krk_valuesEqual(KrkValue a, KrkValue b) {
if (a.type != b.type) return 0; /* uh, maybe not, this is complicated */
switch (a.type) {
case VAL_BOOLEAN: return AS_BOOLEAN(a) == AS_BOOLEAN(b);
case VAL_NONE: return 1; /* None always equals None */
case VAL_KWARGS: /* Equal if same number of args; may be useful for comparing sentinels (0) to arg lists. */
case VAL_INTEGER: return AS_INTEGER(a) == AS_INTEGER(b);
case VAL_FLOATING: return AS_FLOATING(a) == AS_FLOATING(b);
case VAL_HANDLER: {
fprintf(stderr, "Attempted to compare a value to an exception handler. VM leaked a stack value.\n");
exit(1);
if (a.type == b.type) {
switch (a.type) {
case VAL_BOOLEAN: return AS_BOOLEAN(a) == AS_BOOLEAN(b);
case VAL_NONE: return 1; /* None always equals None */
case VAL_KWARGS: /* Equal if same number of args; may be useful for comparing sentinels (0) to arg lists. */
case VAL_INTEGER: return AS_INTEGER(a) == AS_INTEGER(b);
case VAL_FLOATING: return AS_FLOATING(a) == AS_FLOATING(b);
case VAL_HANDLER: krk_runtimeError(vm.exceptions.valueError,"Invalid value"); return 0;
case VAL_OBJECT: {
if (AS_OBJECT(a) == AS_OBJECT(b)) return 1;
} break;
default: break;
}
case VAL_OBJECT: {
if (IS_STRING(a) && IS_STRING(b)) return AS_OBJECT(a) == AS_OBJECT(b);
/* If their pointers are equal, assume they are always equivalent */
if (IS_TUPLE(a) && IS_TUPLE(b)) {
if (AS_TUPLE(a)->values.count != AS_TUPLE(b)->values.count) return 0;
for (size_t i = 0; i < AS_TUPLE(a)->values.count; ++i) {
if (!krk_valuesEqual(AS_TUPLE(a)->values.values[i], AS_TUPLE(b)->values.values[i])) return 0;
}
return 1;
}
if (AS_OBJECT(a) == AS_OBJECT(b)) return 1;
/* TODO: __eq__ */
return 0;
}
default: return 0;
}
if (!IS_OBJECT(a) && !IS_OBJECT(b)) {
switch (a.type) {
case VAL_INTEGER: {
switch (b.type) {
case VAL_BOOLEAN: return AS_INTEGER(a) == AS_BOOLEAN(b);
case VAL_FLOATING: return (double)AS_INTEGER(a) == AS_FLOATING(b);
default: return 0;
}
} break;
case VAL_FLOATING: {
switch (b.type) {
case VAL_BOOLEAN: return AS_FLOATING(a) == (double)AS_BOOLEAN(b);
case VAL_INTEGER: return AS_FLOATING(a) == (double)AS_INTEGER(b);
default: return 0;
}
} break;
case VAL_BOOLEAN: {
switch (b.type) {
case VAL_INTEGER: return AS_BOOLEAN(a) == AS_INTEGER(b);
case VAL_FLOATING: return (double)AS_BOOLEAN(a) == AS_FLOATING(b);
default: return 0;
}
} break;
default: return 0;
}
}
KrkClass * type = AS_CLASS(krk_typeOf(1,(KrkValue[]){a}));
if (type && type->_eq) {
krk_push(a);
krk_push(b);
KrkValue result = krk_callSimple(OBJECT_VAL(type->_eq),2,0);
if (IS_BOOLEAN(result)) return AS_BOOLEAN(result);
return 0;
}
return 0;
}

2
vm.c
View File

@ -225,6 +225,7 @@ void krk_finalizeClass(KrkClass * _class) {
{&_class->_tostr, METHOD_STR},
{&_class->_call, METHOD_CALL},
{&_class->_init, METHOD_INIT},
{&_class->_eq, METHOD_EQ},
{NULL, 0},
};
@ -2385,6 +2386,7 @@ void krk_initVM(int flags) {
vm.specialMethodNames[METHOD_LIST_INT] = OBJECT_VAL(S("__list"));
vm.specialMethodNames[METHOD_DICT_INT] = OBJECT_VAL(S("__dict"));
vm.specialMethodNames[METHOD_INREPR] = OBJECT_VAL(S("__inrepr"));
vm.specialMethodNames[METHOD_EQ] = OBJECT_VAL(S("__eq__"));
/* Create built-in class `object` */
vm.objectClass = krk_newClass(S("object"));

2
vm.h
View File

@ -37,6 +37,7 @@ typedef enum {
METHOD_INREPR,
METHOD_ORD,
METHOD_CALL,
METHOD_EQ,
METHOD__MAX,
} KrkSpecialMethods;
@ -133,3 +134,4 @@ extern int krk_bindMethod(KrkClass * _class, KrkString * name);
extern int krk_callValue(KrkValue callee, int argCount, int extra);
extern KrkValue krk_dict_of(int argc, KrkValue argv[]);
extern KrkValue krk_callSimple(KrkValue value, int argCount, int isMethod);