From fd3939a680c6c60331693ccbcafc4ea26d22fc27 Mon Sep 17 00:00:00 2001 From: "Johan B.W. de Vries" Date: Fri, 10 Nov 2023 15:35:16 +0100 Subject: [PATCH] Feat: Use struct in tuple --- phasm/compiler.py | 4 +- phasm/ourlang.py | 8 +-- phasm/parser.py | 66 +++++++++++------------ tests/integration/test_lang/test_tuple.py | 23 ++++++++ 4 files changed, 63 insertions(+), 38 deletions(-) diff --git a/phasm/compiler.py b/phasm/compiler.py index 7c8d5c1..2a59f2c 100644 --- a/phasm/compiler.py +++ b/phasm/compiler.py @@ -460,7 +460,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: + if isinstance(el_type, type3types.StructType3): + mtyp = 'i32' + elif 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') diff --git a/phasm/ourlang.py b/phasm/ourlang.py index 2c2cc3d..d602051 100644 --- a/phasm/ourlang.py +++ b/phasm/ourlang.py @@ -85,9 +85,9 @@ class ConstantTuple(ConstantMemoryStored): """ __slots__ = ('value', ) - value: List[Union[ConstantPrimitive, ConstantBytes, 'ConstantTuple']] + value: List[Union[ConstantPrimitive, ConstantBytes, 'ConstantTuple', 'ConstantStruct']] - def __init__(self, value: List[Union[ConstantPrimitive, ConstantBytes, 'ConstantTuple']], data_block: 'ModuleDataBlock') -> None: + def __init__(self, value: List[Union[ConstantPrimitive, ConstantBytes, 'ConstantTuple', 'ConstantStruct']], data_block: 'ModuleDataBlock') -> None: super().__init__(data_block) self.value = value @@ -104,9 +104,9 @@ class ConstantStruct(ConstantMemoryStored): __slots__ = ('struct_name', 'value', ) struct_name: str - value: List[Union[ConstantPrimitive, ConstantBytes, ConstantTuple]] + value: List[Union[ConstantPrimitive, ConstantBytes, ConstantTuple, 'ConstantStruct']] - def __init__(self, struct_name: str, value: List[Union[ConstantPrimitive, ConstantBytes, ConstantTuple]], data_block: 'ModuleDataBlock') -> None: + def __init__(self, struct_name: str, value: List[Union[ConstantPrimitive, ConstantBytes, ConstantTuple, 'ConstantStruct']], data_block: 'ModuleDataBlock') -> None: super().__init__(data_block) self.struct_name = struct_name self.value = value diff --git a/phasm/parser.py b/phasm/parser.py index 3a2f8dd..e3799ab 100644 --- a/phasm/parser.py +++ b/phasm/parser.py @@ -208,14 +208,12 @@ class OurVisitor: _raise_static_error(node.target, 'Must be store context') if isinstance(node.value, ast.Constant): - type3 = self.visit_type(module, node.annotation) - value_data = self.visit_Module_Constant(module, node.value) return ModuleConstantDef( node.target.id, node.lineno, - type3, + self.visit_type(module, node.annotation), value_data, ) @@ -233,41 +231,16 @@ class OurVisitor: ) if isinstance(node.value, ast.Call): - # Struct constant - # Stored in memory like a tuple, so much of the code is the same + value_data = self.visit_Module_Constant(module, node.value) - if not isinstance(node.value.func, ast.Name): - _raise_static_error(node.value.func, 'Must be name') - if not isinstance(node.value.func.ctx, ast.Load): - _raise_static_error(node.value.func, 'Must be load context') - - if not node.value.func.id in module.struct_definitions: - _raise_static_error(node.value.func, 'Undefined struct') - - if node.value.keywords: - _raise_static_error(node.value.func, 'Cannot use keywords') - - if not isinstance(node.annotation, ast.Name): - _raise_static_error(node.annotation, 'Must be name') - - struct_data = [ - self.visit_Module_Constant(module, arg_node) - for arg_node in node.value.args - if isinstance(arg_node, ast.Constant) - ] - if len(node.value.args) != len(struct_data): - _raise_static_error(node, 'Struct arguments must be constants') - - # Allocate the data - data_block = ModuleDataBlock(struct_data) - module.data.blocks.append(data_block) + assert isinstance(value_data, ConstantStruct) # type hint # Then return the constant as a pointer return ModuleConstantDef( node.target.id, node.lineno, self.visit_type(module, node.annotation), - ConstantStruct(node.value.func.id, struct_data, data_block), + value_data, ) raise NotImplementedError(f'{node} on Module AnnAssign') @@ -561,12 +534,12 @@ class OurVisitor: return Subscript(varref, slice_expr) - def visit_Module_Constant(self, module: Module, node: Union[ast.Constant, ast.Tuple]) -> Union[ConstantPrimitive, ConstantBytes, ConstantTuple]: + def visit_Module_Constant(self, module: Module, node: Union[ast.Constant, ast.Tuple, ast.Call]) -> Union[ConstantPrimitive, ConstantBytes, ConstantTuple, ConstantStruct]: if isinstance(node, ast.Tuple): tuple_data = [ self.visit_Module_Constant(module, arg_node) for arg_node in node.elts - if isinstance(arg_node, (ast.Constant, ast.Tuple, )) + if isinstance(arg_node, (ast.Constant, ast.Tuple, ast.Call, )) ] if len(node.elts) != len(tuple_data): @@ -578,6 +551,33 @@ class OurVisitor: return ConstantTuple(tuple_data, data_block) + if isinstance(node, ast.Call): + # Struct constant + # Stored in memory like a tuple, so much of the code is the same + + if not isinstance(node.func, ast.Name): + _raise_static_error(node.func, 'Must be name') + if not isinstance(node.func.ctx, ast.Load): + _raise_static_error(node.func, 'Must be load context') + + if not node.func.id in module.struct_definitions: + _raise_static_error(node.func, 'Undefined struct') + + if node.keywords: + _raise_static_error(node.func, 'Cannot use keywords') + + struct_data = [ + self.visit_Module_Constant(module, arg_node) + for arg_node in node.args + if isinstance(arg_node, (ast.Constant, ast.Tuple, ast.Call, )) + ] + if len(node.args) != len(struct_data): + _raise_static_error(node, 'Struct arguments must be constants') + + data_block = ModuleDataBlock(struct_data) + module.data.blocks.append(data_block) + return ConstantStruct(node.func.id, struct_data, data_block) + _not_implemented(node.kind is None, 'Constant.kind') if isinstance(node.value, (int, float, )): diff --git a/tests/integration/test_lang/test_tuple.py b/tests/integration/test_lang/test_tuple.py index 465d305..61332be 100644 --- a/tests/integration/test_lang/test_tuple.py +++ b/tests/integration/test_lang/test_tuple.py @@ -162,6 +162,29 @@ def testEntry() -> u8: assert 0x41 == result.returned_value +@pytest.mark.integration_test +def test_struct_as_part_of_tuple(): + code_py = """ +class ValueStruct: + value: i32 + +CONSTANT: (ValueStruct, u64, ) = (ValueStruct(234), 19, ) + +def l0(c: ValueStruct) -> i32: + return c.value + +def l1(c: (ValueStruct, u64, )) -> i32: + return l0(c[0]) + +@exported +def testEntry() -> i32: + return l1(CONSTANT) +""" + + result = Suite(code_py).run_code() + + assert 234 == result.returned_value + @pytest.mark.integration_test def test_function_call_element_type_mismatch(): code_py = """