// Author: simon // Author: ynwdlxm@163.com // Date: 2022/10/22 13:55 // Desc: Stack VM implement package vm import ( "fmt" "github/runnignwater/monkey/code" "github/runnignwater/monkey/compiler" "github/runnignwater/monkey/object" ) const StackSize = 2048 var True = &object.Boolean{Value: true} var False = &object.Boolean{Value: false} type VM struct { constants []object.Object instructions code.Instructions stack []object.Object sp int // Always points to the next value. Top of stack is stack[sp-1] } func New(byteCode *compiler.ByteCode) *VM { return &VM{ instructions: byteCode.Instructions, constants: byteCode.Constants, stack: make([]object.Object, StackSize), sp: 0, } } // func (vm *VM) StackTop() object.Object { // if vm.sp == 0 { // return nil // } // return vm.stack[vm.sp-1] // } func (vm *VM) Run() error { for ip := 0; ip < len(vm.instructions); ip++ { op := code.Opcode(vm.instructions[ip]) switch op { case code.OpConstant: constIndex := code.ReadUint16(vm.instructions[ip+1:]) ip += 2 // 执行 err := vm.push(vm.constants[constIndex]) if err != nil { return err } case code.OpTrue: err := vm.push(True) if err != nil { return err } case code.OpFalse: err := vm.push(False) if err != nil { return err } case code.OpAdd, code.OpSub, code.OpMul, code.OpDiv: err := vm.executeBinaryOperation(op) if err != nil { return err } case code.OpPop: vm.pop() } } return nil } func (vm *VM) push(o object.Object) error { if vm.sp >= StackSize { return fmt.Errorf("stack overflow") } vm.stack[vm.sp] = o vm.sp++ return nil } func (vm *VM) pop() object.Object { o := vm.stack[vm.sp-1] vm.sp-- return o } func (vm *VM) executeBinaryOperation(op code.Opcode) error { right := vm.pop() left := vm.pop() leftType := left.Type() rightType := right.Type() if leftType == object.IntegerObj && rightType == object.IntegerObj { return vm.executeBinaryIntegerOperation(op, left, right) } return fmt.Errorf("unsupported types of binary operation: %s %s", leftType, rightType) } func (vm *VM) LastPopStackElem() object.Object { return vm.stack[vm.sp] } func (vm *VM) executeBinaryIntegerOperation( op code.Opcode, left, right object.Object, ) error { leftValue := left.(*object.Integer).Value rightValue := right.(*object.Integer).Value var result int64 switch op { case code.OpAdd: result = leftValue + rightValue case code.OpSub: result = leftValue - rightValue case code.OpMul: result = leftValue * rightValue case code.OpDiv: result = leftValue / rightValue default: return fmt.Errorf("unknown integer operator: %d", op) } return vm.push(&object.Integer{Value: result}) }