More work on tuples

This commit is contained in:
Johan B.W. de Vries 2022-12-24 19:40:07 +01:00
parent 17f538d8cc
commit 25b5d6fc06
3 changed files with 88 additions and 16 deletions

View File

@ -203,14 +203,13 @@ def expression(wgn: WasmGenerator, inp: ourlang.Expression) -> None:
wgn.i32.const(inp.variable.data_block.address)
return
# TODO: Broken after new type system
# if isinstance(inp.type, typing.TypeTuple):
# assert isinstance(inp.definition.constant, ourlang.ConstantTuple)
# assert inp.definition.data_block is not None, 'Combined values are memory stored'
# assert inp.definition.data_block.address is not None, 'Value not allocated'
# wgn.i32.const(inp.definition.data_block.address)
# return
#
if inp.type3.base == type3types.tuple:
assert inp.variable.data_block is not None, 'Tuples must be memory stored'
assert inp.variable.data_block.address is not None, 'Value not allocated'
wgn.i32.const(inp.variable.data_block.address)
return
raise NotImplementedError(expression, inp.variable, inp.type3.base)
assert inp.variable.data_block is None, 'Primitives are not memory stored'
@ -338,6 +337,30 @@ def expression(wgn: WasmGenerator, inp: ourlang.Expression) -> None:
wgn.add_statement(f'{mtyp}.load')
return
if inp.varref.type3.base == type3types.tuple:
assert isinstance(inp.index, ourlang.ConstantPrimitive)
assert isinstance(inp.index.value, int)
offset = 0
for el_type in inp.varref.type3.args[0:inp.index.value]:
assert isinstance(el_type, type3types.Type3), type3types.TYPE3_ASSERTION_ERROR
offset += _calculate_alloc_size(el_type)
# This doubles as the out of bounds check
el_type = inp.varref.type3.args[inp.index.value]
assert isinstance(el_type, type3types.Type3), type3types.TYPE3_ASSERTION_ERROR
expression(wgn, inp.varref)
mtyp = LOAD_STORE_TYPE_MAP.get(el_type.name)
if mtyp is None:
# In the future might extend this by having structs or tuples
# as members of struct or tuples
raise NotImplementedError(expression, inp, el_type)
wgn.add_statement(f'{mtyp}.load', f'offset={offset}')
return
raise NotImplementedError(expression, inp, inp.varref.type3)
if isinstance(inp, ourlang.AccessStructMember):

View File

@ -379,6 +379,21 @@ class CanBeSubscriptedConstraint(ConstraintBase):
SameTypeConstraint(self.type3.args[0], self.ret_type3, comment='([]) :: Subscriptable a => a b -> u32 -> b'),
]
if self.type3.base == types.tuple:
if not isinstance(self.index, ourlang.ConstantPrimitive):
return Error('Must index with literal')
if not isinstance(self.index.value, int):
return Error('Must index with integer literal')
if self.index.value < 0 or len(self.type3.args) <= self.index.value:
return Error('Tuple index out of range')
return [
SameTypeConstraint(types.u32, self.index_type3, comment=f'Tuple subscript index {self.index.value}'),
SameTypeConstraint(self.type3.args[self.index.value], self.ret_type3, comment=f'Tuple subscript index {self.index.value}'),
]
# FIXME: bytes
if self.type3.name in types.LOOKUP_TABLE:

View File

@ -2,7 +2,7 @@ import pytest
from phasm.type3.entry import Type3Exception
from ..constants import COMPLETE_NUMERIC_TYPES, TYPE_MAP
from ..constants import ALL_FLOAT_TYPES, COMPLETE_NUMERIC_TYPES, TYPE_MAP
from ..helpers import Suite
@pytest.mark.integration_test
@ -48,9 +48,42 @@ def testEntry() -> u32:
assert 3333 == result.returned_value
@pytest.mark.integration_test
def test_function_call_element_ok():
code_py = """
CONSTANT: (u8, u32, u64, ) = (250, 250000, 250000000, )
@exported
def testEntry() -> u64:
return helper(CONSTANT[2])
def helper(x: u64) -> u64:
return x
"""
result = Suite(code_py).run_code()
assert 250000000 == result.returned_value
@pytest.mark.integration_test
def test_function_call_element_type_mismatch():
code_py = """
CONSTANT: (u8, u32, u64, ) = (250, 250000, 250000000, )
@exported
def testEntry() -> u8:
return helper(CONSTANT[2])
def helper(x: u8) -> u8:
return x
"""
with pytest.raises(Type3Exception, match=r'u8 must be u64 instead'):
Suite(code_py).run_code()
@pytest.mark.integration_test
@pytest.mark.parametrize('type_', COMPLETE_NUMERIC_TYPES)
def test_tuple_simple_constructor(type_):
def test_tuple_simple_constructor_int(type_):
code_py = f"""
@exported
def testEntry() -> {type_}:
@ -66,13 +99,14 @@ def helper(vector: ({type_}, {type_}, {type_}, )) -> {type_}:
assert TYPE_MAP[type_] == type(result.returned_value)
@pytest.mark.integration_test
def test_tuple_float():
code_py = """
@pytest.mark.parametrize('type_', ALL_FLOAT_TYPES)
def test_tuple_simple_constructor_float(type_):
code_py = f"""
@exported
def testEntry() -> f32:
def testEntry() -> {type_}:
return helper((1.0, 2.0, 3.0, ))
def helper(v: (f32, f32, f32, )) -> f32:
def helper(v: ({type_}, {type_}, {type_}, )) -> {type_}:
return sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2])
"""
@ -139,7 +173,7 @@ def testEntry(x: (u8, u32, u64)) -> u64:
return x[CONSTANT]
"""
with pytest.raises(Type3Exception, match='Tuples must be indexed with literals'):
with pytest.raises(Type3Exception, match='Must index with literal'):
Suite(code_py).run_code()
@pytest.mark.integration_test
@ -150,5 +184,5 @@ def testEntry(x: (u8, u32, u64)) -> u64:
return x[0.0]
"""
with pytest.raises(Type3Exception, match='Must be integer'):
with pytest.raises(Type3Exception, match='Must index with integer literal'):
Suite(code_py).run_code()