aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMel <einebeere@gmail.com>2022-07-06 14:06:20 +0200
committerMel <einebeere@gmail.com>2022-07-06 14:06:20 +0200
commitb16b70fd40ffc72ff861afe0517cba0e37ba1145 (patch)
tree1969a77f9c3d00160d53ffbe2f4b6ffa7d408165
parent32ec3e1186b3ed29e910ad60a18f956b823ddc23 (diff)
downloadjinx-b16b70fd40ffc72ff861afe0517cba0e37ba1145.tar.zst
jinx-b16b70fd40ffc72ff861afe0517cba0e37ba1145.zip
Implement most of the binary operations
-rw-r--r--pkg/lang/compiler/compiler.go20
-rw-r--r--pkg/lang/vm/code/op.go8
-rw-r--r--pkg/lang/vm/exec.go443
-rw-r--r--pkg/lang/vm/text/op.go9
-rw-r--r--pkg/lang/vm/vm.go15
5 files changed, 228 insertions, 267 deletions
diff --git a/pkg/lang/compiler/compiler.go b/pkg/lang/compiler/compiler.go
index c51728f..116db1c 100644
--- a/pkg/lang/compiler/compiler.go
+++ b/pkg/lang/compiler/compiler.go
@@ -357,31 +357,25 @@ func (comp *Compiler) compileBinaryExpr(t *code.Builder, expr ast.ExprBinary) er
case ast.BinOpMinus:
t.AppendOp(code.OpSub)
case ast.BinOpStar:
- // t.AppendOp(code.OpMul)
- panic("not implemented")
+ t.AppendOp(code.OpMul)
case ast.BinOpSlash:
- // t.AppendOp(code.OpDiv)
- panic("not implemented")
+ t.AppendOp(code.OpDiv)
case ast.BinOpPercent:
- // t.AppendOp(code.OpMod)
- panic("not implemented")
+ t.AppendOp(code.OpMod)
case ast.BinOpEq:
- // t.AppendOp(code.OpEq)
- panic("not implemented")
+ t.AppendOp(code.OpEq)
case ast.BinOpNeq:
- // t.AppendOp(code.OpNeq)
+ //t.AppendOp(code.OpNeq)
panic("not implemented")
case ast.BinOpLt:
t.AppendOp(code.OpLt)
case ast.BinOpLte:
t.AppendOp(code.OpLte)
case ast.BinOpGt:
- // t.AppendOp(code.OpGt)
- panic("not implemented")
+ t.AppendOp(code.OpGt)
case ast.BinOpGte:
- // t.AppendOp(code.OpGte)
- panic("not implemented")
+ t.AppendOp(code.OpGte)
default:
panic("unknown binary operator")
}
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