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:
|
if inp is type3types.f64:
|
||||||
return wasm.WasmTypeFloat64()
|
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):
|
if isinstance(inp, type3types.StructType3):
|
||||||
# Structs and tuples are passed as pointer
|
# Structs and tuples are passed as pointer
|
||||||
# And pointers are i32
|
# And pointers are i32
|
||||||
@ -273,13 +278,13 @@ def expression(wgn: WasmGenerator, inp: ourlang.Expression) -> None:
|
|||||||
wgn.add_statement(f'f64.{inp.operator}')
|
wgn.add_statement(f'f64.{inp.operator}')
|
||||||
return
|
return
|
||||||
|
|
||||||
# TODO: Broken after new type system
|
if inp.type3 is type3types.u32:
|
||||||
# if isinstance(inp.type, typing.TypeInt32):
|
if inp.operator == 'len':
|
||||||
# if inp.operator == 'len':
|
if inp.right.type3 is type3types.bytes:
|
||||||
# if isinstance(inp.right.type, typing.TypeBytes):
|
wgn.i32.load()
|
||||||
# wgn.i32.load()
|
return
|
||||||
# return
|
|
||||||
|
|
||||||
|
# TODO: Broken after new type system
|
||||||
# if inp.operator == 'cast':
|
# if inp.operator == 'cast':
|
||||||
# if isinstance(inp.type, typing.TypeUInt32) and isinstance(inp.right.type, typing.TypeUInt8):
|
# 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
|
# # Nothing to do, you can use an u8 value as a u32 no problem
|
||||||
|
|||||||
@ -154,6 +154,17 @@ class MustImplementTypeClassConstraint(ConstraintBase):
|
|||||||
type_class3: str
|
type_class3: str
|
||||||
type3: types.Type3OrPlaceholder
|
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:
|
def __init__(self, type_class3: str, type3: types.Type3OrPlaceholder, comment: Optional[str] = None) -> None:
|
||||||
super().__init__(comment=comment)
|
super().__init__(comment=comment)
|
||||||
|
|
||||||
@ -168,14 +179,7 @@ class MustImplementTypeClassConstraint(ConstraintBase):
|
|||||||
if isinstance(typ, types.PlaceholderForType):
|
if isinstance(typ, types.PlaceholderForType):
|
||||||
return RequireTypeSubstitutes()
|
return RequireTypeSubstitutes()
|
||||||
|
|
||||||
if 'BitWiseOperation' == self.type_class3 and (typ is types.u8 or typ is types.u32 or typ is types.u64):
|
if self.type_class3 in self.__class__.DATA.get(typ.name, set()):
|
||||||
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
|
|
||||||
):
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return Error(f'{typ.name} does not implement the {self.type_class3} type class')
|
return Error(f'{typ.name} does not implement the {self.type_class3} type class')
|
||||||
|
|||||||
@ -15,6 +15,8 @@ from .constraints import (
|
|||||||
LiteralFitsConstraint, MustImplementTypeClassConstraint, SameTypeConstraint,
|
LiteralFitsConstraint, MustImplementTypeClassConstraint, SameTypeConstraint,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from . import types as type3types
|
||||||
|
|
||||||
def phasm_type3_generate_constraints(inp: ourlang.Module) -> List[ConstraintBase]:
|
def phasm_type3_generate_constraints(inp: ourlang.Module) -> List[ConstraintBase]:
|
||||||
ctx = Context()
|
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})')
|
comment=f'typeOf("{inp.variable.name}") == typeOf({inp.variable.name})')
|
||||||
return
|
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 isinstance(inp, ourlang.BinaryOp):
|
||||||
if inp.operator in ('|', '&', '^', ):
|
if inp.operator in ('|', '&', '^', ):
|
||||||
yield from expression(ctx, inp.left)
|
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')
|
comment=f'({inp.operator}) :: a -> a -> a')
|
||||||
return
|
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 ('+', '-', '*', '/', ):
|
if inp.operator in ('+', '-', '*', '/', ):
|
||||||
yield from expression(ctx, inp.left)
|
yield from expression(ctx, inp.left)
|
||||||
yield from expression(ctx, inp.right)
|
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)
|
new_placeholder_substitutes_len = len(placeholder_substitutes)
|
||||||
|
|
||||||
if old_constraint_ids == new_constraint_ids and old_placeholder_substitutes_len == new_placeholder_substitutes_len:
|
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')
|
raise Exception('Cannot type this program - not enough information')
|
||||||
|
|
||||||
constraint_list = new_constraint_list
|
constraint_list = new_constraint_list
|
||||||
|
|||||||
@ -215,6 +215,11 @@ f64 = Type3('f64')
|
|||||||
A 32-bits IEEE 754 float, of 64 bits width.
|
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')
|
static_array = Type3('static_array')
|
||||||
"""
|
"""
|
||||||
This is a fixed length piece of memory that can be indexed at runtime.
|
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,
|
'i64': i64,
|
||||||
'f32': f32,
|
'f32': f32,
|
||||||
'f64': f64,
|
'f64': f64,
|
||||||
|
'bytes': bytes,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,13 +20,13 @@ def testEntry(f: bytes) -> bytes:
|
|||||||
def test_bytes_length():
|
def test_bytes_length():
|
||||||
code_py = """
|
code_py = """
|
||||||
@exported
|
@exported
|
||||||
def testEntry(f: bytes) -> i32:
|
def testEntry(f: bytes) -> u32:
|
||||||
return len(f)
|
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
|
@pytest.mark.integration_test
|
||||||
def test_bytes_index():
|
def test_bytes_index():
|
||||||
|
|||||||
@ -468,7 +468,7 @@ def testEntry() -> i32:
|
|||||||
return helper()
|
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()
|
Suite(code_py).run_code()
|
||||||
|
|
||||||
@pytest.mark.integration_test
|
@pytest.mark.integration_test
|
||||||
|
|||||||
@ -99,5 +99,5 @@ def testEntry(arg: Struct) -> (i32, i32, ):
|
|||||||
return arg.param
|
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()
|
Suite(code_py).run_code()
|
||||||
|
|||||||
@ -112,7 +112,7 @@ def test_tuple_constant_type_mismatch():
|
|||||||
CONSTANT: (u32, u8, u8, ) = (24, 4000, 1, )
|
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()
|
Suite(code_py).run_code()
|
||||||
|
|
||||||
@pytest.mark.integration_test
|
@pytest.mark.integration_test
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user