package vm import "core:container/queue" import "core:fmt" import syn "../syntax-tree" VM :: struct { code: []syn.TOKEN, ip: u8, stack: ^queue.Queue(syn.TOKEN), } new_vm :: proc() -> ^VM { when ODIN_DEBUG { fmt.println("Created VM") } vm: ^VM = new(VM) vm.ip = 0 stack := new(queue.Queue(syn.TOKEN)) queue.init(stack) vm.stack = stack return vm } load_code :: proc(vm: ^VM, code: []syn.TOKEN) { vm.code = code } delete_vm :: proc(vm: ^VM) { when ODIN_DEBUG { fmt.println("Deleted VM") } delete(vm.code) queue.destroy(vm.stack) free(vm) } execute :: proc(vm: ^VM) -> f64 { using queue for token in vm.code { #partial switch token.type { case syn.TOKEN_TYPE.NUMBER: push_back(vm.stack, token) case syn.TOKEN_TYPE.OPERATOR: y := pop_back(vm.stack) x := pop_back(vm.stack) switch token.value { case syn.OPERATOR_TYPE.PLUS: push_back(vm.stack, vm_add(&x, &y)) case syn.OPERATOR_TYPE.MINUS: push_back(vm.stack, vm_sub(&x, &y)) case syn.OPERATOR_TYPE.MULTIPLY: push_back(vm.stack, vm_mul(&x, &y)) case syn.OPERATOR_TYPE.DIVIDE: push_back(vm.stack, vm_div(&x, &y)) } } } return pop_back(vm.stack).value.(f64) } @(private) vm_add :: #force_inline proc(x: ^syn.TOKEN, y: ^syn.TOKEN) -> syn.TOKEN { op1 := x.value.(f64) op2 := y.value.(f64) return syn.TOKEN{syn.TOKEN_TYPE.NUMBER, op1 + op2} } @(private) vm_sub :: #force_inline proc(x: ^syn.TOKEN, y: ^syn.TOKEN) -> syn.TOKEN { op1 := x.value.(f64) op2 := y.value.(f64) return syn.TOKEN{syn.TOKEN_TYPE.NUMBER, op1 - op2} } @(private) vm_mul :: #force_inline proc(x: ^syn.TOKEN, y: ^syn.TOKEN) -> syn.TOKEN { op1 := x.value.(f64) op2 := y.value.(f64) return syn.TOKEN{syn.TOKEN_TYPE.NUMBER, op1 * op2} } @(private) vm_div :: #force_inline proc(x: ^syn.TOKEN, y: ^syn.TOKEN) -> syn.TOKEN { op1 := x.value.(f64) op2 := y.value.(f64) return syn.TOKEN{syn.TOKEN_TYPE.NUMBER, op1 / op2} }