Reworks type class instantiation
Before, a type class was a property of a type. But that doesn't make any sense for multi parameter type classes. Had to make a hacky way for type classes with type constructors.
This commit is contained in:
parent
11fde4cb9e
commit
a2e1dfd799
@ -296,7 +296,7 @@ def type3(inp: type3placeholders.Type3OrPlaceholder) -> wasm.WasmType:
|
||||
# And pointers are i32
|
||||
return wasm.WasmTypeInt32()
|
||||
|
||||
if prelude.InternalPassAsPointer in inp.classes:
|
||||
if (prelude.InternalPassAsPointer, (inp, )) in prelude.PRELUDE_TYPE_CLASS_INSTANCES_EXISTING:
|
||||
return wasm.WasmTypeInt32()
|
||||
|
||||
raise NotImplementedError(type3, inp)
|
||||
@ -344,7 +344,7 @@ def tuple_instantiation(wgn: WasmGenerator, inp: ourlang.TupleInstantiation) ->
|
||||
|
||||
assert element.type3 == exp_type3
|
||||
|
||||
if prelude.InternalPassAsPointer in exp_type3.classes:
|
||||
if (prelude.InternalPassAsPointer, (exp_type3, )) in prelude.PRELUDE_TYPE_CLASS_INSTANCES_EXISTING:
|
||||
mtyp = 'i32'
|
||||
else:
|
||||
assert isinstance(exp_type3, type3types.Type3), NotImplementedError('Tuple of applied types / structs')
|
||||
@ -413,7 +413,7 @@ def expression(wgn: WasmGenerator, inp: ourlang.Expression) -> None:
|
||||
if isinstance(inp.variable, ourlang.ModuleConstantDef):
|
||||
assert isinstance(inp.type3, type3types.Type3), type3placeholders.TYPE3_ASSERTION_ERROR
|
||||
|
||||
if prelude.InternalPassAsPointer in inp.type3.classes:
|
||||
if (prelude.InternalPassAsPointer, (inp.type3, )) in prelude.PRELUDE_TYPE_CLASS_INSTANCES_EXISTING:
|
||||
assert isinstance(inp.variable.constant, (ourlang.ConstantBytes, ourlang.ConstantStruct, ourlang.ConstantTuple, ))
|
||||
|
||||
address = inp.variable.constant.data_block.address
|
||||
@ -560,7 +560,7 @@ def expression(wgn: WasmGenerator, inp: ourlang.Expression) -> None:
|
||||
|
||||
expression(wgn, inp.varref)
|
||||
|
||||
if prelude.InternalPassAsPointer in el_type.classes:
|
||||
if (prelude.InternalPassAsPointer, (el_type, )) in prelude.PRELUDE_TYPE_CLASS_INSTANCES_EXISTING:
|
||||
mtyp = 'i32'
|
||||
else:
|
||||
assert isinstance(el_type, type3types.Type3), NotImplementedError('Tuple of applied types / structs')
|
||||
@ -972,7 +972,7 @@ def _generate_struct_constructor(wgn: WasmGenerator, inp: ourlang.StructConstruc
|
||||
# Store each member individually
|
||||
for memname, mtyp3 in st_args.items():
|
||||
mtyp: Optional[str]
|
||||
if prelude.InternalPassAsPointer in mtyp3.classes:
|
||||
if (prelude.InternalPassAsPointer, (mtyp3, )) in prelude.PRELUDE_TYPE_CLASS_INSTANCES_EXISTING:
|
||||
mtyp = 'i32'
|
||||
else:
|
||||
mtyp = LOAD_STORE_TYPE_MAP.get(mtyp3.name)
|
||||
|
||||
@ -247,7 +247,7 @@ class OurVisitor:
|
||||
|
||||
members[stmt.target.id] = self.visit_type(module, stmt.annotation)
|
||||
|
||||
return StructDefinition(prelude.struct(node.name, members, set()), node.lineno)
|
||||
return StructDefinition(prelude.struct(node.name, members), node.lineno)
|
||||
|
||||
def pre_visit_Module_AnnAssign(self, module: Module, node: ast.AnnAssign) -> ModuleConstantDef:
|
||||
if not isinstance(node.target, ast.Name):
|
||||
|
||||
@ -3,7 +3,7 @@ The prelude are all the builtin types, type classes and methods
|
||||
"""
|
||||
|
||||
from ..type3.functions import TypeVariable
|
||||
from ..type3.typeclasses import Type3Class, instance_type_class
|
||||
from ..type3.typeclasses import Type3Class
|
||||
from ..type3.types import (
|
||||
Type3,
|
||||
TypeConstructor_StaticArray,
|
||||
@ -11,40 +11,50 @@ from ..type3.types import (
|
||||
TypeConstructor_Tuple,
|
||||
)
|
||||
|
||||
none = Type3('none', [])
|
||||
PRELUDE_TYPE_CLASS_INSTANCES_EXISTING: set[tuple[Type3Class, tuple[Type3, ...]]] = set()
|
||||
|
||||
|
||||
def instance_type_class(cls: Type3Class, typ: Type3) -> None:
|
||||
global PRELUDE_TYPE_CLASS_INSTANCES_EXISTING
|
||||
|
||||
# TODO: Check for required existing instantiations
|
||||
|
||||
PRELUDE_TYPE_CLASS_INSTANCES_EXISTING.add((cls, (typ, ), ))
|
||||
|
||||
none = Type3('none')
|
||||
"""
|
||||
The none type, for when functions simply don't return anything. e.g., IO().
|
||||
"""
|
||||
|
||||
bool_ = Type3('bool', [])
|
||||
bool_ = Type3('bool')
|
||||
"""
|
||||
The bool type, either True or False
|
||||
|
||||
Suffixes with an underscores, as it's a Python builtin
|
||||
"""
|
||||
|
||||
u8 = Type3('u8', [])
|
||||
u8 = Type3('u8')
|
||||
"""
|
||||
The unsigned 8-bit integer type.
|
||||
|
||||
Operations on variables employ modular arithmetic, with modulus 2^8.
|
||||
"""
|
||||
|
||||
u32 = Type3('u32', [])
|
||||
u32 = Type3('u32')
|
||||
"""
|
||||
The unsigned 32-bit integer type.
|
||||
|
||||
Operations on variables employ modular arithmetic, with modulus 2^32.
|
||||
"""
|
||||
|
||||
u64 = Type3('u64', [])
|
||||
u64 = Type3('u64')
|
||||
"""
|
||||
The unsigned 64-bit integer type.
|
||||
|
||||
Operations on variables employ modular arithmetic, with modulus 2^64.
|
||||
"""
|
||||
|
||||
i8 = Type3('i8', [])
|
||||
i8 = Type3('i8')
|
||||
"""
|
||||
The signed 8-bit integer type.
|
||||
|
||||
@ -52,7 +62,7 @@ Operations on variables employ modular arithmetic, with modulus 2^8, but
|
||||
with the middel point being 0.
|
||||
"""
|
||||
|
||||
i32 = Type3('i32', [])
|
||||
i32 = Type3('i32')
|
||||
"""
|
||||
The unsigned 32-bit integer type.
|
||||
|
||||
@ -60,7 +70,7 @@ Operations on variables employ modular arithmetic, with modulus 2^32, but
|
||||
with the middel point being 0.
|
||||
"""
|
||||
|
||||
i64 = Type3('i64', [])
|
||||
i64 = Type3('i64')
|
||||
"""
|
||||
The unsigned 64-bit integer type.
|
||||
|
||||
@ -68,22 +78,25 @@ Operations on variables employ modular arithmetic, with modulus 2^64, but
|
||||
with the middel point being 0.
|
||||
"""
|
||||
|
||||
f32 = Type3('f32', [])
|
||||
f32 = Type3('f32')
|
||||
"""
|
||||
A 32-bits IEEE 754 float, of 32 bits width.
|
||||
"""
|
||||
|
||||
f64 = Type3('f64', [])
|
||||
f64 = Type3('f64')
|
||||
"""
|
||||
A 32-bits IEEE 754 float, of 64 bits width.
|
||||
"""
|
||||
|
||||
bytes_ = Type3('bytes', [])
|
||||
bytes_ = Type3('bytes')
|
||||
"""
|
||||
This is a runtime-determined length piece of memory that can be indexed at runtime.
|
||||
"""
|
||||
|
||||
static_array = TypeConstructor_StaticArray('static_array', [], [])
|
||||
def sa_on_create(typ: Type3) -> None:
|
||||
instance_type_class(InternalPassAsPointer, typ)
|
||||
|
||||
static_array = TypeConstructor_StaticArray('static_array', on_create=sa_on_create)
|
||||
"""
|
||||
A type constructor.
|
||||
|
||||
@ -93,7 +106,10 @@ It should be applied with one argument. It has a runtime-dynamic length
|
||||
of the same type repeated.
|
||||
"""
|
||||
|
||||
tuple_ = TypeConstructor_Tuple('tuple', [], [])
|
||||
def tp_on_create(typ: Type3) -> None:
|
||||
instance_type_class(InternalPassAsPointer, typ)
|
||||
|
||||
tuple_ = TypeConstructor_Tuple('tuple', on_create=tp_on_create)
|
||||
"""
|
||||
This is a fixed length piece of memory.
|
||||
|
||||
@ -101,7 +117,10 @@ It should be applied with zero or more arguments. It has a compile time
|
||||
determined length, and each argument can be different.
|
||||
"""
|
||||
|
||||
struct = TypeConstructor_Struct('struct', [], [])
|
||||
def st_on_create(typ: Type3) -> None:
|
||||
instance_type_class(InternalPassAsPointer, typ)
|
||||
|
||||
struct = TypeConstructor_Struct('struct', on_create=st_on_create)
|
||||
"""
|
||||
This is like a tuple, but each argument is named, so that developers
|
||||
can get and set fields by name.
|
||||
@ -130,9 +149,9 @@ Internal type class to keep track which types we pass arounds as a pointer.
|
||||
"""
|
||||
|
||||
instance_type_class(InternalPassAsPointer, bytes_)
|
||||
instance_type_class(InternalPassAsPointer, static_array)
|
||||
instance_type_class(InternalPassAsPointer, tuple_)
|
||||
instance_type_class(InternalPassAsPointer, struct)
|
||||
# instance_type_class(InternalPassAsPointer, static_array)
|
||||
# instance_type_class(InternalPassAsPointer, tuple_)
|
||||
# instance_type_class(InternalPassAsPointer, struct)
|
||||
|
||||
Eq = Type3Class('Eq', [a], methods={}, operators={
|
||||
'==': [a, a, bool_],
|
||||
@ -148,7 +167,6 @@ instance_type_class(Eq, i32)
|
||||
instance_type_class(Eq, i64)
|
||||
instance_type_class(Eq, f32)
|
||||
instance_type_class(Eq, f64)
|
||||
instance_type_class(Eq, static_array)
|
||||
|
||||
Ord = Type3Class('Ord', [a], methods={
|
||||
'min': [a, a, a],
|
||||
|
||||
@ -45,7 +45,13 @@ class Context:
|
||||
Context for constraints
|
||||
"""
|
||||
|
||||
__slots__ = ()
|
||||
__slots__ = ('type_class_instances_existing', )
|
||||
|
||||
# Constraint_TypeClassInstanceExists
|
||||
type_class_instances_existing: set[tuple[typeclasses.Type3Class, tuple[types.Type3, ...]]]
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.type_class_instances_existing = set()
|
||||
|
||||
class ConstraintBase:
|
||||
"""
|
||||
@ -239,49 +245,64 @@ class MustImplementTypeClassConstraint(ConstraintBase):
|
||||
"""
|
||||
A type must implement a given type class
|
||||
"""
|
||||
__slots__ = ('type_class3', 'type3', )
|
||||
__slots__ = ('context', 'type_class3', 'types', )
|
||||
|
||||
context: Context
|
||||
type_class3: Union[str, typeclasses.Type3Class]
|
||||
type3: placeholders.Type3OrPlaceholder
|
||||
types: list[placeholders.Type3OrPlaceholder]
|
||||
|
||||
DATA = {
|
||||
'bytes': {'Foldable'},
|
||||
}
|
||||
|
||||
def __init__(self, type_class3: Union[str, typeclasses.Type3Class], type3: placeholders.Type3OrPlaceholder, comment: Optional[str] = None) -> None:
|
||||
def __init__(self, context: Context, type_class3: Union[str, typeclasses.Type3Class], types: list[placeholders.Type3OrPlaceholder], comment: Optional[str] = None) -> None:
|
||||
super().__init__(comment=comment)
|
||||
|
||||
self.context = context
|
||||
self.type_class3 = type_class3
|
||||
self.type3 = type3
|
||||
self.types = types
|
||||
|
||||
def check(self) -> CheckResult:
|
||||
typ = self.type3
|
||||
if isinstance(typ, placeholders.PlaceholderForType) and typ.resolve_as is not None:
|
||||
typ = typ.resolve_as
|
||||
typ_list = []
|
||||
for typ in self.types:
|
||||
if isinstance(typ, placeholders.PlaceholderForType) and typ.resolve_as is not None:
|
||||
typ = typ.resolve_as
|
||||
|
||||
if isinstance(typ, placeholders.PlaceholderForType):
|
||||
return RequireTypeSubstitutes()
|
||||
if isinstance(typ, placeholders.PlaceholderForType):
|
||||
return RequireTypeSubstitutes()
|
||||
|
||||
typ_list.append(typ)
|
||||
|
||||
assert len(typ_list) == len(self.types)
|
||||
|
||||
if isinstance(self.type_class3, typeclasses.Type3Class):
|
||||
if self.type_class3 in typ.classes:
|
||||
key = (self.type_class3, tuple(typ_list), )
|
||||
if key in self.context.type_class_instances_existing:
|
||||
return None
|
||||
else:
|
||||
if self.type_class3 in self.__class__.DATA.get(typ.name, set()):
|
||||
if self.type_class3 in self.__class__.DATA.get(typ_list[0].name, set()):
|
||||
return None
|
||||
|
||||
return Error(f'{typ.name} does not implement the {self.type_class3} type class')
|
||||
typ_cls_name = self.type_class3 if isinstance(self.type_class3, str) else self.type_class3.name
|
||||
typ_name_list = ' '.join(x.name for x in typ_list)
|
||||
return Error(f'Missing type class instantation: {typ_cls_name} {typ_name_list}')
|
||||
|
||||
def human_readable(self) -> HumanReadableRet:
|
||||
keys = {
|
||||
f'type{idx}': typ
|
||||
for idx, typ in enumerate(self.types)
|
||||
}
|
||||
|
||||
return (
|
||||
'{type3} derives {type_class3}',
|
||||
'Exists instance {type_class3} ' + ' '.join(f'{{{x}}}' for x in keys),
|
||||
{
|
||||
'type_class3': str(self.type_class3),
|
||||
'type3': self.type3,
|
||||
**keys,
|
||||
},
|
||||
)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f'MustImplementTypeClassConstraint({repr(self.type_class3)}, {repr(self.type3)}, comment={repr(self.comment)})'
|
||||
return f'MustImplementTypeClassConstraint({repr(self.type_class3)}, {repr(self.types)}, comment={repr(self.comment)})'
|
||||
|
||||
class LiteralFitsConstraint(ConstraintBase):
|
||||
"""
|
||||
|
||||
@ -25,6 +25,7 @@ ConstraintGenerator = Generator[ConstraintBase, None, None]
|
||||
|
||||
def phasm_type3_generate_constraints(inp: ourlang.Module) -> List[ConstraintBase]:
|
||||
ctx = Context()
|
||||
ctx.type_class_instances_existing.update(prelude.PRELUDE_TYPE_CLASS_INSTANCES_EXISTING)
|
||||
|
||||
return [*module(ctx, inp)]
|
||||
|
||||
@ -71,18 +72,16 @@ def expression(ctx: Context, inp: ourlang.Expression) -> ConstraintGenerator:
|
||||
for call_arg in arguments:
|
||||
yield from expression(ctx, call_arg)
|
||||
|
||||
for type_var, constraint_list in signature.context.constraints.items():
|
||||
assert type_var in type_var_map # When can this happen?
|
||||
for constraint in signature.context.constraints:
|
||||
if isinstance(constraint, functions.Constraint_TypeClassInstanceExists):
|
||||
yield MustImplementTypeClassConstraint(
|
||||
ctx,
|
||||
constraint.type_class3,
|
||||
[type_var_map[x] for x in constraint.types],
|
||||
)
|
||||
continue
|
||||
|
||||
for constraint in constraint_list:
|
||||
if isinstance(constraint, functions.TypeVariableConstraint_TypeHasTypeClass):
|
||||
yield MustImplementTypeClassConstraint(
|
||||
constraint.type_class3,
|
||||
type_var_map[type_var],
|
||||
)
|
||||
continue
|
||||
|
||||
raise NotImplementedError(constraint)
|
||||
raise NotImplementedError(constraint)
|
||||
|
||||
for arg_no, (sig_part, arg_expr) in enumerate(zip(signature.args, arguments + [inp], strict=True)):
|
||||
if arg_no == len(arguments):
|
||||
@ -138,7 +137,7 @@ def expression(ctx: Context, inp: ourlang.Expression) -> ConstraintGenerator:
|
||||
|
||||
yield SameTypeConstraint(inp.func.posonlyargs[0].type3, inp.func.returns_type3, inp.base.type3, inp.type3,
|
||||
comment='foldl :: Foldable t => (b -> a -> b) -> b -> t a -> b')
|
||||
yield MustImplementTypeClassConstraint('Foldable', inp.iter.type3)
|
||||
yield MustImplementTypeClassConstraint(ctx, 'Foldable', [inp.iter.type3])
|
||||
|
||||
return
|
||||
|
||||
|
||||
@ -34,26 +34,37 @@ class TypeVariable:
|
||||
def __repr__(self) -> str:
|
||||
return f'TypeVariable({repr(self.letter)})'
|
||||
|
||||
class TypeVariableConstraintBase:
|
||||
class ConstraintBase:
|
||||
__slots__ = ()
|
||||
|
||||
class TypeVariableConstraint_TypeHasTypeClass(TypeVariableConstraintBase):
|
||||
__slots__ = ('type_class3', )
|
||||
class Constraint_TypeClassInstanceExists(ConstraintBase):
|
||||
__slots__ = ('type_class3', 'types', )
|
||||
|
||||
def __init__(self, type_class3: 'Type3Class') -> None:
|
||||
type_class3: 'Type3Class'
|
||||
types: list[TypeVariable]
|
||||
|
||||
def __init__(self, type_class3: 'Type3Class', types: Iterable[TypeVariable]) -> None:
|
||||
self.type_class3 = type_class3
|
||||
self.types = list(types)
|
||||
|
||||
# Sanity check. AFAIK, if you have a multi-parameter type class,
|
||||
# you can only add a constraint by supplying types for all variables
|
||||
assert len(self.type_class3.args) == len(self.types)
|
||||
|
||||
class TypeVariableContext:
|
||||
__slots__ = ('constraints', )
|
||||
__slots__ = ('variables', 'constraints', )
|
||||
|
||||
constraints: dict[TypeVariable, list[TypeVariableConstraintBase]]
|
||||
variables: set[TypeVariable]
|
||||
constraints: list[ConstraintBase]
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.constraints = {}
|
||||
self.variables = set()
|
||||
self.constraints = []
|
||||
|
||||
def __copy__(self) -> 'TypeVariableContext':
|
||||
result = TypeVariableContext()
|
||||
result.constraints.update(self.constraints)
|
||||
result.variables.update(self.variables)
|
||||
result.constraints.extend(self.constraints)
|
||||
return result
|
||||
|
||||
class FunctionSignature:
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
from typing import Any, Dict, Iterable, List, Mapping, Optional, Union
|
||||
from typing import Dict, Iterable, List, Mapping, Optional, Union
|
||||
|
||||
from .functions import (
|
||||
Constraint_TypeClassInstanceExists,
|
||||
FunctionSignature,
|
||||
TypeVariable,
|
||||
TypeVariableConstraint_TypeHasTypeClass,
|
||||
TypeVariableContext,
|
||||
)
|
||||
from .types import Type3, TypeConstructor, TypeConstructor_Struct
|
||||
from .types import Type3
|
||||
|
||||
|
||||
class Type3ClassMethod:
|
||||
@ -43,17 +43,7 @@ class Type3Class:
|
||||
self.args = list(args)
|
||||
|
||||
context = TypeVariableContext()
|
||||
for arg in args:
|
||||
context.constraints[arg] = [
|
||||
TypeVariableConstraint_TypeHasTypeClass(self)
|
||||
]
|
||||
|
||||
# FIXME: Multi parameter class types
|
||||
# To fix this, realise that an instantiation of a multi paramater type class
|
||||
# means that the instantiation depends on the combination of type classes
|
||||
# and so we can't store the type classes on the types anymore
|
||||
# This also means constraints should store a tuple of types as its key
|
||||
assert len(context.constraints) <= 1
|
||||
context.constraints.append(Constraint_TypeClassInstanceExists(self, args))
|
||||
|
||||
self.methods = {
|
||||
k: Type3ClassMethod(k, FunctionSignature(context, v))
|
||||
@ -67,9 +57,3 @@ class Type3Class:
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return self.name
|
||||
|
||||
def instance_type_class(cls: Type3Class, typ: Type3 | TypeConstructor[Any] | TypeConstructor_Struct) -> None:
|
||||
if isinstance(typ, Type3):
|
||||
typ.classes.add(cls)
|
||||
else:
|
||||
typ.type_classes.add(cls)
|
||||
|
||||
@ -2,18 +2,13 @@
|
||||
Contains the final types for use in Phasm, as well as construtors.
|
||||
"""
|
||||
from typing import (
|
||||
TYPE_CHECKING,
|
||||
Any,
|
||||
Callable,
|
||||
Generic,
|
||||
Iterable,
|
||||
Set,
|
||||
Tuple,
|
||||
TypeVar,
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .typeclasses import Type3Class
|
||||
|
||||
|
||||
class KindArgument:
|
||||
pass
|
||||
@ -25,32 +20,18 @@ class Type3(KindArgument):
|
||||
(Having a separate name makes it easier to distinguish from
|
||||
Python's Type)
|
||||
"""
|
||||
__slots__ = ('name', 'classes', )
|
||||
__slots__ = ('name', )
|
||||
|
||||
name: str
|
||||
"""
|
||||
The name of the string, as parsed and outputted by codestyle.
|
||||
"""
|
||||
|
||||
classes: Set['Type3Class']
|
||||
"""
|
||||
The type classes that this type implements
|
||||
"""
|
||||
|
||||
def __init__(self, name: str, classes: Iterable['Type3Class']) -> None:
|
||||
def __init__(self, name: str) -> None:
|
||||
self.name = name
|
||||
self.classes = set(classes)
|
||||
|
||||
for cls in self.classes:
|
||||
for inh_cls in cls.inherited_classes:
|
||||
if inh_cls not in self.classes:
|
||||
raise Exception(
|
||||
f'No instance for ({inh_cls} {self.name})'
|
||||
f'; required for ({cls} {self.name})'
|
||||
)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f'Type3({repr(self.name)}, {repr(self.classes)})'
|
||||
return f'Type3({repr(self.name)})'
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.name
|
||||
@ -118,21 +99,16 @@ class TypeConstructor(Generic[T]):
|
||||
"""
|
||||
Base class for type construtors
|
||||
"""
|
||||
__slots__ = ('name', 'classes', 'type_classes', '_cache', '_reverse_cache')
|
||||
__slots__ = ('name', 'on_create', '_cache', '_reverse_cache')
|
||||
|
||||
name: str
|
||||
"""
|
||||
The name of the type constructor
|
||||
"""
|
||||
|
||||
classes: Set['Type3Class']
|
||||
on_create: Callable[[Type3], None]
|
||||
"""
|
||||
The type classes that this constructor implements
|
||||
"""
|
||||
|
||||
type_classes: Set['Type3Class']
|
||||
"""
|
||||
The type classes that the constructed types implement
|
||||
Who to let know if a type is created
|
||||
"""
|
||||
|
||||
_cache: dict[T, Type3]
|
||||
@ -146,10 +122,9 @@ class TypeConstructor(Generic[T]):
|
||||
Sometimes we need to know the key that created a type.
|
||||
"""
|
||||
|
||||
def __init__(self, name: str, classes: Iterable['Type3Class'], type_classes: Iterable['Type3Class']) -> None:
|
||||
def __init__(self, name: str, on_create: Callable[[Type3], None]) -> None:
|
||||
self.name = name
|
||||
self.classes = set(classes)
|
||||
self.type_classes = set(type_classes)
|
||||
self.on_create = on_create
|
||||
|
||||
self._cache = {}
|
||||
self._reverse_cache = {}
|
||||
@ -175,8 +150,9 @@ class TypeConstructor(Generic[T]):
|
||||
"""
|
||||
result = self._cache.get(key, None)
|
||||
if result is None:
|
||||
self._cache[key] = result = Type3(self.make_name(key), self.type_classes)
|
||||
self._cache[key] = result = Type3(self.make_name(key))
|
||||
self._reverse_cache[result] = key
|
||||
self.on_create(result)
|
||||
|
||||
return result
|
||||
|
||||
@ -225,21 +201,16 @@ class TypeConstructor_Struct:
|
||||
"""
|
||||
Base class for type construtors
|
||||
"""
|
||||
__slots__ = ('name', 'classes', 'type_classes', '_cache', '_reverse_cache')
|
||||
__slots__ = ('name', 'on_create', '_cache', '_reverse_cache')
|
||||
|
||||
name: str
|
||||
"""
|
||||
The name of the type constructor
|
||||
"""
|
||||
|
||||
classes: Set['Type3Class']
|
||||
on_create: Callable[[Type3], None]
|
||||
"""
|
||||
The type classes that this constructor implements
|
||||
"""
|
||||
|
||||
type_classes: Set['Type3Class']
|
||||
"""
|
||||
The type classes that the constructed types implement
|
||||
Who to let know if a type is created
|
||||
"""
|
||||
|
||||
_cache: dict[str, Type3]
|
||||
@ -254,10 +225,9 @@ class TypeConstructor_Struct:
|
||||
used for making the type
|
||||
"""
|
||||
|
||||
def __init__(self, name: str, classes: Iterable['Type3Class'], type_classes: Iterable['Type3Class']) -> None:
|
||||
def __init__(self, name: str, on_create: Callable[[Type3], None]) -> None:
|
||||
self.name = name
|
||||
self.classes = set(classes)
|
||||
self.type_classes = set(type_classes)
|
||||
self.on_create = on_create
|
||||
|
||||
self._cache = {}
|
||||
self._reverse_cache = {}
|
||||
@ -270,8 +240,9 @@ class TypeConstructor_Struct:
|
||||
"""
|
||||
return self._reverse_cache.get(typ)
|
||||
|
||||
def __call__(self, name: str, args: dict[str, Type3], classes: Set['Type3Class']) -> Type3:
|
||||
result = Type3(name, classes | self.type_classes)
|
||||
def __call__(self, name: str, args: dict[str, Type3]) -> Type3:
|
||||
result = Type3(name)
|
||||
self._reverse_cache[result] = args
|
||||
self.on_create(result)
|
||||
|
||||
return result
|
||||
|
||||
@ -354,7 +354,7 @@ def _unpack(runner: runners.RunnerBase, typ: type3types.Type3, inp: bytes) -> An
|
||||
|
||||
return _load_bytes_from_address(runner, typ, adr)
|
||||
|
||||
if prelude.InternalPassAsPointer in typ.classes:
|
||||
if (prelude.InternalPassAsPointer, (typ, )) in prelude.PRELUDE_TYPE_CLASS_INSTANCES_EXISTING:
|
||||
# Note: For applied types, inp should contain a 4 byte pointer
|
||||
assert len(inp) == 4
|
||||
adr = struct.unpack('<I', inp)[0]
|
||||
|
||||
@ -29,7 +29,7 @@ def testEntry(x: Foo, y: Foo) -> Foo:
|
||||
return x == y
|
||||
"""
|
||||
|
||||
with pytest.raises(Type3Exception, match='Foo does not implement the Eq type class'):
|
||||
with pytest.raises(Type3Exception, match='Missing type class instantation: Eq Foo'):
|
||||
Suite(code_py).run_code()
|
||||
|
||||
@pytest.mark.integration_test
|
||||
@ -111,7 +111,7 @@ def testEntry(x: Foo, y: Foo) -> Foo:
|
||||
return x != y
|
||||
"""
|
||||
|
||||
with pytest.raises(Type3Exception, match='Foo does not implement the Eq type class'):
|
||||
with pytest.raises(Type3Exception, match='Missing type class instantation: Eq Foo'):
|
||||
Suite(code_py).run_code()
|
||||
|
||||
@pytest.mark.integration_test
|
||||
|
||||
@ -27,7 +27,7 @@ def testEntry(x: Foo, y: Foo) -> Foo:
|
||||
return x + y
|
||||
"""
|
||||
|
||||
with pytest.raises(Type3Exception, match='Foo does not implement the NatNum type class'):
|
||||
with pytest.raises(Type3Exception, match='Missing type class instantation: NatNum Foo'):
|
||||
Suite(code_py).run_code()
|
||||
|
||||
@pytest.mark.integration_test
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user