source/projects/shoggoth/src/python/ichor/state.py

227 lines
5.7 KiB
Python
Raw Normal View History

2022-06-14 03:11:15 +00:00
#!/usr/bin/env python3
"""The core VM/interpreter model."""
import typing as t
from ichor.isa import Opcode
2022-06-15 07:12:22 +00:00
from lark import Lark, Transformer, v_args, Token
2022-06-14 03:11:15 +00:00
class Identifier(t.NamedTuple):
name: str
2022-06-14 07:19:30 +00:00
GRAMMAR = r"""
fun: constraints ";" name ";" arguments ";" ret
arguments: (type ","?)*
ret: (type ","?)*
constraints: (constraint ","?)*
constraint: type
var: constraints ";" name ";" arms
2022-06-15 07:12:22 +00:00
arms: (arm ","?)+
2022-06-14 07:19:30 +00:00
arm: name "(" bindings ")"
bindings: (binding ","?)*
binding: name ":" type
type: NAME
name: NAME
NAME: /[^;,:(){}|]+/
2022-06-14 07:19:30 +00:00
"""
2022-06-15 07:12:22 +00:00
class FuncT(Transformer):
@v_args(inline=True)
def fun(self, constraints, name, arguments, ret):
return (constraints, name, arguments, ret)
def constraints(self, args):
return (*args,)
def arguments(self, args):
return tuple(args)
def ret(self, args):
return tuple(args)
@v_args(inline=True)
def NAME(self, name: Token):
return name.value
@v_args(inline=True)
def name(self, name):
return name
@v_args(inline=True)
def type(self, name):
return name
FUNC = Lark(GRAMMAR, start="fun", parser='lalr', transformer=FuncT())
2022-06-14 07:19:30 +00:00
2022-06-14 03:11:15 +00:00
class FunctionRef(t.NamedTuple):
name: str
@classmethod
def parse(cls, raw: str):
return cls(raw)
2022-06-14 03:11:15 +00:00
class Function(t.NamedTuple):
name: str
2022-06-14 07:19:30 +00:00
arguments: t.List[str]
returns: t.List[str]
instructions: t.List[Opcode]
typevars: t.List[t.Any] = []
typeconstraints: t.List[t.Any] = []
metadata: dict = {}
2022-06-15 07:12:22 +00:00
@classmethod
def build(cls, name: str, instructions: t.List[Opcode]):
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)}"
2022-06-15 07:12:22 +00:00
class VarT(FuncT):
@v_args(inline=True)
def var(self, constraints, name, arms):
return (constraints, name, arms)
@v_args(inline=True)
def constraint(self, name):
return name
def arms(self, arms):
return tuple(arms)
def binding(self, binding):
return tuple(binding)
def bindings(self, bindings):
return tuple(bindings)
@v_args(inline=True)
def arm(self, name, bindings):
return (name, bindings)
2022-06-14 07:19:30 +00:00
2022-06-15 07:12:22 +00:00
VAR = Lark(GRAMMAR, start="var", parser='lalr', transformer=VarT())
2022-06-14 07:19:30 +00:00
2022-06-14 07:19:30 +00:00
class Type(t.NamedTuple):
name: str
constructors: t.List[t.Tuple[str, t.List[str]]]
typevars: t.List[t.Any] = []
typeconstraints: t.List[t.Any] = []
metadata: dict = {}
2022-06-14 03:11:15 +00:00
@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)
2022-06-16 03:56:52 +00:00
@property
def signature(self):
return self.name
2022-06-14 03:11:15 +00:00
class Closure(t.NamedTuple):
# Note that a closure over a closure is equivalent to a single closure which extends the captured stack fragment, so
# there's no need for a union here as we can simply convert nested closures.
funref: FunctionRef
frag: t.List[t.Any]
class Struct(t.NamedTuple):
name: str
type_params: list
children: t.Mapping[str, t.Any]
class Module(t.NamedTuple):
functions: t.Dict[str, Function] = {}
labels: t.Dict[str, int] = {}
2022-06-14 03:11:15 +00:00
codepage: list = []
types: t.Dict[str, Type] = {}
2022-06-14 03:11:15 +00:00
constants: dict = {}
def copy(self) -> "Module":
return Module(
self.functions.copy(),
self.labels.copy(),
self.codepage.copy(),
2022-06-14 03:11:15 +00:00
self.types.copy(),
self.constants.copy(),
)
@staticmethod
def translate(start: int, end: int, i: Opcode):
# FIXME: Consolidate bounds checks somehow
match i:
case Opcode.IF(t):
d = t + start
assert start <= d < end
return Opcode.IF(d)
case Opcode.GOTO(t):
d = t + start
assert start <= d < end
return Opcode.GOTO(d)
case _:
return i
def define_function(self, name, opcodes):
"""Enter a function into module.
Side-effects the codepage and name table.
"""
func = Function.build(name, opcodes)
self.functions[func.signature] = func
self.labels[func.signature] = start = len(self.codepage)
2022-06-14 03:11:15 +00:00
for op in opcodes:
self.codepage.append(self.translate(start, start + len(opcodes), op))
return func.signature
2022-06-14 03:11:15 +00:00
2022-06-16 03:56:52 +00:00
def define_type(self, name):
type = Type.build(name)
self.types[type.signature] = type
return type.signature
2022-06-14 03:11:15 +00:00
def __str__(self):
b = []
2022-06-15 15:46:03 +00:00
b.append("functions:")
for sig, fun in self.functions.items():
b.append(f" {sig!r}:")
b.append(f" name: {fun.name}")
b.append(f" typeconstraints: {fun.typeconstraints}")
b.append(f" arguments: {fun.arguments}")
b.append(f" returns: {fun.returns}")
b.append(f" ip: {self.labels[fun.signature]}")
b.append("codepage:")
marks = {v: k for k, v in self.labels.items()}
2022-06-14 03:11:15 +00:00
for i, o in zip(range(1<<64), self.codepage):
if(i in marks):
2022-06-15 15:46:03 +00:00
b.append(f" {marks[i]!r}:")
b.append(f" {i: >10}: {o}")
2022-06-14 03:11:15 +00:00
return "\n".join(b)