Get VARAINT/VTEST implemented
This commit is contained in:
parent
7fe052e7fc
commit
25234f8f00
2 changed files with 75 additions and 23 deletions
|
@ -13,7 +13,7 @@ from copy import deepcopy
|
|||
import typing as t
|
||||
|
||||
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):
|
||||
|
@ -120,22 +120,65 @@ class Interpreter(object):
|
|||
print("{0}{1: <50} {2}: {3}".format(" " * stackframe.depth, str(stackframe._stack), stackframe._ip, op))
|
||||
|
||||
match op:
|
||||
case Opcode.TRUE():
|
||||
stackframe.push(True)
|
||||
case Opcode.IDENTIFIERC(name):
|
||||
if not (name in mod.functions or name in mod.types):
|
||||
_error("IDENTIFIERC references unknown entity")
|
||||
|
||||
case Opcode.FALSE():
|
||||
stackframe.push(False)
|
||||
stackframe.push(Identifier(name))
|
||||
|
||||
case Opcode.IF(target):
|
||||
if len(stackframe) < 1:
|
||||
case Opcode.TYPEREF():
|
||||
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")
|
||||
|
||||
val = stackframe.pop()
|
||||
if val not in [True, False]:
|
||||
_error("Type violation")
|
||||
# FIXME: Where does type variable to type binding occur?
|
||||
# Certainly needs to be AT LEAST here, where we also need to be doing some typechecking
|
||||
v = Variant(armref.type.name, armref.arm, tuple(stackframe._stack[:n]))
|
||||
stackframe.drop(n)
|
||||
stackframe.push(v)
|
||||
|
||||
if val is False:
|
||||
stackframe.goto(target)
|
||||
case Opcode.VTEST(n):
|
||||
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
|
||||
|
||||
case Opcode.GOTO(n):
|
||||
|
@ -169,12 +212,6 @@ class Interpreter(object):
|
|||
_error("SLOT reference out of range")
|
||||
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():
|
||||
id = stackframe.pop()
|
||||
if not isinstance(id, Identifier):
|
||||
|
|
|
@ -95,7 +95,7 @@ class Function(t.NamedTuple):
|
|||
return f"{self.name};{len(self.arguments)};{len(self.returns)}"
|
||||
|
||||
|
||||
class VarT(FuncT):
|
||||
class TypeT(FuncT):
|
||||
@v_args(inline=True)
|
||||
def var(self, 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):
|
||||
name: str
|
||||
constructors: t.List[t.Tuple[str, t.List[str]]]
|
||||
constructors: t.Dict[str, t.List[str]]
|
||||
typevars: t.List[t.Any] = []
|
||||
typeconstraints: t.List[t.Any] = []
|
||||
metadata: dict = {}
|
||||
|
||||
@classmethod
|
||||
def build(cls, name: str):
|
||||
constraints, name, arms = VAR.parse(name)
|
||||
constraints, name, arms = TYPE.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)
|
||||
return cls(name, dict(arms), typeconstraints=constraints)
|
||||
|
||||
@property
|
||||
def signature(self):
|
||||
return self.name
|
||||
|
||||
|
||||
class Variant(t.NamedTuple):
|
||||
type: str
|
||||
variant: str
|
||||
fields: t.Tuple[t.Any]
|
||||
|
||||
|
||||
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.
|
||||
|
|
Loading…
Reference in a new issue