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(";
;;", opcodes)] + stackframe.ip = mod.labels[mod.define_function(";
;;", 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)