about summary refs log tree commit diff
path: root/pkg/lang
diff options
context:
space:
mode:
authorMel <einebeere@gmail.com>2022-05-20 00:05:20 +0200
committerMel <einebeere@gmail.com>2022-05-20 00:05:20 +0200
commit360f092fe693f66219891581417026a3cffd2709 (patch)
tree61370560419450ce0b306a68d20e85ce2c9f69a5 /pkg/lang
parentfe93d5c015e8e2c883d2c1e74f2e5ce071256cb5 (diff)
downloadjinx-360f092fe693f66219891581417026a3cffd2709.tar.zst
jinx-360f092fe693f66219891581417026a3cffd2709.zip
More VM operations needed for Fib
Diffstat (limited to 'pkg/lang')
-rw-r--r--pkg/lang/vm/code/op.go11
-rw-r--r--pkg/lang/vm/errors.go9
-rw-r--r--pkg/lang/vm/exec.go139
-rw-r--r--pkg/lang/vm/text/op.go9
-rw-r--r--pkg/lang/vm/vm.go23
5 files changed, 186 insertions, 5 deletions
diff --git a/pkg/lang/vm/code/op.go b/pkg/lang/vm/code/op.go
index ae37603..cb2811a 100644
--- a/pkg/lang/vm/code/op.go
+++ b/pkg/lang/vm/code/op.go
@@ -16,19 +16,28 @@ const (
 	OpPushFunction
 	OpPushObject
 
+	OpDrop
+
 	OpGetGlobal
 	OpGetLocal
 	OpGetMember
+	OpGetMethod
 	OpGetArg
 	OpGetEnv
 
 	OpAdd
 	OpSub
 	OpIndex
+	OpLte
 	OpCall
 
 	OpJmp
-	OpJez
+	OpJt
+	OpJf
 
 	OpRet
+
+	// Temporary operations, which will be removed with the advent of methods.
+	OpTempArrLen
+	OpTempArrPush
 )
diff --git a/pkg/lang/vm/errors.go b/pkg/lang/vm/errors.go
index 9859feb..045f9a9 100644
--- a/pkg/lang/vm/errors.go
+++ b/pkg/lang/vm/errors.go
@@ -47,6 +47,15 @@ func (e ErrInvalidOp) Error() string {
 
 // Non-fatal errors, which will later be implemented as catchable exceptions
 
+type ErrInvalidOperandType struct {
+	Op code.Op
+	X  value.Type
+}
+
+func (e ErrInvalidOperandType) Error() string {
+	return fmt.Sprintf("invalid operand type for op %s: %v", text.OpToString(e.Op), e.X)
+}
+
 type ErrInvalidOperandTypes struct {
 	Op code.Op
 	X  value.Type
diff --git a/pkg/lang/vm/exec.go b/pkg/lang/vm/exec.go
index 54f43db..1b94572 100644
--- a/pkg/lang/vm/exec.go
+++ b/pkg/lang/vm/exec.go
@@ -227,3 +227,142 @@ func (vm *VM) execIndex() error {
 
 	return nil
 }
+
+func (vm *VM) execLte() 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.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().Kind {
+		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(),
+		}
+	}
+
+	top.Push(res)
+	return nil
+}
+
+func (vm *VM) execJumpIf(pc int, cond bool) error {
+	top := vm.stack.Top()
+
+	b, err := top.Pop()
+	if err != nil {
+		return err
+	}
+
+	switch b.Type().Kind {
+	case value.BoolType:
+		bl := b.Data().(value.BoolData)
+		if bl.Get() == cond {
+			vm.pc = pc
+		}
+	default:
+		var op code.Op
+		if cond {
+			op = code.OpJt
+		} else {
+			op = code.OpJf
+		}
+
+		return ErrInvalidOperandType{
+			Op: op,
+			X:  b.Type(),
+		}
+	}
+
+	return nil
+}
+
+func (vm *VM) execTempArrLen() error {
+	top := vm.stack.Top()
+
+	a, err := top.Pop()
+	if err != nil {
+		return err
+	}
+
+	switch a.Type().Kind {
+	case value.ArrayType:
+		arr := a.Data().(value.ArrayData)
+		res := value.NewInt(int64(arr.Len()))
+		top.Push(res)
+	default:
+		return ErrInvalidOperandTypes{
+			Op: code.OpTempArrLen,
+			X:  a.Type(),
+		}
+	}
+
+	return nil
+}
+
+func (vm *VM) execTempArrPush() error {
+	top := vm.stack.Top()
+
+	a, err := top.Pop()
+	if err != nil {
+		return err
+	}
+	e, err := top.Pop()
+	if err != nil {
+		return err
+	}
+
+	switch a.Type().Kind {
+	case value.ArrayType:
+		arr := a.Data().(value.ArrayData)
+		arr.Push(e)
+	default:
+		return ErrInvalidOperandType{
+			Op: code.OpTempArrPush,
+			X:  a.Type(),
+		}
+	}
+
+	return nil
+}
diff --git a/pkg/lang/vm/text/op.go b/pkg/lang/vm/text/op.go
index a8f3663..bbcc2d4 100644
--- a/pkg/lang/vm/text/op.go
+++ b/pkg/lang/vm/text/op.go
@@ -15,18 +15,25 @@ var (
 		code.OpPushArray:    "push_array",
 		code.OpPushFunction: "push_function",
 		code.OpPushObject:   "push_object",
+		code.OpDrop:         "drop",
 		code.OpGetGlobal:    "get_global",
 		code.OpGetLocal:     "get_local",
 		code.OpGetMember:    "get_member",
+		code.OpGetMethod:    "get_method",
 		code.OpGetArg:       "get_arg",
 		code.OpGetEnv:       "get_env",
 		code.OpAdd:          "add",
 		code.OpSub:          "sub",
 		code.OpIndex:        "index",
+		code.OpLte:          "lte",
 		code.OpCall:         "call",
 		code.OpJmp:          "jmp",
-		code.OpJez:          "jez",
+		code.OpJt:           "jt",
+		code.OpJf:           "jf",
 		code.OpRet:          "ret",
+
+		code.OpTempArrPush: "temp_arr_push",
+		code.OpTempArrLen:  "temp_arr_len",
 	}
 	stringToOp = reverseMap(opToString)
 )
