package vm import ( "jinx/pkg/lang/vm/code" "jinx/pkg/lang/vm/value" ) func (vm *VM) execPushInt(x int64) { vm.stack.Top().Push(value.NewInt(x)) } func (vm *VM) execPushFloat(x float64) { vm.stack.Top().Push(value.NewFloat(x)) } func (vm *VM) execPushString(str string) { vm.stack.Top().Push(value.NewString(str)) } func (vm *VM) execPushBool(b bool) { vm.stack.Top().Push(value.NewBool(b)) } func (vm *VM) execPushNull() { vm.stack.Top().Push(value.NewNull()) } func (vm *VM) execPushArray() { vm.stack.Top().Push(value.NewArray([]value.Value{})) } func (vm *VM) execGetLocal(offset int) error { top := vm.stack.Top() local, err := top.At(int(offset)) if err != nil { return err } top.Push(local) return nil } func (vm *VM) execGetArg() error { prev, err := vm.stack.Prev() if err != nil { return err } arg, err := prev.Pop() if err != nil { return err } vm.stack.Top().Push(arg) return nil } func (vm *VM) execAdd() error { top := vm.stack.Top() x, err := top.Pop() if err != nil { return err } y, err := top.Pop() if err != nil { return err } var res value.Value switch x.Type().Kind { case value.IntType: xv := x.Data().(value.IntData).Get() switch y.Type().Kind { case value.IntType: yv := y.Data().(value.IntData).Get() res = value.NewInt(xv + yv) case value.FloatType: yv := y.Data().(value.FloatData).Get() res = value.NewFloat(float64(xv) + yv) default: return ErrInvalidOperandTypes{ Op: code.OpAdd, X: x.Type(), Y: y.Type(), } } case value.FloatType: xv := x.Data().(value.FloatData).Get() switch y.Type().Kind { case value.IntType: yv := y.Data().(value.IntData).Get() res = value.NewFloat(xv + float64(yv)) case value.FloatType: yv := y.Data().(value.FloatData).Get() res = value.NewFloat(xv + yv) default: return ErrInvalidOperandTypes{ Op: code.OpAdd, X: x.Type(), Y: y.Type(), } } case value.StringType: switch y.Type().Kind { case value.StringType: res = value.NewString(x.Data().(value.StringData).Get() + y.Data().(value.StringData).Get()) default: return ErrInvalidOperandTypes{ Op: code.OpAdd, X: x.Type(), Y: y.Type(), } } default: return ErrInvalidOperandTypes{ Op: code.OpAdd, X: x.Type(), Y: y.Type(), } } top.Push(res) return nil } func (vm *VM) execSub() error { top := vm.stack.Top() x, err := top.Pop() if err != nil { return err } y, err := top.Pop() if err != nil { return err } var res value.Value switch x.Type().Kind { case value.IntType: xv := x.Data().(value.IntData).Get() switch y.Type().Kind { case value.IntType: yv := y.Data().(value.IntData).Get() res = value.NewInt(xv - yv) case value.FloatType: yv := y.Data().(value.FloatData).Get() res = value.NewFloat(float64(xv) - yv) default: return ErrInvalidOperandTypes{ Op: code.OpSub, X: x.Type(), Y: y.Type(), } } case value.FloatType: xv := x.Data().(value.FloatData).Get() switch y.Type().Kind { case value.IntType: yv := y.Data().(value.IntData).Get() res = value.NewFloat(xv - float64(yv)) case value.FloatType: yv := y.Data().(value.FloatData).Get() res = value.NewFloat(xv - yv) default: return ErrInvalidOperandTypes{ Op: code.OpSub, X: x.Type(), Y: y.Type(), } } default: return ErrInvalidOperandTypes{ Op: code.OpSub, X: x.Type(), Y: y.Type(), } } top.Push(res) return nil } func (vm *VM) execIndex() error { top := vm.stack.Top() v, err := top.Pop() if err != nil { return err } i, err := top.Pop() if err != nil { return err } switch v.Type().Kind { case value.ArrayType: arr := v.Data().(value.ArrayData) switch i.Type().Kind { case value.IntType: idx := i.Data().(value.IntData).Get() if idx < 0 || idx >= int64(arr.Len()) { return ErrArrayIndexOutOfBounds{ Index: int(idx), Len: arr.Len(), } } top.Push(arr.At(int(idx))) default: return ErrInvalidOperandTypes{ Op: code.OpIndex, X: i.Type(), Y: v.Type(), } } default: return ErrInvalidOperandTypes{ Op: code.OpIndex, X: v.Type(), Y: i.Type(), } } return nil }