#include "../include/value.h" #include "../include/std_gc/hash_map.h" #include #include #ifdef DEBUG #define GC_DEBUG #endif #include static uint64_t hash_range(const uint8_t *data, size_t size) { uint64_t result = 0xdec05eba; while(size) { result = ((result << 5) + result) + *data; ++data; --size; } return result; } static void tsl_string_to_ref(const TslString *self, TslStringView *result) { result->data = self->data; result->size = self->size; } uint64_t tsl_value_hash(const TslValue *key) { switch((TslType)key->type) { case TSL_TYPE_NULL: return 0; case TSL_TYPE_NUMBER: return *(uint64_t*)&key->data.number; case TSL_TYPE_STRING: return hash_range((uint8_t*)key->data.string->data, key->data.string->size); case TSL_TYPE_STRING_REF: return hash_range((uint8_t*)key->data.string_ref.data, key->data.string_ref.size); case TSL_TYPE_BOOL: return key->data.boolean; case TSL_TYPE_LIST: return (uint64_t)key->data.list; case TSL_TYPE_MAP: return (uint64_t)key->data.map; case TSL_TYPE_FUNCTION: return key->data.function; case TSL_TYPE_USERDATA: return (uint64_t)key->data.userdata; } return 0; } int tsl_value_equals(const TslValue *lhs, const TslValue *rhs) { if(lhs->type == rhs->type) { if(lhs->type == TSL_TYPE_STRING) { return lhs->data.string->size == rhs->data.string->size && memcmp(lhs->data.string->data, rhs->data.string->data, lhs->data.string->size) == 0; } else if(lhs->type == TSL_TYPE_STRING_REF) { return lhs->data.string_ref.size == rhs->data.string_ref.size && memcmp(lhs->data.string_ref.data, rhs->data.string_ref.data, lhs->data.string_ref.size) == 0; } else { return *(uint64_t*)&lhs->data == *(uint64_t*)&rhs->data; } } else if(lhs->type == TSL_TYPE_STRING && rhs->type == TSL_TYPE_STRING_REF) { return lhs->data.string->size == rhs->data.string_ref.size && memcmp(lhs->data.string->data, rhs->data.string_ref.data, lhs->data.string->size) == 0; } else if(lhs->type == TSL_TYPE_STRING_REF && rhs->type == TSL_TYPE_STRING) { return lhs->data.string_ref.size == rhs->data.string->size && memcmp(lhs->data.string_ref.data, rhs->data.string->data, lhs->data.string_ref.size) == 0; } else { return 0; } } void tsl_value_clear(TslValue *self) { memset(self, 0, sizeof(TslValue)); } static int tsl_string_merge(const TslStringView *str1, const TslStringView *str2, TslString **result) { size_t new_size = str1->size + str2->size; char *new_str_data; *result = GC_MALLOC_ATOMIC(sizeof(TslString)); new_str_data = GC_MALLOC_ATOMIC(new_size + 1); if(!*result) { GC_FREE(*result); GC_FREE(new_str_data); fprintf(stderr, "Error: out of memory\n"); return 0; } if(!new_str_data) { GC_FREE(*result); GC_FREE(new_str_data); fprintf(stderr, "Error: out of memory\n"); return 0; } memcpy(new_str_data, str1->data, str1->size); memcpy(new_str_data + str1->size, str2->data, str2->size); new_str_data[new_size] = '\0'; (*result)->data = new_str_data; (*result)->size = new_size; return 1; } int tsl_value_add(const TslValue *lhs_value, const TslValue *rhs_value, TslValue *result) { tsl_value_clear(result); switch((TslType)lhs_value->type) { case TSL_TYPE_NULL: case TSL_TYPE_BOOL: case TSL_TYPE_MAP: case TSL_TYPE_FUNCTION: case TSL_TYPE_USERDATA: { fprintf(stderr, "Error: Unable to perform operation '+' on a TODO\n"); return 0; } case TSL_TYPE_NUMBER: { if(rhs_value->type != TSL_TYPE_NUMBER) { fprintf(stderr, "Error: Unable to perform operation '+' on a number and a TODO\n"); return 0; } result->data.number = lhs_value->data.number + rhs_value->data.number; result->type = TSL_TYPE_NUMBER; return 1; } case TSL_TYPE_STRING: { TslStringView lhs_str; tsl_string_to_ref(lhs_value->data.string, &lhs_str); result->type = TSL_TYPE_STRING; if(rhs_value->type == TSL_TYPE_STRING) { TslStringView rhs_str; tsl_string_to_ref(rhs_value->data.string, &rhs_str); return tsl_string_merge(&lhs_str, &rhs_str, &result->data.string); } else if(rhs_value->type == TSL_TYPE_STRING_REF) { return tsl_string_merge(&lhs_str, &rhs_value->data.string_ref, &result->data.string); } else { fprintf(stderr, "Error: Unable to perform operation '+' on a string and TODO\n"); return 0; } result->type = TSL_TYPE_STRING; return 1; } case TSL_TYPE_STRING_REF: { result->type = TSL_TYPE_STRING; if(rhs_value->type == TSL_TYPE_STRING) { TslStringView rhs_str; tsl_string_to_ref(rhs_value->data.string, &rhs_str); return tsl_string_merge(&lhs_value->data.string_ref, &rhs_str, &result->data.string); } else if(rhs_value->type == TSL_TYPE_STRING_REF) { return tsl_string_merge(&lhs_value->data.string_ref, &rhs_value->data.string_ref, &result->data.string); } else { fprintf(stderr, "Error: Unable to perform operation '+' on a string and TODO\n"); return 0; } result->type = TSL_TYPE_STRING; return 1; } case TSL_TYPE_LIST: { /* Create a new list by combining lhs_value list and rhs_value list. For example, [1, 2] + [3, 4] becomes [1, 2, 3, 4] */ size_t list_size = sizeof(TslValue) * (lhs_value->data.list->size + rhs_value->data.list->size); if(rhs_value->type != TSL_TYPE_LIST) { fprintf(stderr, "Error: Unable to perform operation '+' on a list and a TODO\n"); return 0; } result->data.list = GC_MALLOC(sizeof(TslList)); if(!result->data.list) { fprintf(stderr, "Error: Failed to create list. Reason: out of memory\n"); return 0; } tsl_list_set_capacity_hint(result->data.list, list_size); result->data.list->size = list_size; memcpy((char*)result->data.list->data, lhs_value->data.list->data, lhs_value->data.list->size); memcpy((char*)result->data.list->data + lhs_value->data.list->size, rhs_value->data.list->data, rhs_value->data.list->size); result->type = TSL_TYPE_LIST; return 1; } } return 0; } TslValue* tsl_string_ref_get(const TslStringView *self, double index) { /* TODO: Verify if overflow check is needed */ intptr_t index_i = index; if(index_i >= 0 && index_i < (intptr_t)self->size / (intptr_t)sizeof(TslValue)) return (TslValue*)self->data + index_i; return NULL; }