diff --git a/next/core/value.c b/next/core/value.c index db781ea..828b2a8 100644 --- a/next/core/value.c +++ b/next/core/value.c @@ -1,4 +1,5 @@ #include +#include uint32_t growl_type(Growl obj) { if (obj == GROWL_NIL) @@ -10,9 +11,65 @@ uint32_t growl_type(Growl obj) { } int growl_equals(Growl a, Growl b) { - if (a != b) + if (a == b) + return 1; + uint32_t type_a = growl_type(a); + uint32_t type_b = growl_type(b); + if (type_a != type_b) return 0; - if (growl_type(a) != growl_type(b)) + switch (type_a) { + case GROWL_TYPE_NIL: + case GROWL_TYPE_NUMBER: + // Already checked by pointer equality return 0; - return 1; + 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; + } } diff --git a/next/core/vm.c b/next/core/vm.c index afc7619..a574ffa 100644 --- a/next/core/vm.c +++ b/next/core/vm.c @@ -109,21 +109,11 @@ static GrowlFrame callstack_pop(GrowlVM *vm) { 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) { for (;;) { switch (growl_type(obj)) { case GROWL_TYPE_QUOTATION: { GrowlQuotation *q = (GrowlQuotation *)(GROWL_UNBOX(obj) + 1); - root_constants(vm, q); vm->current_quotation = q; vm->ip = q->data; return; @@ -156,8 +146,6 @@ int growl_vm_execute(GrowlVM *vm, GrowlQuotation *quot) { return result; } - root_constants(vm, quot); - vm->ip = quot->data; vm->current_quotation = quot; @@ -334,7 +322,7 @@ int growl_vm_execute(GrowlVM *vm, GrowlQuotation *quot) { if (GROWL_IMM(b) && GROWL_IMM(a)) { \ growl_push(vm, GROWL_NUM(GROWL_ORD(a) op GROWL_ORD(b))); \ } else { \ - vm_error(vm, "arithmetic on non-numbers"); \ + vm_error(vm, "numeric op on non-numbers"); \ } \ VM_NEXT(); \ } @@ -350,7 +338,7 @@ int growl_vm_execute(GrowlVM *vm, GrowlQuotation *quot) { vm_error(vm, "division by zero"); growl_push(vm, GROWL_NUM(GROWL_ORD(a) / GROWL_ORD(b))); } else { - vm_error(vm, "arithmetic on non-numbers"); + vm_error(vm, "numeric op on non-numbers"); }; VM_NEXT(); } @@ -362,7 +350,7 @@ int growl_vm_execute(GrowlVM *vm, GrowlQuotation *quot) { vm_error(vm, "division by zero"); growl_push(vm, GROWL_NUM(GROWL_ORD(a) % GROWL_ORD(b))); } else { - vm_error(vm, "arithmetic on non-numbers"); + vm_error(vm, "numeric op on non-numbers"); }; VM_NEXT(); } @@ -378,6 +366,28 @@ int growl_vm_execute(GrowlVM *vm, GrowlQuotation *quot) { } 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_END() diff --git a/next/include/growl.h b/next/include/growl.h index c518432..3821f55 100644 --- a/next/include/growl.h +++ b/next/include/growl.h @@ -46,19 +46,22 @@ enum { 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 { size_t size; 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 { size_t len; char data[];