about summary refs log tree commit diff
path: root/pkg/lang/vm/exec.go
diff options
context:
space:
mode:
authorMel <einebeere@gmail.com>2022-06-01 19:51:40 +0000
committerGitHub <noreply@github.com>2022-06-01 19:51:40 +0000
commitedca72c160967f1918b65c91a40de89ecd8badda (patch)
treeb79feabc0889a3f6cfddf09906a486d09e5c60a1 /pkg/lang/vm/exec.go
parent33671436680e7922001df9921ee582c486c7c3f4 (diff)
downloadjinx-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.go172
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 {