diff options
| author | Mel <einebeere@gmail.com> | 2022-05-20 00:05:20 +0200 |
|---|---|---|
| committer | Mel <einebeere@gmail.com> | 2022-05-20 00:05:20 +0200 |
| commit | 360f092fe693f66219891581417026a3cffd2709 (patch) | |
| tree | 61370560419450ce0b306a68d20e85ce2c9f69a5 /pkg/lang/vm | |
| parent | fe93d5c015e8e2c883d2c1e74f2e5ce071256cb5 (diff) | |
| download | jinx-360f092fe693f66219891581417026a3cffd2709.tar.zst jinx-360f092fe693f66219891581417026a3cffd2709.zip | |
More VM operations needed for Fib
Diffstat (limited to 'pkg/lang/vm')
| -rw-r--r-- | pkg/lang/vm/code/op.go | 11 | ||||
| -rw-r--r-- | pkg/lang/vm/errors.go | 9 | ||||
| -rw-r--r-- | pkg/lang/vm/exec.go | 139 | ||||
| -rw-r--r-- | pkg/lang/vm/text/op.go | 9 | ||||
| -rw-r--r-- | pkg/lang/vm/vm.go | 23 |
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)} } |
