about summary refs log tree commit diff
path: root/pkg/lang/vm/exec.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/lang/vm/exec.go')
-rw-r--r--pkg/lang/vm/exec.go82
1 files changed, 74 insertions, 8 deletions
diff --git a/pkg/lang/vm/exec.go b/pkg/lang/vm/exec.go
index c5b0539..5a8eb05 100644
--- a/pkg/lang/vm/exec.go
+++ b/pkg/lang/vm/exec.go
@@ -44,7 +44,7 @@ func (vm *VM) execPushArray() error {
 
 func (vm *VM) execPushFunction(pc int) {
 	// TODO: Make push ops into functions, where the argCount can be passed.
-	vm.stack.Push(value.NewFunction(pc, 0))
+	vm.stack.Push(value.NewFunction(code.NewPos(vm.module(), pc), 0))
 }
 
 func (vm *VM) execPushObject() error {
@@ -57,6 +57,72 @@ func (vm *VM) execPushObject() error {
 	return nil
 }
 
+func (vm *VM) execAddGlobal(name string) error {
+	if !vm.canAddGlobals {
+		return ErrCantAddGlobalFromMain{GlobalName: name}
+	}
+
+	if _, ok := vm.globals[name]; ok {
+		return ErrGlobalAlreadyExists{GlobalName: name}
+	}
+
+	v, err := vm.stack.Pop()
+	if err != nil {
+		return err
+	}
+
+	globalPtr, err := vm.memory.Allocate(mem.CellKindGlobal)
+	if err != nil {
+		return err
+	}
+
+	globalCell := value.GlobalCell(v)
+	if err := vm.memory.Set(globalPtr, globalCell); err != nil {
+		return err
+	}
+
+	vm.globals[name] = globalPtr
+
+	return nil
+}
+
+func (vm *VM) execGetGlobal(name string) error {
+	ptr, ok := vm.globals[name]
+	if !ok {
+		return ErrNoSuchGlobal{GlobalName: name}
+	}
+
+	cell, err := vm.getMemCell(ptr, mem.CellKindGlobal, false)
+	if err != nil {
+		return err
+	}
+
+	v := cell.(value.GlobalCell).Get()
+	v = v.Clone(vm.memory)
+
+	vm.stack.Push(v)
+	return nil
+}
+
+func (vm *VM) execSetGlobal(name string) error {
+	ptr, ok := vm.globals[name]
+	if !ok {
+		return ErrNoSuchGlobal{GlobalName: name}
+	}
+
+	new, err := vm.stack.Pop()
+	if err != nil {
+		return err
+	}
+
+	globalCell := value.GlobalCell(new)
+	if err := vm.memory.Set(ptr, globalCell); err != nil {
+		return err
+	}
+
+	return nil
+}
+
 func (vm *VM) execGetLocal(offset int) error {
 	local, err := vm.stack.Local(int(offset))
 	if err != nil {
@@ -165,7 +231,7 @@ func (vm *VM) execGetMember(name string) error {
 				return err
 			}
 
-			method := value.NewFunction(0, 0).WithData(methodData.WithEnv(envPtr))
+			method := value.NewFunction(code.Pos{}, 0).WithData(methodData.WithEnv(envPtr))
 			// method = method.Clone(vm.memory) will only be necessary when we support methods with environments.
 
 			vm.stack.Push(method)
@@ -219,7 +285,7 @@ func (vm *VM) execGetMember(name string) error {
 
 	member = member.WithEnv(envPtr)
 
-	val := value.NewFunction(0, 0).WithData(member)
+	val := value.NewFunction(code.Pos{}, 0).WithData(member)
 	vm.stack.Push(val)
 
 	parent.Drop(vm.memory)
@@ -781,7 +847,7 @@ func (vm *VM) execCall(argCount uint) error {
 		}
 	}
 
-	if err = vm.stack.PushCall(fn.Pc(), vm.pc, fn.Env()); err != nil {
+	if err = vm.stack.PushCall(fn.Pos(), vm.pos, fn.Env()); err != nil {
 		return err
 	}
 
@@ -806,7 +872,7 @@ func (vm *VM) execCall(argCount uint) error {
 		vm.stack.Push(arg)
 	}
 
-	vm.pc = fn.Pc()
+	vm.setPos(fn.Pos())
 
 	return nil
 }
@@ -821,7 +887,7 @@ func (vm *VM) execJumpIf(pc int, cond bool) error {
 	case value.BoolType:
 		bl := b.Data().(value.BoolData)
 		if bl.Get() == cond {
-			vm.pc = pc
+			vm.setPC(pc)
 		}
 	default:
 		var op code.Op
@@ -846,13 +912,13 @@ func (vm *VM) execRet() error {
 		return err
 	}
 
-	pc, err := vm.popCallAndDrop()
+	pos, err := vm.popCallAndDrop()
 	if err != nil {
 		return err
 	}
 
 	vm.stack.Push(returned)
-	vm.pc = pc
+	vm.setPos(pos)
 	return nil
 }