From 366440a3b9f52d7e4b6cf028d00efce685cf9032 Mon Sep 17 00:00:00 2001
From: Reid 'arrdem' McKenzie <me@arrdem.com>
Date: Wed, 15 Jun 2022 01:46:32 -0600
Subject: [PATCH] [broken] Almost to a reworked Function model

---
 projects/shoggoth/src/python/ichor/impl.py  | 23 ++++---
 projects/shoggoth/src/python/ichor/state.py | 66 ++++++++++-----------
 2 files changed, 47 insertions(+), 42 deletions(-)

diff --git a/projects/shoggoth/src/python/ichor/impl.py b/projects/shoggoth/src/python/ichor/impl.py
index 7569bb3..bae747e 100644
--- a/projects/shoggoth/src/python/ichor/impl.py
+++ b/projects/shoggoth/src/python/ichor/impl.py
@@ -10,9 +10,10 @@ context (a virtual machine) which DOES have an easily introspected and serialize
 
 
 from copy import deepcopy
+import typing as t
 
 from ichor.isa import Opcode
-from ichor.state import Closure, FunctionRef, Identifier, Module
+from ichor.state import Closure, FunctionRef, Identifier, Module, Function
 
 
 def rotate(l):
@@ -20,7 +21,10 @@ def rotate(l):
 
 
 class Stackframe(object):
-    def __init__(self, stack=None, name=None, ip=None, parent=None, depth=0):
+    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
@@ -33,13 +37,13 @@ class Stackframe(object):
     def pop(self):
         return self.stack.pop(0)
 
-    def call(self, signature: FunctionRef, ip) -> "Stackframe":
+    def call(self, fun: Function, ip) -> "Stackframe":
         self.ip += 1
