From 34c550ba7f0e6f92536f36021cbd46833849d3e9 Mon Sep 17 00:00:00 2001 From: "Reid D. 'arrdem' McKenzie" Date: Tue, 7 Jun 2022 10:32:15 -0600 Subject: [PATCH] Tapping towards structs and variants --- projects/shoggoth/src/python/ichor/impl.py | 19 ++++- projects/shoggoth/src/python/ichor/isa.py | 78 ++++++++++++++++++-- projects/shoggoth/src/python/ichor/typing.py | 21 ++++-- 3 files changed, 107 insertions(+), 11 deletions(-) diff --git a/projects/shoggoth/src/python/ichor/impl.py b/projects/shoggoth/src/python/ichor/impl.py index 1da2a5a..ac57eb9 100644 --- a/projects/shoggoth/src/python/ichor/impl.py +++ b/projects/shoggoth/src/python/ichor/impl.py @@ -236,7 +236,7 @@ class Interpreter(object): if n + len(c.frag) != len(c.funref.args): _error("CALLC target vionation; argument count missmatch") if n > len(stack): - _error("Stack size vionation") + _error("Stack size violation") # Extract the function signature sig = c.funref @@ -253,6 +253,23 @@ class Interpreter(object): stack = stack.call(sig, ip) continue + case Opcode.STRUCT(structref, n): + if not (t := module.types.get(structref)): + _error(f"STRUCT must reference a known type, {structref!r} is undefined") + if n > len(stack): + _error("Stack size violation") + + args = stack[:n] + stack.drop(n) + + # FIXME: typecheck + for arg, ftype in zip(args, t.children): + pass + + inst = Struct(structref, [], dict(zip(t.field_names, args))) + + stack.push(inst) + case _: raise Exception(f"Unhandled interpreter state {op}") diff --git a/projects/shoggoth/src/python/ichor/isa.py b/projects/shoggoth/src/python/ichor/isa.py index 2acb7c2..a980740 100644 --- a/projects/shoggoth/src/python/ichor/isa.py +++ b/projects/shoggoth/src/python/ichor/isa.py @@ -175,19 +175,58 @@ class Opcode: #################################################################################################### # Structures #################################################################################################### + + # FIXME: This lacks any sort of way to do dynamic field references + + class IDENTIFIERC(t.NamedTuple): + """() -> (CONST) + + An inline constant which produces an identifier to the stack. + + Identifiers name functions, fields and types but are not strings. + They are a VM-internal naming structure with reference to the module. + + """ + + val: str + + class TYPEREF(t.NamedTuple): + """(IDENTIFIER) -> (TYPEREF) + + Produces a TYPEREF to the type named by the provided IDENTIFIER. + + """ + + class FIELDREF(t.NamedTuple): + """(IDENTIFIER, TYPEREF) -> (FIELDREF) + + + Produces a FIELDREF to the field named by the provided IDENTIFIER. + The FIELDREF must be within and with reference to a sum type. + + """ + + class VARIANTREF(t.NamedTuple): + """(IDENTIFIER, TYPEREF) -> (VARIANTREF) + + Produce a VARIANTREF to an 'arm' of the given variant type. + + """ + class STRUCT(t.NamedTuple): - """(*) -> (T) + """(STRUCTREF, ...) -> (S) Consume the top N items of the stack, producing a struct of the type `structref`. The name and module path of the current function MUST match the name and module path of `structref`. + The arity of this opcode MUST match the arity of the struct. + The signature of the struct MUST match the signature fo the top N of the stack. """ - structref: str - nargs: int + nargs: int = 0 class FLOAD(t.NamedTuple): - """(A) -> (B) + """(FIELDREF, S) -> (T) Consume the struct reference at the top of the stack, producing the value of the referenced field. @@ -196,7 +235,7 @@ class Opcode: fieldref: str class FSTORE(t.NamedTuple): - """(A, B) -> (A) + """(FIELDREF, S, T) -> (S) Consume the struct reference at the top of the stack and a value, producing a new copy of the struct in which that field has been updated to the new value. @@ -205,6 +244,35 @@ class Opcode: fieldref: str + class VARIANT(t.NamedTuple): + """(VARIANTREF, ...) -> (B) + + Construct an instance of an 'arm' of a variant. + The type of the 'arm' is considered to be the type of the whole variant. + + The name and module path of the current function MUST match the name and module path of `VARIANTREF`. + The arity of this opcode MUST match the arity of the arm. + The signature of the arm MUST match the signature fo the top N of the stack. + """ + + nargs: int = 0 + + class VTEST(t.NamedTuple): + """(VARIANTREF, B) -> (bool) + + Test whether B is a given arm of a variant A . + + """ + + class VLOAD(t.NamedTuple): + """(VARIANTREF, B) -> (A) + + Load the value of the variant arm. + VLOAD errors (undefined) if B is not within the variant. + VLOAD errors (undefined) if the value in B is not an A - use VTEST as needed. + + """ + #################################################################################################### # Arrays #################################################################################################### diff --git a/projects/shoggoth/src/python/ichor/typing.py b/projects/shoggoth/src/python/ichor/typing.py index 0ccddf2..fe8ac89 100644 --- a/projects/shoggoth/src/python/ichor/typing.py +++ b/projects/shoggoth/src/python/ichor/typing.py @@ -22,6 +22,14 @@ class ProductExpr(t.NamedTuple): children: t.Mapping[str, t.Any] +# FIXME: How exactly +class StructExpr(t.NamedTuple): + name: str + type_params: list + field_names: t.List[str] + children: t.List[t.Any] + + #################################################################################################### #################################################################################################### #################################################################################################### @@ -50,8 +58,10 @@ class FunctionRef(t.NamedTuple): class Closure(t.NamedTuple): - target: t.Union["Closure", FunctionRef] - args: t.List[t.Any] + # 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 FunctionSignature(t.NamedTuple): @@ -77,6 +87,7 @@ class FunctionSignature(t.NamedTuple): ) -class Closure(t.NamedTuple): - funref: FunctionRef - frag: t.List[t.Any] +class Struct(t.NamedTuple): + name: str + type_params: list + children: t.Mapping[str, t.Any]