diff options
author | dec05eba <dec05eba@protonmail.com> | 2020-01-26 08:02:17 +0100 |
---|---|---|
committer | dec05eba <dec05eba@protonmail.com> | 2020-01-26 08:03:53 +0100 |
commit | 31519e8a586791d60e6e56e558c2a3bf973cc1f9 (patch) | |
tree | 9195b99953568103fe58025d5888960a48a0c051 /src | |
parent | 5df950e0b35207930c645e8ce0c3e9ed1c9fcea5 (diff) |
Implement plus operator and indexing of strings
Diffstat (limited to 'src')
-rw-r--r-- | src/program.c | 52 | ||||
-rw-r--r-- | src/std_gc/hash_map.c | 37 | ||||
-rw-r--r-- | src/std_gc/list.c | 2 | ||||
-rw-r--r-- | src/value.c | 130 |
4 files changed, 206 insertions, 15 deletions
diff --git a/src/program.c b/src/program.c index 78533f6..2f0a9df 100644 --- a/src/program.c +++ b/src/program.c @@ -47,6 +47,29 @@ static int program_output_temp(char *data, int size, void *userdata) { return 1; } +static void tsl_string_to_ref(const TslString *self, TslStringView *result) { + result->data = self->data; + result->size = self->size; +} + +static TslProgramResult tsl_string_ref_get_item_at_index(const TslStringView *self, const TslValue *key, TslValue *result) { + TslValue *list_item; + if(key->type != TSL_TYPE_NUMBER) { + /* TODO: Print type as string */ + fprintf(stderr, "Error: Unable to index string %s using a variable of type %d. The index has to be a number\n", "TODO", key->type); + return TSL_PROGRAM_RESULT_ERR; + } + + list_item = tsl_string_ref_get(self, key->data.number); + if(list_item) { + *result = *list_item; + } else { + result->type = TSL_TYPE_NULL; + } + + return TSL_PROGRAM_RESULT_OK; +} + static TslProgramResult tsl_value_create_from_stack_value(TslProgram *self, TslStackValue *src, TslValue *dst) { tsl_value_clear(dst); switch(src->type) { @@ -93,7 +116,7 @@ static TslProgramResult tsl_value_create_from_stack_value(TslProgram *self, TslS dst->type = TSL_TYPE_FUNCTION; break; } - case TSL_STACK_VALUE_TYPE_VARIABLE: { + case TSL_STACK_VALUE_TYPE_VARIABLE_NAME: { TslValue *var; TslValue map_key; map_key.type = TSL_TYPE_STRING_REF; @@ -108,6 +131,10 @@ static TslProgramResult tsl_value_create_from_stack_value(TslProgram *self, TslS *dst = *var; break; } + case TSL_STACK_VALUE_TYPE_VARIABLE: { + *dst = src->data.variable; + break; + } case TSL_STACK_VALUE_TYPE_LIST: { TslStackValue *items_begin = tsl_buffer_pop(&self->stack_values, sizeof(TslStackValue) * src->data.integer); TslStackValue *items_end = items_begin + src->data.integer; @@ -174,6 +201,7 @@ static TslProgramResult tsl_value_create_from_stack_value(TslProgram *self, TslS } else { dst->type = TSL_TYPE_NULL; } + return TSL_PROGRAM_RESULT_OK; } else if(var.type == TSL_TYPE_MAP) { TslValue *map_value = tsl_hash_map_get(var.data.map, &key); if(map_value) { @@ -181,12 +209,18 @@ static TslProgramResult tsl_value_create_from_stack_value(TslProgram *self, TslS } else { dst->type = TSL_TYPE_NULL; } + return TSL_PROGRAM_RESULT_OK; + } else if(var.type == TSL_TYPE_STRING) { + TslStringView str_ref; + tsl_string_to_ref(var.data.string, &str_ref); + return tsl_string_ref_get_item_at_index(&str_ref, &key, dst); + } else if(var.type == TSL_TYPE_STRING_REF) { + return tsl_string_ref_get_item_at_index(&var.data.string_ref, &key, dst); } else { /* TODO: Print type as string */ fprintf(stderr, "Error: Unable to index data of type %d. Expected list or map\n", var.type); return TSL_PROGRAM_RESULT_ERR; } - break; } case TSL_STACK_VALUE_TYPE_NULL: { dst->type = TSL_TYPE_NULL; @@ -264,7 +298,7 @@ TslProgramResult tsl_program_run(TslProgram *self) { case TSL_OPCODE_LOADV: { TslStackValue stack_value; stack_value.data.str = instruction_type4->value; - stack_value.type = TSL_STACK_VALUE_TYPE_VARIABLE; + stack_value.type = TSL_STACK_VALUE_TYPE_VARIABLE_NAME; cleanup_if_error(tsl_buffer_append(&self->stack_values, &stack_value, sizeof(stack_value))); printf("loadv \"%.*s\"\n", (int)instruction_type4->value.size, instruction_type4->value.data); instruction += sizeof(TslInstructionType4); @@ -330,8 +364,16 @@ TslProgramResult tsl_program_run(TslProgram *self) { } case TSL_OPCODE_ADD: { TslStackValue *args = tsl_buffer_pop(&self->stack_values, sizeof(TslStackValue) * 2); - (void)args; - /* TODO: Implement this */ + TslValue lhs_value; + TslValue rhs_value; + TslStackValue stack_value; + + cleanup_if_error(tsl_value_create_from_stack_value(self, args + 1, &rhs_value)); + cleanup_if_error(tsl_value_create_from_stack_value(self, args, &lhs_value)); + cleanup_if_error(tsl_value_add(&lhs_value, &rhs_value, &stack_value.data.variable)); + + stack_value.type = TSL_STACK_VALUE_TYPE_VARIABLE; + cleanup_if_error(tsl_buffer_append(&self->stack_values, &stack_value, sizeof(stack_value))); printf("add\n"); instruction += sizeof(TslInstructionType5); break; diff --git a/src/std_gc/hash_map.c b/src/std_gc/hash_map.c index 4d4c026..3f12f35 100644 --- a/src/std_gc/hash_map.c +++ b/src/std_gc/hash_map.c @@ -1,18 +1,9 @@ #include "../../include/std_gc/hash_map.h" -#include "../../include/value.h" #include <assert.h> #include <string.h> #include <stdio.h> #include <gc.h> -typedef struct TslHashMapNode TslHashMapNode; -struct TslHashMapNode { - uint64_t hash; - TslValue key; - TslValue value; - TslHashMapNode *next; -}; - void tsl_hash_map_init(TslHashMap *self) { self->buckets_data = NULL; self->buckets_size = 0; @@ -193,3 +184,31 @@ TslValue* tsl_hash_map_get_or_create(TslHashMap *self, const TslValue *key) { return value; } + +void tsl_hash_map_create_iterator(TslHashMap *self, TslHashMapIterator *iterator) { + iterator->hash_map = self; + iterator->index = -1; + iterator->node = NULL; +} + +int tsl_hash_map_iterator_next(TslHashMapIterator *self) { + if(self->node) { + TslHashMapNode *new_node = self->node->next; + if(new_node) { + self->node = new_node; + return 1; + } + } + + ++self->index; + while(self->index < self->hash_map->buckets_size) { + TslHashMapNode **bucket = (TslHashMapNode**)self->hash_map->buckets_data + self->index; + if(*bucket) { + self->node = *bucket; + return 1; + } + ++self->index; + } + + return 0; +} diff --git a/src/std_gc/list.c b/src/std_gc/list.c index 5b7c7b6..7c56d64 100644 --- a/src/std_gc/list.c +++ b/src/std_gc/list.c @@ -58,7 +58,7 @@ TslValue* tsl_list_end(TslList *self) { return (TslValue*)((char*)self->data + self->size); } -TslValue* tsl_list_get(TslList *self, double index) { +TslValue* tsl_list_get(const TslList *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)) diff --git a/src/value.c b/src/value.c index 1a76880..61d6d4a 100644 --- a/src/value.c +++ b/src/value.c @@ -1,5 +1,11 @@ #include "../include/value.h" +#include "../include/std_gc/hash_map.h" #include <string.h> +#include <stdio.h> +#ifdef DEBUG +#define GC_DEBUG +#endif +#include <gc.h> static uint64_t hash_range(const uint8_t *data, size_t size) { uint64_t result = 0xdec05eba; @@ -11,6 +17,11 @@ static uint64_t hash_range(const uint8_t *data, size_t 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: @@ -60,3 +71,122 @@ int tsl_value_equals(const TslValue *lhs, const TslValue *rhs) { 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; +} |