Mako/vm/vm.go
2025-05-06 11:14:36 -05:00

105 lines
1.9 KiB
Go

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