Reimplements casting and foldl

Probably not 100% type checked yet.

Also, fixed logical right shift; standard says the type
is different.
This commit is contained in:
Johan B.W. de Vries 2022-12-26 13:11:36 +01:00
parent a164976f63
commit 1afa3efc31
5 changed files with 72 additions and 18 deletions

View File

@ -297,11 +297,10 @@ def expression(wgn: WasmGenerator, inp: ourlang.Expression) -> None:
wgn.i32.load()
return
# TODO: Broken after new type system
# if inp.operator == 'cast':
# if isinstance(inp.type, typing.TypeUInt32) and isinstance(inp.right.type, typing.TypeUInt8):
# # Nothing to do, you can use an u8 value as a u32 no problem
# return
if inp.operator == 'cast':
if inp.type3 == type3types.u32 and inp.right.type3 == type3types.u8:
# Nothing to do, you can use an u8 value as a u32 no problem
return
raise NotImplementedError(expression, inp.type3, inp.operator)
@ -397,10 +396,8 @@ def expression_fold(wgn: WasmGenerator, inp: ourlang.Fold) -> None:
"""
assert isinstance(inp.type3, type3types.Type3), type3types.TYPE3_ASSERTION_ERROR
raise NotImplementedError('TODO: Broken after new type system')
if inp.iter.type.__class__.__name__ != 'TypeBytes':
raise NotImplementedError(expression, inp, inp.iter.type)
if inp.iter.type3 is not type3types.bytes:
raise NotImplementedError(expression_fold, inp, inp.iter.type3)
wgn.add_statement('nop', comment='acu :: u8')
acu_var = wgn.temp_var_u8(f'fold_{codestyle.type3(inp.type3)}_acu')

View File

@ -563,8 +563,6 @@ class OurVisitor:
if 2 != len(func.posonlyargs):
_raise_static_error(node, f'Function {node.func.id} requires a function with 2 arguments but a function with {len(func.posonlyargs)} args is given')
raise NotImplementedError('TODO: Broken after new type system')
return Fold(
Fold.Direction.LEFT,
func,

View File

@ -147,6 +147,50 @@ class SameTypeConstraint(ConstraintBase):
return f'SameTypeConstraint({args}, comment={repr(self.comment)})'
class CastableConstraint(ConstraintBase):
"""
A type can be cast to another type
"""
__slots__ = ('from_type3', 'to_type3', )
from_type3: types.Type3OrPlaceholder
to_type3: types.Type3OrPlaceholder
def __init__(self, from_type3: types.Type3OrPlaceholder, to_type3: types.Type3OrPlaceholder, comment: Optional[str] = None) -> None:
super().__init__(comment=comment)
self.from_type3 = from_type3
self.to_type3 = to_type3
def check(self, smap: SubstitutionMap) -> CheckResult:
ftyp = self.from_type3
if isinstance(ftyp, types.PlaceholderForType) and ftyp in smap:
ftyp = smap[ftyp]
ttyp = self.to_type3
if isinstance(ttyp, types.PlaceholderForType) and ttyp in smap:
ttyp = smap[ttyp]
if isinstance(ftyp, types.PlaceholderForType) or isinstance(ttyp, types.PlaceholderForType):
return RequireTypeSubstitutes()
if ftyp is types.u8 and ttyp is types.u32:
return None
return Error(f'Cannot cast {ftyp.name} to {ttyp.name}')
def human_readable(self) -> HumanReadableRet:
return (
'{to_type3}({from_type3})',
{
'to_type3': self.to_type3,
'from_type3': self.from_type3,
},
)
def __repr__(self) -> str:
return f'CastableConstraint({repr(self.from_type3)}, {repr(self.to_type3)}, comment={repr(self.comment)})'
class MustImplementTypeClassConstraint(ConstraintBase):
"""
A type must implement a given type class
@ -162,7 +206,7 @@ class MustImplementTypeClassConstraint(ConstraintBase):
'u64': {'BitWiseOperation', 'BasicMathOperation'},
'i32': {'BasicMathOperation'},
'i64': {'BasicMathOperation'},
'bytes': {'Sized'},
'bytes': {'Foldable', 'Sized'},
'f32': {'BasicMathOperation', 'FloatingPoint'},
'f64': {'BasicMathOperation', 'FloatingPoint'},
}

View File

@ -11,7 +11,7 @@ from .constraints import (
Context,
ConstraintBase,
CanBeSubscriptedConstraint,
CastableConstraint, CanBeSubscriptedConstraint,
LiteralFitsConstraint, MustImplementTypeClassConstraint, SameTypeConstraint,
)
@ -52,6 +52,11 @@ def expression(ctx: Context, inp: ourlang.Expression) -> Generator[ConstraintBas
yield SameTypeConstraint(inp.right.type3, inp.type3, comment='sqrt :: FloatingPoint a => a -> a')
return
if 'cast' == inp.operator:
yield from expression(ctx, inp.right)
yield CastableConstraint(inp.right.type3, inp.type3)
return
raise NotImplementedError(expression, inp, inp.operator)
if isinstance(inp, ourlang.BinaryOp):
@ -69,10 +74,8 @@ def expression(ctx: Context, inp: ourlang.Expression) -> Generator[ConstraintBas
yield from expression(ctx, inp.right)
yield MustImplementTypeClassConstraint('BitWiseOperation', inp.left.type3)
yield SameTypeConstraint(inp.left.type3, inp.type3,
comment=f'({inp.operator}) :: a -> u64 -> a')
yield SameTypeConstraint(type3types.u64, inp.right.type3,
comment=f'({inp.operator}) :: a -> u64 -> a')
yield SameTypeConstraint(inp.left.type3, inp.right.type3, inp.type3,
comment=f'({inp.operator}) :: a -> a -> a')
return
if inp.operator in ('+', '-', '*', '/', ):
@ -112,6 +115,16 @@ def expression(ctx: Context, inp: ourlang.Expression) -> Generator[ConstraintBas
comment=f'The type of a struct member reference is the same as the type of struct member {inp.struct_type3.name}.{inp.member}')
return
if isinstance(inp, ourlang.Fold):
yield from expression(ctx, inp.base)
yield from expression(ctx, inp.iter)
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)
return
raise NotImplementedError(expression, inp)
def function(ctx: Context, inp: ourlang.Function) -> Generator[ConstraintBase, None, None]:

View File

@ -111,7 +111,9 @@ def testEntry() -> {type_}:
return 10 >> 3
"""
result = Suite(code_py).run_code()
# Check with wasmtime, as other engines don't mind if the type
# doesn't match. They'll complain when: (>>) : u32 -> u64 -> u32
result = Suite(code_py).run_code(runtime='wasmtime')
assert 1 == result.returned_value
assert TYPE_MAP[type_] == type(result.returned_value)