#ifndef BDL_VM_H #define BDL_VM_H #include "types.h" #include "errors.h" #include "chunk.h" #include "ops.h" #include "debug.h" #define VM_STACK_CAP 1024 typedef struct VM { // Program code. Chunk *chunk; // Program counter. u8 *pc; // Stack. Object *stack; } VM; VM vm_init(void); void vm_free(VM vm); void vm_interpret(VM vm); VM vm_init(void) { VM vm = { .chunk = chunk_init(), }; array_init(vm.stack, VM_STACK_CAP); return vm; } void vm_free(VM vm) { chunk_free(vm.chunk); array_free(vm.stack); } void vm_interpret(VM vm) { if (vm.chunk->code == NULL || array_size(vm.chunk->code) == 0) { error_push((Error){ .type = ERR_TYPE_RUNTIME, .value = ERR_EMPTY_CHUNK, }); return; } vm.pc = vm.chunk->code; u8 *last = vm.chunk->code + array_size(vm.chunk->code); while (vm.pc < last) { #ifdef DEBUG_TRACE_EXECUTION printf("stack: [ "); for (size_t i = 0; i < array_size(vm.stack); i++) { display(vm.stack[i]); if (i < array_size(vm.stack) - 1) { printf(" | "); } } printf(" ]\nop: "); disassemble_instruction(vm.chunk, (vm.pc - vm.chunk->code)); #endif u8 instruction = *vm.pc++; switch (instruction) { case OP_CONSTANT: { u8 constant = *vm.pc++; Object obj = vm.chunk->constants[constant]; array_push(vm.stack, obj); } break; case OP_SUM: { Object a = array_pop(vm.stack); Object b = array_pop(vm.stack); array_push(vm.stack, a + b); } break; case OP_SUB: { Object a = array_pop(vm.stack); Object b = array_pop(vm.stack); array_push(vm.stack, a - b); } break; case OP_MUL: { Object a = array_pop(vm.stack); Object b = array_pop(vm.stack); array_push(vm.stack, a * b); } break; case OP_DIV: { Object a = array_pop(vm.stack); Object b = array_pop(vm.stack); array_push(vm.stack, a / b); } break; case OP_MOD: { Object a = array_pop(vm.stack); Object b = array_pop(vm.stack); array_push(vm.stack, a % b); } break; case OP_RETURN: { display(array_pop(vm.stack)); printf("\n"); return; } break; default: { error_push((Error){ .type = ERR_TYPE_RUNTIME, .value = ERR_NOT_IMPLEMENTED, .line = vm.chunk->lines[0].line, .col = vm.chunk->lines[0].col, }); return; } break; } } error_push((Error){ .type = ERR_TYPE_RUNTIME, .value = ERR_PC_OOB, .line = vm.chunk->lines[0].line, .col = vm.chunk->lines[0].col, }); } #endif // BDL_VM_H