Get VARAINT/VTEST implemented

This commit is contained in:
Reid 'arrdem' McKenzie 2022-06-16 10:55:18 -06:00
parent 3eda062c21
commit 102210bcee
2 changed files with 75 additions and 23 deletions

View file

@ -13,7 +13,7 @@ from copy import deepcopy
import typing as t import typing as t
from ichor.isa import Opcode from ichor.isa import Opcode
from ichor.state import Closure, FunctionRef, Identifier, Module, Function from ichor.state import Closure, FunctionRef, Identifier, Module, Function, Type, TypeRef, VariantRef, Variant
def rotate(l): def rotate(l):
@ -120,22 +120,65 @@ class Interpreter(object):
print("{0}{1: <50} {2}: {3}".format(" " * stackframe.depth, str(stackframe._stack), stackframe._ip, op)) print("{0}{1: <50} {2}: {3}".format(" " * stackframe.depth, str(stackframe._stack), stackframe._ip, op))
match op: match op:
case Opcode.TRUE(): case Opcode.IDENTIFIERC(name):
stackframe.push(True) if not (name in mod.functions or name in mod.types):
_error("IDENTIFIERC references unknown entity")
case Opcode.FALSE(): stackframe.push(Identifier(name))
stackframe.push(False)
case Opcode.IF(target): case Opcode.TYPEREF():
if len(stackframe) < 1: id = stackframe.pop()
if not isinstance(id, Identifier):
_error("TYPEREF consumes an identifier")
if not id.name in mod.types:
_error("TYPEREF must be given a valid type identifier")
stackframe.push(TypeRef(id.name))
case Opcode.VARIANTREF():
id: Identifier = stackframe.pop()
if not isinstance(id, Identifier):
_error("VARIANTREF consumes an identifier and a typeref")
t: TypeRef = stackframe.pop()
if not isinstance(id, TypeRef):
_error("VARIANTREF consumes an identifier and a typeref")
type = mod.types[t.name]
if id.name not in type.constructors:
_error(f"VARIANTREF given {id.name!r} which does not name a constructor within {type!r}")
stackframe.push(VariantRef(t, id.name))
case Opcode.VARIANT(n):
armref: VariantRef = stackframe.pop()
if not isinstance(armref, VariantRef):
_error("VARIANT must be given a valid constructor reference")
ctor = mod.types[armref.type.name].constructors[armref.arm]
if n != len(ctor):
_error("VARIANT given n-args inconsistent with the type constructor")
if n > len(stackframe):
_error("Stack size violation") _error("Stack size violation")
val = stackframe.pop() # FIXME: Where does type variable to type binding occur?
if val not in [True, False]: # Certainly needs to be AT LEAST here, where we also need to be doing some typechecking
_error("Type violation") v = Variant(armref.type.name, armref.arm, tuple(stackframe._stack[:n]))
stackframe.drop(n)
stackframe.push(v)
if val is False: case Opcode.VTEST(n):
stackframe.goto(target) armref: VariantRef = stackframe.pop()
if not isinstance(armref, VariantRef):
_error("VTEST must be given a variant reference")
inst: Variant = stackframe.pop()
if not isinstance(inst, Variant):
_error("VTEST must be given an instance of a variant")
if inst.type == armref.type.name and inst.variant == armref.arm:
stackframe.goto(n)
continue continue
case Opcode.GOTO(n): case Opcode.GOTO(n):
@ -169,12 +212,6 @@ class Interpreter(object):
_error("SLOT reference out of range") _error("SLOT reference out of range")
stackframe.slot(n) stackframe.slot(n)
case Opcode.IDENTIFIERC(name):
if not (name in mod.functions or name in mod.types):
_error("IDENTIFIERC references unknown entity")
stackframe.push(Identifier(name))
case Opcode.FUNREF(): case Opcode.FUNREF():
id = stackframe.pop() id = stackframe.pop()
if not isinstance(id, Identifier): if not isinstance(id, Identifier):

View file

@ -95,7 +95,7 @@ class Function(t.NamedTuple):
return f"{self.name};{len(self.arguments)};{len(self.returns)}" return f"{self.name};{len(self.arguments)};{len(self.returns)}"
class VarT(FuncT): class TypeT(FuncT):
@v_args(inline=True) @v_args(inline=True)
def var(self, constraints, name, arms): def var(self, constraints, name, arms):
return (constraints, name, arms) return (constraints, name, arms)
@ -119,29 +119,44 @@ class VarT(FuncT):
VAR = Lark(GRAMMAR, start="var", parser='lalr', transformer=VarT()) TYPE = Lark(GRAMMAR, start="var", parser='lalr', transformer=TypeT())
class TypeRef(t.NamedTuple):
name: str
class VariantRef(t.NamedTuple):
type: TypeRef
arm: str
class Type(t.NamedTuple): class Type(t.NamedTuple):
name: str name: str
constructors: t.List[t.Tuple[str, t.List[str]]] constructors: t.Dict[str, t.List[str]]
typevars: t.List[t.Any] = [] typevars: t.List[t.Any] = []
typeconstraints: t.List[t.Any] = [] typeconstraints: t.List[t.Any] = []
metadata: dict = {} metadata: dict = {}
@classmethod @classmethod
def build(cls, name: str): def build(cls, name: str):
constraints, name, arms = VAR.parse(name) constraints, name, arms = TYPE.parse(name)
# FIXME: Constraints probably needs some massaging # FIXME: Constraints probably needs some massaging
# FIXME: Need to get typevars from somewhere # FIXME: Need to get typevars from somewhere
# They both probably live in the same list # They both probably live in the same list
return cls(name, arms, typeconstraints=constraints) return cls(name, dict(arms), typeconstraints=constraints)
@property @property
def signature(self): def signature(self):
return self.name return self.name
class Variant(t.NamedTuple):
type: str
variant: str
fields: t.Tuple[t.Any]
class Closure(t.NamedTuple): class Closure(t.NamedTuple):
# Note that a closure over a closure is equivalent to a single closure which extends the captured stack fragment, so # 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. # there's no need for a union here as we can simply convert nested closures.