about summary refs log tree commit diff
path: root/pkg/lang/vm/exec.go
diff options
context:
space:
mode:
authorMel <einebeere@gmail.com>2022-05-29 21:42:32 +0000
committerGitHub <noreply@github.com>2022-05-29 21:42:32 +0000
commitd2f69dccb3643834a79da79be4ece189a7178c9e (patch)
tree7e32365a25f37bee199dde36dfdfef12916de46f /pkg/lang/vm/exec.go
parent11bcf772bf8d9aa353eb4c04bfb85378ba392b1e (diff)
downloadjinx-d2f69dccb3643834a79da79be4ece189a7178c9e.tar.zst
jinx-d2f69dccb3643834a79da79be4ece189a7178c9e.zip
Types, Methods and basic Core Lib
Diffstat (limited to 'pkg/lang/vm/exec.go')
-rw-r--r--pkg/lang/vm/exec.go113
1 files changed, 95 insertions, 18 deletions
diff --git a/pkg/lang/vm/exec.go b/pkg/lang/vm/exec.go
index 10ac604..79016fa 100644
--- a/pkg/lang/vm/exec.go
+++ b/pkg/lang/vm/exec.go
@@ -58,6 +58,82 @@ func (vm *VM) execGetLocal(offset int) error {
 	return nil
 }
 
