Various small fixes
Re-implementing some things that were broken. Also, if a typing error is found, and we detect an infinite loop, we return the errors instead, as that's probably what causing the loop anyhow.
This commit is contained in:
parent
05e7c356ea
commit
6d426753c8
@ -63,6 +63,11 @@ def type3(inp: type3types.Type3OrPlaceholder) -> wasm.WasmType:
|
||||
if inp is type3types.f64:
|
||||
return wasm.WasmTypeFloat64()
|
||||
|
||||
if inp is type3types.bytes:
|
||||
# bytes are passed as pointer
|
||||
# And pointers are i32
|
||||
return wasm.WasmTypeInt32()
|
||||
|
||||
if isinstance(inp, type3types.StructType3):
|
||||
# Structs and tuples are passed as pointer
|
||||
# And pointers are i32
|
||||
@ -273,13 +278,13 @@ def expression(wgn: WasmGenerator, inp: ourlang.Expression) -> None:
|
||||
wgn.add_statement(f'f64.{inp.operator}')
|
||||
return
|
||||
|
||||
# TODO: Broken after new type system
|
||||
# if isinstance(inp.type, typing.TypeInt32):
|
||||
# if inp.operator == 'len':
|
||||
# if isinstance(inp.right.type, typing.TypeBytes):
|
||||
# wgn.i32.load()
|
||||
# return
|
||||
if inp.type3 is type3types.u32:
|
||||
if inp.operator == 'len':
|
||||
if inp.right.type3 is type3types.bytes:
|
||||
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
|
||||
|
||||
@ -154,6 +154,17 @@ class MustImplementTypeClassConstraint(ConstraintBase):
|
||||
type_class3: str
|
||||
type3: types.Type3OrPlaceholder
|
||||
|
||||
DATA = {
|
||||
'u8': {'BitWiseOperation', 'BasicMathOperation'},
|
||||
'u32': {'BitWiseOperation', 'BasicMathOperation'},
|
||||
'u64': {'BitWiseOperation', 'BasicMathOperation'},
|
||||
'i32': {'BasicMathOperation'},
|
||||
'i64': {'BasicMathOperation'},
|
||||
'bytes': {'Sized'},
|
||||
'f32': {'BasicMathOperation', 'FloatingPoint'},
|
||||
'f64': {'BasicMathOperation', 'FloatingPoint'},
|
||||
}
|
||||
|
||||
def __init__(self, type_class3: str, type3: types.Type3OrPlaceholder, comment: Optional[str] = None) -> None:
|
||||
super().__init__(comment=comment)
|
||||
|
||||
@ -168,14 +179,7 @@ class MustImplementTypeClassConstraint(ConstraintBase):
|
||||
if isinstance(typ, types.PlaceholderForType):
|
||||
return RequireTypeSubstitutes()
|
||||
|
||||
if 'BitWiseOperation' == self.type_class3 and (typ is types.u8 or typ is types.u32 or typ is types.u64):
|
||||
return None
|
||||
|
||||
if 'BasicMathOperation' == self.type_class3 and (
|
||||
typ is types.u8 or typ is types.u32 or typ is types.u64
|
||||
or typ is types.i32 or typ is types.i64
|
||||
or typ is types.f32 or typ is types.f64
|
||||
):
|
||||
if self.type_class3 in self.__class__.DATA.get(typ.name, set()):
|
||||
return None
|
||||
|
||||
return Error(f'{typ.name} does not implement the {self.type_class3} type class')
|
||||
|
||||
@ -15,6 +15,8 @@ from .constraints import (
|
||||
LiteralFitsConstraint, MustImplementTypeClassConstraint, SameTypeConstraint,
|
||||
)
|
||||
|
||||
from . import types as type3types
|
||||
|
||||
def phasm_type3_generate_constraints(inp: ourlang.Module) -> List[ConstraintBase]:
|
||||
ctx = Context()
|
||||
|
||||
@ -37,6 +39,21 @@ def expression(ctx: Context, inp: ourlang.Expression) -> Generator[ConstraintBas
|
||||
comment=f'typeOf("{inp.variable.name}") == typeOf({inp.variable.name})')
|
||||
return
|
||||
|
||||
if isinstance(inp, ourlang.UnaryOp):
|
||||
if 'len' == inp.operator:
|
||||
yield from expression(ctx, inp.right)
|
||||
yield MustImplementTypeClassConstraint('Sized', inp.right.type3)
|
||||
yield SameTypeConstraint(type3types.u32, inp.type3, comment='len :: Sized a => a -> u32')
|
||||
return
|
||||
|
||||
if 'sqrt' == inp.operator:
|
||||
yield from expression(ctx, inp.right)
|
||||
yield MustImplementTypeClassConstraint('FloatingPoint', inp.right.type3)
|
||||
yield SameTypeConstraint(inp.right.type3, inp.type3, comment='sqrt :: FloatingPoint a => a -> a')
|
||||
return
|
||||
|
||||
raise NotImplementedError(expression, inp, inp.operator)
|
||||
|
||||
if isinstance(inp, ourlang.BinaryOp):
|
||||
if inp.operator in ('|', '&', '^', ):
|
||||
yield from expression(ctx, inp.left)
|
||||
@ -47,6 +64,17 @@ def expression(ctx: Context, inp: ourlang.Expression) -> Generator[ConstraintBas
|
||||
comment=f'({inp.operator}) :: a -> a -> a')
|
||||
return
|
||||
|
||||
if inp.operator in ('>>', '<<', ):
|
||||
yield from expression(ctx, inp.left)
|
||||
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')
|
||||
return
|
||||
|
||||
if inp.operator in ('+', '-', '*', '/', ):
|
||||
yield from expression(ctx, inp.left)
|
||||
yield from expression(ctx, inp.right)
|
||||
|
||||
@ -76,6 +76,9 @@ def phasm_type3(inp: ourlang.Module, verbose: bool = False) -> None:
|
||||
new_placeholder_substitutes_len = len(placeholder_substitutes)
|
||||
|
||||
if old_constraint_ids == new_constraint_ids and old_placeholder_substitutes_len == new_placeholder_substitutes_len:
|
||||
if error_list:
|
||||
raise Type3Exception(error_list)
|
||||
|
||||
raise Exception('Cannot type this program - not enough information')
|
||||
|
||||
constraint_list = new_constraint_list
|
||||
|
||||
@ -215,6 +215,11 @@ f64 = Type3('f64')
|
||||
A 32-bits IEEE 754 float, of 64 bits width.
|
||||
"""
|
||||
|
||||
bytes = Type3('bytes')
|
||||
"""
|
||||
This is a runtime-determined length piece of memory that can be indexed at runtime.
|
||||
"""
|
||||
|
||||
static_array = Type3('static_array')
|
||||
"""
|
||||
This is a fixed length piece of memory that can be indexed at runtime.
|
||||
@ -241,4 +246,5 @@ LOOKUP_TABLE: Dict[str, Type3] = {
|
||||
'i64': i64,
|
||||
'f32': f32,
|
||||
'f64': f64,
|
||||
'bytes': bytes,
|
||||
}
|
||||
|
||||
@ -20,13 +20,13 @@ def testEntry(f: bytes) -> bytes:
|
||||
def test_bytes_length():
|
||||
code_py = """
|
||||
@exported
|
||||
def testEntry(f: bytes) -> i32:
|
||||
def testEntry(f: bytes) -> u32:
|
||||
return len(f)
|
||||
"""
|
||||
|
||||
result = Suite(code_py).run_code(b'This is another test')
|
||||
result = Suite(code_py).run_code(b'This yet is another test')
|
||||
|
||||
assert 20 == result.returned_value
|
||||
assert 24 == result.returned_value
|
||||
|
||||
@pytest.mark.integration_test
|
||||
def test_bytes_index():
|
||||
|
||||
@ -468,7 +468,7 @@ def testEntry() -> i32:
|
||||
return helper()
|
||||
"""
|
||||
|
||||
with pytest.raises(Type3Exception, match=r'i32.*i64'):
|
||||
with pytest.raises(Type3Exception, match=r'i64 must be i32 instead'):
|
||||
Suite(code_py).run_code()
|
||||
|
||||
@pytest.mark.integration_test
|
||||
|
||||
@ -99,5 +99,5 @@ def testEntry(arg: Struct) -> (i32, i32, ):
|
||||
return arg.param
|
||||
"""
|
||||
|
||||
with pytest.raises(Type3Exception, match=r'\(i32, i32, \) must be ' + type_ + ' instead'):
|
||||
with pytest.raises(Type3Exception, match=type_ + r' must be tuple \(i32\) \(i32\) instead'):
|
||||
Suite(code_py).run_code()
|
||||
|
||||
@ -112,7 +112,7 @@ def test_tuple_constant_type_mismatch():
|
||||
CONSTANT: (u32, u8, u8, ) = (24, 4000, 1, )
|
||||
"""
|
||||
|
||||
with pytest.raises(Type3Exception, match='Must fit in 1 byte(s)'):
|
||||
with pytest.raises(Type3Exception, match=r'Must fit in 1 byte\(s\)'):
|
||||
Suite(code_py).run_code()
|
||||
|
||||
@pytest.mark.integration_test
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user