From b16b70fd40ffc72ff861afe0517cba0e37ba1145 Mon Sep 17 00:00:00 2001 From: Mel Date: Wed, 6 Jul 2022 14:06:20 +0200 Subject: Implement most of the binary operations --- pkg/lang/vm/code/op.go | 8 +- pkg/lang/vm/exec.go | 443 ++++++++++++++++++++++--------------------------- pkg/lang/vm/text/op.go | 9 +- pkg/lang/vm/vm.go | 15 +- 4 files changed, 221 insertions(+), 254 deletions(-) (limited to 'pkg/lang/vm') diff --git a/pkg/lang/vm/code/op.go b/pkg/lang/vm/code/op.go index d0b2555..665742d 100644 --- a/pkg/lang/vm/code/op.go +++ b/pkg/lang/vm/code/op.go @@ -33,10 +33,16 @@ const ( OpAdd OpSub + OpMul + OpDiv OpMod - OpIndex + OpEq OpLt + OpGt OpLte + OpGte + + OpIndex OpCall OpJmp diff --git a/pkg/lang/vm/exec.go b/pkg/lang/vm/exec.go index 181d74e..32b1013 100644 --- a/pkg/lang/vm/exec.go +++ b/pkg/lang/vm/exec.go @@ -1,6 +1,7 @@ package vm import ( + "fmt" "jinx/pkg/lang/vm/code" "jinx/pkg/lang/vm/mem" "jinx/pkg/lang/vm/value" @@ -432,7 +433,10 @@ func (vm *VM) execAnchorType() error { return nil } -func (vm *VM) execAdd() error { +type binaryOperation = func(value.Value, value.Value) (value.Value, error) +type typesToBinaryOperation = map[value.TypeKind]map[value.TypeKind]binaryOperation + +func (vm *VM) execGenericBinaryOperation(op code.Op, fns typesToBinaryOperation) error { y, err := vm.stack.Pop() if err != nil { return err @@ -442,73 +446,32 @@ func (vm *VM) execAdd() error { return err } - var res value.Value - - switch x.Type() { - case value.IntType: - xv := x.Data().(value.IntData).Get() - switch y.Type() { - 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() { - 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: - xv, err := x.Data().(value.StringData).RawString(vm.memory) - if err != nil { - return err + subTypes, ok := fns[x.Type()] + if !ok { + return ErrInvalidOperandTypes{ + Op: op, + X: x.Type(), + Y: y.Type(), } + } - switch y.Type() { - case value.StringType: - yv, err := y.Data().(value.StringData).RawString(vm.memory) - if err != nil { - return err - } - - res, err = value.NewString(vm.memory, xv+yv) - if err != nil { - return err - } - default: - return ErrInvalidOperandTypes{ - Op: code.OpAdd, - X: x.Type(), - Y: y.Type(), - } - } - default: + binaryOp, ok := subTypes[y.Type()] + if !ok { return ErrInvalidOperandTypes{ - Op: code.OpAdd, + Op: op, X: x.Type(), Y: y.Type(), } } + fmt.Print(x) + fmt.Print(y) + + res, err := binaryOp(x, y) + if err != nil { + return err + } + x.Drop(vm.memory) y.Drop(vm.memory) @@ -516,99 +479,195 @@ func (vm *VM) execAdd() error { return nil } -func (vm *VM) execSub() error { - y, err := vm.popAndDrop() - if err != nil { - return err +func createGenericNumericBinaryOperationTypes(ifn func(int64, int64) int64, ffn func(float64, float64) float64) typesToBinaryOperation { + return typesToBinaryOperation{ + value.IntType: { + value.IntType: func(x, y value.Value) (value.Value, error) { + xv := x.Data().(value.IntData).Get() + yv := y.Data().(value.IntData).Get() + return value.NewInt(ifn(xv, yv)), nil + }, + value.FloatType: func(x, y value.Value) (value.Value, error) { + xv := x.Data().(value.IntData).Get() + yv := y.Data().(value.FloatData).Get() + return value.NewFloat(ffn(float64(xv), yv)), nil + }, + }, + value.FloatType: { + value.IntType: func(x, y value.Value) (value.Value, error) { + xv := x.Data().(value.FloatData).Get() + yv := y.Data().(value.IntData).Get() + return value.NewFloat(ffn(xv, float64(yv))), nil + }, + value.FloatType: func(x, y value.Value) (value.Value, error) { + xv := x.Data().(value.FloatData).Get() + yv := y.Data().(value.FloatData).Get() + return value.NewFloat(ffn(xv, yv)), nil + }, + }, } - x, err := vm.popAndDrop() - if err != nil { - return err +} + +func createGenericComparisonBinaryOperationTypes(ifn func(int64, int64) bool, ffn func(float64, float64) bool) typesToBinaryOperation { + return typesToBinaryOperation{ + value.IntType: { + value.IntType: func(x, y value.Value) (value.Value, error) { + xv := x.Data().(value.IntData).Get() + yv := y.Data().(value.IntData).Get() + return value.NewBool(ifn(xv, yv)), nil + }, + value.FloatType: func(x, y value.Value) (value.Value, error) { + xv := x.Data().(value.IntData).Get() + yv := y.Data().(value.FloatData).Get() + return value.NewBool(ffn(float64(xv), yv)), nil + }, + }, + value.FloatType: { + value.IntType: func(x, y value.Value) (value.Value, error) { + xv := x.Data().(value.FloatData).Get() + yv := y.Data().(value.IntData).Get() + return value.NewBool(ffn(xv, float64(yv))), nil + }, + value.FloatType: func(x, y value.Value) (value.Value, error) { + xv := x.Data().(value.FloatData).Get() + yv := y.Data().(value.FloatData).Get() + return value.NewBool(ffn(xv, yv)), nil + }, + }, } +} - var res value.Value +func (vm *VM) execAdd() error { + return vm.execGenericBinaryOperation(code.OpAdd, typesToBinaryOperation{ + value.IntType: { + value.IntType: func(x, y value.Value) (value.Value, error) { + xv := x.Data().(value.IntData).Get() + yv := y.Data().(value.IntData).Get() + return value.NewInt(xv + yv), nil + }, + value.FloatType: func(x, y value.Value) (value.Value, error) { + xv := x.Data().(value.IntData).Get() + yv := y.Data().(value.FloatData).Get() + return value.NewFloat(float64(xv) + yv), nil + }, + }, + value.FloatType: { + value.IntType: func(x, y value.Value) (value.Value, error) { + xv := x.Data().(value.FloatData).Get() + yv := y.Data().(value.IntData).Get() + return value.NewFloat(xv + float64(yv)), nil + }, + value.FloatType: func(x, y value.Value) (value.Value, error) { + xv := x.Data().(value.FloatData).Get() + yv := y.Data().(value.FloatData).Get() + return value.NewFloat(xv + yv), nil + }, + }, + value.StringType: { + value.StringType: func(x, y value.Value) (value.Value, error) { + xv, err := x.Data().(value.StringData).RawString(vm.memory) + if err != nil { + return value.Value{}, err + } + yv, err := y.Data().(value.StringData).RawString(vm.memory) + if err != nil { + return value.Value{}, err + } - switch x.Type() { - case value.IntType: - xv := x.Data().(value.IntData).Get() - switch y.Type() { - 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() { - 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(), - } - } + return value.NewString(vm.memory, xv+yv) + }, + }, + }) +} - vm.stack.Push(res) - return nil +func (vm *VM) execSub() error { + return vm.execGenericBinaryOperation(code.OpSub, createGenericNumericBinaryOperationTypes( + func(x, y int64) int64 { return x - y }, + func(x, y float64) float64 { return x - y }, + )) +} + +func (vm *VM) execMul() error { + return vm.execGenericBinaryOperation(code.OpMul, createGenericNumericBinaryOperationTypes( + func(x, y int64) int64 { return x * y }, + func(x, y float64) float64 { return x * y }, + )) +} + +func (vm *VM) execDiv() error { + return vm.execGenericBinaryOperation(code.OpDiv, createGenericNumericBinaryOperationTypes( + func(x, y int64) int64 { return x / y }, + func(x, y float64) float64 { return x / y }, + )) } func (vm *VM) execMod() error { - y, err := vm.popAndDrop() + return vm.execGenericBinaryOperation(code.OpMod, typesToBinaryOperation{ + value.IntType: { + value.IntType: func(x, y value.Value) (value.Value, error) { + xv := x.Data().(value.IntData).Get() + yv := y.Data().(value.IntData).Get() + return value.NewInt(xv % yv), nil + }, + }, + }) +} + +func (vm *VM) execEq() error { + y, err := vm.stack.Pop() if err != nil { return err } - x, err := vm.popAndDrop() + x, err := vm.stack.Pop() if err != nil { return err } - var res value.Value + result := func(res bool) error { + x.Drop(vm.memory) + y.Drop(vm.memory) - switch x.Type() { - case value.IntType: - xv := x.Data().(value.IntData).Get() - switch y.Type() { - case value.IntType: - yv := y.Data().(value.IntData).Get() - res = value.NewInt(xv % yv) - default: - return ErrInvalidOperandTypes{ - Op: code.OpMod, - X: x.Type(), - Y: y.Type(), - } - } - default: - return ErrInvalidOperandTypes{ - Op: code.OpMod, - X: x.Type(), - Y: y.Type(), - } + vm.stack.Push(value.NewBool(res)) + return nil } - vm.stack.Push(res) - return nil + if x.Type() != y.Type() { + return result(false) + } + + if x.Data() != y.Data() { + return result(false) + } + + return result(true) +} + +func (vm *VM) execLt() error { + return vm.execGenericBinaryOperation(code.OpLt, createGenericComparisonBinaryOperationTypes( + func(x, y int64) bool { return x < y }, + func(x, y float64) bool { return x < y }, + )) +} + +func (vm *VM) execGt() error { + return vm.execGenericBinaryOperation(code.OpGt, createGenericComparisonBinaryOperationTypes( + func(x, y int64) bool { return x > y }, + func(x, y float64) bool { return x > y }, + )) +} + +func (vm *VM) execLte() error { + return vm.execGenericBinaryOperation(code.OpLte, createGenericComparisonBinaryOperationTypes( + func(x, y int64) bool { return x <= y }, + func(x, y float64) bool { return x <= y }, + )) +} + +func (vm *VM) execGte() error { + return vm.execGenericBinaryOperation(code.OpGte, createGenericComparisonBinaryOperationTypes( + func(x, y int64) bool { return x >= y }, + func(x, y float64) bool { return x >= y }, + )) } func (vm *VM) execIndex() error { @@ -662,120 +721,6 @@ func (vm *VM) execIndex() error { return nil } -func (vm *VM) execLt() error { - y, err := vm.popAndDrop() - if err != nil { - return err - } - x, err := vm.popAndDrop() - if err != nil { - return err - } - - var res value.Value - - switch x.Type() { - case value.IntType: - xv := x.Data().(value.IntData).Get() - switch y.Type() { - case value.IntType: - yv := y.Data().(value.IntData).Get() - res = value.NewBool(xv < yv) - case value.FloatType: - yv := y.Data().(value.FloatData).Get() - res = value.NewBool(float64(xv) < yv) - default: - return ErrInvalidOperandTypes{ - Op: code.OpLte, - X: x.Type(), - Y: y.Type(), - } - } - case value.FloatType: - xv := x.Data().(value.FloatData).Get() - switch y.Type() { - case value.IntType: - yv := y.Data().(value.IntData).Get() - res = value.NewBool(xv < float64(yv)) - case value.FloatType: - yv := y.Data().(value.FloatData).Get() - res = value.NewBool(xv < yv) - default: - return ErrInvalidOperandTypes{ - Op: code.OpLte, - X: x.Type(), - Y: y.Type(), - } - } - default: - return ErrInvalidOperandTypes{ - Op: code.OpLte, - X: x.Type(), - Y: y.Type(), - } - } - - vm.stack.Push(res) - return nil -} - -func (vm *VM) execLte() error { - y, err := vm.popAndDrop() - if err != nil { - return err - } - x, err := vm.popAndDrop() - if err != nil { - return err - } - - var res value.Value - - switch x.Type() { - case value.IntType: - xv := x.Data().(value.IntData).Get() - switch y.Type() { - case value.IntType: - yv := y.Data().(value.IntData).Get() - res = value.NewBool(xv <= yv) - case value.FloatType: - yv := y.Data().(value.FloatData).Get() - res = value.NewBool(float64(xv) <= yv) - default: - return ErrInvalidOperandTypes{ - Op: code.OpLte, - X: x.Type(), - Y: y.Type(), - } - } - case value.FloatType: - xv := x.Data().(value.FloatData).Get() - switch y.Type() { - case value.IntType: - yv := y.Data().(value.IntData).Get() - res = value.NewBool(xv <= float64(yv)) - case value.FloatType: - yv := y.Data().(value.FloatData).Get() - res = value.NewBool(xv <= yv) - default: - return ErrInvalidOperandTypes{ - Op: code.OpLte, - X: x.Type(), - Y: y.Type(), - } - } - default: - return ErrInvalidOperandTypes{ - Op: code.OpLte, - X: x.Type(), - Y: y.Type(), - } - } - - vm.stack.Push(res) - return nil -} - func (vm *VM) execCall(argCount uint) error { var err error diff --git a/pkg/lang/vm/text/op.go b/pkg/lang/vm/text/op.go index 17f4847..d438a25 100644 --- a/pkg/lang/vm/text/op.go +++ b/pkg/lang/vm/text/op.go @@ -28,10 +28,15 @@ var ( code.OpAnchorType: "anchor_type", code.OpAdd: "add", code.OpSub: "sub", + code.OpMul: "mul", + code.OpDiv: "div", code.OpMod: "mod", - code.OpIndex: "index", - code.OpLt: "lt", + code.OpEq: "eq", + code.OpGt: "gt", + code.OpLt: "lt", code.OpLte: "lte", + code.OpGte: "gte", + code.OpIndex: "index", code.OpCall: "call", code.OpJmp: "jmp", code.OpJt: "jt", diff --git a/pkg/lang/vm/vm.go b/pkg/lang/vm/vm.go index 3f0703a..54fd8ee 100644 --- a/pkg/lang/vm/vm.go +++ b/pkg/lang/vm/vm.go @@ -164,14 +164,25 @@ func (vm *VM) step(op code.Op) (stepDecision, error) { err = vm.execAdd() case code.OpSub: err = vm.execSub() + case code.OpMul: + err = vm.execMul() + case code.OpDiv: + err = vm.execDiv() case code.OpMod: err = vm.execMod() - case code.OpIndex: - err = vm.execIndex() + case code.OpEq: + err = vm.execEq() case code.OpLt: err = vm.execLt() + case code.OpGt: + err = vm.execGt() case code.OpLte: err = vm.execLte() + case code.OpGte: + err = vm.execGte() + + case code.OpIndex: + err = vm.execIndex() case code.OpCall: argCount, advance := vm.code.GetUint(vm.pc) vm.pc += advance -- cgit 1.4.1