+func (vm *VM) execGetMember(name string) error {
+	parent, err := vm.stack.Pop()
+	if err != nil {
+		return err
+	}
+
+	typeCell, err := vm.getMemCell(parent.TypePtr(), mem.CellKindType, false)
+	if err != nil {
+		return err
+	}
+
+	t := typeCell.(value.TypeCell).Get()
+
+	member, ok := t.GetMethod(name)
+	if !ok {
+		vm.stack.Push(value.NewNull())
+		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)
+	} else {
+		// Clone the environment, with the parent at env 0.
+		oldEnvCell, err := vm.getMemCell(member.Env(), mem.CellKindEnv, false)
+		if err != nil {
+			return err
+		}
+
+		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)
+		}
+
+		envPtr, err = vm.memory.Allocate(mem.CellKindEnv)
+		if err != nil {
+			return err
+		}
+		vm.memory.Set(envPtr, value.EnvCell(newEnv))
+		member = member.WithEnv(envPtr)
+	}
+
+	val := value.NewFunction(0).WithData(member)
+	vm.stack.Push(val)
+
+	parent.Drop(vm.memory)
+
+	return nil
+}
+
 func (vm *VM) execGetEnv(envIndex int) error {
 	envCell, err := vm.getMemCell(vm.stack.CurrentCallEnv(), mem.CellKindEnv, false)
 	if err != nil {
@@ -136,7 +212,7 @@ func (vm *VM) execAddToEnv(localIndex int) error {
 		return err
 	}
 
-	if f.Type().Kind != value.FunctionType {
+	if f.Type() != value.FunctionType {
 		return ErrInvalidOperandType{
 			Op: code.OpAddToEnv,
 			X:  f.Type(),
@@ -206,10 +282,10 @@ func (vm *VM) execAdd() error {
 
 	var res value.Value
 
-	switch x.Type().Kind {
+	switch x.Type() {
 	case value.IntType:
 		xv := x.Data().(value.IntData).Get()
-		switch y.Type().Kind {
+		switch y.Type() {
 		case value.IntType:
 			yv := y.Data().(value.IntData).Get()
 			res = value.NewInt(xv + yv)
@@ -225,7 +301,7 @@ func (vm *VM) execAdd() error {
 		}
 	case value.FloatType:
 		xv := x.Data().(value.FloatData).Get()
-		switch y.Type().Kind {
+		switch y.Type() {
 		case value.IntType:
 			yv := y.Data().(value.IntData).Get()
 			res = value.NewFloat(xv + float64(yv))
@@ -240,7 +316,7 @@ func (vm *VM) execAdd() error {
 			}
 		}
 	case value.StringType:
-		switch y.Type().Kind {
+		switch y.Type() {
 		case value.StringType:
 			panic("not implemented")
 			// res = value.NewString(x.Data().(value.StringData).Get() + y.Data().(value.StringData).Get())
@@ -275,10 +351,10 @@ func (vm *VM) execSub() error {
 
 	var res value.Value
 
-	switch x.Type().Kind {
+	switch x.Type() {
 	case value.IntType:
 		xv := x.Data().(value.IntData).Get()
-		switch y.Type().Kind {
+		switch y.Type() {
 		case value.IntType:
 			yv := y.Data().(value.IntData).Get()
 			res = value.NewInt(xv - yv)
@@ -294,7 +370,7 @@ func (vm *VM) execSub() error {
 		}
 	case value.FloatType:
 		xv := x.Data().(value.FloatData).Get()
-		switch y.Type().Kind {
+		switch y.Type() {
 		case value.IntType:
 			yv := y.Data().(value.IntData).Get()
 			res = value.NewFloat(xv - float64(yv))
@@ -330,10 +406,10 @@ func (vm *VM) execIndex() error {
 		return err
 	}
 
-	switch v.Type().Kind {
+	switch v.Type() {
 	case value.ArrayType:
 		arr := v.Data().(value.ArrayData)
-		switch i.Type().Kind {
+		switch i.Type() {
 		case value.IntType:
 			idx := i.Data().(value.IntData).Get()
 			len, err := arr.Len(vm.memory)
@@ -383,10 +459,10 @@ func (vm *VM) execLte() error {
 
 	var res value.Value
 
-	switch x.Type().Kind {
+	switch x.Type() {
 	case value.IntType:
 		xv := x.Data().(value.IntData).Get()
-		switch y.Type().Kind {
+		switch y.Type() {
 		case value.IntType:
 			yv := y.Data().(value.IntData).Get()
 			res = value.NewBool(xv <= yv)
@@ -402,7 +478,7 @@ func (vm *VM) execLte() error {
 		}
 	case value.FloatType:
 		xv := x.Data().(value.FloatData).Get()
-		switch y.Type().Kind {
+		switch y.Type() {
 		case value.IntType:
 			yv := y.Data().(value.IntData).Get()
 			res = value.NewBool(xv <= float64(yv))
@@ -434,7 +510,7 @@ func (vm *VM) execCall() error {
 		return err
 	}
 
-	if f.Type().Kind != value.FunctionType {
+	if f.Type() != value.FunctionType {
 		return ErrInvalidOperandType{
 			Op: code.OpCall,
 			X:  f.Type(),
@@ -471,7 +547,7 @@ func (vm *VM) execJumpIf(pc int, cond bool) error {
 		return err
 	}
 
-	switch b.Type().Kind {
+	switch b.Type() {
 	case value.BoolType:
 		bl := b.Data().(value.BoolData)
 		if bl.Get() == cond {
@@ -511,12 +587,12 @@ func (vm *VM) execRet() error {
 }
 
 func (vm *VM) execTempArrLen() error {
-	a, err := vm.popAndDrop()
+	a, err := vm.stack.Pop()
 	if err != nil {
 		return err
 	}
 
-	switch a.Type().Kind {
+	switch a.Type() {
 	case value.ArrayType:
 		arr := a.Data().(value.ArrayData)
 		len, err := arr.Len(vm.memory)
@@ -525,6 +601,7 @@ func (vm *VM) execTempArrLen() error {
 		}
 		res := value.NewInt(int64(len))
 		vm.stack.Push(res)
+		a.Drop(vm.memory)
 	default:
 		return ErrInvalidOperandTypes{
 			Op: code.OpTempArrLen,
@@ -545,7 +622,7 @@ func (vm *VM) execTempArrPush() error {
 		return err
 	}
 
-	switch a.Type().Kind {
+	switch a.Type() {
 	case value.ArrayType:
 		arr := a.Data().(value.ArrayData)
 		arr.Push(vm.memory, e)