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}
}