Compare commits
2 Commits
3be4599fc1
...
e8e7acc102
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e8e7acc102 | ||
|
|
83186cce78 |
@ -15,8 +15,10 @@ from .type3.types import (
|
|||||||
IntType3,
|
IntType3,
|
||||||
Type3,
|
Type3,
|
||||||
TypeApplication_Struct,
|
TypeApplication_Struct,
|
||||||
|
TypeApplication_Type,
|
||||||
TypeApplication_TypeInt,
|
TypeApplication_TypeInt,
|
||||||
TypeApplication_TypeStar,
|
TypeApplication_TypeStar,
|
||||||
|
TypeConstructor_DynamicArray,
|
||||||
TypeConstructor_Function,
|
TypeConstructor_Function,
|
||||||
TypeConstructor_StaticArray,
|
TypeConstructor_StaticArray,
|
||||||
TypeConstructor_Tuple,
|
TypeConstructor_Tuple,
|
||||||
@ -109,12 +111,25 @@ def tuple_instantiation(wgn: WasmGenerator, mod: ourlang.Module, inp: ourlang.Tu
|
|||||||
|
|
||||||
args: tuple[Type3, ...]
|
args: tuple[Type3, ...]
|
||||||
|
|
||||||
if isinstance(inp.type3.application, TypeApplication_TypeStar):
|
alloc_size_header = None
|
||||||
|
|
||||||
|
if isinstance(inp.type3.application, TypeApplication_Type):
|
||||||
|
# Possibly paranoid assert. If we have a future variadic type,
|
||||||
|
# does it also do this tuple instantation like this?
|
||||||
|
assert isinstance(inp.type3.application.constructor, TypeConstructor_DynamicArray)
|
||||||
|
|
||||||
|
sa_type, = inp.type3.application.arguments
|
||||||
|
|
||||||
|
args = tuple(sa_type for _ in inp.elements)
|
||||||
|
alloc_size = 4 + calculate_alloc_size(sa_type, is_member=False) * len(inp.elements)
|
||||||
|
alloc_size_header = len(inp.elements)
|
||||||
|
elif isinstance(inp.type3.application, TypeApplication_TypeStar):
|
||||||
# Possibly paranoid assert. If we have a future variadic type,
|
# Possibly paranoid assert. If we have a future variadic type,
|
||||||
# does it also do this tuple instantation like this?
|
# does it also do this tuple instantation like this?
|
||||||
assert isinstance(inp.type3.application.constructor, TypeConstructor_Tuple)
|
assert isinstance(inp.type3.application.constructor, TypeConstructor_Tuple)
|
||||||
|
|
||||||
args = inp.type3.application.arguments
|
args = inp.type3.application.arguments
|
||||||
|
alloc_size = calculate_alloc_size(inp.type3, is_member=False)
|
||||||
elif isinstance(inp.type3.application, TypeApplication_TypeInt):
|
elif isinstance(inp.type3.application, TypeApplication_TypeInt):
|
||||||
# Possibly paranoid assert. If we have a future type of kind * -> Int -> *,
|
# Possibly paranoid assert. If we have a future type of kind * -> Int -> *,
|
||||||
# does it also do this tuple instantation like this?
|
# does it also do this tuple instantation like this?
|
||||||
@ -123,6 +138,7 @@ def tuple_instantiation(wgn: WasmGenerator, mod: ourlang.Module, inp: ourlang.Tu
|
|||||||
sa_type, sa_len = inp.type3.application.arguments
|
sa_type, sa_len = inp.type3.application.arguments
|
||||||
|
|
||||||
args = tuple(sa_type for _ in range(sa_len.value))
|
args = tuple(sa_type for _ in range(sa_len.value))
|
||||||
|
alloc_size = calculate_alloc_size(inp.type3, is_member=False)
|
||||||
else:
|
else:
|
||||||
raise NotImplementedError('tuple_instantiation', inp.type3)
|
raise NotImplementedError('tuple_instantiation', inp.type3)
|
||||||
|
|
||||||
@ -135,12 +151,17 @@ def tuple_instantiation(wgn: WasmGenerator, mod: ourlang.Module, inp: ourlang.Tu
|
|||||||
wgn.add_statement('nop', comment=f'{tmp_var.name} := ({comment_elements})')
|
wgn.add_statement('nop', comment=f'{tmp_var.name} := ({comment_elements})')
|
||||||
|
|
||||||
# Allocated the required amounts of bytes in memory
|
# Allocated the required amounts of bytes in memory
|
||||||
wgn.i32.const(calculate_alloc_size(inp.type3, is_member=False))
|
wgn.i32.const(alloc_size)
|
||||||
wgn.call(stdlib_alloc.__alloc__)
|
wgn.call(stdlib_alloc.__alloc__)
|
||||||
wgn.local.set(tmp_var)
|
wgn.local.set(tmp_var)
|
||||||
|
|
||||||
|
if alloc_size_header is not None:
|
||||||
|
wgn.local.get(tmp_var)
|
||||||
|
wgn.i32.const(alloc_size_header)
|
||||||
|
wgn.i32.store()
|
||||||
|
|
||||||
# Store each element individually
|
# Store each element individually
|
||||||
offset = 0
|
offset = 0 if alloc_size_header is None else 4
|
||||||
for element, exp_type3 in zip(inp.elements, args, strict=True):
|
for element, exp_type3 in zip(inp.elements, args, strict=True):
|
||||||
assert element.type3 == exp_type3
|
assert element.type3 == exp_type3
|
||||||
|
|
||||||
|
|||||||
@ -270,6 +270,9 @@ class FunctionParam:
|
|||||||
self.name = name
|
self.name = name
|
||||||
self.type3 = type3
|
self.type3 = type3
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return f'FunctionParam({self.name!r}, {self.type3!r})'
|
||||||
|
|
||||||
class Function:
|
class Function:
|
||||||
"""
|
"""
|
||||||
A function processes input and produces output
|
A function processes input and produces output
|
||||||
|
|||||||
@ -632,8 +632,15 @@ class OurVisitor:
|
|||||||
|
|
||||||
if isinstance(node.slice, ast.Slice):
|
if isinstance(node.slice, ast.Slice):
|
||||||
_raise_static_error(node, 'Must subscript using an index')
|
_raise_static_error(node, 'Must subscript using an index')
|
||||||
|
|
||||||
if not isinstance(node.slice, ast.Constant):
|
if not isinstance(node.slice, ast.Constant):
|
||||||
_raise_static_error(node, 'Must subscript using a constant index')
|
_raise_static_error(node, 'Must subscript using a constant index')
|
||||||
|
|
||||||
|
if node.slice.value is Ellipsis:
|
||||||
|
return prelude.dynamic_array(
|
||||||
|
self.visit_type(module, node.value),
|
||||||
|
)
|
||||||
|
|
||||||
if not isinstance(node.slice.value, int):
|
if not isinstance(node.slice.value, int):
|
||||||
_raise_static_error(node, 'Must subscript using a constant integer index')
|
_raise_static_error(node, 'Must subscript using a constant integer index')
|
||||||
if not isinstance(node.ctx, ast.Load):
|
if not isinstance(node.ctx, ast.Load):
|
||||||
|
|||||||
@ -20,6 +20,7 @@ from ..type3.types import (
|
|||||||
Type3,
|
Type3,
|
||||||
TypeApplication_Nullary,
|
TypeApplication_Nullary,
|
||||||
TypeConstructor_Base,
|
TypeConstructor_Base,
|
||||||
|
TypeConstructor_DynamicArray,
|
||||||
TypeConstructor_Function,
|
TypeConstructor_Function,
|
||||||
TypeConstructor_StaticArray,
|
TypeConstructor_StaticArray,
|
||||||
TypeConstructor_Struct,
|
TypeConstructor_Struct,
|
||||||
@ -158,9 +159,15 @@ f64 = Type3('f64', TypeApplication_Nullary(None, None))
|
|||||||
A 32-bits IEEE 754 float, of 64 bits width.
|
A 32-bits IEEE 754 float, of 64 bits width.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
bytes_ = Type3('bytes', TypeApplication_Nullary(None, None))
|
def da_on_create(args: tuple[Type3], typ: Type3) -> None:
|
||||||
|
instance_type_class(InternalPassAsPointer, typ)
|
||||||
|
|
||||||
|
dynamic_array = TypeConstructor_DynamicArray('dynamic_array', on_create=da_on_create)
|
||||||
"""
|
"""
|
||||||
This is a runtime-determined length piece of memory that can be indexed at runtime.
|
This is a dynamic length piece of memory.
|
||||||
|
|
||||||
|
It should be applied with two arguments. It has a runtime
|
||||||
|
determined length, and each argument is the same.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def sa_on_create(args: tuple[Type3, IntType3], typ: Type3) -> None:
|
def sa_on_create(args: tuple[Type3, IntType3], typ: Type3) -> None:
|
||||||
@ -168,12 +175,10 @@ def sa_on_create(args: tuple[Type3, IntType3], typ: Type3) -> None:
|
|||||||
|
|
||||||
static_array = TypeConstructor_StaticArray('static_array', on_create=sa_on_create)
|
static_array = TypeConstructor_StaticArray('static_array', on_create=sa_on_create)
|
||||||
"""
|
"""
|
||||||
A type constructor.
|
This is a fixed length piece of memory.
|
||||||
|
|
||||||
Any static array is a fixed length piece of memory that can be indexed at runtime.
|
It should be applied with two arguments. It has a compile time
|
||||||
|
determined length, and each argument is the same.
|
||||||
It should be applied with one argument. It has a runtime-dynamic length
|
|
||||||
of the same type repeated.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def tp_on_create(args: tuple[Type3, ...], typ: Type3) -> None:
|
def tp_on_create(args: tuple[Type3, ...], typ: Type3) -> None:
|
||||||
@ -208,20 +213,6 @@ This is like a tuple, but each argument is named, so that developers
|
|||||||
can get and set fields by name.
|
can get and set fields by name.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
PRELUDE_TYPES: dict[str, Type3] = {
|
|
||||||
'none': none,
|
|
||||||
'bool': bool_,
|
|
||||||
'u8': u8,
|
|
||||||
'u32': u32,
|
|
||||||
'u64': u64,
|
|
||||||
'i8': i8,
|
|
||||||
'i32': i32,
|
|
||||||
'i64': i64,
|
|
||||||
'f32': f32,
|
|
||||||
'f64': f64,
|
|
||||||
'bytes': bytes_,
|
|
||||||
}
|
|
||||||
|
|
||||||
a = TypeVariable('a', TypeVariableApplication_Nullary(None, None))
|
a = TypeVariable('a', TypeVariableApplication_Nullary(None, None))
|
||||||
b = TypeVariable('b', TypeVariableApplication_Nullary(None, None))
|
b = TypeVariable('b', TypeVariableApplication_Nullary(None, None))
|
||||||
|
|
||||||
@ -232,7 +223,7 @@ InternalPassAsPointer = Type3Class('InternalPassAsPointer', (a, ), methods={}, o
|
|||||||
Internal type class to keep track which types we pass arounds as a pointer.
|
Internal type class to keep track which types we pass arounds as a pointer.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
instance_type_class(InternalPassAsPointer, bytes_)
|
# instance_type_class(InternalPassAsPointer, bytes_)
|
||||||
# instance_type_class(InternalPassAsPointer, static_array)
|
# instance_type_class(InternalPassAsPointer, static_array)
|
||||||
# instance_type_class(InternalPassAsPointer, tuple_)
|
# instance_type_class(InternalPassAsPointer, tuple_)
|
||||||
# instance_type_class(InternalPassAsPointer, struct)
|
# instance_type_class(InternalPassAsPointer, struct)
|
||||||
@ -537,12 +528,15 @@ instance_type_class(Floating, f64, methods={
|
|||||||
'sqrt': stdtypes.f64_floating_sqrt,
|
'sqrt': stdtypes.f64_floating_sqrt,
|
||||||
})
|
})
|
||||||
|
|
||||||
Sized_ = Type3Class('Sized', (a, ), methods={
|
Sized_ = Type3Class('Sized', (t, ), methods={
|
||||||
'len': [a, u32],
|
'len': [t(a), u32],
|
||||||
}, operators={}) # FIXME: Once we get type class families, add [] here
|
}, operators={}) # FIXME: Once we get type class families, add [] here
|
||||||
|
|
||||||
instance_type_class(Sized_, bytes_, methods={
|
instance_type_class(Sized_, dynamic_array, methods={
|
||||||
'len': stdtypes.bytes_sized_len,
|
'len': stdtypes.dynamic_array_sized_len,
|
||||||
|
})
|
||||||
|
instance_type_class(Sized_, static_array, methods={
|
||||||
|
'len': stdtypes.static_array_sized_len,
|
||||||
})
|
})
|
||||||
|
|
||||||
Extendable = Type3Class('Extendable', (a, b, ), methods={
|
Extendable = Type3Class('Extendable', (a, b, ), methods={
|
||||||
@ -593,12 +587,33 @@ Foldable = Type3Class('Foldable', (t, ), methods={
|
|||||||
'sum': [Constraint_TypeClassInstanceExists(NatNum, (a, ))],
|
'sum': [Constraint_TypeClassInstanceExists(NatNum, (a, ))],
|
||||||
})
|
})
|
||||||
|
|
||||||
|
instance_type_class(Foldable, dynamic_array, methods={
|
||||||
|
'sum': stdtypes.dynamic_array_sum,
|
||||||
|
'foldl': stdtypes.dynamic_array_foldl,
|
||||||
|
'foldr': stdtypes.dynamic_array_foldr,
|
||||||
|
})
|
||||||
instance_type_class(Foldable, static_array, methods={
|
instance_type_class(Foldable, static_array, methods={
|
||||||
'sum': stdtypes.static_array_sum,
|
'sum': stdtypes.static_array_sum,
|
||||||
'foldl': stdtypes.static_array_foldl,
|
'foldl': stdtypes.static_array_foldl,
|
||||||
'foldr': stdtypes.static_array_foldr,
|
'foldr': stdtypes.static_array_foldr,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
bytes_ = dynamic_array(u8)
|
||||||
|
|
||||||
|
PRELUDE_TYPES: dict[str, Type3] = {
|
||||||
|
'none': none,
|
||||||
|
'bool': bool_,
|
||||||
|
'u8': u8,
|
||||||
|
'u32': u32,
|
||||||
|
'u64': u64,
|
||||||
|
'i8': i8,
|
||||||
|
'i32': i32,
|
||||||
|
'i64': i64,
|
||||||
|
'f32': f32,
|
||||||
|
'f64': f64,
|
||||||
|
'bytes': bytes_,
|
||||||
|
}
|
||||||
|
|
||||||
PRELUDE_TYPE_CLASSES = {
|
PRELUDE_TYPE_CLASSES = {
|
||||||
'Eq': Eq,
|
'Eq': Eq,
|
||||||
'Ord': Ord,
|
'Ord': Ord,
|
||||||
|
|||||||
@ -1008,11 +1008,23 @@ def f64_intnum_neg(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|||||||
## ###
|
## ###
|
||||||
## Class Sized
|
## Class Sized
|
||||||
|
|
||||||
def bytes_sized_len(g: Generator, tv_map: TypeVariableLookup) -> None:
|
def dynamic_array_sized_len(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
del tv_map
|
del tv_map
|
||||||
# The length is stored in the first 4 bytes
|
# The length is stored in the first 4 bytes
|
||||||
g.i32.load()
|
g.i32.load()
|
||||||
|
|
||||||
|
def static_array_sized_len(g: Generator, tvl: TypeVariableLookup) -> None:
|
||||||
|
tv_map, tc_map = tvl
|
||||||
|
|
||||||
|
tvn_map = {
|
||||||
|
x.name: y
|
||||||
|
for x, y in tv_map.items()
|
||||||
|
}
|
||||||
|
|
||||||
|
sa_len = tvn_map['a*']
|
||||||
|
assert isinstance(sa_len, IntType3)
|
||||||
|
g.i32.const(sa_len.value)
|
||||||
|
|
||||||
## ###
|
## ###
|
||||||
## Extendable
|
## Extendable
|
||||||
|
|
||||||
@ -1083,6 +1095,12 @@ def f32_f64_demote(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|||||||
del tv_map
|
del tv_map
|
||||||
g.f32.demote_f64()
|
g.f32.demote_f64()
|
||||||
|
|
||||||
|
## ###
|
||||||
|
## Foldable
|
||||||
|
|
||||||
|
def dynamic_array_sum(g: Generator, tvl: TypeVariableLookup) -> None:
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
def static_array_sum(g: Generator, tvl: TypeVariableLookup) -> None:
|
def static_array_sum(g: Generator, tvl: TypeVariableLookup) -> None:
|
||||||
tv_map, tc_map = tvl
|
tv_map, tc_map = tvl
|
||||||
|
|
||||||
@ -1196,6 +1214,9 @@ def static_array_sum(g: Generator, tvl: TypeVariableLookup) -> None:
|
|||||||
g.nop(comment=f'Completed sum for {sa_type.name}[{sa_len.value}]')
|
g.nop(comment=f'Completed sum for {sa_type.name}[{sa_len.value}]')
|
||||||
# End result: [sum]
|
# End result: [sum]
|
||||||
|
|
||||||
|
def dynamic_array_foldl(g: Generator, tvl: TypeVariableLookup) -> None:
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
def static_array_foldl(g: Generator, tvl: TypeVariableLookup) -> None:
|
def static_array_foldl(g: Generator, tvl: TypeVariableLookup) -> None:
|
||||||
tv_map, tc_map = tvl
|
tv_map, tc_map = tvl
|
||||||
|
|
||||||
@ -1311,6 +1332,9 @@ def static_array_foldl(g: Generator, tvl: TypeVariableLookup) -> None:
|
|||||||
|
|
||||||
# Stack: [b]
|
# Stack: [b]
|
||||||
|
|
||||||
|
def dynamic_array_foldr(g: Generator, tvl: TypeVariableLookup) -> None:
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
def static_array_foldr(g: Generator, tvl: TypeVariableLookup) -> None:
|
def static_array_foldr(g: Generator, tvl: TypeVariableLookup) -> None:
|
||||||
tv_map, tc_map = tvl
|
tv_map, tc_map = tvl
|
||||||
|
|
||||||
|
|||||||
@ -15,6 +15,7 @@ from .types import (
|
|||||||
Type3,
|
Type3,
|
||||||
TypeApplication_Nullary,
|
TypeApplication_Nullary,
|
||||||
TypeApplication_Struct,
|
TypeApplication_Struct,
|
||||||
|
TypeApplication_Type,
|
||||||
TypeApplication_TypeInt,
|
TypeApplication_TypeInt,
|
||||||
TypeApplication_TypeStar,
|
TypeApplication_TypeStar,
|
||||||
TypeConstructor_Base,
|
TypeConstructor_Base,
|
||||||
@ -199,6 +200,13 @@ class SameTypeArgumentConstraint(ConstraintBase):
|
|||||||
# So we can let the MustImplementTypeClassConstraint handle it.
|
# So we can let the MustImplementTypeClassConstraint handle it.
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
if isinstance(tc_typ.application, TypeApplication_Type):
|
||||||
|
return [SameTypeConstraint(
|
||||||
|
tc_typ.application.arguments[0],
|
||||||
|
self.arg_var,
|
||||||
|
comment=self.comment,
|
||||||
|
)]
|
||||||
|
|
||||||
# FIXME: This feels sketchy. Shouldn't the type variable
|
# FIXME: This feels sketchy. Shouldn't the type variable
|
||||||
# have the exact same number as arguments?
|
# have the exact same number as arguments?
|
||||||
if isinstance(tc_typ.application, TypeApplication_TypeInt):
|
if isinstance(tc_typ.application, TypeApplication_TypeInt):
|
||||||
@ -289,6 +297,14 @@ class TupleMatchConstraint(ConstraintBase):
|
|||||||
self.exp_type = exp_type
|
self.exp_type = exp_type
|
||||||
self.args = list(args)
|
self.args = list(args)
|
||||||
|
|
||||||
|
def _generate_dynamic_array(self, sa_args: tuple[Type3]) -> CheckResult:
|
||||||
|
sa_type, = sa_args
|
||||||
|
|
||||||
|
return [
|
||||||
|
SameTypeConstraint(arg, sa_type)
|
||||||
|
for arg in self.args
|
||||||
|
]
|
||||||
|
|
||||||
def _generate_static_array(self, sa_args: tuple[Type3, IntType3]) -> CheckResult:
|
def _generate_static_array(self, sa_args: tuple[Type3, IntType3]) -> CheckResult:
|
||||||
sa_type, sa_len = sa_args
|
sa_type, sa_len = sa_args
|
||||||
|
|
||||||
@ -310,6 +326,7 @@ class TupleMatchConstraint(ConstraintBase):
|
|||||||
]
|
]
|
||||||
|
|
||||||
GENERATE_ROUTER = TypeApplicationRouter['TupleMatchConstraint', CheckResult]()
|
GENERATE_ROUTER = TypeApplicationRouter['TupleMatchConstraint', CheckResult]()
|
||||||
|
GENERATE_ROUTER.add(prelude.dynamic_array, _generate_dynamic_array)
|
||||||
GENERATE_ROUTER.add(prelude.static_array, _generate_static_array)
|
GENERATE_ROUTER.add(prelude.static_array, _generate_static_array)
|
||||||
GENERATE_ROUTER.add(prelude.tuple_, _generate_tuple)
|
GENERATE_ROUTER.add(prelude.tuple_, _generate_tuple)
|
||||||
|
|
||||||
@ -356,7 +373,7 @@ class MustImplementTypeClassConstraint(ConstraintBase):
|
|||||||
typ_list.append(typ)
|
typ_list.append(typ)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if isinstance(typ.application, (TypeApplication_TypeInt, TypeApplication_TypeStar)):
|
if isinstance(typ.application, (TypeApplication_Type, TypeApplication_TypeInt, TypeApplication_TypeStar)):
|
||||||
typ_list.append(typ.application.constructor)
|
typ_list.append(typ.application.constructor)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@ -409,6 +426,29 @@ class LiteralFitsConstraint(ConstraintBase):
|
|||||||
self.type3 = type3
|
self.type3 = type3
|
||||||
self.literal = literal
|
self.literal = literal
|
||||||
|
|
||||||
|
def _generate_dynamic_array(self, da_args: tuple[Type3]) -> CheckResult:
|
||||||
|
if not isinstance(self.literal, ourlang.ConstantTuple):
|
||||||
|
return Error('Must be tuple', comment=self.comment)
|
||||||
|
|
||||||
|
da_type, = da_args
|
||||||
|
|
||||||
|
res: list[ConstraintBase] = []
|
||||||
|
|
||||||
|
res.extend(
|
||||||
|
LiteralFitsConstraint(da_type, y)
|
||||||
|
for y in self.literal.value
|
||||||
|
)
|
||||||
|
|
||||||
|
# Generate placeholders so each Literal expression
|
||||||
|
# gets updated when we figure out the type of the
|
||||||
|
# expression the literal is used in
|
||||||
|
res.extend(
|
||||||
|
SameTypeConstraint(da_type, PlaceholderForType([y]))
|
||||||
|
for y in self.literal.value
|
||||||
|
)
|
||||||
|
|
||||||
|
return res
|
||||||
|
|
||||||
def _generate_static_array(self, sa_args: tuple[Type3, IntType3]) -> CheckResult:
|
def _generate_static_array(self, sa_args: tuple[Type3, IntType3]) -> CheckResult:
|
||||||
if not isinstance(self.literal, ourlang.ConstantTuple):
|
if not isinstance(self.literal, ourlang.ConstantTuple):
|
||||||
return Error('Must be tuple', comment=self.comment)
|
return Error('Must be tuple', comment=self.comment)
|
||||||
@ -490,6 +530,7 @@ class LiteralFitsConstraint(ConstraintBase):
|
|||||||
return res
|
return res
|
||||||
|
|
||||||
GENERATE_ROUTER = TypeApplicationRouter['LiteralFitsConstraint', CheckResult]()
|
GENERATE_ROUTER = TypeApplicationRouter['LiteralFitsConstraint', CheckResult]()
|
||||||
|
GENERATE_ROUTER.add(prelude.dynamic_array, _generate_dynamic_array)
|
||||||
GENERATE_ROUTER.add(prelude.static_array, _generate_static_array)
|
GENERATE_ROUTER.add(prelude.static_array, _generate_static_array)
|
||||||
GENERATE_ROUTER.add(prelude.struct, _generate_struct)
|
GENERATE_ROUTER.add(prelude.struct, _generate_struct)
|
||||||
GENERATE_ROUTER.add(prelude.tuple_, _generate_tuple)
|
GENERATE_ROUTER.add(prelude.tuple_, _generate_tuple)
|
||||||
|
|||||||
@ -176,7 +176,10 @@ def _expression_function_call(
|
|||||||
if not isinstance(sig_arg.application, TypeVariableApplication_Unary):
|
if not isinstance(sig_arg.application, TypeVariableApplication_Unary):
|
||||||
raise NotImplementedError(sig_arg.application)
|
raise NotImplementedError(sig_arg.application)
|
||||||
|
|
||||||
assert sig_arg.application.arguments in type_var_map # When does this happen?
|
if sig_arg.application.arguments not in type_var_map:
|
||||||
|
# e.g., len :: t a -> u32
|
||||||
|
# i.e. "a" does not matter at all
|
||||||
|
continue
|
||||||
|
|
||||||
yield SameTypeArgumentConstraint(
|
yield SameTypeArgumentConstraint(
|
||||||
type_var_map[sig_arg],
|
type_var_map[sig_arg],
|
||||||
|
|||||||
@ -7,7 +7,13 @@ from .functions import (
|
|||||||
TypeVariableApplication_Unary,
|
TypeVariableApplication_Unary,
|
||||||
)
|
)
|
||||||
from .typeclasses import Type3ClassArgs
|
from .typeclasses import Type3ClassArgs
|
||||||
from .types import KindArgument, Type3, TypeApplication_TypeInt, TypeConstructor_Base
|
from .types import (
|
||||||
|
KindArgument,
|
||||||
|
Type3,
|
||||||
|
TypeApplication_Type,
|
||||||
|
TypeApplication_TypeInt,
|
||||||
|
TypeConstructor_Base,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class NoRouteForTypeException(Exception):
|
class NoRouteForTypeException(Exception):
|
||||||
@ -110,6 +116,12 @@ class TypeClassArgsRouter[S, R]:
|
|||||||
arguments[1][tc_arg] = typ.application.constructor
|
arguments[1][tc_arg] = typ.application.constructor
|
||||||
|
|
||||||
if isinstance(tvar.application, TypeVariableApplication_Unary):
|
if isinstance(tvar.application, TypeVariableApplication_Unary):
|
||||||
|
if isinstance(typ.application, TypeApplication_Type):
|
||||||
|
da_type, = typ.application.arguments
|
||||||
|
sa_type_tv = tvar.application.arguments
|
||||||
|
arguments[0][sa_type_tv] = da_type
|
||||||
|
continue
|
||||||
|
|
||||||
# FIXME: This feels sketchy. Shouldn't the type variable
|
# FIXME: This feels sketchy. Shouldn't the type variable
|
||||||
# have the exact same number as arguments?
|
# have the exact same number as arguments?
|
||||||
if isinstance(typ.application, TypeApplication_TypeInt):
|
if isinstance(typ.application, TypeApplication_TypeInt):
|
||||||
|
|||||||
@ -195,6 +195,26 @@ class TypeConstructor_Base[T]:
|
|||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return f'{self.__class__.__name__}({self.name!r}, ...)'
|
return f'{self.__class__.__name__}({self.name!r}, ...)'
|
||||||
|
|
||||||
|
class TypeConstructor_Type(TypeConstructor_Base[Tuple[Type3]]):
|
||||||
|
"""
|
||||||
|
Base class type constructors of kind: * -> *
|
||||||
|
|
||||||
|
Notably, static array.
|
||||||
|
"""
|
||||||
|
__slots__ = ()
|
||||||
|
|
||||||
|
def make_application(self, key: Tuple[Type3]) -> 'TypeApplication_Type':
|
||||||
|
return TypeApplication_Type(self, key)
|
||||||
|
|
||||||
|
def make_name(self, key: Tuple[Type3]) -> str:
|
||||||
|
return f'{self.name} {key[0].name} '
|
||||||
|
|
||||||
|
def __call__(self, arg0: Type3) -> Type3:
|
||||||
|
return self.construct((arg0, ))
|
||||||
|
|
||||||
|
class TypeApplication_Type(TypeApplication_Base[TypeConstructor_Type, Tuple[Type3]]):
|
||||||
|
pass
|
||||||
|
|
||||||
class TypeConstructor_TypeInt(TypeConstructor_Base[Tuple[Type3, IntType3]]):
|
class TypeConstructor_TypeInt(TypeConstructor_Base[Tuple[Type3, IntType3]]):
|
||||||
"""
|
"""
|
||||||
Base class type constructors of kind: * -> Int -> *
|
Base class type constructors of kind: * -> Int -> *
|
||||||
@ -231,6 +251,13 @@ class TypeConstructor_TypeStar(TypeConstructor_Base[Tuple[Type3, ...]]):
|
|||||||
class TypeApplication_TypeStar(TypeApplication_Base[TypeConstructor_TypeStar, Tuple[Type3, ...]]):
|
class TypeApplication_TypeStar(TypeApplication_Base[TypeConstructor_TypeStar, Tuple[Type3, ...]]):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
class TypeConstructor_DynamicArray(TypeConstructor_Type):
|
||||||
|
def make_name(self, key: Tuple[Type3]) -> str:
|
||||||
|
if 'u8' == key[0].name:
|
||||||
|
return 'bytes'
|
||||||
|
|
||||||
|
return f'{key[0].name}[...]'
|
||||||
|
|
||||||
class TypeConstructor_StaticArray(TypeConstructor_TypeInt):
|
class TypeConstructor_StaticArray(TypeConstructor_TypeInt):
|
||||||
def make_name(self, key: Tuple[Type3, IntType3]) -> str:
|
def make_name(self, key: Tuple[Type3, IntType3]) -> str:
|
||||||
return f'{key[0].name}[{key[1].value}]'
|
return f'{key[0].name}[{key[1].value}]'
|
||||||
|
|||||||
@ -152,6 +152,25 @@ def _allocate_memory_stored_bytes(attrs: tuple[runners.RunnerBase, bytes]) -> in
|
|||||||
runner.interpreter_write_memory(adr + 4, val)
|
runner.interpreter_write_memory(adr + 4, val)
|
||||||
return adr
|
return adr
|
||||||
|
|
||||||
|
def _allocate_memory_stored_dynamic_array(attrs: tuple[runners.RunnerBase, Any], da_args: tuple[type3types.Type3]) -> int:
|
||||||
|
runner, val = attrs
|
||||||
|
|
||||||
|
da_type, = da_args
|
||||||
|
|
||||||
|
if not isinstance(val, tuple):
|
||||||
|
raise InvalidArgumentException(f'Expected tuple; got {val!r} instead')
|
||||||
|
|
||||||
|
alloc_size = 4 + len(val) * calculate_alloc_size(da_type, True)
|
||||||
|
adr = runner.call('stdlib.alloc.__alloc__', alloc_size)
|
||||||
|
assert isinstance(adr, int) # Type int
|
||||||
|
sys.stderr.write(f'Allocation 0x{adr:08x} {repr(val)}\n')
|
||||||
|
|
||||||
|
offset = adr
|
||||||
|
offset += _write_memory_stored_value(runner, offset, prelude.u32, len(val))
|
||||||
|
for val_el_val in val:
|
||||||
|
offset += _write_memory_stored_value(runner, offset, da_type, val_el_val)
|
||||||
|
return adr
|
||||||
|
|
||||||
def _allocate_memory_stored_static_array(attrs: tuple[runners.RunnerBase, Any], sa_args: tuple[type3types.Type3, type3types.IntType3]) -> int:
|
def _allocate_memory_stored_static_array(attrs: tuple[runners.RunnerBase, Any], sa_args: tuple[type3types.Type3, type3types.IntType3]) -> int:
|
||||||
runner, val = attrs
|
runner, val = attrs
|
||||||
|
|
||||||
@ -211,6 +230,7 @@ def _allocate_memory_stored_tuple(attrs: tuple[runners.RunnerBase, Any], tp_args
|
|||||||
|
|
||||||
ALLOCATE_MEMORY_STORED_ROUTER = TypeApplicationRouter[tuple[runners.RunnerBase, Any], Any]()
|
ALLOCATE_MEMORY_STORED_ROUTER = TypeApplicationRouter[tuple[runners.RunnerBase, Any], Any]()
|
||||||
ALLOCATE_MEMORY_STORED_ROUTER.add_n(prelude.bytes_, _allocate_memory_stored_bytes)
|
ALLOCATE_MEMORY_STORED_ROUTER.add_n(prelude.bytes_, _allocate_memory_stored_bytes)
|
||||||
|
ALLOCATE_MEMORY_STORED_ROUTER.add(prelude.dynamic_array, _allocate_memory_stored_dynamic_array)
|
||||||
ALLOCATE_MEMORY_STORED_ROUTER.add(prelude.static_array, _allocate_memory_stored_static_array)
|
ALLOCATE_MEMORY_STORED_ROUTER.add(prelude.static_array, _allocate_memory_stored_static_array)
|
||||||
ALLOCATE_MEMORY_STORED_ROUTER.add(prelude.struct, _allocate_memory_stored_struct)
|
ALLOCATE_MEMORY_STORED_ROUTER.add(prelude.struct, _allocate_memory_stored_struct)
|
||||||
ALLOCATE_MEMORY_STORED_ROUTER.add(prelude.tuple_, _allocate_memory_stored_tuple)
|
ALLOCATE_MEMORY_STORED_ROUTER.add(prelude.tuple_, _allocate_memory_stored_tuple)
|
||||||
@ -325,6 +345,26 @@ def _split_read_bytes(all_bytes: bytes, split_sizes: Iterable[int]) -> Generator
|
|||||||
yield all_bytes[offset:offset + size]
|
yield all_bytes[offset:offset + size]
|
||||||
offset += size
|
offset += size
|
||||||
|
|
||||||
|
def _load_dynamic_array_from_address(attrs: tuple[runners.RunnerBase, int], da_args: tuple[type3types.Type3]) -> Any:
|
||||||
|
runner, adr = attrs
|
||||||
|
da_type, = da_args
|
||||||
|
|
||||||
|
sys.stderr.write(f'Reading 0x{adr:08x} {da_type:s}[...]\n')
|
||||||
|
|
||||||
|
read_bytes = runner.interpreter_read_memory(adr, 4)
|
||||||
|
array_len, = struct.unpack('<I', read_bytes)
|
||||||
|
adr += 4
|
||||||
|
|
||||||
|
arg_size_1 = calculate_alloc_size(da_type, is_member=True)
|
||||||
|
arg_sizes = [arg_size_1 for _ in range(array_len)] # _split_read_bytes requires one arg per value
|
||||||
|
|
||||||
|
read_bytes = runner.interpreter_read_memory(adr, sum(arg_sizes))
|
||||||
|
|
||||||
|
return tuple(
|
||||||
|
_unpack(runner, da_type, arg_bytes)
|
||||||
|
for arg_bytes in _split_read_bytes(read_bytes, arg_sizes)
|
||||||
|
)
|
||||||
|
|
||||||
def _load_static_array_from_address(attrs: tuple[runners.RunnerBase, int], sa_args: tuple[type3types.Type3, type3types.IntType3]) -> Any:
|
def _load_static_array_from_address(attrs: tuple[runners.RunnerBase, int], sa_args: tuple[type3types.Type3, type3types.IntType3]) -> Any:
|
||||||
runner, adr = attrs
|
runner, adr = attrs
|
||||||
sub_typ, len_typ = sa_args
|
sub_typ, len_typ = sa_args
|
||||||
@ -379,6 +419,7 @@ def _load_tuple_from_address(attrs: tuple[runners.RunnerBase, int], tp_args: tup
|
|||||||
|
|
||||||
LOAD_FROM_ADDRESS_ROUTER = TypeApplicationRouter[tuple[runners.RunnerBase, int], Any]()
|
LOAD_FROM_ADDRESS_ROUTER = TypeApplicationRouter[tuple[runners.RunnerBase, int], Any]()
|
||||||
LOAD_FROM_ADDRESS_ROUTER.add_n(prelude.bytes_, _load_bytes_from_address)
|
LOAD_FROM_ADDRESS_ROUTER.add_n(prelude.bytes_, _load_bytes_from_address)
|
||||||
|
LOAD_FROM_ADDRESS_ROUTER.add(prelude.dynamic_array, _load_dynamic_array_from_address)
|
||||||
LOAD_FROM_ADDRESS_ROUTER.add(prelude.static_array, _load_static_array_from_address)
|
LOAD_FROM_ADDRESS_ROUTER.add(prelude.static_array, _load_static_array_from_address)
|
||||||
LOAD_FROM_ADDRESS_ROUTER.add(prelude.struct, _load_struct_from_address)
|
LOAD_FROM_ADDRESS_ROUTER.add(prelude.struct, _load_struct_from_address)
|
||||||
LOAD_FROM_ADDRESS_ROUTER.add(prelude.tuple_, _load_tuple_from_address)
|
LOAD_FROM_ADDRESS_ROUTER.add(prelude.tuple_, _load_tuple_from_address)
|
||||||
|
|||||||
@ -60,7 +60,7 @@ CONSTANT: (u32, ) = $VAL0
|
|||||||
```
|
```
|
||||||
|
|
||||||
```py
|
```py
|
||||||
if TYPE_NAME.startswith('tuple_') or TYPE_NAME.startswith('static_array_'):
|
if TYPE_NAME.startswith('tuple_') or TYPE_NAME.startswith('static_array_') or TYPE_NAME.startswith('dynamic_array_'):
|
||||||
expect_type_error(
|
expect_type_error(
|
||||||
'Tuple element count mismatch',
|
'Tuple element count mismatch',
|
||||||
'The given literal must fit the expected type',
|
'The given literal must fit the expected type',
|
||||||
@ -113,7 +113,7 @@ def testEntry() -> i32:
|
|||||||
```
|
```
|
||||||
|
|
||||||
```py
|
```py
|
||||||
if TYPE_NAME.startswith('tuple_') or TYPE_NAME.startswith('static_array_'):
|
if TYPE_NAME.startswith('tuple_') or TYPE_NAME.startswith('static_array_') or TYPE_NAME.startswith('dynamic_array_'):
|
||||||
expect_type_error(
|
expect_type_error(
|
||||||
'Mismatch between applied types argument count',
|
'Mismatch between applied types argument count',
|
||||||
'The type of a tuple is a combination of its members',
|
'The type of a tuple is a combination of its members',
|
||||||
@ -175,7 +175,7 @@ def testEntry() -> i32:
|
|||||||
```
|
```
|
||||||
|
|
||||||
```py
|
```py
|
||||||
if TYPE_NAME.startswith('tuple_') or TYPE_NAME.startswith('static_array_') or TYPE_NAME.startswith('struct_'):
|
if TYPE_NAME.startswith('tuple_') or TYPE_NAME.startswith('static_array_') or TYPE_NAME.startswith('dynamic_array_') or TYPE_NAME.startswith('struct_'):
|
||||||
expect_type_error(
|
expect_type_error(
|
||||||
TYPE + ' must be (u32, ) instead',
|
TYPE + ' must be (u32, ) instead',
|
||||||
'The type of the value returned from function constant should match its return type',
|
'The type of the value returned from function constant should match its return type',
|
||||||
@ -226,7 +226,7 @@ def select(x: $TYPE) -> (u32, ):
|
|||||||
```
|
```
|
||||||
|
|
||||||
```py
|
```py
|
||||||
if TYPE_NAME.startswith('tuple_') or TYPE_NAME.startswith('static_array_') or TYPE_NAME.startswith('struct_'):
|
if TYPE_NAME.startswith('tuple_') or TYPE_NAME.startswith('static_array_') or TYPE_NAME.startswith('dynamic_array_') or TYPE_NAME.startswith('struct_'):
|
||||||
expect_type_error(
|
expect_type_error(
|
||||||
TYPE + ' must be (u32, ) instead',
|
TYPE + ' must be (u32, ) instead',
|
||||||
'The type of the value returned from function select should match its return type',
|
'The type of the value returned from function select should match its return type',
|
||||||
@ -273,7 +273,7 @@ def testEntry() -> i32:
|
|||||||
```
|
```
|
||||||
|
|
||||||
```py
|
```py
|
||||||
if TYPE_NAME.startswith('tuple_') or TYPE_NAME.startswith('static_array_'):
|
if TYPE_NAME.startswith('tuple_') or TYPE_NAME.startswith('static_array_') or TYPE_NAME.startswith('dynamic_array_'):
|
||||||
expect_type_error(
|
expect_type_error(
|
||||||
'Mismatch between applied types argument count',
|
'Mismatch between applied types argument count',
|
||||||
# FIXME: Shouldn't this be the same as for the else statement?
|
# FIXME: Shouldn't this be the same as for the else statement?
|
||||||
@ -330,7 +330,7 @@ def testEntry() -> i32:
|
|||||||
```
|
```
|
||||||
|
|
||||||
```py
|
```py
|
||||||
if TYPE_NAME.startswith('tuple_') or TYPE_NAME.startswith('static_array_') or TYPE_NAME.startswith('struct_'):
|
if TYPE_NAME.startswith('tuple_') or TYPE_NAME.startswith('static_array_') or TYPE_NAME.startswith('dynamic_array_') or TYPE_NAME.startswith('struct_'):
|
||||||
expect_type_error(
|
expect_type_error(
|
||||||
TYPE + ' must be (u32, ) instead',
|
TYPE + ' must be (u32, ) instead',
|
||||||
'The type of the value passed to argument 0 of function helper should match the type of that argument',
|
'The type of the value passed to argument 0 of function helper should match the type of that argument',
|
||||||
|
|||||||
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"TYPE_NAME": "dynamic_array_u64",
|
||||||
|
"TYPE": "u64[...]",
|
||||||
|
"VAL0": "(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, )"
|
||||||
|
}
|
||||||
@ -6,7 +6,7 @@ from ..helpers import Suite
|
|||||||
@pytest.mark.integration_test
|
@pytest.mark.integration_test
|
||||||
@pytest.mark.parametrize('type_, in_put, exp_result', [
|
@pytest.mark.parametrize('type_, in_put, exp_result', [
|
||||||
('bytes', b'Hello, world!', 13),
|
('bytes', b'Hello, world!', 13),
|
||||||
# ('u8[4]', (1, 2, 3, 4), 4), # FIXME: Implement this
|
('u8[4]', (1, 2, 3, 4), 4),
|
||||||
])
|
])
|
||||||
def test_len(type_, in_put, exp_result):
|
def test_len(type_, in_put, exp_result):
|
||||||
code_py = f"""
|
code_py = f"""
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user