about summary refs log tree commit diff
path: root/pkg/lang
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/lang')
-rw-r--r--pkg/lang/vm/errors.go26
-rw-r--r--pkg/lang/vm/exec.go24
-rw-r--r--pkg/lang/vm/mem/cell.go2
-rw-r--r--pkg/lang/vm/mem/mem.go32
-rw-r--r--pkg/lang/vm/stack/errors.go34
-rw-r--r--pkg/lang/vm/stack/stack.go (renamed from pkg/lang/vm/stack.go)86
-rw-r--r--pkg/lang/vm/utils.go2
-rw-r--r--pkg/lang/vm/value/cells.go8
-rw-r--r--pkg/lang/vm/value/data.go20
-rw-r--r--pkg/lang/vm/value/value.go8
-rw-r--r--pkg/lang/vm/vm.go7
11 files changed, 146 insertions, 103 deletions
diff --git a/pkg/lang/vm/errors.go b/pkg/lang/vm/errors.go
index 2f5b56a..a717c09 100644
--- a/pkg/lang/vm/errors.go
+++ b/pkg/lang/vm/errors.go
@@ -25,35 +25,9 @@ func (e Error) Error() string {
 // Fatal errors
 
 var (
-	ErrStackOverflow  = errors.New("stack overflow (max depth: 1000)")
-	ErrStackUnderflow = errors.New("local stack underflow")
-
-	ErrReachedMaxCallDepth  = errors.New("reached max call depth (max depth: 1000)")
-	ErrReachedRootCallFrame = errors.New("reached root call frame")
-
-	ErrCallBaseCantBeNegative = errors.New("call base cannot be negative")
-
 	ErrEnvNotSet = errors.New("env not set")
 )
 
-type ErrLocalIndexOutOfBounds struct {
-	Index int
-	Len   int
-}
-
-func (e ErrLocalIndexOutOfBounds) Error() string {
-	return fmt.Sprintf("local index out of bounds: %d (len: %d)", e.Index, e.Len)
-}
-
-type ErrStackIndexOutOfBounds struct {
-	Index int
-	Len   int
-}
-
-func (e ErrStackIndexOutOfBounds) Error() string {
-	return fmt.Sprintf("stack index out of bounds: %d (len: %d)", e.Index, e.Len)
-}
-
 type ErrInvalidOp struct {
 	Op uint8
 }
diff --git a/pkg/lang/vm/exec.go b/pkg/lang/vm/exec.go
index c9b8615..bd4cdf5 100644
--- a/pkg/lang/vm/exec.go
+++ b/pkg/lang/vm/exec.go
@@ -15,7 +15,7 @@ func (vm *VM) execPushFloat(x float64) {
 }
 
 func (vm *VM) execPushString(str string) error {
-	val, err := value.NewString(&vm.memory, str)
+	val, err := value.NewString(vm.memory, str)
 	if err != nil {
 		return err
 	}
@@ -33,7 +33,7 @@ func (vm *VM) execPushNull() {
 }
 
 func (vm *VM) execPushArray() error {
-	val, err := value.NewArray(&vm.memory, []value.Value{})
+	val, err := value.NewArray(vm.memory, []value.Value{})
 	if err != nil {
 		return err
 	}
@@ -52,7 +52,7 @@ func (vm *VM) execGetLocal(offset int) error {
 		return err
 	}
 
-	v := local.Clone(&vm.memory)
+	v := local.Clone(vm.memory)
 
 	vm.stack.Push(v)
 	return nil
@@ -75,7 +75,7 @@ func (vm *VM) execGetEnv(envIndex int) error {
 	if outletCell != nil {
 		// Outlet is not null, so value escaped.
 		outlet := outletCell.(value.OutletCell).Get()
-		val := outlet.Clone(&vm.memory)
+		val := outlet.Clone(vm.memory)
 		vm.stack.Push(val)
 		return nil
 	}
@@ -87,7 +87,7 @@ func (vm *VM) execGetEnv(envIndex int) error {
 		return err
 	}
 
-	val = val.Clone(&vm.memory)
+	val = val.Clone(vm.memory)
 	vm.stack.Push(val)
 
 	return nil
@@ -114,7 +114,7 @@ func (vm *VM) execSetEnv(envIndex int) error {
 	if outletCell != nil {
 		// Outlet is not null, so value escaped.
 		outlet := outletCell.(value.OutletCell).Get()
-		outlet.Drop(&vm.memory)
+		outlet.Drop(vm.memory)
 		vm.memory.Set(outletPtr, value.OutletCell(new))
 		return nil
 	}
@@ -125,7 +125,7 @@ func (vm *VM) execSetEnv(envIndex int) error {
 		return err
 	}
 
-	old.Drop(&vm.memory)
+	old.Drop(vm.memory)
 
 	return vm.stack.Set(stackIndex, new)
 }
@@ -336,7 +336,7 @@ func (vm *VM) execIndex() error {
 		switch i.Type().Kind {
 		case value.IntType:
 			idx := i.Data().(value.IntData).Get()
-			len, err := arr.Len(&vm.memory)
+			len, err := arr.Len(vm.memory)
 			if err != nil {
 				return err
 			}
@@ -347,11 +347,11 @@ func (vm *VM) execIndex() error {
 				}
 			}
 
-			val, err := arr.At(&vm.memory, int(idx))
+			val, err := arr.At(vm.memory, int(idx))
 			if err != nil {
 				return err
 			}
-			val = val.Clone(&vm.memory)
+			val = val.Clone(vm.memory)
 			vm.stack.Push(val)
 		default:
 			return ErrInvalidOperandTypes{
@@ -506,7 +506,7 @@ func (vm *VM) execTempArrLen() error {
 	switch a.Type().Kind {
 	case value.ArrayType:
 		arr := a.Data().(value.ArrayData)
-		len, err := arr.Len(&vm.memory)
+		len, err := arr.Len(vm.memory)
 		if err != nil {
 			return err
 		}
@@ -535,7 +535,7 @@ func (vm *VM) execTempArrPush() error {
 	switch a.Type().Kind {
 	case value.ArrayType:
 		arr := a.Data().(value.ArrayData)
-		arr.Push(&vm.memory, e)
+		arr.Push(vm.memory, e)
 	default:
 		return ErrInvalidOperandType{
 			Op: code.OpTempArrPush,
diff --git a/pkg/lang/vm/mem/cell.go b/pkg/lang/vm/mem/cell.go
index fcf9a50..830d382 100644
--- a/pkg/lang/vm/mem/cell.go
+++ b/pkg/lang/vm/mem/cell.go
@@ -39,5 +39,5 @@ type cell struct {
 }
 
 type CellData interface {
-	DropCell(*Mem)
+	DropCell(Mem)
 }
diff --git a/pkg/lang/vm/mem/mem.go b/pkg/lang/vm/mem/mem.go
index bdcf01f..a645ee2 100644
--- a/pkg/lang/vm/mem/mem.go
+++ b/pkg/lang/vm/mem/mem.go
@@ -1,6 +1,18 @@
 package mem
 
-type Mem struct {
+type Mem interface {
+	Allocate(kind CellKind) (Ptr, error)
+
+	Set(ptr Ptr, v CellData) error
+	Get(ptr Ptr) (CellData, error)
+	Is(ptr Ptr, kind CellKind) bool
+	Kind(ptr Ptr) CellKind
+
+	Retain(ptr Ptr) error
+	Release(ptr Ptr) error
+}
+
+type memImpl struct {
 	cells []cell
 	free  []Ptr
 }
@@ -11,13 +23,13 @@ func New() Mem {
 	// Reserve NullPtr
 	cells[NullPtr].kind = CellKindForbidden
 
-	return Mem{
+	return &memImpl{
 		cells: cells,
 		free:  make([]Ptr, 0),
 	}
 }
 
-func (m *Mem) Allocate(kind CellKind) (Ptr, error) {
+func (m *memImpl) Allocate(kind CellKind) (Ptr, error) {
 	if len(m.free) > 0 {
 		idx := m.free[len(m.free)-1]
 		m.free = m.free[:len(m.free)-1]
@@ -40,7 +52,7 @@ func (m *Mem) Allocate(kind CellKind) (Ptr, error) {
 
 }
 
-func (m *Mem) Set(ptr Ptr, v CellData) error {
+func (m *memImpl) Set(ptr Ptr, v CellData) error {
 	if err := m.validPtr(ptr); err != nil {
 		return err
 	}
@@ -49,7 +61,7 @@ func (m *Mem) Set(ptr Ptr, v CellData) error {
 	return nil
 }
 
-func (m *Mem) Get(ptr Ptr) (CellData, error) {
+func (m *memImpl) Get(ptr Ptr) (CellData, error) {
 	if err := m.validPtr(ptr); err != nil {
 		return nil, err
 	}
@@ -57,7 +69,7 @@ func (m *Mem) Get(ptr Ptr) (CellData, error) {
 	return m.cells[ptr].data, nil
 }
 
-func (m *Mem) Is(ptr Ptr, kind CellKind) bool {
+func (m *memImpl) Is(ptr Ptr, kind CellKind) bool {
 	if ptr >= Ptr(len(m.cells)) {
 		return false
 	}
@@ -65,7 +77,7 @@ func (m *Mem) Is(ptr Ptr, kind CellKind) bool {
 	return m.cells[ptr].kind == kind
 }
 
-func (m *Mem) Kind(ptr Ptr) CellKind {
+func (m *memImpl) Kind(ptr Ptr) CellKind {
 	if ptr >= Ptr(len(m.cells)) {
 		return CellKindForbidden
 	}
@@ -73,7 +85,7 @@ func (m *Mem) Kind(ptr Ptr) CellKind {
 	return m.cells[ptr].kind
 }
 
-func (m *Mem) Retain(ptr Ptr) error {
+func (m *memImpl) Retain(ptr Ptr) error {
 	if err := m.validPtr(ptr); err != nil {
 		return err
 	}
@@ -82,7 +94,7 @@ func (m *Mem) Retain(ptr Ptr) error {
 	return nil
 }
 
-func (m *Mem) Release(ptr Ptr) error {
+func (m *memImpl) Release(ptr Ptr) error {
 	if err := m.validPtr(ptr); err != nil {
 		return err
 	}
@@ -99,7 +111,7 @@ func (m *Mem) Release(ptr Ptr) error {
 	return nil
 }
 
-func (m *Mem) validPtr(ptr Ptr) error {
+func (m *memImpl) validPtr(ptr Ptr) error {
 	if ptr >= Ptr(len(m.cells)) {
 		return ErrInvalidMemAccess{ptr}
 	}
diff --git a/pkg/lang/vm/stack/errors.go b/pkg/lang/vm/stack/errors.go
new file mode 100644
index 0000000..55ef2ea
--- /dev/null
+++ b/pkg/lang/vm/stack/errors.go
@@ -0,0 +1,34 @@
+package stack
+
+import (
+	"errors"
+	"fmt"
+)
+
+var (
+	ErrStackOverflow  = errors.New("stack overflow (max depth: 1000)")
+	ErrStackUnderflow = errors.New("local stack underflow")
+
+	ErrReachedMaxCallDepth  = errors.New("reached max call depth (max depth: 1000)")
+	ErrReachedRootCallFrame = errors.New("reached root call frame")
+
+	ErrCallBaseCantBeNegative = errors.New("call base cannot be negative")
+)
+
+type ErrLocalIndexOutOfBounds struct {
+	Index int
+	Len   int
+}
+
+func (e ErrLocalIndexOutOfBounds) Error() string {
+	return fmt.Sprintf("local index out of bounds: %d (len: %d)", e.Index, e.Len)
+}
+
+type ErrStackIndexOutOfBounds struct {
+	Index int
+	Len   int
+}
+
+func (e ErrStackIndexOutOfBounds) Error() string {
+	return fmt.Sprintf("stack index out of bounds: %d (len: %d)", e.Index, e.Len)
+}
diff --git a/pkg/lang/vm/stack.go b/pkg/lang/vm/stack/stack.go
index a8965ec..314d0c6 100644
--- a/pkg/lang/vm/stack.go
+++ b/pkg/lang/vm/stack/stack.go
@@ -1,16 +1,38 @@
-package vm
+package stack
 
 import (
 	"jinx/pkg/lang/vm/mem"
 	"jinx/pkg/lang/vm/value"
 )
 
-type Stack struct {
+type Stack interface {
+	Push(value value.Value)
+	Pop() (value.Value, error)
+
+	Get(index int) (value.Value, error)
+	Set(index int, value value.Value) error
+	Local(offset int) (value.Value, error)
+	Top() (value.Value, error)
+
+	Len() int
+	IsEmpty() bool
+
+	PushCall(newPc, returnPc int, env mem.Ptr) error
+	PopCall() (int, error)
+	ShiftTopCallBase(by int) error
+
+	CurrentCallEnv() mem.Ptr
+	CallDepth() int
+	ReachedBaseOfCall() bool
+	LocalToStackIndex(local int) int
+}
+
+type stackImpl struct {
 	data  []value.Value
 	calls []callFrame
 }
 
-func NewStack() Stack {
+func New() Stack {
 	data := make([]value.Value, 0, 64)
 	calls := make([]callFrame, 0, 8)
 
@@ -20,17 +42,17 @@ func NewStack() Stack {
 		base:     0,
 	})
 
-	return Stack{
+	return &stackImpl{
 		data:  data,
 		calls: calls,
 	}
 }
 
-func (stack *Stack) Push(value value.Value) {
+func (stack *stackImpl) Push(value value.Value) {
 	stack.data = append(stack.data, value)
 }
 
-func (stack *Stack) Pop() (value.Value, error) {
+func (stack *stackImpl) Pop() (value.Value, error) {
 	if stack.IsEmpty() || stack.ReachedBaseOfCall() {
 		return value.Value{}, ErrStackUnderflow
 	}
@@ -44,7 +66,7 @@ func (stack *Stack) Pop() (value.Value, error) {
 	return v, nil
 }
 
-func (stack *Stack) Get(index int) (value.Value, error) {
+func (stack *stackImpl) Get(index int) (value.Value, error) {
 	if index < 0 || index >= stack.Len() {
 		return value.Value{}, ErrStackIndexOutOfBounds{Index: index, Len: stack.Len()}
 	}
@@ -52,7 +74,7 @@ func (stack *Stack) Get(index int) (value.Value, error) {
 	return stack.data[index], nil
 }
 
-func (stack *Stack) Set(index int, value value.Value) error {
+func (stack *stackImpl) Set(index int, value value.Value) error {
 	if index < 0 || index >= stack.Len() {
 		return ErrStackIndexOutOfBounds{Index: index, Len: stack.Len()}
 	}
@@ -61,7 +83,7 @@ func (stack *Stack) Set(index int, value value.Value) error {
 	return nil
 }
 
-func (stack *Stack) Local(offset int) (value.Value, error) {
+func (stack *stackImpl) Local(offset int) (value.Value, error) {
 	if stack.ReachedBaseOfCall() {
 		return value.Value{}, ErrStackUnderflow
 	}
@@ -69,7 +91,7 @@ func (stack *Stack) Local(offset int) (value.Value, error) {
 	return stack.Get(stack.LocalToStackIndex(offset))
 }
 
-func (stack *Stack) Top() (value.Value, error) {
+func (stack *stackImpl) Top() (value.Value, error) {
 	if stack.IsEmpty() || stack.ReachedBaseOfCall() {
 		return value.Value{}, ErrStackUnderflow
 	}
@@ -77,15 +99,15 @@ func (stack *Stack) Top() (value.Value, error) {
 	return stack.data[stack.Len()-1], nil
 }
 
-func (stack *Stack) Len() int {
+func (stack *stackImpl) Len() int {
 	return len(stack.data)
 }
 
-func (stack *Stack) IsEmpty() bool {
+func (stack *stackImpl) IsEmpty() bool {
 	return len(stack.data) == 0
 }
 
-func (stack *Stack) PushCall(newPc, returnPc int, env mem.Ptr) error {
+func (stack *stackImpl) PushCall(newPc, returnPc int, env mem.Ptr) error {
 	if stack.CallDepth() == 1000 {
 		return ErrReachedMaxCallDepth
 	}
@@ -100,27 +122,19 @@ func (stack *Stack) PushCall(newPc, returnPc int, env mem.Ptr) error {
 	return nil
 }
 
-func (stack *Stack) PopCall() (int, error) {
+func (stack *stackImpl) PopCall() (int, error) {
 	if stack.CallDepth() == 0 {
 		return 0, ErrReachedRootCallFrame
 	}
 
-	call := stack.TopCall()
+	call := stack.topCall()
 	stack.calls = stack.calls[:stack.CallDepth()-1]
 
 	return call.returnPc, nil
 }
 
-func (stack *Stack) CurrentCallEnv() mem.Ptr {
-	if stack.CallDepth() == 0 || stack.TopCall().env.IsNull() {
-		return mem.NullPtr
-	}
-
-	return stack.TopCall().env
-}
-
-func (stack *Stack) ShiftTopCallBase(by int) error {
-	call := stack.TopCall()
+func (stack *stackImpl) ShiftTopCallBase(by int) error {
+	call := stack.topCall()
 	newBase := call.base - by
 
 	if newBase < 0 {
@@ -131,23 +145,31 @@ func (stack *Stack) ShiftTopCallBase(by int) error {
 	return nil
 }
 
-func (stack *Stack) TopCall() *callFrame {
-	return &stack.calls[len(stack.calls)-1]
+func (stack *stackImpl) CurrentCallEnv() mem.Ptr {
+	if stack.CallDepth() == 0 || stack.topCall().env.IsNull() {
+		return mem.NullPtr
+	}
+
+	return stack.topCall().env
 }
 
-func (stack *Stack) CallDepth() int {
+func (stack *stackImpl) CallDepth() int {
 	return len(stack.calls)
 }
 
-func (stack *Stack) ReachedBaseOfCall() bool {
-	return stack.TopCall().base == stack.Len()
+func (stack *stackImpl) ReachedBaseOfCall() bool {
+	return stack.topCall().base == stack.Len()
 }
 
-func (stack *Stack) LocalToStackIndex(local int) int {
+func (stack *stackImpl) LocalToStackIndex(local int) int {
 	if stack.CallDepth() == 0 {
 		return local
 	}
-	return stack.TopCall().base + local
+	return stack.topCall().base + local
+}
+
+func (stack *stackImpl) topCall() *callFrame {
+	return &stack.calls[len(stack.calls)-1]
 }
 
 type callFrame struct {
diff --git a/pkg/lang/vm/utils.go b/pkg/lang/vm/utils.go
index 95c0298..11c195e 100644
--- a/pkg/lang/vm/utils.go
+++ b/pkg/lang/vm/utils.go
@@ -10,7 +10,7 @@ func (vm *VM) popAndDrop() (value.Value, error) {
 	if err != nil {
 		return value.Value{}, err
 	}
-	v.Drop(&vm.memory)
+	v.Drop(vm.memory)
 	return v, nil
 }
 
diff --git a/pkg/lang/vm/value/cells.go b/pkg/lang/vm/value/cells.go
index 17a0916..1c34762 100644
--- a/pkg/lang/vm/value/cells.go
+++ b/pkg/lang/vm/value/cells.go
@@ -4,7 +4,7 @@ import "jinx/pkg/lang/vm/mem"
 
 type ArrayCell []Value
 
-func (a ArrayCell) DropCell(m *mem.Mem) {
+func (a ArrayCell) DropCell(m mem.Mem) {
 	for _, v := range a {
 		v.Drop(m)
 	}
@@ -16,7 +16,7 @@ func (a ArrayCell) Get() []Value {
 
 type StringCell string
 
-func (s StringCell) DropCell(m *mem.Mem) {
+func (s StringCell) DropCell(m mem.Mem) {
 }
 
 func (s StringCell) Get() string {
@@ -25,7 +25,7 @@ func (s StringCell) Get() string {
 
 type OutletCell Value
 
-func (o OutletCell) DropCell(m *mem.Mem) {
+func (o OutletCell) DropCell(m mem.Mem) {
 	Value(o).Drop(m)
 }
 
@@ -35,7 +35,7 @@ func (o OutletCell) Get() Value {
 
 type EnvCell Env
 
-func (e EnvCell) DropCell(m *mem.Mem) {
+func (e EnvCell) DropCell(m mem.Mem) {
 	for _, v := range e.references {
 		m.Release(v.outlet)
 	}
diff --git a/pkg/lang/vm/value/data.go b/pkg/lang/vm/value/data.go
index 2e3b3e6..4e39bc8 100644
--- a/pkg/lang/vm/value/data.go
+++ b/pkg/lang/vm/value/data.go
@@ -8,7 +8,7 @@ import (
 )
 
 type Data interface {
-	String(*mem.Mem) (string, error)
+	String(mem.Mem) (string, error)
 }
 
 type IntData int64
@@ -17,7 +17,7 @@ func (i IntData) Get() int64 {
 	return int64(i)
 }
 
-func (i IntData) String(_ *mem.Mem) (string, error) {
+func (i IntData) String(_ mem.Mem) (string, error) {
 	return strconv.FormatInt(int64(i), 10), nil
 }
 
@@ -27,7 +27,7 @@ func (f FloatData) Get() float64 {
 	return float64(f)
 }
 
-func (f FloatData) String(_ *mem.Mem) (string, error) {
+func (f FloatData) String(_ mem.Mem) (string, error) {
 	return strconv.FormatFloat(float64(f), 'f', -1, 64), nil
 }
 
@@ -35,7 +35,7 @@ type StringData struct {
 	data mem.Ptr
 }
 
-func (s StringData) String(m *mem.Mem) (string, error) {
+func (s StringData) String(m mem.Mem) (string, error) {
 	if data, err := m.Get(s.data); err == nil {
 		return "\"" + data.(StringCell).Get() + "\"", nil
 	} else {
@@ -49,7 +49,7 @@ func (b BoolData) Get() bool {
 	return bool(b)
 }
 
-func (b BoolData) String(_ *mem.Mem) (string, error) {
+func (b BoolData) String(_ mem.Mem) (string, error) {
 	return strconv.FormatBool(bool(b)), nil
 }
 
@@ -57,7 +57,7 @@ type ArrayData struct {
 	data mem.Ptr
 }
 
-func (a ArrayData) String(m *mem.Mem) (string, error) {
+func (a ArrayData) String(m mem.Mem) (string, error) {
 	val, err := m.Get(a.data)
 	if err != nil {
 		return "", err
@@ -81,7 +81,7 @@ func (a ArrayData) String(m *mem.Mem) (string, error) {
 	return builder.String(), nil
 }
 
-func (a ArrayData) Len(m *mem.Mem) (int, error) {
+func (a ArrayData) Len(m mem.Mem) (int, error) {
 	data, err := m.Get(a.data)
 	if err != nil {
 		return 0, err
@@ -90,7 +90,7 @@ func (a ArrayData) Len(m *mem.Mem) (int, error) {
 	return len(arr), nil
 }
 
-func (a ArrayData) At(m *mem.Mem, i int) (Value, error) {
+func (a ArrayData) At(m mem.Mem, i int) (Value, error) {
 	data, err := m.Get(a.data)
 	if err != nil {
 		return Value{}, err
@@ -99,7 +99,7 @@ func (a ArrayData) At(m *mem.Mem, i int) (Value, error) {
 	return arr[i], nil
 }
 
-func (a ArrayData) Push(m *mem.Mem, v Value) error {
+func (a ArrayData) Push(m mem.Mem, v Value) error {
 	data, err := m.Get(a.data)
 	if err != nil {
 		return err
@@ -131,7 +131,7 @@ func (f FunctionData) WithEnv(env mem.Ptr) FunctionData {
 	return FunctionData{pc: f.pc, env: env}
 }
 
-func (f FunctionData) String(_ *mem.Mem) (string, error) {
+func (f FunctionData) String(_ mem.Mem) (string, error) {
 	return fmt.Sprintf("<fn %d>", f.pc), nil
 }
 
diff --git a/pkg/lang/vm/value/value.go b/pkg/lang/vm/value/value.go
index f98740e..a2909ba 100644
--- a/pkg/lang/vm/value/value.go
+++ b/pkg/lang/vm/value/value.go
@@ -20,7 +20,7 @@ func NewFloat(x float64) Value {
 	return Value{t: t, d: FloatData(x)}
 }
 
-func NewString(m *mem.Mem, str string) (Value, error) {
+func NewString(m mem.Mem, str string) (Value, error) {
 	t := Type{Kind: StringType}
 
 	ptr, err := m.Allocate(mem.CellKindString)
@@ -38,7 +38,7 @@ func NewBool(b bool) Value {
 	return Value{t: t, d: BoolData(b)}
 }
 
-func NewArray(m *mem.Mem, arr []Value) (Value, error) {
+func NewArray(m mem.Mem, arr []Value) (Value, error) {
 	t := Type{Kind: ArrayType}
 
 	ptr, err := m.Allocate(mem.CellKindArray)
@@ -85,7 +85,7 @@ func (v Value) WithOutlet(outlet mem.Ptr) Value {
 	return Value{t: v.t, d: v.d, outlet: outlet}
 }
 
-func (v Value) Clone(m *mem.Mem) Value {
+func (v Value) Clone(m mem.Mem) Value {
 	if v.t.Kind == StringType {
 		str := v.d.(StringData)
 		m.Retain(str.data)
@@ -104,7 +104,7 @@ func (v Value) Clone(m *mem.Mem) Value {
 	return v
 }
 
-func (v Value) Drop(m *mem.Mem) {
+func (v Value) Drop(m mem.Mem) {
 	// If value has an outlet, don't drop it and instead move it to the outlet.
 	if !v.outlet.IsNull() {
 		m.Set(v.outlet, OutletCell(v))
diff --git a/pkg/lang/vm/vm.go b/pkg/lang/vm/vm.go
index 9c17a3f..2ac689b 100644
--- a/pkg/lang/vm/vm.go
+++ b/pkg/lang/vm/vm.go
@@ -3,12 +3,13 @@ package vm
 import (
 	"jinx/pkg/lang/vm/code"
 	"jinx/pkg/lang/vm/mem"
+	"jinx/pkg/lang/vm/stack"
 )
 
 type VM struct {
 	code   *code.Code
 	pc     int
-	stack  Stack
+	stack  stack.Stack
 	memory mem.Mem
 }
 
@@ -16,7 +17,7 @@ func New(code *code.Code) *VM {
 	return &VM{
 		code:   code,
 		pc:     0,
-		stack:  NewStack(),
+		stack:  stack.New(),
 		memory: mem.New(),
 	}
 }
@@ -27,7 +28,7 @@ func (vm *VM) GetResult() (string, error) {
 		return "", err
 	}
 
-	if str, err := res.Data().String(&vm.memory); err == nil {
+	if str, err := res.Data().String(vm.memory); err == nil {
 		return str, nil
 	} else {
 		return "", err