From 4b2b8d3176e84f76510cc69a627dbfa089c1dd35 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Sat, 25 Jan 2020 09:48:56 +0100 Subject: Implement almost all instructions --- src/program.c | 248 ++++++++++++++++++++++++++++++++++++++++++-------- src/std_gc/hash_map.c | 31 ++++--- src/std_gc/list.c | 67 ++++++++++++++ src/value.c | 19 +++- 4 files changed, 310 insertions(+), 55 deletions(-) create mode 100644 src/std_gc/list.c (limited to 'src') diff --git a/src/program.c b/src/program.c index 0a0027b..dc7fe8d 100644 --- a/src/program.c +++ b/src/program.c @@ -1,6 +1,7 @@ #include "../include/program.h" #include "../include/bytecode.h" #include "../include/command.h" +#include "../include/std_gc/list.h" #ifdef DEBUG #define GC_DEBUG #endif @@ -10,7 +11,7 @@ #include #include -#define return_if_error(expr) \ +#define cleanup_if_error(expr) \ { \ if(!(expr)) { \ result = TSL_PROGRAM_RESULT_ERR; \ @@ -18,6 +19,12 @@ } \ } +#define return_if_error(expr) \ + { \ + if(!(expr)) \ + return TSL_PROGRAM_RESULT_ERR; \ + } + void tsl_program_init(TslProgram *self) { GC_INIT(); /* TODO: Remove this */ tsl_buffer_init(&self->function_bytecode_list); @@ -40,6 +47,156 @@ static int program_output_temp(char *data, int size, void *userdata) { return 1; } +static TslProgramResult tsl_value_create_from_stack_value(TslProgram *self, TslStackValue *src, TslValue *dst) { + tsl_value_clear(dst); + switch(src->type) { + case TSL_STACK_VALUE_TYPE_NUMBER: { + dst->data.number = src->data.number; + dst->type = TSL_TYPE_NUMBER; + break; + } + case TSL_STACK_VALUE_TYPE_BOOL: { + dst->data.boolean = src->data.boolean; + dst->type = TSL_TYPE_BOOL; + break; + } + case TSL_STACK_VALUE_TYPE_STRING: { + TslString *str = GC_MALLOC_ATOMIC(sizeof(TslString)); + str->data = GC_MALLOC_ATOMIC(src->data.str.size + 1); + if(!str) { + GC_FREE(str); + GC_FREE(str->data); + fprintf(stderr, "Error: out of memory\n"); + return TSL_PROGRAM_RESULT_ERR; + } + if(!str->data) { + GC_FREE(str); + GC_FREE(str->data); + fprintf(stderr, "Error: out of memory\n"); + return TSL_PROGRAM_RESULT_ERR; + } + + memcpy(str->data, src->data.str.data, src->data.str.size); + str->data[src->data.str.size] = '\0'; + str->size = src->data.str.size; + + dst->data.string = str; + dst->type = TSL_TYPE_STRING; + break; + } + case TSL_STACK_VALUE_TYPE_FUNCTION: { + dst->data.function = src->data.integer; + dst->type = TSL_TYPE_FUNCTION; + break; + } + case TSL_STACK_VALUE_TYPE_VARIABLE: { + TslValue *var; + TslValue map_key; + map_key.type = TSL_TYPE_STRING_VIEW; + map_key.data.string_view = src->data.str; + + var = tsl_hash_map_get(self->variables, &map_key); + if(!var) { + fprintf(stderr, "Error: Trying to access a non-existing variable \"%.*s\"\n", (int)src->data.str.size, src->data.str.data); + return TSL_PROGRAM_RESULT_ERR; + } + + *dst = *var; + 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; + TslStackValue *item = items_end - 1; + TslValue *list_item; + dst->data.list = GC_MALLOC(sizeof(TslList)); + return_if_error(dst->data.list); + + tsl_list_init(dst->data.list); + return_if_error(tsl_list_set_capacity_hint(dst->data.list, sizeof(TslValue) * src->data.integer)); + dst->data.list->size = sizeof(TslValue) * src->data.integer; + list_item = tsl_list_end(dst->data.list) - sizeof(TslValue); + + while(item != items_begin - 1) { + return_if_error(tsl_value_create_from_stack_value(self, item, list_item)); + --list_item; + --item; + } + + dst->type = TSL_TYPE_LIST; + break; + } + case TSL_STACK_VALUE_TYPE_MAP: { + TslStackValue *items_begin = tsl_buffer_pop(&self->stack_values, sizeof(TslStackValue) * src->data.integer); + TslStackValue *items_end = items_begin + src->data.integer; + TslStackValue *item = items_end - 1; + + dst->data.map = GC_MALLOC(sizeof(TslHashMap)); + return_if_error(dst->data.map); + tsl_hash_map_init(dst->data.map); + + assert(src->data.integer % 2 == 0); + while(item != items_begin - 1) { + TslValue map_key; + TslValue map_value; + return_if_error(tsl_value_create_from_stack_value(self, item, &map_value)); + return_if_error(tsl_value_create_from_stack_value(self, item - 1, &map_key)); + return_if_error(tsl_hash_map_insert(dst->data.map, &map_key, &map_value)); + item -= 2; + } + + dst->type = TSL_TYPE_MAP; + break; + } + case TSL_STACK_VALUE_TYPE_INDEX: { + TslStackValue *args = tsl_buffer_pop(&self->stack_values, sizeof(TslStackValue) * 2); + TslValue var; + TslValue key; + + return_if_error(tsl_value_create_from_stack_value(self, args + 1, &key)); + return_if_error(tsl_value_create_from_stack_value(self, args, &var)); + + if(var.type == TSL_TYPE_LIST) { + TslValue *list_item; + if(key.type != TSL_TYPE_NUMBER) { + /* TODO: Print type as string */ + fprintf(stderr, "Error: Unable to index list %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_list_get(var.data.list, key.data.number); + if(list_item) { + *dst = *list_item; + } else { + dst->type = TSL_TYPE_NULL; + } + } else if(var.type == TSL_TYPE_MAP) { + TslValue *map_value = tsl_hash_map_get(var.data.map, &key); + if(map_value) { + *dst = *map_value; + } else { + dst->type = TSL_TYPE_NULL; + } + } 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; + break; + } + case TSL_STACK_VALUE_TYPE_COMMAND_ARG: { + assert(0 && "This is a bug in the compiler. Unable to convert command arg to tsl value"); + abort(); + break; + } + } + return TSL_PROGRAM_RESULT_OK; +} + TslProgramResult tsl_program_run(TslProgram *self) { TslProgramResult result = TSL_PROGRAM_RESULT_OK; TslBytecode *file_scope_bytecode = tsl_buffer_begin(&self->function_bytecode_list); @@ -68,7 +225,7 @@ TslProgramResult tsl_program_run(TslProgram *self) { TslStackValue stack_value; stack_value.data.number = instruction_type2->value; stack_value.type = TSL_STACK_VALUE_TYPE_NUMBER; - return_if_error(tsl_buffer_append(&self->stack_values, &stack_value, sizeof(stack_value))); + cleanup_if_error(tsl_buffer_append(&self->stack_values, &stack_value, sizeof(stack_value))); printf("loadn %f\n", instruction_type2->value); instruction += sizeof(TslInstructionType2); break; @@ -77,31 +234,16 @@ TslProgramResult tsl_program_run(TslProgram *self) { TslStackValue stack_value; stack_value.data.boolean = instruction_type3->value; stack_value.type = TSL_STACK_VALUE_TYPE_BOOL; - return_if_error(tsl_buffer_append(&self->stack_values, &stack_value, sizeof(stack_value))); + cleanup_if_error(tsl_buffer_append(&self->stack_values, &stack_value, sizeof(stack_value))); printf("loadb %s\n", instruction_type3->value ? "true" : "false"); instruction += sizeof(TslInstructionType3); break; } case TSL_OPCODE_LOADS: { - #if 0 - TslString *str = GC_MALLOC(sizeof(TslString)); - char *str_data = GC_MALLOC_ATOMIC(instruction_type4->value.size + 1); - if(!str) { - fprintf(stderr, "Error: out of memory\n"); - return TSL_PROGRAM_RESULT_ERR; - } - if(!str_data) { - fprintf(stderr, "Error: out of memory\n"); - return TSL_PROGRAM_RESULT_ERR; - } - memcpy(str->data, instruction_type4->value.data, instruction_type4->value.size); - str->data[instruction_type4->value.size] = '\0'; - str->size = instruction_type4->value.size; - #endif TslStackValue stack_value; stack_value.data.str = instruction_type4->value; stack_value.type = TSL_STACK_VALUE_TYPE_STRING; - return_if_error(tsl_buffer_append(&self->stack_values, &stack_value, sizeof(stack_value))); + cleanup_if_error(tsl_buffer_append(&self->stack_values, &stack_value, sizeof(stack_value))); printf("loads \"%.*s\"\n", (int)instruction_type4->value.size, instruction_type4->value.data); instruction += sizeof(TslInstructionType4); break; @@ -110,7 +252,7 @@ TslProgramResult tsl_program_run(TslProgram *self) { TslStackValue stack_value; stack_value.data.integer = instruction_type1->value; stack_value.type = TSL_STACK_VALUE_TYPE_FUNCTION; - return_if_error(tsl_buffer_append(&self->stack_values, &stack_value, sizeof(stack_value))); + cleanup_if_error(tsl_buffer_append(&self->stack_values, &stack_value, sizeof(stack_value))); printf("loadf %d\n", instruction_type1->value); instruction += sizeof(TslInstructionType1); break; @@ -119,7 +261,7 @@ TslProgramResult tsl_program_run(TslProgram *self) { TslStackValue stack_value; stack_value.data.str = instruction_type4->value; stack_value.type = TSL_STACK_VALUE_TYPE_VARIABLE; - return_if_error(tsl_buffer_append(&self->stack_values, &stack_value, sizeof(stack_value))); + 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); break; @@ -127,61 +269,89 @@ TslProgramResult tsl_program_run(TslProgram *self) { case TSL_OPCODE_LOADNULL: { TslStackValue stack_value; stack_value.type = TSL_STACK_VALUE_TYPE_NULL; - return_if_error(tsl_buffer_append(&self->stack_values, &stack_value, sizeof(stack_value))); + cleanup_if_error(tsl_buffer_append(&self->stack_values, &stack_value, sizeof(stack_value))); printf("loadnull\n"); instruction += sizeof(TslInstructionType5); break; } case TSL_OPCODE_SETV: { + TslStackValue *stack_value = tsl_buffer_pop(&self->stack_values, sizeof(TslStackValue)); TslValue map_key; - TslValue *stack_value; TslValue *map_value; map_key.type = TSL_TYPE_STRING_VIEW; map_key.data.string_view = instruction_type4->value; - stack_value = tsl_buffer_pop(&self->stack_values, sizeof(TslStackValue)); + map_value = tsl_hash_map_get_or_create(self->variables, &map_key); - return_if_error(map_value); - *map_value = *stack_value; + cleanup_if_error(map_value); + + cleanup_if_error(tsl_value_create_from_stack_value(self, stack_value, map_value)); printf("setv \"%.*s\"\n", (int)instruction_type4->value.size, instruction_type4->value.data); instruction += sizeof(TslInstructionType4); break; } case TSL_OPCODE_LIST: { + TslStackValue stack_value; + stack_value.data.integer = instruction_type1->value; + stack_value.type = TSL_STACK_VALUE_TYPE_LIST; + cleanup_if_error(tsl_buffer_append(&self->stack_values, &stack_value, sizeof(stack_value))); printf("list %d\n", instruction_type1->value); instruction += sizeof(TslInstructionType1); break; } case TSL_OPCODE_MAP: { + TslStackValue stack_value; + stack_value.data.integer = instruction_type1->value; + stack_value.type = TSL_STACK_VALUE_TYPE_MAP; + cleanup_if_error(tsl_buffer_append(&self->stack_values, &stack_value, sizeof(stack_value))); printf("map %d\n", instruction_type1->value); instruction += sizeof(TslInstructionType1); break; } case TSL_OPCODE_MINDEX: { + TslStackValue stack_value; + stack_value.type = TSL_STACK_VALUE_TYPE_INDEX; + cleanup_if_error(tsl_buffer_append(&self->stack_values, &stack_value, sizeof(stack_value))); printf("mindex\n"); instruction += sizeof(TslInstructionType5); break; } case TSL_OPCODE_CALLF: { + /* + 1, since the first arg is the function index and the other args are the args for the function */ + TslStackValue *args = tsl_buffer_pop(&self->stack_values, sizeof(TslStackValue) * (1 + instruction_type1->value)); + (void)args; + /* TODO: Implement this */ printf("callf %d\n", instruction_type1->value); instruction += sizeof(TslInstructionType1); break; } case TSL_OPCODE_ADD: { + TslStackValue *args = tsl_buffer_pop(&self->stack_values, sizeof(TslStackValue) * 2); + (void)args; + /* TODO: Implement this */ printf("add\n"); instruction += sizeof(TslInstructionType5); break; } case TSL_OPCODE_SUB: { + TslStackValue *args = tsl_buffer_pop(&self->stack_values, sizeof(TslStackValue) * 2); + (void)args; + /* TODO: Implement this */ printf("sub\n"); instruction += sizeof(TslInstructionType5); break; } case TSL_OPCODE_MUL: { + TslStackValue *args = tsl_buffer_pop(&self->stack_values, sizeof(TslStackValue) * 2); + (void)args; + /* TODO: Implement this */ printf("mul\n"); instruction += sizeof(TslInstructionType5); break; } case TSL_OPCODE_DIV: { + TslStackValue *args = tsl_buffer_pop(&self->stack_values, sizeof(TslStackValue) * 2); + (void)args; + /* TODO: Implement this */ printf("div\n"); instruction += sizeof(TslInstructionType5); break; @@ -190,7 +360,7 @@ TslProgramResult tsl_program_run(TslProgram *self) { TslStackValue stack_value; stack_value.data.str = instruction_type4->value; stack_value.type = TSL_STACK_VALUE_TYPE_COMMAND_ARG; - return_if_error(tsl_buffer_append(&self->stack_values, &stack_value, sizeof(stack_value))); + cleanup_if_error(tsl_buffer_append(&self->stack_values, &stack_value, sizeof(stack_value))); printf("loadca \"%.*s\"\n", (int)instruction_type4->value.size, instruction_type4->value.data); instruction += sizeof(TslInstructionType4); break; @@ -198,7 +368,7 @@ TslProgramResult tsl_program_run(TslProgram *self) { case TSL_OPCODE_CALLC: { TslStackValue *args_begin = tsl_buffer_pop(&self->stack_values, sizeof(TslStackValue) * instruction_type1->value); TslStackValue *args_end = args_begin + instruction_type1->value; - TslStackValue *args = args_begin; + TslStackValue *arg = args_begin; char *command_args[255]; char temp_null_save[255]; size_t arg_index = 0; @@ -207,15 +377,15 @@ TslProgramResult tsl_program_run(TslProgram *self) { /* TODO: Support infinite amount of args */ assert(args_end - args_begin < 255); printf("Running command: "); - while(args != args_end) { - assert(args->type == TSL_STACK_VALUE_TYPE_COMMAND_ARG); - temp_null_save[arg_index] = args->data.str.data[args->data.str.size]; - args->data.str.data[args->data.str.size] = '\0'; + while(arg != args_end) { + assert(arg->type == TSL_STACK_VALUE_TYPE_COMMAND_ARG); + temp_null_save[arg_index] = arg->data.str.data[arg->data.str.size]; + arg->data.str.data[arg->data.str.size] = '\0'; - command_args[arg_index] = args->data.str.data; + command_args[arg_index] = arg->data.str.data; printf("%s ", command_args[arg_index]); ++arg_index; - ++args; + ++arg; } command_args[arg_index] = NULL; printf("\n"); @@ -224,13 +394,13 @@ TslProgramResult tsl_program_run(TslProgram *self) { tsl_command_exec(command_args, program_output_temp, NULL); { - args = args_begin; + arg = args_begin; arg_index = 0; /* TODO: Support infinite amount of args */ - while(args != args_end) { - args->data.str.data[args->data.str.size] = temp_null_save[arg_index]; + while(arg != args_end) { + arg->data.str.data[arg->data.str.size] = temp_null_save[arg_index]; ++arg_index; - ++args; + ++arg; } command_args[arg_index] = NULL; } @@ -243,7 +413,7 @@ TslProgramResult tsl_program_run(TslProgram *self) { } cleanup: - assert(self->stack_values.size == 0); /* All push instructions (mostly load) haven't been handled yet. This is a bug in tsl */ + assert(self->stack_values.size == 0); /* All push instructions (mostly load) haven't been handled yet. This is a bug in the compiler */ tsl_buffer_deinit(&self->stack_values); GC_FREE(self->variables); /* Free the root object, resulting in all objects in the program being free'd */ self->variables = NULL; diff --git a/src/std_gc/hash_map.c b/src/std_gc/hash_map.c index 1960ffc..4d4c026 100644 --- a/src/std_gc/hash_map.c +++ b/src/std_gc/hash_map.c @@ -1,4 +1,5 @@ #include "../../include/std_gc/hash_map.h" +#include "../../include/value.h" #include #include #include @@ -127,9 +128,6 @@ static int tsl_hash_map_ensure_bucket_capacity_for_one_new_item(TslHashMap *self } } - if(old_capacity == 0) - return 1; - tsl_hash_map_reorder_nodes(self, old_capacity); return 1; } @@ -169,23 +167,26 @@ TslValue* tsl_hash_map_get(TslHashMap *self, const TslValue *key) { TslValue* tsl_hash_map_get_or_create(TslHashMap *self, const TslValue *key) { uint64_t hash; size_t index; - TslHashMapNode **bucket; - TslHashMapNode *node; TslValue *value; - if(self->buckets_capacity == 0) { - if(!tsl_hash_map_ensure_bucket_capacity_for_one_new_item(self)) - return NULL; - } + TslHashMapNode **bucket; hash = tsl_value_hash(key); + if(self->buckets_capacity > 0) { + size_t index = tsl_hash_map_get_index(self, hash); + TslHashMapNode **bucket = (TslHashMapNode**)self->buckets_data + index; + TslHashMapNode *node = *bucket; + while(node) { + if(hash == node->hash && tsl_value_equals(key, &node->key)) + return &node->value; + node = node->next; + } + } + + if(!tsl_hash_map_ensure_bucket_capacity_for_one_new_item(self)) + return NULL; + index = tsl_hash_map_get_index(self, hash); bucket = (TslHashMapNode**)self->buckets_data + index; - node = *bucket; - while(node) { - if(hash == node->hash && tsl_value_equals(key, &node->key)) - return &node->value; - node = node->next; - } if(!tsl_hash_map_append_bucket(bucket, hash, key, NULL, &value)) return NULL; diff --git a/src/std_gc/list.c b/src/std_gc/list.c new file mode 100644 index 0000000..5b7c7b6 --- /dev/null +++ b/src/std_gc/list.c @@ -0,0 +1,67 @@ +#include "../../include/std_gc/list.h" +#include "../../include/value.h" +#include +#include +#include +#ifdef DEBUG +#define GC_DEBUG +#endif +#include + +void tsl_list_init(TslList *self) { + self->data = NULL; + self->size = 0; + self->capacity = 0; +} + +static int tsl_list_ensure_capacity(TslList *self, size_t new_size) { + void *new_ptr; + size_t new_capacity = self->capacity; + if(new_size <= self->capacity) + return 1; + + if(new_capacity == 0) + new_capacity = 8; + + while(new_capacity < new_size) { + new_capacity <<= 1; + } + + new_ptr = GC_REALLOC(self->data, new_capacity); + if(!new_ptr) { + fprintf(stderr, "Error: buffer append failed. Reason: out of memory\n"); + return 0; + } + + self->data = new_ptr; + self->capacity = new_capacity; + return 1; +} + +int tsl_list_append(TslList *self, const TslValue *data) { + if(!tsl_list_ensure_capacity(self, self->size + sizeof(TslValue))) + return 0; + memcpy((char*)self->data + self->size, data, sizeof(TslValue)); + self->size += sizeof(TslValue); + return 1; +} + +int tsl_list_set_capacity_hint(TslList *self, size_t capacity) { + return tsl_list_ensure_capacity(self, capacity); +} + +TslValue* tsl_list_begin(TslList *self) { + return self->data; +} + +TslValue* tsl_list_end(TslList *self) { + return (TslValue*)((char*)self->data + self->size); +} + +TslValue* tsl_list_get(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)) + return (TslValue*)self->data + index_i; + return NULL; +} diff --git a/src/value.c b/src/value.c index 690527f..c08048a 100644 --- a/src/value.c +++ b/src/value.c @@ -12,19 +12,23 @@ static uint64_t hash_range(const uint8_t *data, size_t size) { } uint64_t tsl_value_hash(const TslValue *key) { - switch(key->type) { + 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(key->data.string->data, key->data.string->size); + case TSL_TYPE_STRING_VIEW: + return hash_range((uint8_t*)key->data.string_view.data, key->data.string_view.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; } @@ -36,10 +40,23 @@ int tsl_value_equals(const TslValue *lhs, const TslValue *rhs) { 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_VIEW) { + return lhs->data.string_view.size == rhs->data.string_view.size + && memcmp(lhs->data.string_view.data, rhs->data.string_view.data, lhs->data.string_view.size) == 0; } else { return *(uint64_t*)&lhs->data == *(uint64_t*)&rhs->data; } + } else if(lhs->type == TSL_TYPE_STRING && rhs->type == TSL_TYPE_STRING_VIEW) { + return lhs->data.string->size == rhs->data.string_view.size + && memcmp(lhs->data.string->data, rhs->data.string_view.data, lhs->data.string->size) == 0; + } else if(lhs->type == TSL_TYPE_STRING_VIEW && rhs->type == TSL_TYPE_STRING) { + return lhs->data.string_view.size == rhs->data.string->size + && memcmp(lhs->data.string_view.data, rhs->data.string->data, lhs->data.string_view.size) == 0; } else { return 0; } } + +void tsl_value_clear(TslValue *self) { + memset(self, 0, sizeof(TslValue)); +} -- cgit v1.2.3