about summary refs log tree commit diff
path: root/pkg/lang
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/lang')
-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