diff --git a/pkg/lang/vm/vm.go b/pkg/lang/vm/vm.go
index 0de8fb9..8fdc0d5 100644
--- a/pkg/lang/vm/vm.go
+++ b/pkg/lang/vm/vm.go
@@ -89,6 +89,9 @@ func (vm *VM) step(op code.Op) (stepDecision, error) {
 	case code.OpPushObject:
 		panic("not implemented")
 
+	case code.OpDrop:
+		_, err = vm.stack.Top().Pop()
+
 	case code.OpGetGlobal:
 		panic("not implemented")
 	case code.OpGetLocal:
@@ -98,6 +101,8 @@ func (vm *VM) step(op code.Op) (stepDecision, error) {
 		err = vm.execGetLocal(int(offset))
 	case code.OpGetMember:
 		panic("not implemented")
+	case code.OpGetMethod:
+		panic("not implemented")
 	case code.OpGetArg:
 		vm.execGetArg()
 	case code.OpGetEnv:
@@ -109,18 +114,30 @@ func (vm *VM) step(op code.Op) (stepDecision, error) {
 		err = vm.execSub()
 	case code.OpIndex:
 		err = vm.execIndex()
+	case code.OpLte:
+		err = vm.execLte()
 	case code.OpCall:
 		panic("not implemented")
 
 	case code.OpJmp:
 		pc, _ := vm.code.GetUint(vm.pc)
 		vm.pc = int(pc)
-	case code.OpJez:
-		panic("not implemented")
-
+	case code.OpJt:
+		pc, advance := vm.code.GetUint(vm.pc)
+		vm.pc += advance
+		err = vm.execJumpIf(int(pc), true)
+	case code.OpJf:
+		pc, advance := vm.code.GetUint(vm.pc)
+		vm.pc += advance
+		err = vm.execJumpIf(int(pc), false)
 	case code.OpRet:
 		panic("not implemented")
 
+	case code.OpTempArrLen:
+		err = vm.execTempArrLen()
+	case code.OpTempArrPush:
+		err = vm.execTempArrPush()
+
 	default:
 		err = ErrInvalidOp{Op: uint8(op)}
 	}