Add partial tuple of tuple support

This commit is contained in:
Johan B.W. de Vries 2023-11-10 14:00:29 +01:00
parent a85129254d
commit 20d177e2c5
3 changed files with 80 additions and 10 deletions

View File

@ -171,7 +171,7 @@ def tuple_instantiation(wgn: WasmGenerator, inp: ourlang.TupleInstantiation) ->
wgn.add_statement('nop', comment=f'{tmp_var.name} := ({comment_elements})')
# Allocated the required amounts of bytes in memory
wgn.i32.const(_calculate_alloc_size(inp.type3))
wgn.i32.const(_calculate_alloc_size(inp.type3, is_member=False))
wgn.call(stdlib_alloc.__alloc__)
wgn.local.set(tmp_var)
@ -184,14 +184,19 @@ def tuple_instantiation(wgn: WasmGenerator, inp: ourlang.TupleInstantiation) ->
assert element.type3 == exp_type3
if isinstance(exp_type3, type3types.AppliedType3) and exp_type3.base is type3types.tuple:
mtyp = 'i32'
else:
assert isinstance(exp_type3, type3types.PrimitiveType3), NotImplementedError('Tuple of applied types / structs')
mtyp = LOAD_STORE_TYPE_MAP[exp_type3.name]
wgn.add_statement('nop', comment='PRE')
wgn.local.get(tmp_var)
expression(wgn, element)
wgn.add_statement(f'{mtyp}.store', 'offset=' + str(offset))
wgn.add_statement('nop', comment='POST')
offset += _calculate_alloc_size(exp_type3)
offset += _calculate_alloc_size(exp_type3, is_member=True)
# Return the allocated address
wgn.local.get(tmp_var)
@ -445,6 +450,9 @@ def expression(wgn: WasmGenerator, inp: ourlang.Expression) -> None:
expression(wgn, inp.varref)
if isinstance(el_type, type3types.AppliedType3) and el_type.base is type3types.tuple:
mtyp = 'i32'
else:
assert isinstance(el_type, type3types.PrimitiveType3), NotImplementedError('Tuple of applied types / structs')
mtyp = LOAD_STORE_TYPE_MAP[el_type.name]
@ -814,7 +822,7 @@ def _generate_struct_constructor(wgn: WasmGenerator, inp: ourlang.StructConstruc
# Return the allocated address
wgn.local.get(tmp_var)
def _calculate_alloc_size(typ: Union[type3types.StructType3, type3types.Type3]) -> int:
def _calculate_alloc_size(typ: Union[type3types.StructType3, type3types.Type3], is_member: bool = False) -> int:
if typ == type3types.u8:
return 4 # FIXME: We allocate 4 bytes for every u8 since you load them into an i32
@ -825,6 +833,10 @@ def _calculate_alloc_size(typ: Union[type3types.StructType3, type3types.Type3])
return 8
if isinstance(typ, type3types.StructType3):
if is_member:
# Structs referred to by other structs or tuples are pointers
return 4
return sum(
_calculate_alloc_size(x)
for x in typ.members.values()
@ -832,6 +844,10 @@ def _calculate_alloc_size(typ: Union[type3types.StructType3, type3types.Type3])
if isinstance(typ, type3types.AppliedType3):
if typ.base is type3types.tuple:
if is_member:
# tuples referred to by other structs or tuples are pointers
return 4
size = 0
for arg in typ.args:
assert not isinstance(arg, type3types.IntType3)
@ -840,7 +856,7 @@ def _calculate_alloc_size(typ: Union[type3types.StructType3, type3types.Type3])
assert not arg.resolve_as is None
arg = arg.resolve_as
size += _calculate_alloc_size(arg)
size += _calculate_alloc_size(arg, is_member=True)
return size
@ -853,6 +869,6 @@ def _calculate_member_offset(struct_type3: type3types.StructType3, member: str)
if member == mem:
return result
result += _calculate_alloc_size(memtyp)
result += _calculate_alloc_size(memtyp, is_member=True)
raise Exception(f'{member} not in {struct_type3}')

View File

@ -442,7 +442,7 @@ class OurVisitor:
arguments = [
self.visit_Module_FunctionDef_expr(module, function, our_locals, arg_node)
for arg_node in node.elts
if isinstance(arg_node, ast.Constant)
if isinstance(arg_node, (ast.Constant, ast.Tuple, ))
]
if len(arguments) != len(node.elts):

View File

@ -65,6 +65,60 @@ def helper(x: u64) -> u64:
assert 250000000 == result.returned_value
@pytest.mark.integration_test
def test_tuple():
code_py = """
def l1(c: (u64, )) -> u64:
return c[0]
@exported
def testEntry() -> u64:
return l1((32, ))
"""
result = Suite(code_py).run_code()
assert 32 == result.returned_value
@pytest.mark.integration_test
def test_tuple_of_tuple():
code_py = """
def l1(c: (u64, )) -> u64:
return c[0]
def l2(c: ((u64, ), u64, )) -> u64:
return l1(c[0])
@exported
def testEntry() -> u64:
return l2(((64, ), 32, ))
"""
result = Suite(code_py).run_code()
assert 64 == result.returned_value
@pytest.mark.integration_test
def test_tuple_of_tuple_of_tuple():
code_py = """
def l1(c: (u64, )) -> u64:
return c[0]
def l2(c: ((u64, ), u64, )) -> u64:
return l1(c[0])
def l3(c: (((u64, ), u64, ), u64, )) -> u64:
return l2(c[0])
@exported
def testEntry() -> u64:
return l3((((128, ), 64, ), 32, ))
"""
result = Suite(code_py).run_code()
assert 128 == result.returned_value
@pytest.mark.integration_test
def test_function_call_element_type_mismatch():
code_py = """