diff --git a/projects/shoggoth/src/python/ichor/impl.py b/projects/shoggoth/src/python/ichor/impl.py
index bae747e..35c9678 100644
--- a/projects/shoggoth/src/python/ichor/impl.py
+++ b/projects/shoggoth/src/python/ichor/impl.py
@@ -22,51 +22,67 @@ def rotate(l):
 
 class Stackframe(object):
     def __init__(self,
-                 stack=None,
-                 fun: t.Optional[Function] = None,
-                 ip=None, parent=None, depth=0):
-        self.stack = stack or []
-        self.name = name or ";unknown;;"
-        self.ip = ip or 0
-        self.parent = parent
-        self.depth = depth
+                 fun: Function,
+                 ip: int,
+                 stack: t.Optional[t.List[t.Any]] = None,
+                 parent: t.Optional["Stackframe"] = None):
+        self._fun = fun
+        self._ip = ip
+        self._stack = stack or []
+        self._parent = parent
 
     def push(self, obj):
-        self.stack.insert(0, obj)
+        self._stack.insert(0, obj)
 
     def pop(self):
-        return self.stack.pop(0)
+        return self._stack.pop(0)
 
     def call(self, fun: Function, ip) -> "Stackframe":
-        self.ip += 1
+        assert isinstance(fun, Function)
+        assert isinstance(ip, int)
+        self._ip += 1
         nargs = len(fun.arguments)
-        args, self.stack = self.stack[:nargs], self.stack[nargs:]
+        args, self._stack = self._stack[:nargs], self._stack[nargs:]
         return Stackframe(
+            fun,
+            ip,
             stack=args,
-            name=fun.signature,
-            ip=ip,
             parent=self,
-            depth=self.depth+1
         )
 
     def ret(self, nargs) -> "Stackframe":
-        self.parent.stack = self.stack[:nargs] + self.parent.stack
-        return self.parent
+        assert nargs >= 0
+        assert isinstance(self._parent, Stackframe)
+        self._parent._stack = self._stack[:nargs] + self._parent._stack
+        return self._parent
 
     def dup(self, nargs):
-        self.stack = self.stack[:nargs] + self.stack
+        self._stack = self._stack[:nargs] + self._stack
 
     def drop(self, nargs):
-        self.stack = self.stack[nargs:]
+        self._stack = self._stack[nargs:]
 
     def rot(self, nargs):
-        self.stack = rotate(self.stack[:nargs]) + self.stack[nargs:]
+        self._stack = rotate(self._stack[:nargs]) + self._stack[nargs:]
+
+    def slot(self, n):
+        self.push(self._stack[len(self) - n - 1])
+
+    def goto(self, target: int):
+        self._ip = target
+
+    @property
+    def depth(self):
+        if self._parent == None:
+            return 0
+        else:
+            return self._parent.depth + 1
 
     def __getitem__(self, key):
-        return self.stack.__getitem__(key)
+        return self._stack.__getitem__(key)
 
     def __len__(self):
-        return len(self.stack)
+        return len(self._stack)
 
 
 class InterpreterError(Exception):
@@ -86,9 +102,11 @@ class Interpreter(object):
     def run(self, opcodes, stack=[]):
         """Directly interpret some opcodes in the configured environment."""
 
-        stackframe = Stackframe(stack=stack)
         mod = self.bootstrap.copy()
-        stackframe.ip = mod.labels[mod.define_function(";<main>;;", opcodes)]
+        main = mod.define_function(";<main>;;", opcodes)
+        main_fun = mod.functions[main]
+        main_ip = mod.labels[main]
+        stackframe = Stackframe(main_fun, main_ip, stack)
 
         print(mod)
 
@@ -98,8 +116,8 @@ class Interpreter(object):
             raise InterpreterError(mod, deepcopy(stackframe), msg)
 
         while True:
-            op = mod.codepage[stackframe.ip]
-            print("{0}{1: <50} {2}: {3}".format("  " * stackframe.depth, str(stackframe.stack), stackframe.ip, op))
+            op = mod.codepage[stackframe._ip]
+            print("{0}{1: <50} {2}: {3}".format("  " * stackframe.depth, str(stackframe._stack), stackframe._ip, op))
 
             match op:
                 case Opcode.TRUE():
