package vm import ( "fmt" "git.sharkk.net/Sharkk/Mako/types" ) type Opcode byte const ( OpConstant Opcode = iota OpSetGlobal OpGetGlobal OpEcho ) type Instruction struct { Opcode Opcode Operand int } type Bytecode struct { Constants []any Instructions []Instruction } type VM struct { constants []any globals map[string]types.Value stack []types.Value sp int // Stack pointer } func New() *VM { return &VM{ globals: make(map[string]types.Value), stack: make([]types.Value, 1024), // Fixed stack size for now sp: 0, } } func (vm *VM) Run(bytecode *Bytecode) { vm.constants = bytecode.Constants for ip := 0; ip < len(bytecode.Instructions); ip++ { instruction := bytecode.Instructions[ip] switch instruction.Opcode { case OpConstant: // Push constant to stack constIndex := instruction.Operand constant := vm.constants[constIndex] switch v := constant.(type) { case string: vm.push(types.NewString(v)) case float64: vm.push(types.NewNumber(v)) } case OpSetGlobal: // Set global variable constIndex := instruction.Operand name := vm.constants[constIndex].(string) value := vm.pop() vm.globals[name] = value case OpGetGlobal: // Get global variable constIndex := instruction.Operand name := vm.constants[constIndex].(string) if val, ok := vm.globals[name]; ok { vm.push(val) } else { vm.push(types.NewNull()) } case OpEcho: // Print value value := vm.pop() switch value.Type { case types.TypeString: fmt.Println(value.Data.(string)) case types.TypeNumber: fmt.Println(value.Data.(float64)) case types.TypeBoolean: fmt.Println(value.Data.(bool)) case types.TypeNull: fmt.Println("null") } } } } func (vm *VM) push(value types.Value) { vm.stack[vm.sp] = value vm.sp++ } func (vm *VM) pop() types.Value { vm.sp-- return vm.stack[vm.sp] }