From 2ce9ebc39011831f9bd73511f696f1dd567ac0b9 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Wed, 29 Jan 2020 19:04:00 +0100 Subject: Allow passing variables to commands as args --- example.tsl | 13 ++++-- include/bytecode.h | 1 - include/program.h | 3 +- src/bytecode.c | 1 - src/parser.c | 12 +++++- src/program.c | 118 +++++++++++++++++++++++++++-------------------------- 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]; } { -- cgit v1.2.3