From 70ffb3a8f795fc4161d38ab6071adb95abbed13f Mon Sep 17 00:00:00 2001 From: Reid 'arrdem' McKenzie Date: Wed, 15 Jun 2022 09:21:43 -0600 Subject: [PATCH] Code better in the morning --- projects/shoggoth/src/python/ichor/impl.py | 106 ++++++++++++--------- 1 file changed, 62 insertions(+), 44 deletions(-) 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(";
;;", opcodes)] + main = mod.define_function(";
;;", 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