#include "../include/program.h" #include "../include/bytecode.h" #include "../include/command.h" #ifdef DEBUG #define GC_DEBUG #endif #include #include #include #include #include #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); } void tsl_program_deinit(TslProgram *self) { TslBytecode *bytecode_writer = tsl_buffer_begin(&self->function_bytecode_list); TslBytecode *bytecode_writer_end = tsl_buffer_end(&self->function_bytecode_list); while(bytecode_writer != bytecode_writer_end) { tsl_bytecode_deinit(bytecode_writer); ++bytecode_writer; } tsl_buffer_deinit(&self->function_bytecode_list); } 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) { 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"); /* TODO: Verify if these don't cause unaligned memory access on non-x86 platforms */ while(instruction != instruction_end) { TslOpcode opcode = *(TslOpcode*)instruction; TslInstructionType1 *instruction_type1 = (TslInstructionType1*)instruction; TslInstructionType2 *instruction_type2 = (TslInstructionType2*)instruction; TslInstructionType3 *instruction_type3 = (TslInstructionType3*)instruction; 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); 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"); 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 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); instruction += sizeof(TslInstructionType4); break; } case TSL_OPCODE_LIST: { printf("list %d\n", instruction_type1->value); instruction += sizeof(TslInstructionType1); break; } case TSL_OPCODE_MAP: { printf("map %d\n", instruction_type1->value); instruction += sizeof(TslInstructionType1); break; } case TSL_OPCODE_MINDEX: { printf("mindex\n"); instruction += sizeof(TslInstructionType5); break; } case TSL_OPCODE_CALLF: { printf("callf %d\n", instruction_type1->value); instruction += sizeof(TslInstructionType1); break; } case TSL_OPCODE_ADD: { printf("add\n"); instruction += sizeof(TslInstructionType5); break; } case TSL_OPCODE_SUB: { printf("sub\n"); instruction += sizeof(TslInstructionType5); break; } case TSL_OPCODE_MUL: { printf("mul\n"); instruction += sizeof(TslInstructionType5); break; } case TSL_OPCODE_DIV: { printf("div\n"); 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; 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; } } } 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; }