aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2020-01-29 19:04:00 +0100
committerdec05eba <dec05eba@protonmail.com>2020-01-29 19:04:00 +0100
commit2ce9ebc39011831f9bd73511f696f1dd567ac0b9 (patch)
tree92f937d43ea7b2711879e0c00d23a1e3eade648d
parent1ab8f5d8bd9a730f8d6b11335343835b19fc4c3e (diff)
Allow passing variables to commands as args
-rwxr-xr-xexample.tsl13
-rw-r--r--include/bytecode.h1
-rw-r--r--include/program.h3
-rw-r--r--src/bytecode.c1
-rw-r--r--src/parser.c12
-rw-r--r--src/program.c118
6 files changed, 82 insertions, 66 deletions
diff --git a/example.tsl b/example.tsl
index 076ee30..879c0ce 100755
--- a/example.tsl
+++ b/example.tsl
@@ -104,9 +104,14 @@ value9["sayHello"]()
# setv "value1"
value1 = value1 + 23
-# loadca "curl"
-# loadca "https://example.com"
-# callc 2
+# loads "world"
+# setv "arg"
+arg = "world"
+
+# loads "echo"
+# loads "hello"
+# loadv "arg"
+# callc 3
# setv "response"
-response = $(echo hello world)
+response = $(echo hello $arg)
# compile error (empty command): $() \ No newline at end of file
diff --git a/include/bytecode.h b/include/bytecode.h
index 912da89..c0930ad 100644
--- a/include/bytecode.h
+++ b/include/bytecode.h
@@ -24,7 +24,6 @@ typedef enum {
TSL_OPCODE_SUB,
TSL_OPCODE_MUL,
TSL_OPCODE_DIV,
- TSL_OPCODE_LOADCA, /* add command argument to stack */
TSL_OPCODE_CALLC /* run a program using N arguments from the stack, where the bottom value is the name of the program */
} TslOpcode;
diff --git a/include/program.h b/include/program.h
index 52b4fe4..2fcdb07 100644
--- a/include/program.h
+++ b/include/program.h
@@ -16,8 +16,7 @@ typedef enum {
TSL_STACK_VALUE_TYPE_VARIABLE,
TSL_STACK_VALUE_TYPE_LIST,
TSL_STACK_VALUE_TYPE_MAP,
- TSL_STACK_VALUE_TYPE_INDEX,
- TSL_STACK_VALUE_TYPE_COMMAND_ARG
+ TSL_STACK_VALUE_TYPE_INDEX
} TslStackValueType;
typedef struct {
diff --git a/src/bytecode.c b/src/bytecode.c
index b8342b4..6f6e6aa 100644
--- a/src/bytecode.c
+++ b/src/bytecode.c
@@ -19,7 +19,6 @@ const char* tsl_opcode_to_string(TslOpcode opcode) {
case TSL_OPCODE_SUB: return "sub";
case TSL_OPCODE_MUL: return "mul";
case TSL_OPCODE_DIV: return "div";
- case TSL_OPCODE_LOADCA: return "loadca";
case TSL_OPCODE_CALLC: return "callc";
}
return "";
diff --git a/src/parser.c b/src/parser.c
index a6f340f..347e0de 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -226,7 +226,17 @@ static TslParseResult tsl_parser_parse_command(TslParser *self, int *num_args) {
TslCommandToken command_token = tsl_tokenizer_next_command_arg(&self->tokenizer, &command_arg);
if(command_token == TSL_COMMAND_TOKEN_ARG) {
++*num_args;
- return_if_error(tsl_bytecode_add_ins4(get_function_bytecode(self), TSL_OPCODE_LOADCA, &command_arg));
+ if(command_arg.data[0] == '$') {
+ command_arg.data += 1;
+ command_arg.size -= 1;
+ if(command_arg.size == 0) {
+ fprintf(stderr, "Error: Expected variable name after '$'\n");
+ return TSL_PARSE_RESULT_ERR;
+ }
+ return_if_error(tsl_bytecode_add_ins4(get_function_bytecode(self), TSL_OPCODE_LOADV, &command_arg));
+ } else {
+ return_if_error(tsl_bytecode_add_ins4(get_function_bytecode(self), TSL_OPCODE_LOADS, &command_arg));
+ }
} else if(command_token == TSL_COMMAND_TOKEN_END) {
return TSL_PARSE_RESULT_OK;
} else {
diff --git a/src/program.c b/src/program.c
index 71b310e..030d5aa 100644
--- a/src/program.c
+++ b/src/program.c
@@ -225,11 +225,6 @@ static TslProgramResult tsl_value_create_from_stack_value(TslProgram *self, TslV
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;
}
@@ -378,31 +373,41 @@ static TslProgramResult tsl_program_run_function(TslProgram *self, int function_
}
case TSL_OPCODE_CALLF: {
size_t args_size = 1 + instruction_type1->value;
- TslStackValue *args = (TslStackValue*)tsl_buffer_end(&self->stack_values) - args_size;
+ TslStackValue *args;
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;
+ /* Resolve args (which may have more than one stack value each) and then readd them onto the stack */
+
+ TslValue resolved_args[255];
+ size_t resolved_arg_index = 0;
TslStackValue *arg = (TslStackValue*)tsl_buffer_end(&self->stack_values) - 1;
- TslStackValue *args_begin = args - 1;
+ TslStackValue *args_begin = (TslStackValue*)tsl_buffer_end(&self->stack_values) - args_size - 1;
+ /* TODO: Support more than 255 args */
+ assert(self->stack_values.size / sizeof(TslStackValue) <= 255);
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;
+ cleanup_if_error(tsl_value_create_from_stack_value(self, &resolved_args[resolved_arg_index]));
+ ++resolved_arg_index;
--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;
+
+ {
+ size_t i = 0;
+ for(; i < resolved_arg_index; ++i) {
+ TslStackValue stack_value;
+ stack_value.data.variable = resolved_args[i];
+ stack_value.type = TSL_STACK_VALUE_TYPE_VARIABLE;
+ tsl_buffer_append(&self->stack_values, &stack_value, sizeof(stack_value));
+ }
+ }
}
+
+ args = (TslStackValue*)tsl_buffer_end(&self->stack_values) - args_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");
+ result = TSL_PROGRAM_RESULT_ERR;
goto cleanup;
}
@@ -453,53 +458,52 @@ static TslProgramResult tsl_program_run_function(TslProgram *self, int function_
instruction += sizeof(TslInstructionType5);
break;
}
- case TSL_OPCODE_LOADCA: {
- TslStackValue stack_value;
- stack_value.data.str = instruction_type4->value;
- stack_value.type = TSL_STACK_VALUE_TYPE_COMMAND_ARG;
- 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;
- }
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 *arg = args_begin;
char *command_args[255];
+ size_t command_arg_sizes[255];
char temp_null_save[255];
- size_t arg_index = 0;
- assert(instruction_type1->value > 0);
+ int arg_index = 254;
+
+
{
- /* TODO: Support infinite amount of args */
- assert(args_end - args_begin < 255);
- /*printf("Running command: ");*/
- 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] = arg->data.str.data;
- /*printf("%s ", command_args[arg_index]);*/
- ++arg_index;
- ++arg;
+ /* Resolve args (which may have more than one stack value each) and then readd them onto the stack */
+ int args_size = instruction_type1->value;
+ assert(args_size > 0);
+ /* TODO: Support more than 255 args */
+ assert(self->stack_values.size / sizeof(TslStackValue) <= 255);
+ for(; args_size > 0; --args_size) {
+ TslValue resolved_arg;
+ cleanup_if_error(tsl_value_create_from_stack_value(self, &resolved_arg));
+
+ switch(resolved_arg.type) {
+ case TSL_TYPE_STRING: {
+ --arg_index;
+ command_args[arg_index] = resolved_arg.data.string->data;
+ command_arg_sizes[arg_index] = resolved_arg.data.string->size;
+ break;
+ }
+ case TSL_TYPE_STRING_REF: {
+ --arg_index;
+ temp_null_save[arg_index] = resolved_arg.data.string_ref.data[resolved_arg.data.string_ref.size];
+ resolved_arg.data.string_ref.data[resolved_arg.data.string_ref.size] = '\0';
+ command_args[arg_index] = resolved_arg.data.string_ref.data;
+ command_arg_sizes[arg_index] = resolved_arg.data.string_ref.size;
+ break;
+ }
+ default:
+ fprintf(stderr, "Error: Unable to convert %s to a string in a command\n", "TODO");
+ result = TSL_PROGRAM_RESULT_ERR;
+ goto cleanup;
+ }
}
- command_args[arg_index] = NULL;
- /*printf("\n");*/
+ command_args[254] = NULL;
}
- tsl_command_exec(command_args, program_output_temp, NULL);
+ tsl_command_exec(command_args + arg_index, program_output_temp, NULL);
- {
- arg = args_begin;
- arg_index = 0;
- /* TODO: Support infinite amount of args */
- while(arg != args_end) {
- arg->data.str.data[arg->data.str.size] = temp_null_save[arg_index];
- ++arg_index;
- ++arg;
- }
- command_args[arg_index] = NULL;
+ /* Restore null terminate character switched. TODO: Only do this once at program launch, when tsl owns the source code buffer */
+ for(; arg_index < 254; ++arg_index) {
+ command_args[arg_index][command_arg_sizes[arg_index]] = temp_null_save[arg_index];
}
{