aboutsummaryrefslogtreecommitdiff
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)}
}