@@ -117,14 +135,13 @@ class Interpreter(object):
                         _error("Type violation")
 
                     if val is False:
-                        stackframe.ip = target
+                        stackframe.goto(target)
                         continue
 
                 case Opcode.GOTO(n):
                     if (n < 0):
                         _error("Illegal branch target")
-
-                    stackframe.ip = n
+                    stackframe.goto(n)
                     continue
 
                 case Opcode.DUP(n):
@@ -148,9 +165,9 @@ class Interpreter(object):
                 case Opcode.SLOT(n):
                     if (n < 0):
                         _error("SLOT must have a positive reference")
-                    if (n > len(stackframe.stack) - 1):
+                    if (n > len(stackframe) - 1):
                         _error("SLOT reference out of range")
-                    stackframe.push(stackframe.stack[len(stackframe) - n - 1])
+                    stackframe.slot(n)
 
                 case Opcode.IDENTIFIERC(name):
                     if not (name in mod.functions or name in mod.types):
@@ -179,7 +196,7 @@ class Interpreter(object):
                         _error("Stack size violation")
 
                     try:
-                        ip = mod.codepage[sig.raw]
+                        ip = mod.labels[fun.signature]
                     except KeyError:
                         _error("Unknown target")
 
@@ -193,8 +210,7 @@ class Interpreter(object):
                     if stackframe.depth == 0:
                         return stackframe[:n]
 
-                    sig = FunctionRef.parse(stackframe.name)
-                    if (len(sig.ret) != n):
+                    if (len(stackframe._fun.returns) != n):
                         _error("Signature violation")
 
                     stackframe = stackframe.ret(n)
@@ -204,14 +220,15 @@ class Interpreter(object):
                     sig = stackframe.pop()
                     if not isinstance(sig, FunctionRef):
                         _error("CLOSUREF requires a funref at top of stack")
-                    if not n <= len(sig.args):
+                    fun = mod.functions[sig.name]
+                    if not n <= len(fun.arguments):
                         _error("CLOSUREF target violation; too many parameters provided")
                     if n > len(stackframe):
                         _error("Stack size violation")
 
                     c = Closure(
                         sig,
-                        stackframe.stack[:n]
+                        stackframe._stack[:n]
                     )
                     stackframe.drop(n)
                     stackframe.push(c)
@@ -220,14 +237,15 @@ class Interpreter(object):
                     c = stackframe.pop()
                     if not isinstance(c, Closure):
                         _error("CLOSUREC requires a closure at top of stack")
-                    if n + len(c.frag) > len(c.funref.args):
+                    fun = mod.functions[c.funref.name]
+                    if n + len(c.frag) > len(fun.arguments):
                         _error("CLOSUREC target violation; too many parameters provided")
                     if n > len(stackframe):
                         _error("Stack size violation")
 
                     c = Closure(
                         c.funref,
-                        stackframe.stack[:n] + c.frag
+                        stackframe._stack[:n] + c.frag
                     )
                     stackframe.drop(n)
                     stackframe.push(c)
@@ -236,27 +254,27 @@ class Interpreter(object):
                     c = stackframe.pop()
                     if not isinstance(c, Closure):
                         _error("CALLC requires a closure at top of stack")
-                    if n + len(c.frag) != len(c.funref.args):
+                    fun = mod.functions[c.funref.name]
+                    if n + len(c.frag) != len(fun.arguments):
                         _error("CALLC target vionation; argument count missmatch")
                     if n > len(stackframe):
                         _error("Stack size violation")
 
                     # Extract the function signature
-                    sig = c.funref
 
                     # Push the closure's stack fragment
-                    stackframe.stack = c.frag + stackframe.stack
+                    stackframe._stack = c.frag + stackframe._stack
 
                     # Perform a "normal" funref call
                     try:
-                        ip = mod.functions[sig.raw]
+                        ip = mod.labels[fun.signature]
                     except KeyError:
                         _error("Unknown target")
 
-                    stackframe = stackframe.call(sig, ip)
+                    stackframe = stackframe.call(fun, ip)
                     continue
 
                 case _:
                     raise Exception(f"Unhandled interpreter state {op}")
 
-            stackframe.ip += 1
+            stackframe._ip += 1