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
|
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):
|
||||||
|
|
|
@ -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.
|
||||||
|
|
Loading…
Reference in a new issue