-        nargs = len(signature.args)
+        nargs = len(fun.arguments)
         args, self.stack = self.stack[:nargs], self.stack[nargs:]
         return Stackframe(
             stack=args,
-            name=signature.raw,
+            name=fun.signature,
             ip=ip,
             parent=self,
             depth=self.depth+1
@@ -84,7 +88,7 @@ class Interpreter(object):
 
         stackframe = Stackframe(stack=stack)
         mod = self.bootstrap.copy()
-        stackframe.ip = mod.functions[mod.define_function(";<main>;;", opcodes)]
+        stackframe.ip = mod.labels[mod.define_function(";<main>;;", opcodes)]
 
         print(mod)
 
@@ -168,17 +172,18 @@ class Interpreter(object):
                     sig = stackframe.pop()
                     if not isinstance(sig, FunctionRef):
                         _error("CALLF requires a funref at top of stack")
-                    if n != len(sig.args):
+                    fun = mod.functions[sig.name]
+                    if n != len(fun.arguments):
                         _error("CALLF target violation; argument count missmatch")
                     if n > len(stackframe):
                         _error("Stack size violation")
 
                     try:
-                        ip = mod.functions[sig.raw]
+                        ip = mod.codepage[sig.raw]
                     except KeyError:
                         _error("Unknown target")
 
-                    stackframe = stackframe.call(sig, ip)
+                    stackframe = stackframe.call(fun, ip)
                     continue
 
                 case Opcode.RETURN(n):
diff --git a/projects/shoggoth/src/python/ichor/state.py b/projects/shoggoth/src/python/ichor/state.py
index e40bd6b..f2b15e5 100644
--- a/projects/shoggoth/src/python/ichor/state.py
+++ b/projects/shoggoth/src/python/ichor/state.py
@@ -30,9 +30,10 @@ binding: name ":" type
 
 type: NAME
 name: NAME
-NAME: /[^;,:⊢()<>\[\]{}|]+/
+NAME: /[^;,:⊢(){}|]+/
 """
 
+
 class FuncT(Transformer):
     @v_args(inline=True)
     def fun(self, constraints, name, arguments, ret):
@@ -64,26 +65,11 @@ FUNC = Lark(GRAMMAR, start="fun", parser='lalr', transformer=FuncT())
 
 
 class FunctionRef(t.NamedTuple):
-    raw: str
-    type_params: list
     name: str
-    args: list
-    ret: list
-
-    @staticmethod
-    def parse_list(l):
-        return [e for e in l.split(",") if e]
 
     @classmethod
     def parse(cls, raw: str):
-        vars, name, args, ret = raw.split(";")
-        return cls(
-            raw,
-            cls.parse_list(vars),
-            name,
-            cls.parse_list(args),
-            cls.parse_list(ret)
-        )
+        return cls(raw)
 
 
 class Function(t.NamedTuple):
@@ -97,7 +83,16 @@ class Function(t.NamedTuple):
 
     @classmethod
     def build(cls, name: str, instructions: t.List[Opcode]):
-        pass
+        constraints, name, args, rets = FUNC.parse(name)
+        # FIXME: Constraints probably needs some massaging
+        # FIXME: Need to get typevars from somewhere
+        # They both probably live in the same list
+        return cls(name, args, rets, instructions, typeconstraints=constraints)
+
+    @property
+    def signature(self):
+        # FIXME: This should be more meaningful - likely including a type and code fingerprint
+        return f"{self.name};{len(self.arguments)};{len(self.returns)}"
 
 
 class VarT(FuncT):
@@ -126,6 +121,7 @@ class VarT(FuncT):
 
 VAR = Lark(GRAMMAR, start="var", parser='lalr', transformer=VarT())
 
+
 class Type(t.NamedTuple):
     name: str
     constructors: t.List[t.Tuple[str, t.List[str]]]
@@ -133,6 +129,14 @@ class Type(t.NamedTuple):
     typeconstraints: t.List[t.Any] = []
     metadata: dict = {}
 
+    @classmethod
+    def build(cls, name: str):
+        constraints, name, arms = VAR.parse(name)
+        # FIXME: Constraints probably needs some massaging
+        # FIXME: Need to get typevars from somewhere
+        # They both probably live in the same list
+        return cls(name, arms, typeconstraints=constraints)
+
 
 class Closure(t.NamedTuple):
     # Note that a closure over a closure is equivalent to a single closure which extends the captured stack fragment, so
@@ -148,15 +152,17 @@ class Struct(t.NamedTuple):
 
 
 class Module(t.NamedTuple):
+    functions: t.Dict[str, Function] = {}
+    labels: t.Dict[str, int] = {}
     codepage: list = []
-    functions: dict = {}
-    types: dict = {}
+    types: t.Dict[str, Type] = {}
     constants: dict = {}
 
     def copy(self) -> "Module":
         return Module(
-            self.codepage.copy(),
             self.functions.copy(),
+            self.labels.copy(),
+            self.codepage.copy(),
             self.types.copy(),
             self.constants.copy(),
         )
@@ -184,18 +190,12 @@ class Module(t.NamedTuple):
         Side-effects the codepage and name table.
 
         """
-
-        try:
-            sig = FunctionRef.parse(name)
-            assert sig.name
-        except:
-            raise ValueError("Illegal name provided")
-
-        start = len(self.codepage)
-        self.functions[name] = start
+        func = Function.build(name, opcodes)
+        self.functions[func.signature] = func
+        self.labels[func.signature] = start = len(self.codepage)
         for op in opcodes:
             self.codepage.append(self.translate(start, start + len(opcodes), op))
-        return name
+        return func.signature
 
     def define_type(self, name, signature):
         self.types[name] = signature
@@ -203,9 +203,9 @@ class Module(t.NamedTuple):
 
     def __str__(self):
         b = []
-        marks = {v: k for k, v in self.functions.items()}
+        marks = {v: k for k, v in self.labels.items()}
         for i, o in zip(range(1<<64), self.codepage):
             if(i in marks):
                 b.append(f"{marks[i]}:")
-                b.append(f"{i: >10}: {o}")
+            b.append(f"{i: >10}: {o}")
         return "\n".join(b)