next: implement equality
This commit is contained in:
parent
58ba150c93
commit
653082c4d8
3 changed files with 96 additions and 26 deletions
|
|
@ -1,4 +1,5 @@
|
||||||
#include <growl.h>
|
#include <growl.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
uint32_t growl_type(Growl obj) {
|
uint32_t growl_type(Growl obj) {
|
||||||
if (obj == GROWL_NIL)
|
if (obj == GROWL_NIL)
|
||||||
|
|
@ -10,9 +11,65 @@ uint32_t growl_type(Growl obj) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int growl_equals(Growl a, Growl b) {
|
int growl_equals(Growl a, Growl b) {
|
||||||
if (a != b)
|
if (a == b)
|
||||||
return 0;
|
|
||||||
if (growl_type(a) != growl_type(b))
|
|
||||||
return 0;
|
|
||||||
return 1;
|
return 1;
|
||||||
|
uint32_t type_a = growl_type(a);
|
||||||
|
uint32_t type_b = growl_type(b);
|
||||||
|
if (type_a != type_b)
|
||||||
|
return 0;
|
||||||
|
switch (type_a) {
|
||||||
|
case GROWL_TYPE_NIL:
|
||||||
|
case GROWL_TYPE_NUMBER:
|
||||||
|
// Already checked by pointer equality
|
||||||
|
return 0;
|
||||||
|
case GROWL_TYPE_STRING: {
|
||||||
|
GrowlString *str_a = growl_unwrap_string(a);
|
||||||
|
GrowlString *str_b = growl_unwrap_string(b);
|
||||||
|
if (str_a->len != str_b->len)
|
||||||
|
return 0;
|
||||||
|
return memcmp(str_a->data, str_b->data, str_a->len) == 0;
|
||||||
|
}
|
||||||
|
case GROWL_TYPE_LIST: {
|
||||||
|
GrowlList *list_a = (GrowlList *)(GROWL_UNBOX(a) + 1);
|
||||||
|
GrowlList *list_b = (GrowlList *)(GROWL_UNBOX(b) + 1);
|
||||||
|
return growl_equals(list_a->head, list_b->head) &&
|
||||||
|
growl_equals(list_a->tail, list_b->tail);
|
||||||
|
}
|
||||||
|
case GROWL_TYPE_TUPLE: {
|
||||||
|
GrowlTuple *tuple_a = growl_unwrap_tuple(a);
|
||||||
|
GrowlTuple *tuple_b = growl_unwrap_tuple(b);
|
||||||
|
if (tuple_a->count != tuple_b->count)
|
||||||
|
return 0;
|
||||||
|
for (size_t i = 0; i < tuple_a->count; i++) {
|
||||||
|
if (!growl_equals(tuple_a->data[i], tuple_b->data[i]))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
case GROWL_TYPE_QUOTATION: {
|
||||||
|
GrowlQuotation *quot_a = (GrowlQuotation *)(GROWL_UNBOX(a) + 1);
|
||||||
|
GrowlQuotation *quot_b = (GrowlQuotation *)(GROWL_UNBOX(b) + 1);
|
||||||
|
if (quot_a->count != quot_b->count)
|
||||||
|
return 0;
|
||||||
|
if (memcmp(quot_a->data, quot_b->data, quot_a->count) != 0)
|
||||||
|
return 0;
|
||||||
|
return growl_equals(quot_a->constants, quot_b->constants);
|
||||||
|
}
|
||||||
|
case GROWL_TYPE_COMPOSE: {
|
||||||
|
GrowlCompose *comp_a = (GrowlCompose *)(GROWL_UNBOX(a) + 1);
|
||||||
|
GrowlCompose *comp_b = (GrowlCompose *)(GROWL_UNBOX(b) + 1);
|
||||||
|
return growl_equals(comp_a->first, comp_b->first) &&
|
||||||
|
growl_equals(comp_a->second, comp_b->second);
|
||||||
|
}
|
||||||
|
case GROWL_TYPE_CURRY: {
|
||||||
|
GrowlCurry *curry_a = (GrowlCurry *)(GROWL_UNBOX(a) + 1);
|
||||||
|
GrowlCurry *curry_b = (GrowlCurry *)(GROWL_UNBOX(b) + 1);
|
||||||
|
return growl_equals(curry_a->value, curry_b->value) &&
|
||||||
|
growl_equals(curry_a->callable, curry_b->callable);
|
||||||
|
}
|
||||||
|
case GROWL_TYPE_TABLE:
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -109,21 +109,11 @@ static GrowlFrame callstack_pop(GrowlVM *vm) {
|
||||||
return *--vm->csp;
|
return *--vm->csp;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void root_constants(GrowlVM *vm, GrowlQuotation *quot) {
|
|
||||||
GrowlTuple *constants = growl_unwrap_tuple(quot->constants);
|
|
||||||
if (constants != NULL) {
|
|
||||||
for (size_t i = 0; i < constants->count; ++i) {
|
|
||||||
growl_gc_root(vm, &constants->data[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void dispatch(GrowlVM *vm, Growl obj) {
|
static inline void dispatch(GrowlVM *vm, Growl obj) {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
switch (growl_type(obj)) {
|
switch (growl_type(obj)) {
|
||||||
case GROWL_TYPE_QUOTATION: {
|
case GROWL_TYPE_QUOTATION: {
|
||||||
GrowlQuotation *q = (GrowlQuotation *)(GROWL_UNBOX(obj) + 1);
|
GrowlQuotation *q = (GrowlQuotation *)(GROWL_UNBOX(obj) + 1);
|
||||||
root_constants(vm, q);
|
|
||||||
vm->current_quotation = q;
|
vm->current_quotation = q;
|
||||||
vm->ip = q->data;
|
vm->ip = q->data;
|
||||||
return;
|
return;
|
||||||
|
|
@ -156,8 +146,6 @@ int growl_vm_execute(GrowlVM *vm, GrowlQuotation *quot) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
root_constants(vm, quot);
|
|
||||||
|
|
||||||
vm->ip = quot->data;
|
vm->ip = quot->data;
|
||||||
vm->current_quotation = quot;
|
vm->current_quotation = quot;
|
||||||
|
|
||||||
|
|
@ -334,7 +322,7 @@ int growl_vm_execute(GrowlVM *vm, GrowlQuotation *quot) {
|
||||||
if (GROWL_IMM(b) && GROWL_IMM(a)) { \
|
if (GROWL_IMM(b) && GROWL_IMM(a)) { \
|
||||||
growl_push(vm, GROWL_NUM(GROWL_ORD(a) op GROWL_ORD(b))); \
|
growl_push(vm, GROWL_NUM(GROWL_ORD(a) op GROWL_ORD(b))); \
|
||||||
} else { \
|
} else { \
|
||||||
vm_error(vm, "arithmetic on non-numbers"); \
|
vm_error(vm, "numeric op on non-numbers"); \
|
||||||
} \
|
} \
|
||||||
VM_NEXT(); \
|
VM_NEXT(); \
|
||||||
}
|
}
|
||||||
|
|
@ -350,7 +338,7 @@ int growl_vm_execute(GrowlVM *vm, GrowlQuotation *quot) {
|
||||||
vm_error(vm, "division by zero");
|
vm_error(vm, "division by zero");
|
||||||
growl_push(vm, GROWL_NUM(GROWL_ORD(a) / GROWL_ORD(b)));
|
growl_push(vm, GROWL_NUM(GROWL_ORD(a) / GROWL_ORD(b)));
|
||||||
} else {
|
} else {
|
||||||
vm_error(vm, "arithmetic on non-numbers");
|
vm_error(vm, "numeric op on non-numbers");
|
||||||
};
|
};
|
||||||
VM_NEXT();
|
VM_NEXT();
|
||||||
}
|
}
|
||||||
|
|
@ -362,7 +350,7 @@ int growl_vm_execute(GrowlVM *vm, GrowlQuotation *quot) {
|
||||||
vm_error(vm, "division by zero");
|
vm_error(vm, "division by zero");
|
||||||
growl_push(vm, GROWL_NUM(GROWL_ORD(a) % GROWL_ORD(b)));
|
growl_push(vm, GROWL_NUM(GROWL_ORD(a) % GROWL_ORD(b)));
|
||||||
} else {
|
} else {
|
||||||
vm_error(vm, "arithmetic on non-numbers");
|
vm_error(vm, "numeric op on non-numbers");
|
||||||
};
|
};
|
||||||
VM_NEXT();
|
VM_NEXT();
|
||||||
}
|
}
|
||||||
|
|
@ -378,6 +366,28 @@ int growl_vm_execute(GrowlVM *vm, GrowlQuotation *quot) {
|
||||||
}
|
}
|
||||||
VM_NEXT();
|
VM_NEXT();
|
||||||
}
|
}
|
||||||
|
VM_OP(EQ) {
|
||||||
|
Growl b = growl_pop(vm);
|
||||||
|
Growl a = growl_pop(vm);
|
||||||
|
int equals = growl_equals(a, b);
|
||||||
|
if (equals) {
|
||||||
|
growl_push(vm, GROWL_NUM(1));
|
||||||
|
} else {
|
||||||
|
growl_push(vm, GROWL_NIL);
|
||||||
|
}
|
||||||
|
VM_NEXT();
|
||||||
|
}
|
||||||
|
VM_OP(NEQ) {
|
||||||
|
Growl b = growl_pop(vm);
|
||||||
|
Growl a = growl_pop(vm);
|
||||||
|
int equals = growl_equals(a, b);
|
||||||
|
if (!equals) {
|
||||||
|
growl_push(vm, GROWL_NUM(1));
|
||||||
|
} else {
|
||||||
|
growl_push(vm, GROWL_NIL);
|
||||||
|
}
|
||||||
|
VM_NEXT();
|
||||||
|
}
|
||||||
VM_DEFAULT() { vm_error(vm, "unknown opcode %d", opcode); }
|
VM_DEFAULT() { vm_error(vm, "unknown opcode %d", opcode); }
|
||||||
VM_END()
|
VM_END()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -46,19 +46,22 @@ enum {
|
||||||
GROWL_TYPE_ALIEN,
|
GROWL_TYPE_ALIEN,
|
||||||
};
|
};
|
||||||
|
|
||||||
uint32_t growl_type(Growl obj);
|
|
||||||
uint64_t growl_hash_combine(uint64_t a, uint64_t b);
|
|
||||||
uint64_t growl_hash_bytes(const uint8_t *data, size_t len);
|
|
||||||
uint64_t growl_hash(Growl obj);
|
|
||||||
void growl_print_to(FILE *file, Growl value);
|
|
||||||
void growl_print(Growl value);
|
|
||||||
void growl_println(Growl value);
|
|
||||||
|
|
||||||
struct GrowlObjectHeader {
|
struct GrowlObjectHeader {
|
||||||
size_t size;
|
size_t size;
|
||||||
uint32_t type;
|
uint32_t type;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
uint32_t growl_type(Growl obj);
|
||||||
|
uint64_t growl_hash_combine(uint64_t a, uint64_t b);
|
||||||
|
uint64_t growl_hash_bytes(const uint8_t *data, size_t len);
|
||||||
|
uint64_t growl_hash(Growl obj);
|
||||||
|
|
||||||
|
void growl_print_to(FILE *file, Growl value);
|
||||||
|
void growl_print(Growl value);
|
||||||
|
void growl_println(Growl value);
|
||||||
|
|
||||||
|
int growl_equals(Growl a, Growl b);
|
||||||
|
|
||||||
struct GrowlString {
|
struct GrowlString {
|
||||||
size_t len;
|
size_t len;
|
||||||
char data[];
|
char data[];
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue