aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2020-01-26 08:02:17 +0100
committerdec05eba <dec05eba@protonmail.com>2020-01-26 08:03:53 +0100
commit31519e8a586791d60e6e56e558c2a3bf973cc1f9 (patch)
tree9195b99953568103fe58025d5888960a48a0c051
parent5df950e0b35207930c645e8ce0c3e9ed1c9fcea5 (diff)
Implement plus operator and indexing of strings
-rw-r--r--example.tsl6
-rw-r--r--include/program.h2
-rw-r--r--include/std_gc/hash_map.h33
-rw-r--r--include/std_gc/list.h2
-rw-r--r--include/value.h12
-rw-r--r--src/program.c52
-rw-r--r--src/std_gc/hash_map.c37
-rw-r--r--src/std_gc/list.c2
-rw-r--r--src/value.c130
9 files changed, 257 insertions, 19 deletions
diff --git a/example.tsl b/example.tsl
index e85b779..e868f77 100644
--- a/example.tsl
+++ b/example.tsl
@@ -18,6 +18,12 @@ value3 = null
# setv "value4"
value4 = "hello world"
+# loadv "value4"
+# loadn 0.000000
+# mindex
+# setv "c"
+c = value4[0]
+
# loads "hello"
# loads "world"
# loadn 5
diff --git a/include/program.h b/include/program.h
index bbd3f37..52b4fe4 100644
--- a/include/program.h
+++ b/include/program.h
@@ -12,6 +12,7 @@ typedef enum {
TSL_STACK_VALUE_TYPE_STRING,
TSL_STACK_VALUE_TYPE_NULL,
TSL_STACK_VALUE_TYPE_FUNCTION,
+ TSL_STACK_VALUE_TYPE_VARIABLE_NAME,
TSL_STACK_VALUE_TYPE_VARIABLE,
TSL_STACK_VALUE_TYPE_LIST,
TSL_STACK_VALUE_TYPE_MAP,
@@ -25,6 +26,7 @@ typedef struct {
double number;
TslBool boolean;
TslStringView str;
+ TslValue variable;
} data;
TslStackValueType type;
} TslStackValue;
diff --git a/include/std_gc/hash_map.h b/include/std_gc/hash_map.h
index e1a016d..fb6221b 100644
--- a/include/std_gc/hash_map.h
+++ b/include/std_gc/hash_map.h
@@ -2,15 +2,30 @@
#define TSL_HASH_MAP_H
#include "../forward_decl.h"
+#include "../value.h"
#include <stdint.h>
#include <stddef.h>
+typedef struct TslHashMapNode TslHashMapNode;
+struct TslHashMapNode {
+ uint64_t hash;
+ TslValue key;
+ TslValue value;
+ TslHashMapNode *next;
+};
+
/* TODO: Optimize small hash map by using the members of the struct instead of allocating on heap */
-typedef struct {
+struct TslHashMap {
void *buckets_data; /* value=TslHashMapNode */
size_t buckets_size;
size_t buckets_capacity;
-} TslHashMap;
+};
+
+typedef struct {
+ TslHashMap *hash_map;
+ size_t index;
+ TslHashMapNode *node;
+} TslHashMapIterator;
void tsl_hash_map_init(TslHashMap *self);
@@ -27,4 +42,18 @@ TslValue* tsl_hash_map_get(TslHashMap *self, const TslValue *key);
*/
TslValue* tsl_hash_map_get_or_create(TslHashMap *self, const TslValue *key);
+/*
+ How to use the iterator:
+
+ TslHashMapIterator iterator;
+ tsl_hash_map_create_iterator(hash_map, &iterator);
+ while(tsl_hash_map_iterator_next(&iterator)) {
+ TslValue *key = &iterator.node->key;
+ TslValue *value = &iterator.node->value;
+ }
+*/
+
+void tsl_hash_map_create_iterator(TslHashMap *self, TslHashMapIterator *iterator);
+int tsl_hash_map_iterator_next(TslHashMapIterator *self);
+
#endif /* TSL_HASH_MAP_H */
diff --git a/include/std_gc/list.h b/include/std_gc/list.h
index 469f585..a97f311 100644
--- a/include/std_gc/list.h
+++ b/include/std_gc/list.h
@@ -16,6 +16,6 @@ int tsl_list_set_capacity_hint(TslList *self, size_t capacity);
TslValue* tsl_list_begin(TslList *self);
TslValue* tsl_list_end(TslList *self);
/* Returns NULL if index is out of bounds of the list */
-TslValue* tsl_list_get(TslList *self, double index);
+TslValue* tsl_list_get(const TslList *self, double index);
#endif /* TSL_LIST_H */
diff --git a/include/value.h b/include/value.h
index 7dd6d28..b90b446 100644
--- a/include/value.h
+++ b/include/value.h
@@ -6,7 +6,6 @@
#include <stdint.h>
#include "string_view.h"
#include "std_gc/list.h"
-#include "std_gc/hash_map.h"
typedef enum {
TSL_TYPE_NULL,
@@ -36,10 +35,16 @@ typedef struct {
/* This is an index to the function */
typedef int TslFunction;
+typedef struct TslHashMap TslHashMap;
+
struct TslValue {
union {
TslNumber number;
TslString *string;
+ /*
+ TODO: Make this an int that refers to the index in the bytecode which contains the string view.
+ Then the size of this union will be 8 bytes instead of 16 bytes on 64-bit systems.
+ */
TslStringView string_ref;
TslBool boolean;
TslBool null;
@@ -58,4 +63,9 @@ int tsl_value_equals(const TslValue *lhs, const TslValue *rhs);
/* This should be called before setting/modifying the data of the value */
void tsl_value_clear(TslValue *self);
+int tsl_value_add(const TslValue *lhs_value, const TslValue *rhs_value, TslValue *result);
+
+/* Returns NULL if index is out of bounds of the list */
+TslValue* tsl_string_ref_get(const TslStringView *self, double index);
+
#endif /* TSL_VALUE_H */
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;
+}