diff options
| author | Mel <einebeere@gmail.com> | 2022-06-01 19:51:40 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-06-01 19:51:40 +0000 |
| commit | edca72c160967f1918b65c91a40de89ecd8badda (patch) | |
| tree | b79feabc0889a3f6cfddf09906a486d09e5c60a1 /pkg/lang/vm/exec.go | |
| parent | 33671436680e7922001df9921ee582c486c7c3f4 (diff) | |
| download | jinx-edca72c160967f1918b65c91a40de89ecd8badda.tar.zst jinx-edca72c160967f1918b65c91a40de89ecd8badda.zip | |
Implement proper object types
Diffstat (limited to 'pkg/lang/vm/exec.go')
| -rw-r--r-- | pkg/lang/vm/exec.go | 172 |
1 files changed, 130 insertions, 42 deletions
diff --git a/pkg/lang/vm/exec.go b/pkg/lang/vm/exec.go index 94557dc..be72158 100644 --- a/pkg/lang/vm/exec.go +++ b/pkg/lang/vm/exec.go @@ -69,6 +69,16 @@ func (vm *VM) execGetLocal(offset int) error { return nil } +func (vm *VM) execPushType(name string) error { + ref, err := value.NewType(vm.memory, name) + if err != nil { + return err + } + + vm.stack.Push(ref) + return nil +} + func (vm *VM) execGetMember(name string) error { parent, err := vm.stack.Pop() if err != nil { @@ -88,13 +98,53 @@ func (vm *VM) execGetMember(name string) error { member, ok := objCell.Get()[name] if ok { member = member.Clone(vm.memory) - } else { - member = value.NewNull() + + vm.stack.Push(member) + parent.Drop(vm.memory) + return nil } + } - vm.stack.Push(member) - parent.Drop(vm.memory) - return nil + if parent.Outlet().IsNull() { + outletPtr, err := vm.memory.Allocate(mem.CellKindOutlet) + if err != nil { + return err + } + parent = parent.WithOutlet(outletPtr) + } + + if parent.Type() == value.TypeRefType { + ref := parent.Data().(value.TypeRefData) + ptr := ref.TypeRef() + + cell, err := vm.getMemCell(ptr, mem.CellKindType, false) + if err != nil { + return err + } + + typ := cell.(value.TypeCell).Get() + + methodData, ok := typ.GetMethod(name) + + if !methodData.Env().IsNull() { + panic("methods with environments not implemented yet") + } + + if ok { + newEnv := value.NewEnv() + newEnv.Add(0, parent.Outlet()) + envPtr, err := newEnv.Allocate(vm.memory) + if err != nil { + return err + } + + method := value.NewFunction(0, 0).WithData(methodData.WithEnv(envPtr)) + // method = method.Clone(vm.memory) will only be necessary when we support methods with environments. + + vm.stack.Push(method) + parent.Drop(vm.memory) + return nil + } } typeCell, err := vm.getMemCell(parent.TypePtr(), mem.CellKindType, false) @@ -110,26 +160,15 @@ func (vm *VM) execGetMember(name string) error { return nil } - if parent.Outlet().IsNull() { - outletPtr, err := vm.memory.Allocate(mem.CellKindOutlet) - if err != nil { - return err - } - parent = parent.WithOutlet(outletPtr) - } - var envPtr mem.Ptr if member.Env().IsNull() { - envPtr, err = vm.memory.Allocate(mem.CellKindEnv) - if err != nil { - return err - } - newEnv := value.NewEnv() newEnv.Add(0, parent.Outlet()) // stackIndex can be 0, because the parent will be dropped when the function returns. - vm.memory.Set(envPtr, value.EnvCell(newEnv)) - member = member.WithEnv(envPtr) + envPtr, err = newEnv.Allocate(vm.memory) + if err != nil { + return err + } } else { // Clone the environment, with the parent at env 0. oldEnvCell, err := vm.getMemCell(member.Env(), mem.CellKindEnv, false) @@ -138,27 +177,21 @@ func (vm *VM) execGetMember(name string) error { } oldEnv := oldEnvCell.(value.EnvCell).Get() - newEnv := value.NewEnv() - - newEnv.Add(0, parent.Outlet()) - - for i := 0; i < oldEnv.Len(); i++ { - differentOutlet := oldEnv.GetOutlet(i) - if err = vm.memory.Retain(differentOutlet); err != nil { - return err - } - - newEnv.Add(oldEnv.GetStackIndex(i), differentOutlet) + newEnv, err := oldEnv.Clone(vm.memory) + if err != nil { + return err } - envPtr, err = vm.memory.Allocate(mem.CellKindEnv) + newEnv.Prepend(0, parent.Outlet()) + + envPtr, err = newEnv.Allocate(vm.memory) if err != nil { return err } - vm.memory.Set(envPtr, value.EnvCell(newEnv)) - member = member.WithEnv(envPtr) } + member = member.WithEnv(envPtr) + val := value.NewFunction(0, 0).WithData(member) vm.stack.Push(val) @@ -343,12 +376,51 @@ func (vm *VM) execAddToEnv(localIndex int) error { return nil } +func (vm *VM) execAnchorType() error { + o, err := vm.stack.Pop() + if err != nil { + return err + } + + t, err := vm.stack.Pop() + if err != nil { + return err + } + + if o.Type() != value.ObjectType { + return ErrInvalidOperandTypes{ + Op: code.OpAnchorType, + X: o.Type(), + Y: t.Type(), + } + } + + if t.Type() != value.TypeRefType { + return ErrInvalidOperandTypes{ + Op: code.OpAnchorType, + X: o.Type(), + Y: t.Type(), + } + } + + if !o.TypePtr().IsNull() { + return ErrCantReanchorType{ + Type: o.Type(), + } + } + + o = o.WithType(t.Data().(value.TypeRefData).TypeRef()) + + vm.stack.Push(o) + return nil +} + func (vm *VM) execAdd() error { - x, err := vm.popAndDrop() + x, err := vm.stack.Pop() if err != nil { return err } - y, err := vm.popAndDrop() + y, err := vm.stack.Pop() if err != nil { return err } @@ -389,10 +461,22 @@ func (vm *VM) execAdd() error { } } case value.StringType: + xv, err := x.Data().(value.StringData).RawString(vm.memory) + if err != nil { + return err + } + switch y.Type() { case value.StringType: - panic("not implemented") - // res = value.NewString(x.Data().(value.StringData).Get() + y.Data().(value.StringData).Get()) + 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, @@ -408,6 +492,9 @@ func (vm *VM) execAdd() error { } } + x.Drop(vm.memory) + y.Drop(vm.memory) + vm.stack.Push(res) return nil } @@ -593,10 +680,11 @@ func (vm *VM) execCall(argCount uint) error { fn := f.Data().(value.FunctionData) if argCount != fn.Args() { - return ErrWrongNumberOfArguments{ - Got: argCount, - Needed: fn.Args(), - } + // TODO: Uncomment when push_function can set fn.Args() + // return ErrWrongNumberOfArguments{ + // Got: argCount, + // Needed: fn.Args(), + // } } if err = vm.stack.PushCall(fn.Pc(), vm.pc, fn.Env()); err != nil { |
