diff options
author | dec05eba <dec05eba@protonmail.com> | 2020-01-24 09:11:53 +0100 |
---|---|---|
committer | dec05eba <dec05eba@protonmail.com> | 2020-01-24 09:11:53 +0100 |
commit | 1dd53ce54c2008e3a11a636a496853cf6f9a5d65 (patch) | |
tree | 73f8ff8d048c8b1e4c6cf7acfd3e229650d044d5 /src | |
parent | 26f8fbc2c657ecffc874410691dd3fc83ba11131 (diff) |
Convert hash map to gc, implement more instructions and call command
Diffstat (limited to 'src')
-rw-r--r-- | src/command.c | 90 | ||||
-rw-r--r-- | src/main.c | 19 | ||||
-rw-r--r-- | src/parser.c | 13 | ||||
-rw-r--r-- | src/program.c | 162 | ||||
-rw-r--r-- | src/std/buffer.c | 25 | ||||
-rw-r--r-- | src/std_gc/hash_map.c (renamed from src/std/hash_map.c) | 127 | ||||
-rw-r--r-- | src/tokenizer.c | 2 | ||||
-rw-r--r-- | src/value.c | 45 |
8 files changed, 340 insertions, 143 deletions
diff --git a/src/command.c b/src/command.c new file mode 100644 index 0000000..c413502 --- /dev/null +++ b/src/command.c @@ -0,0 +1,90 @@ +#include "../include/command.h" +#include <unistd.h> +#include <sys/wait.h> +#include <errno.h> +#include <string.h> +#include <stdio.h> +#include <assert.h> + +#define READ_END 0 +#define WRITE_END 1 + +int tsl_command_exec(char **args, ProgramOutputCallback output_callback, void *userdata) { + int fd[2]; + pid_t pid; + + /* 1 arguments */ + if(args[0] == NULL) + return -1; + + if(pipe(fd) == -1) { + perror("Failed to open pipe"); + return -2; + } + + pid = fork(); + if(pid == -1) { + perror("Failed to fork"); + return -3; + } else if(pid == 0) { /* child */ + dup2(fd[WRITE_END], STDOUT_FILENO); + close(fd[READ_END]); + close(fd[WRITE_END]); + + execvp(args[0], args); + return 0; + } else { /* parent */ + int result = 0; + int status; + char buffer[2048]; + int exit_status; + + close(fd[WRITE_END]); + for(;;) { + ssize_t bytes_read = read(fd[READ_END], buffer, sizeof(buffer) - 1); + if(bytes_read == 0) { + break; + } else if(bytes_read == -1) { + int err = errno; + fprintf(stderr, "Failed to read from pipe to program %s, error: %s\n", args[0], strerror(err)); + result = -err; + goto cleanup; + } + + buffer[bytes_read] = '\0'; + if(output_callback && !output_callback(buffer, bytes_read, userdata)) + break; + } + + if(waitpid(pid, &status, 0) == -1) { + perror("waitpid failed"); + result = -5; + goto cleanup; + } + + if(!WIFEXITED(status)) { + result = -4; + goto cleanup; + } + + exit_status = WEXITSTATUS(status); + if(exit_status != 0) { + char **arg = args; + fprintf(stderr, "Failed to execute program ("); + + while(*arg) { + if(arg != args) + fputc(' ', stderr); + fprintf(stderr, "'%s'", *arg); + ++arg; + } + fprintf(stderr, "), exit status %d\n", exit_status); + result = -exit_status; + goto cleanup; + } + + cleanup: + close(fd[READ_END]); + return result; + } +} @@ -56,6 +56,7 @@ int main(int argc, char **argv) { char *file_content; size_t filesize; TslProgram program; + int result = 0; if(argc != 2) { usage(); @@ -64,16 +65,22 @@ int main(int argc, char **argv) { file_content = file_get_content(argv[1], &filesize); if(!file_content) - return 1; + return 2; tsl_program_init(&program); - if(!tsl_parse(file_content, filesize, &program)) - return 2; - if(!tsl_program_run(&program)) - return 3; + if(!tsl_parse(file_content, filesize, &program)) { + result = 3; + goto cleanup; + } + + if(!tsl_program_run(&program)) { + result = 4; + goto cleanup; + } + cleanup: free(file_content); tsl_program_deinit(&program); - return 0; + return result; } diff --git a/src/parser.c b/src/parser.c index 098962a..a6f340f 100644 --- a/src/parser.c +++ b/src/parser.c @@ -26,7 +26,7 @@ static int tsl_parser_get_current_function_index(TslParser *self) { static TslParseResult tsl_parser_parse_rhs(TslParser *self); static TslParseResult tsl_parser_parse_expressions(TslParser *self, TslToken end_token); -static int tsl_parser_init(TslParser *self, const char *code, size_t code_size) { +static int tsl_parser_init(TslParser *self, char *code, size_t code_size) { TslBytecode bytecode_writer; int result1 = 1; int result2 = 1; @@ -216,7 +216,6 @@ static TslParseResult tsl_parser_parse_func_call(TslParser *self, int *num_args) } } -/* TODO: Do not allow empty command */ /* TODO: Allow command inside another command */ /* COMMAND = '(' TSL_COMMAND_TOKEN_ARG* ')' */ static TslParseResult tsl_parser_parse_command(TslParser *self, int *num_args) { @@ -328,8 +327,12 @@ TslParseResult tsl_parser_parse_rhs(TslParser *self) { } case TSL_TOKEN_DOLLAR_SIGN: { int num_args; - return tsl_parser_parse_command(self, &num_args) && - tsl_bytecode_add_ins1(get_function_bytecode(self), TSL_OPCODE_CALLC, num_args); + return_if_error(tsl_parser_parse_command(self, &num_args)) + if(num_args == 0) { + fprintf(stderr, "Error: Command can't be empty\n"); + return TSL_PARSE_RESULT_ERR; + } + return tsl_bytecode_add_ins1(get_function_bytecode(self), TSL_OPCODE_CALLC, num_args); } default: fprintf(stderr, "Error: Expected variable, number, bool, null, map, list, function or command, got TODO (%d) (line: %d)\n", token, tsl_tokenizer_get_line_by_index(&self->tokenizer, self->tokenizer.prev_code_index)); @@ -365,7 +368,7 @@ TslParseResult tsl_parser_parse_expressions(TslParser *self, TslToken end_token) return TSL_PARSE_RESULT_OK; } -TslParseResult tsl_parse(const char *code, size_t code_size, TslProgram *program_output) { +TslParseResult tsl_parse(char *code, size_t code_size, TslProgram *program_output) { TslParseResult result; TslParser parser; diff --git a/src/program.c b/src/program.c index 3ec6f85..0a0027b 100644 --- a/src/program.c +++ b/src/program.c @@ -1,12 +1,26 @@ #include "../include/program.h" #include "../include/bytecode.h" +#include "../include/command.h" +#ifdef DEBUG +#define GC_DEBUG +#endif +#include <gc.h> #include <stdio.h> #include <assert.h> +#include <stdlib.h> +#include <string.h> + +#define return_if_error(expr) \ + { \ + if(!(expr)) { \ + result = TSL_PROGRAM_RESULT_ERR; \ + goto cleanup; \ + } \ + } void tsl_program_init(TslProgram *self) { + GC_INIT(); /* TODO: Remove this */ tsl_buffer_init(&self->function_bytecode_list); - tsl_hash_map_init(&self->variables); - self->stack_index = 0; } void tsl_program_deinit(TslProgram *self) { @@ -17,34 +31,31 @@ void tsl_program_deinit(TslProgram *self) { ++bytecode_writer; } tsl_buffer_deinit(&self->function_bytecode_list); - tsl_hash_map_deinit(&self->variables); } -static uint64_t hash_string_view(const void *data, size_t size) { - uint64_t result = 0xdec05eba; - const uint8_t *p = data; - while(size) { - result = ((result << 5) + result) + *p; - ++p; - --size; - } - return result; +static int program_output_temp(char *data, int size, void *userdata) { + (void)size; + (void)userdata; + fputs(data, stdout); + return 1; } TslProgramResult tsl_program_run(TslProgram *self) { - #define push(value, type_enum, value_field) \ - do { \ - if(self->stack_index == TSL_STACK_MAX_SIZE) \ - return TSL_PROGRAM_RESULT_ERR; \ - self->stack_values[self->stack_index].data.value_field = (value); \ - self->stack_values[self->stack_index].type = (type_enum); \ - ++self->stack_index; \ - } while(0) - + TslProgramResult result = TSL_PROGRAM_RESULT_OK; TslBytecode *file_scope_bytecode = tsl_buffer_begin(&self->function_bytecode_list); char *instruction = tsl_buffer_begin(&file_scope_bytecode->buffer); char *instruction_end = tsl_buffer_end(&file_scope_bytecode->buffer); - printf("#############################\n"); + + self->variables = GC_MALLOC_UNCOLLECTABLE(sizeof(TslHashMap)); + if(!self->variables) { + fprintf(stderr, "Error: Failed to allocate root object\n"); + return TSL_PROGRAM_RESULT_ERR; + } + tsl_hash_map_init(self->variables); + tsl_buffer_init(&self->stack_values); + + printf("###########################\n"); + /* TODO: Verify if these don't cause unaligned memory access on non-x86 platforms */ while(instruction != instruction_end) { TslOpcode opcode = *(TslOpcode*)instruction; @@ -54,46 +65,84 @@ TslProgramResult tsl_program_run(TslProgram *self) { TslInstructionType4 *instruction_type4 = (TslInstructionType4*)instruction; switch(opcode) { case TSL_OPCODE_LOADN: { + 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))); printf("loadn %f\n", instruction_type2->value); - push(instruction_type2->value, TSL_TYPE_NUMBER, number); instruction += sizeof(TslInstructionType2); break; } case TSL_OPCODE_LOADB: { + 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))); printf("loadb %s\n", instruction_type3->value ? "true" : "false"); - push(instruction_type3->value, TSL_TYPE_BOOL, boolean); 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))); printf("loads \"%.*s\"\n", (int)instruction_type4->value.size, instruction_type4->value.data); instruction += sizeof(TslInstructionType4); break; } case TSL_OPCODE_LOADF: { + 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))); printf("loadf %d\n", instruction_type1->value); instruction += sizeof(TslInstructionType1); break; } case TSL_OPCODE_LOADV: { + 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))); printf("loadv \"%.*s\"\n", (int)instruction_type4->value.size, instruction_type4->value.data); instruction += sizeof(TslInstructionType4); break; } 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))); printf("loadnull\n"); instruction += sizeof(TslInstructionType5); break; } case TSL_OPCODE_SETV: { - TslValue stack_value; - TslValue *value; + 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; printf("setv \"%.*s\"\n", (int)instruction_type4->value.size, instruction_type4->value.data); - assert(self->stack_index > 0); - stack_value = self->stack_values[--self->stack_index]; - if(!tsl_hash_map_get_or_create(&self->variables, &instruction_type4->value, sizeof(TslValue), hash_string_view, (void**)&value)) - return TSL_PROGRAM_RESULT_ERR; - *value = stack_value; instruction += sizeof(TslInstructionType4); break; } @@ -138,16 +187,65 @@ TslProgramResult tsl_program_run(TslProgram *self) { break; } case TSL_OPCODE_LOADCA: { + 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))); printf("loadca \"%.*s\"\n", (int)instruction_type4->value.size, instruction_type4->value.data); instruction += sizeof(TslInstructionType4); break; } 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; + char *command_args[255]; + char temp_null_save[255]; + size_t arg_index = 0; + assert(instruction_type1->value > 0); + { + /* 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'; + + command_args[arg_index] = args->data.str.data; + printf("%s ", command_args[arg_index]); + ++arg_index; + ++args; + } + command_args[arg_index] = NULL; + printf("\n"); + } + + tsl_command_exec(command_args, program_output_temp, NULL); + + { + args = 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]; + ++arg_index; + ++args; + } + command_args[arg_index] = NULL; + } + printf("callc %d\n", instruction_type1->value); instruction += sizeof(TslInstructionType1); break; } } } - return TSL_PROGRAM_RESULT_OK; + + cleanup: + assert(self->stack_values.size == 0); /* All push instructions (mostly load) haven't been handled yet. This is a bug in tsl */ + 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; + return result; } diff --git a/src/std/buffer.c b/src/std/buffer.c index 343173a..b0099bb 100644 --- a/src/std/buffer.c +++ b/src/std/buffer.c @@ -18,24 +18,25 @@ void tsl_buffer_deinit(TslBuffer *self) { static int tsl_buffer_ensure_capacity(TslBuffer *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; - if(self->capacity != 0) { - size_t new_capacity = self->capacity; - while(new_capacity < new_size) { - new_capacity <<= 1; - } - new_size = new_capacity; + while(new_capacity < new_size) { + new_capacity <<= 1; } - new_ptr = realloc(self->data, new_size); + + new_ptr = 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_size; + self->capacity = new_capacity; return 1; } @@ -47,9 +48,15 @@ int tsl_buffer_append(TslBuffer *self, const void *data, size_t size) { return 1; } -void tsl_buffer_pop(TslBuffer *self, size_t size) { +void* tsl_buffer_pop(TslBuffer *self, size_t size) { assert(self->size >= size); self->size -= size; + return (char*)self->data + self->size; +} + +void* tsl_buffer_top(TslBuffer *self, size_t data_size) { + tsl_buffer_pop(self, data_size); + return (char*)self->data + self->size; } void* tsl_buffer_begin(TslBuffer *self) { diff --git a/src/std/hash_map.c b/src/std_gc/hash_map.c index 9d8b4c4..1960ffc 100644 --- a/src/std/hash_map.c +++ b/src/std_gc/hash_map.c @@ -1,81 +1,44 @@ -#include "../../include/std/hash_map.h" +#include "../../include/std_gc/hash_map.h" #include <assert.h> #include <string.h> -#include <stdlib.h> #include <stdio.h> +#include <gc.h> typedef struct TslHashMapNode TslHashMapNode; struct TslHashMapNode { - void *data; + uint64_t hash; + TslValue key; + TslValue value; TslHashMapNode *next; }; -static void hash_map_node_get(TslHashMapNode *self, uint64_t *hash, TslStringView *key, size_t *size, uint8_t **data) { - memcpy(hash, (uint8_t*)self->data, sizeof(uint64_t)); - memcpy(&key->size, (uint8_t*)self->data + sizeof(uint64_t), sizeof(key->size)); - key->data = (const char*)self->data + sizeof(uint64_t) + sizeof(key->size); - memcpy(size, (uint8_t*)self->data + sizeof(uint64_t) + sizeof(key->size) + key->size, sizeof(size_t)); - *data = (uint8_t*)self->data + sizeof(uint64_t) + sizeof(key->size) + key->size + sizeof(size_t); -} - void tsl_hash_map_init(TslHashMap *self) { self->buckets_data = NULL; self->buckets_size = 0; self->buckets_capacity = 0; } -void tsl_hash_map_deinit(TslHashMap *self) { - TslHashMapNode **bucket = (TslHashMapNode**)self->buckets_data; - TslHashMapNode **bucket_end = (TslHashMapNode**)((char*)self->buckets_data + self->buckets_capacity); - while(bucket != bucket_end) { - TslHashMapNode *node = *bucket; - while(node) { - TslHashMapNode *prev_node = node; - node = node->next; - free(prev_node->data); - free(prev_node); - } - ++bucket; - } - free(self->buckets_data); -} - /* TODO: Remove if (data) and if (output) */ -static int tsl_hash_map_append_bucket(TslHashMapNode **head_node, uint64_t hash, const TslStringView *key, size_t size, const void *data, void **output) { +static int tsl_hash_map_append_bucket(TslHashMapNode **head_node, uint64_t hash, const TslValue *key, TslValue *value, TslValue **output) { TslHashMapNode *next_node; - uint8_t *node_data = malloc(sizeof(hash) + sizeof(key->size) + key->size + sizeof(size) + size); if(output) *output = NULL; - if(!node_data) { - fprintf(stderr, "Error: hash map append failed. Reason: out of memory\n"); - return 0; - } - - next_node = malloc(sizeof(TslHashMapNode)); + next_node = GC_MALLOC(sizeof(TslHashMapNode)); if(!next_node) { - free(node_data); - fprintf(stderr, "Error: hash map append failed. Reason: out of memory\n"); + fprintf(stderr, "Error: hash map insert failed. Reason: out of memory\n"); return 0; } - memcpy(node_data, &hash, sizeof(hash)); - /* TODO: Instead of allocating space for the key, use the key data pointer and size directly. */ - memcpy(node_data + sizeof(hash), &key->size, sizeof(key->size)); - memcpy(node_data + sizeof(hash) + sizeof(key->size), key->data, key->size); - /* - TODO: Instead of allocating space for the data, allow the user to pass a pointer in the insert - method and use that directly. - */ - memcpy(node_data + sizeof(hash) + sizeof(key->size) + key->size, &size, sizeof(size)); - if(data) - memcpy(node_data + sizeof(hash) + sizeof(key->size) + key->size + sizeof(size), data, size); + next_node->hash = hash; + next_node->key = *key; + if(value) + next_node->value = *value; if(output) - *output = node_data + sizeof(hash) + sizeof(key->size) + key->size + sizeof(size); + *output = &next_node->value; - next_node->data = node_data; if(*head_node) { next_node->next = (*head_node)->next; (*head_node)->next = next_node; @@ -83,6 +46,7 @@ static int tsl_hash_map_append_bucket(TslHashMapNode **head_node, uint64_t hash, next_node->next = NULL; *head_node = next_node; } + return 1; } @@ -100,15 +64,9 @@ static void tsl_hash_map_reorder_nodes(TslHashMap *self, size_t old_capacity) { TslHashMapNode *node = *bucket; TslHashMapNode *prev_node = node; /* Set to node for optimization reason, where prev_node->next = node->next; which becomes no-op */ int all_nodes_moved = 1; + while(node) { - uint64_t hash; - TslStringView key; - size_t size; - uint8_t *data; - size_t index; - hash_map_node_get(node, &hash, &key, &size, &data); - - index = tsl_hash_map_get_index(self, hash); + size_t index = tsl_hash_map_get_index(self, node->hash); if(index != bucket_index) { TslHashMapNode **new_bucket = (TslHashMapNode**)self->buckets_data + index; prev_node->next = node->next; @@ -151,7 +109,7 @@ static int tsl_hash_map_ensure_bucket_capacity_for_one_new_item(TslHashMap *self new_capacity <<= 1; } - new_ptr = realloc(self->buckets_data, new_capacity); + new_ptr = GC_REALLOC(self->buckets_data, new_capacity); if(!new_ptr) { fprintf(stderr, "Error: hash map realloc failed. Reason: out of memory\n"); return 0; @@ -160,6 +118,7 @@ static int tsl_hash_map_ensure_bucket_capacity_for_one_new_item(TslHashMap *self self->buckets_data = new_ptr; self->buckets_capacity = new_capacity; { + /* TODO: Remove this. This is not needed since GC_REALLOC sets the data to 0 */ TslHashMapNode **bucket = (TslHashMapNode**)((char*)self->buckets_data + old_capacity); TslHashMapNode **bucket_end = (TslHashMapNode**)((char*)self->buckets_data + new_capacity); while(bucket != bucket_end) { @@ -175,73 +134,61 @@ static int tsl_hash_map_ensure_bucket_capacity_for_one_new_item(TslHashMap *self return 1; } -int tsl_hash_map_insert(TslHashMap *self, const TslStringView *key, const void *data, size_t size, TslHashFunc hash_func) { - uint64_t hash = hash_func(key->data, key->size); +int tsl_hash_map_insert(TslHashMap *self, const TslValue *key, TslValue *value) { + uint64_t hash = tsl_value_hash(key); size_t index; TslHashMapNode **bucket; - assert(!tsl_hash_map_get(self, key, hash_func)); - assert(size > 0); + assert(!tsl_hash_map_get(self, key)); if(!tsl_hash_map_ensure_bucket_capacity_for_one_new_item(self)) return 0; index = tsl_hash_map_get_index(self, hash); bucket = (TslHashMapNode**)self->buckets_data + index; - return tsl_hash_map_append_bucket(bucket, hash, key, size, data, NULL); + return tsl_hash_map_append_bucket(bucket, hash, key, value, NULL); } -void* tsl_hash_map_get(TslHashMap *self, const TslStringView *key, TslHashFunc hash_func) { +TslValue* tsl_hash_map_get(TslHashMap *self, const TslValue *key) { uint64_t hash; size_t index; TslHashMapNode *node; if(self->buckets_capacity == 0) return NULL; - hash = hash_func(key->data, key->size); + hash = tsl_value_hash(key); index = tsl_hash_map_get_index(self, hash); node = *((TslHashMapNode**)self->buckets_data + index); while(node) { - uint64_t node_hash; - TslStringView node_key; - size_t node_size; - uint8_t *node_data; - hash_map_node_get(node, &node_hash, &node_key, &node_size, &node_data); - if(hash == node_hash && key->size == node_key.size && memcmp(key->data, node_key.data, node_key.size) == 0) - return node_data; + if(hash == node->hash && tsl_value_equals(key, &node->key)) + return &node->value; node = node->next; } return NULL; } -int tsl_hash_map_get_or_create(TslHashMap *self, const TslStringView *key, size_t size, TslHashFunc hash_func, void **output) { +TslValue* tsl_hash_map_get_or_create(TslHashMap *self, const TslValue *key) { uint64_t hash; size_t index; TslHashMapNode **bucket; TslHashMapNode *node; - assert(size > 0); + TslValue *value; if(self->buckets_capacity == 0) { - if(!tsl_hash_map_ensure_bucket_capacity_for_one_new_item(self)) { - *output = NULL; - return 0; - } + if(!tsl_hash_map_ensure_bucket_capacity_for_one_new_item(self)) + return NULL; } - hash = hash_func(key->data, key->size); + hash = tsl_value_hash(key); index = tsl_hash_map_get_index(self, hash); bucket = (TslHashMapNode**)self->buckets_data + index; node = *bucket; while(node) { - uint64_t node_hash; - TslStringView node_key; - size_t node_size; - uint8_t *node_data; - hash_map_node_get(node, &node_hash, &node_key, &node_size, &node_data); - if(hash == node_hash && key->size == node_key.size && memcmp(key->data, node_key.data, node_key.size) == 0) { - *output = node_data; - return 1; - } + if(hash == node->hash && tsl_value_equals(key, &node->key)) + return &node->value; node = node->next; } - return tsl_hash_map_append_bucket(bucket, hash, key, size, NULL, output); + if(!tsl_hash_map_append_bucket(bucket, hash, key, NULL, &value)) + return NULL; + + return value; } diff --git a/src/tokenizer.c b/src/tokenizer.c index 02592a9..a990052 100644 --- a/src/tokenizer.c +++ b/src/tokenizer.c @@ -4,7 +4,7 @@ #include <assert.h> #include <stdint.h> -void tsl_tokenizer_init(TslTokenizer *self, const char *code, size_t code_size) { +void tsl_tokenizer_init(TslTokenizer *self, char *code, size_t code_size) { self->code = code; self->code_size = code_size; self->code_index = 0; diff --git a/src/value.c b/src/value.c new file mode 100644 index 0000000..690527f --- /dev/null +++ b/src/value.c @@ -0,0 +1,45 @@ +#include "../include/value.h" +#include <string.h> + +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; +} + +uint64_t tsl_value_hash(const TslValue *key) { + switch(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_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_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 { + return *(uint64_t*)&lhs->data == *(uint64_t*)&rhs->data; + } + } else { + return 0; + } +} |