aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2020-01-26 11:56:53 +0100
committerdec05eba <dec05eba@protonmail.com>2020-01-26 11:56:53 +0100
commitfa1f9af151526a6679d605c8af91d502cef90b75 (patch)
treeb600601afa01fa8cc672c364381603c35eb61df1
parent699482118d0fa92ffc0a4a185bc35c6398f5f4fe (diff)
Implement the basis of a function call
-rw-r--r--Makefile5
-rw-r--r--README.md2
-rwxr-xr-x[-rw-r--r--]example.tsl4
-rwxr-xr-xexamples/curl.tsl3
-rw-r--r--src/program.c136
5 files changed, 103 insertions, 47 deletions
diff --git a/Makefile b/Makefile
index f6ec581..095856f 100644
--- a/Makefile
+++ b/Makefile
@@ -3,7 +3,7 @@ LIBS = -lgc
OBJ = build/main.o build/tokenizer.o build/parser.o build/program.o build/bytecode.o build/value.o build/command.o build/buffer.o build/hash_map.o build/list.o
CC = cc
-all: build_dir $(OBJ)
+build: build_dir $(OBJ)
$(CC) -o build/tsl $(OBJ) $(LIBS)
clean:
@@ -15,6 +15,9 @@ build_dir:
compiledb:
make clean; bear make
+install: build
+ install -m +x -s build/tsl /usr/local/bin/tsl
+
build/main.o: src/main.c include/tokenizer.h
$(CC) -c src/main.c -o build/main.o $(CFLAGS)
diff --git a/README.md b/README.md
index 072cc5c..1426b2e 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,8 @@
A tiny scripting language that is designed to be a replacement for small shell/python scripts.\
Written in ANSI C to allow embedding everywhere and a WTFPL license that allows it to be used anywhere without any restrictions.\
See example.tsl for an example of what tsl looks like.
+# Installation
+Run: `sudo make install`. The tsl binary will be installed in /usr/bin/local.
# TODO
* Remove dependency on `gc`. Write our own gc instead.
* Implement big int, which numbers should automatically switch to when they are too large to fit into double.
diff --git a/example.tsl b/example.tsl
index 5146713..092e7e5 100644..100755
--- a/example.tsl
+++ b/example.tsl
@@ -1,3 +1,5 @@
+#!/usr/bin/env tsl
+
# loadn 1
# setv "value1"
value1 = 1
@@ -80,7 +82,7 @@ value8 = fn (value) {}
value9 = {
"hello": "world",
"sayHello": fn() {
-
+ result = $(echo hello)
}
}
diff --git a/examples/curl.tsl b/examples/curl.tsl
new file mode 100755
index 0000000..9f722d4
--- /dev/null
+++ b/examples/curl.tsl
@@ -0,0 +1,3 @@
+#!/usr/bin/env tsl
+
+result = $(curl https://wttr.in/)
diff --git a/src/program.c b/src/program.c
index efb9407..88f94a4 100644
--- a/src/program.c
+++ b/src/program.c
@@ -38,6 +38,7 @@ void tsl_program_deinit(TslProgram *self) {
++bytecode_writer;
}
tsl_buffer_deinit(&self->function_bytecode_list);
+ GC_deinit(); /* TODO: Remove this */
}
static int program_output_temp(char *data, int size, void *userdata) {
@@ -70,7 +71,8 @@ static TslProgramResult tsl_string_ref_get_item_at_index(const TslStringView *se
return TSL_PROGRAM_RESULT_OK;
}
-static TslProgramResult tsl_value_create_from_stack_value(TslProgram *self, TslStackValue *src, TslValue *dst) {
+static TslProgramResult tsl_value_create_from_stack_value(TslProgram *self, TslValue *dst) {
+ TslStackValue *src = tsl_buffer_pop(&self->stack_values, sizeof(TslStackValue));
tsl_value_clear(dst);
switch(src->type) {
case TSL_STACK_VALUE_TYPE_NUMBER: {
@@ -136,10 +138,8 @@ static TslProgramResult tsl_value_create_from_stack_value(TslProgram *self, TslS
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;
+ int i = src->data.integer - 1;
dst->data.list = GC_MALLOC(sizeof(TslList));
return_if_error(dst->data.list);
@@ -148,44 +148,40 @@ static TslProgramResult tsl_value_create_from_stack_value(TslProgram *self, TslS
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));
+ while(i >= 0) {
+ return_if_error(tsl_value_create_from_stack_value(self, list_item));
--list_item;
- --item;
+ --i;
}
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;
+ int i = src->data.integer - 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) {
+ while(i >= 0) {
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_value_create_from_stack_value(self, &map_value));
+ return_if_error(tsl_value_create_from_stack_value(self, &map_key));
return_if_error(tsl_hash_map_insert(dst->data.map, &map_key, &map_value));
- item -= 2;
+ i -= 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));
+ return_if_error(tsl_value_create_from_stack_value(self, &key));
+ return_if_error(tsl_value_create_from_stack_value(self, &var));
if(var.type == TSL_TYPE_LIST) {
TslValue *list_item;
@@ -236,13 +232,12 @@ static TslProgramResult tsl_value_create_from_stack_value(TslProgram *self, TslS
}
static TslProgramResult tsl_program_perform_operation(TslProgram *self, TslNumber(*operation_func)(TslNumber lhs, TslNumber rhs)) {
- TslStackValue *args = tsl_buffer_pop(&self->stack_values, sizeof(TslStackValue) * 2);
TslValue lhs_value;
TslValue rhs_value;
TslStackValue stack_value;
- return_if_error(tsl_value_create_from_stack_value(self, args + 1, &rhs_value));
- return_if_error(tsl_value_create_from_stack_value(self, args, &lhs_value));
+ return_if_error(tsl_value_create_from_stack_value(self, &rhs_value));
+ return_if_error(tsl_value_create_from_stack_value(self, &lhs_value));
if(lhs_value.type != TSL_TYPE_NUMBER) {
fprintf(stderr, "Error: Unable to perform operation '+' between a TODO and a TODO\n");
@@ -270,21 +265,12 @@ static TslNumber number_operation_div(TslNumber lhs, TslNumber rhs) {
return lhs / rhs;
}
-TslProgramResult tsl_program_run(TslProgram *self) {
+static TslProgramResult tsl_program_run_function(TslProgram *self, int function_index) {
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);
-
- 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");
+ TslBytecode *function_bytecode = (TslBytecode*)tsl_buffer_begin(&self->function_bytecode_list) + function_index;
+ char *instruction = tsl_buffer_begin(&function_bytecode->buffer);
+ char *instruction_end = tsl_buffer_end(&function_bytecode->buffer);
+ size_t prev_stack_value_size = self->stack_values.size;
/* TODO: Verify if these don't cause unaligned memory access on non-x86 platforms */
while(instruction != instruction_end) {
@@ -348,7 +334,6 @@ TslProgramResult tsl_program_run(TslProgram *self) {
break;
}
case TSL_OPCODE_SETV: {
- TslStackValue *stack_value = tsl_buffer_pop(&self->stack_values, sizeof(TslStackValue));
TslValue map_key;
TslValue *map_value;
map_key.type = TSL_TYPE_STRING_REF;
@@ -357,7 +342,7 @@ TslProgramResult tsl_program_run(TslProgram *self) {
map_value = tsl_hash_map_get_or_create(self->variables, &map_key);
cleanup_if_error(map_value);
- cleanup_if_error(tsl_value_create_from_stack_value(self, stack_value, map_value));
+ cleanup_if_error(tsl_value_create_from_stack_value(self, map_value));
/*printf("setv \"%.*s\"\n", (int)instruction_type4->value.size, instruction_type4->value.data);*/
instruction += sizeof(TslInstructionType4);
break;
@@ -389,22 +374,56 @@ TslProgramResult tsl_program_run(TslProgram *self) {
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;
+ size_t args_size = 1 + instruction_type1->value;
+ TslStackValue *args = (TslStackValue*)tsl_buffer_end(&self->stack_values) - args_size;
+ assert(self->stack_values.size >= args_size);
+
+ {
+ /* Resolved values pushed to stack and replace them in the stack */
+ size_t prev_stack_size = self->stack_values.size;
+ TslStackValue *arg = (TslStackValue*)tsl_buffer_end(&self->stack_values) - 1;
+ TslStackValue *args_begin = args - 1;
+ while(arg != args_begin) {
+ TslValue new_value;
+ cleanup_if_error(tsl_value_create_from_stack_value(self, &new_value));
+ arg->data.variable = new_value;
+ arg->type = TSL_STACK_VALUE_TYPE_VARIABLE;
+ --arg;
+ }
+ /*
+ Reset the stack size here because @tsl_value_create_from_stack_value which is called above pops the stack (without reallocation).
+ TODO: Modify @tsl_value_create_from_stack_value to not pop stack and instead operate with stack pointer.
+ */
+ self->stack_values.size = prev_stack_size;
+ }
+
+ assert(args[0].type == TSL_STACK_VALUE_TYPE_VARIABLE);
+ if(args[0].data.variable.type != TSL_TYPE_FUNCTION) {
+ fprintf(stderr, "Error: Unable to call a non-function type\n");
+ goto cleanup;
+ }
+
+ cleanup_if_error(tsl_program_run_function(self, args[0].data.variable.data.function));
+ tsl_buffer_pop(&self->stack_values, sizeof(TslStackValue) * args_size);
+
/* TODO: Implement this */
+ {
+ /* TODO: This is only temporary. This should be replaced with push the result of the function call onto the stack */
+ TslStackValue stack_value;
+ stack_value.type = TSL_STACK_VALUE_TYPE_NULL;
+ cleanup_if_error(tsl_buffer_append(&self->stack_values, &stack_value, sizeof(stack_value)));
+ }
/*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);
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_create_from_stack_value(self, &rhs_value));
+ cleanup_if_error(tsl_value_create_from_stack_value(self, &lhs_value));
cleanup_if_error(tsl_value_add(&lhs_value, &rhs_value, &stack_value.data.variable));
stack_value.type = TSL_STACK_VALUE_TYPE_VARIABLE;
@@ -479,6 +498,13 @@ TslProgramResult tsl_program_run(TslProgram *self) {
}
command_args[arg_index] = NULL;
}
+
+ {
+ /* TODO: This is only temporary. This should be replaced with push the result of the command onto the stack */
+ TslStackValue stack_value;
+ stack_value.type = TSL_STACK_VALUE_TYPE_NULL;
+ cleanup_if_error(tsl_buffer_append(&self->stack_values, &stack_value, sizeof(stack_value)));
+ }
/*printf("callc %d\n", instruction_type1->value);*/
instruction += sizeof(TslInstructionType1);
@@ -489,9 +515,29 @@ TslProgramResult tsl_program_run(TslProgram *self) {
cleanup:
/*
- If self->stack_values.size is more than 0, then there are operations (for example CALLF) that pushes a value to the stack but the returned value
- is not assigned to any variable. At the end of functions, these stack values are cleaned up even if they are not handled.
+ This a bug in the compiler. The compiler pop'ed more values that pushed to the stack.
+ It's fine if there were values that were pushed to the stack but not pop'ed. This happens for example if there is a function call
+ and the result is not assigned to a variable (in other words, the result is ignored).
+ This will automatically be cleaned up here and in loops it will be cleaned up at the end of the loop scope.
*/
+ assert(self->stack_values.size >= prev_stack_value_size);
+ self->stack_values.size = prev_stack_value_size;
+ return result;
+}
+
+TslProgramResult tsl_program_run(TslProgram *self) {
+ TslProgramResult result = TSL_PROGRAM_RESULT_OK;
+
+ 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");
+ result = tsl_program_run_function(self, 0);
tsl_buffer_deinit(&self->stack_values);
GC_FREE(self->variables); /* Free the root object, resulting in all objects in the program being free'd */