def create_structure_symbol(table): ''' Utility to create a symbol of derived type and add it to the supplied symbol table. :param table: the symbol table to which to add the new symbol. :type table: :py:class:`psyclone.psyir.symbols.SymbolTable` :returns: the new DataSymbol representing a derived type. :rtype: :py:class:`psyclone.psyir.symbols.DataSymbol` ''' region_type = symbols.StructureType.create([ ("nx", symbols.INTEGER_TYPE, symbols.Symbol.Visibility.PUBLIC), ("ny", symbols.INTEGER_TYPE, symbols.Symbol.Visibility.PUBLIC), ("domain", symbols.DataTypeSymbol("dom_type", symbols.DeferredType()), symbols.Symbol.Visibility.PUBLIC)]) region_type_sym = symbols.DataTypeSymbol("grid_type", region_type) region_array_type = symbols.ArrayType(region_type_sym, [2, 2]) grid_type = symbols.StructureType.create([ ("dx", symbols.INTEGER_TYPE, symbols.Symbol.Visibility.PUBLIC), ("area", region_type_sym, symbols.Symbol.Visibility.PUBLIC), ("levels", region_array_type, symbols.Symbol.Visibility.PUBLIC)]) grid_type_sym = symbols.DataTypeSymbol("grid_type", grid_type) grid_var = symbols.DataSymbol("grid", grid_type_sym) table.add(grid_type_sym) table.add(grid_var) return grid_var
def make_component_symbol(): ''' Creates a Symbol of type "grid_type" equivalent to the Fortran: type :: grid_type integer :: nx type(region_type) :: region end type and type :: region_type integer :: startx end type :returns: symbol named "grid" of type "grid_type". :rtype: :py:class:`psyclone.psyir.symbols.DataSymbol` ''' region_type = symbols.StructureType.create([ ("startx", symbols.INTEGER_TYPE, symbols.Symbol.Visibility.PUBLIC)]) region_type_symbol = symbols.DataTypeSymbol("region_type", region_type) grid_type = symbols.StructureType.create([ ("nx", symbols.INTEGER_TYPE, symbols.Symbol.Visibility.PUBLIC), ("region", region_type_symbol, symbols.Symbol.Visibility.PUBLIC)]) grid_type_symbol = symbols.DataTypeSymbol("grid_type", grid_type) grid_array_type = symbols.ArrayType(grid_type_symbol, [5]) ssym = symbols.DataSymbol("grid", grid_array_type) return ssym
def test_struc_ref_create(): ''' Tests for the create method. ''' region_type = symbols.StructureType.create([ ("startx", symbols.INTEGER_TYPE, symbols.Symbol.Visibility.PUBLIC) ]) region_type_symbol = symbols.DataTypeSymbol("region_type", region_type) grid_type = symbols.StructureType.create([ ("nx", symbols.INTEGER_TYPE, symbols.Symbol.Visibility.PUBLIC), ("region", region_type_symbol, symbols.Symbol.Visibility.PRIVATE), ("sub_grids", symbols.ArrayType(region_type_symbol, [3]), symbols.Symbol.Visibility.PUBLIC), ("data", symbols.ArrayType(symbols.REAL_TYPE, [10, 10]), symbols.Symbol.Visibility.PUBLIC) ]) grid_type_symbol = symbols.DataTypeSymbol("grid_type", grid_type) ssym = symbols.DataSymbol("grid", grid_type_symbol) # Reference to scalar member of structure sref = nodes.StructureReference.create(ssym, ["nx"]) assert sref.symbol is ssym assert len(sref.children) == 1 assert sref.children[0].name == "nx" check_links(sref, sref.children) # Reference to scalar member of structure member of structure rref = nodes.StructureReference.create(ssym, ["region", "startx"]) assert rref.children[0].name == "region" assert rref.children[0].children[0].name == "startx" check_links(rref.children[0], rref.children[0].children) # Reference to an element of an array member of the structure aref = nodes.StructureReference.create(ssym, [("data", [ nodes.Literal("1", symbols.INTEGER_TYPE), nodes.Literal("5", symbols.INTEGER_TYPE) ])]) assert isinstance(aref.children[0], nodes.ArrayMember) assert aref.children[0].name == "data" assert isinstance(aref.children[0].children[1], nodes.Literal) assert aref.children[0].children[1].value == "5" check_links(aref, aref.children) check_links(aref.children[0], aref.children[0].children) # Reference to an array of structures within a structure structarray_ref = nodes.StructureReference.create( ssym, [("sub_grids", [nodes.Literal("1", symbols.INTEGER_TYPE)])]) assert isinstance(structarray_ref.children[0], nodes.ArrayMember) # Reference to a scalar member of an element of an array of structures # contained in a structure dref = nodes.StructureReference.create( ssym, [("sub_grids", [nodes.Literal("2", symbols.INTEGER_TYPE)]), "startx"]) assert isinstance(dref.children[0], nodes.ArrayOfStructuresMember) assert isinstance(dref.children[0].children[0], nodes.Member) assert isinstance(dref.children[0].children[1], nodes.Literal) check_links(dref, dref.children) check_links(dref.children[0], dref.children[0].children)
def test_struc_ref_str(): ''' Test the __str__ method of StructureReference. ''' grid_type = symbols.StructureType.create([ ("nx", symbols.INTEGER_TYPE, symbols.Symbol.Visibility.PUBLIC) ]) grid_type_symbol = symbols.DataTypeSymbol("grid_type", grid_type) ssym = symbols.DataSymbol("grid", grid_type_symbol) # Reference to scalar member of structure sref = nodes.StructureReference.create(ssym, ["nx"]) assert (str(sref) == "StructureReference[name:'grid']\n" "Member[name:'nx']")
def test_ast_str(): ''' Test that the __str__ method of the StructureReference class works OK when we have an ArrayOfStructuresReference. ''' grid_type = symbols.StructureType.create([ ("nx", symbols.INTEGER_TYPE, symbols.Symbol.Visibility.PUBLIC)]) grid_type_symbol = symbols.DataTypeSymbol("grid_type", grid_type) grid_array_type = symbols.ArrayType(grid_type_symbol, [5]) ssym = symbols.DataSymbol("grid", grid_array_type) asref = nodes.ArrayOfStructuresReference.create( ssym, [nodes.Literal("2", symbols.INTEGER_TYPE)], ["nx"]) assert (str(asref) == "ArrayOfStructuresReference[name:'grid']\n" "Member[name:'nx']\n" "Literal[value:'2', Scalar<INTEGER, UNDEFINED>]")
def test_reference_accesses(): ''' Test the reference_accesses method. ''' dref = nodes.StructureReference.create( symbols.DataSymbol( "grid", symbols.DataTypeSymbol("grid_type", symbols.DeferredType())), ["data"]) var_access_info = VariablesAccessInfo() dref.reference_accesses(var_access_info) assert var_access_info.all_signatures == [Signature(("grid", "data"))] # By default all accesses are marked as read assert str(var_access_info) == "grid%data: READ"
def test_struc_ref_semantic_nav(): ''' Test the 'member' property of the StructureReference. ''' grid_type = symbols.StructureType.create([ ("nx", symbols.INTEGER_TYPE, symbols.Symbol.Visibility.PUBLIC) ]) grid_type_symbol = symbols.DataTypeSymbol("grid_type", grid_type) ssym = symbols.DataSymbol("grid", grid_type_symbol) # Reference to scalar member of structure sref = nodes.StructureReference.create(ssym, ["nx"]) assert sref.member is sref.children[0] # Break the first child to check that we get the expected error sref._children = ["broken"] with pytest.raises(InternalError) as err: _ = sref.member assert ("StructureReference malformed or incomplete. It must have a " "single child that must be a (sub-class of) Member, but " "found: ['broken']" in str(err.value))
def test_struc_ref_validate_child(): ''' Tests for the _validate_child method. ''' grid_type = symbols.StructureType.create([ ("nx", symbols.INTEGER_TYPE, symbols.Symbol.Visibility.PUBLIC) ]) grid_type_symbol = symbols.DataTypeSymbol("grid_type", grid_type) ssym = symbols.DataSymbol("grid", grid_type_symbol) # Reference to scalar member of structure sref = nodes.StructureReference.create(ssym, ["nx"]) # a StructureReference is only allowed (at most) one child. with pytest.raises(GenerationError) as err: sref.addchild("wrong") assert ("Item 'str' can't be child 1 of 'StructureReference'" in str(err.value)) # If present, the first child has to be a MemberReference with pytest.raises(GenerationError) as err: sref.children[0] = "wrong" assert ("Item 'str' can't be child 0 of 'StructureReference'" in str(err.value))
def test_struc_ref_create_errors(): ''' Tests for the validation checks in the create method. ''' with pytest.raises(TypeError) as err: _ = nodes.StructureReference.create(None, []) assert ("'symbol' argument to StructureReference.create() should be a " "DataSymbol but found 'NoneType'" in str(err.value)) with pytest.raises(TypeError) as err: _ = nodes.StructureReference.create( symbols.DataSymbol("fake", symbols.INTEGER_TYPE), []) assert ("symbol that is (or could be) a structure, however symbol " "'fake' has type 'Scalar" in str(err.value)) with pytest.raises(TypeError) as err: _ = nodes.StructureReference.create( symbols.DataSymbol("grid", symbols.DeferredType()), 1) assert ("'members' argument to StructureReference._create() must be a " "list but found 'int'" in str(err.value)) with pytest.raises(ValueError) as err: _ = nodes.StructureReference.create( symbols.DataSymbol("grid", symbols.DeferredType()), []) assert ("one or more structure 'members' that are being accessed but " "got an empty list for symbol 'grid'" in str(err.value)) grid_type = symbols.StructureType.create([ ("nx", symbols.INTEGER_TYPE, symbols.Symbol.Visibility.PUBLIC) ]) tsymbol_known = symbols.DataTypeSymbol("grid_type", grid_type) with pytest.raises(TypeError) as err: _ = nodes.StructureReference.create( symbols.DataSymbol("grid", tsymbol_known), [1]) assert ("'members' passed to StructureType._create() must consist of " "either 'str' or 2-tuple entries but found 'int' in the last " "entry while attempting to create reference to symbol 'grid'" in str(err.value)) with pytest.raises(TypeError) as err: _ = nodes.StructureReference.create( symbols.DataSymbol("grid", tsymbol_known), [1, "hello"]) assert ("'members' passed to StructureType._create() must consist of " "either 'str' or 2-tuple entries but found 'int' while " "attempting to create reference to symbol 'grid'" in str(err.value))
def test_am_is_lower_upper_bound(): ''' Test the is_lower/upper_bound methods of ArrayMember. ''' one = nodes.Literal("1", symbols.INTEGER_TYPE) two = nodes.Literal("2", symbols.INTEGER_TYPE) amem1 = nodes.ArrayMember.create( "subdomains", [one.copy(), nodes.Literal("2", symbols.INTEGER_TYPE)]) assert amem1.is_lower_bound(0) is False assert amem1.is_upper_bound(0) is False grid_type = symbols.DataTypeSymbol("grid_type", symbols.DeferredType()) sym = symbols.DataSymbol("grid_var", grid_type) ref = nodes.StructureReference.create(sym, ["data"]) # Start and stop for the range are binary operators but not the right ones start = nodes.operation.BinaryOperation.create( nodes.operation.BinaryOperation.Operator.UBOUND, ref.copy(), one.copy()) stop = nodes.operation.BinaryOperation.create( nodes.operation.BinaryOperation.Operator.LBOUND, ref.copy(), one.copy()) my_range = nodes.Range.create(start, stop) sref = nodes.StructureReference.create(sym, [("data", [my_range])]) amem2 = sref.walk(nodes.ArrayMember)[0] assert amem2.is_lower_bound(0) is False assert amem2.is_upper_bound(0) is False # Correct binary operators but wrong types of operand start = nodes.operation.BinaryOperation.create( nodes.operation.BinaryOperation.Operator.LBOUND, one.copy(), one.copy()) stop = nodes.operation.BinaryOperation.create( nodes.operation.BinaryOperation.Operator.UBOUND, one.copy(), one.copy()) my_range = nodes.Range.create(start, stop) sref = nodes.StructureReference.create(sym, [("data", [my_range])]) amem2 = sref.walk(nodes.ArrayMember)[0] assert amem2.is_lower_bound(0) is False assert amem2.is_upper_bound(0) is False # Correct start and stop arguments to Range start = nodes.operation.BinaryOperation.create( nodes.operation.BinaryOperation.Operator.LBOUND, ref.copy(), one.copy()) stop = nodes.operation.BinaryOperation.create( nodes.operation.BinaryOperation.Operator.UBOUND, ref.copy(), one.copy()) my_range = nodes.Range.create(start, stop) sref = nodes.StructureReference.create(sym, [("data", [my_range])]) amem2 = sref.walk(nodes.ArrayMember)[0] assert amem2.is_lower_bound(0) is True assert amem2.is_upper_bound(0) is True # Range in a dimension other than the first start = nodes.operation.BinaryOperation.create( nodes.operation.BinaryOperation.Operator.LBOUND, ref.copy(), two.copy()) stop = nodes.operation.BinaryOperation.create( nodes.operation.BinaryOperation.Operator.UBOUND, ref.copy(), two.copy()) my_range = nodes.Range.create(start, stop) sref = nodes.StructureReference.create(sym, [("data", [one.copy(), my_range])]) amem2 = sref.walk(nodes.ArrayMember)[0] assert amem2.is_lower_bound(0) is False assert amem2.is_upper_bound(0) is False assert amem2.is_lower_bound(1) is True assert amem2.is_upper_bound(1) is True
def test_am_matching_access(): ''' Test the _matching_access method of ArrayMember. ''' one = nodes.Literal("1", symbols.INTEGER_TYPE) two = nodes.Literal("2", symbols.INTEGER_TYPE) amem1 = nodes.ArrayMember.create( "subdomains", [one.copy(), nodes.Literal("2", symbols.INTEGER_TYPE)]) # Check when the ArrayMember has no parent Reference result = amem1._matching_access( nodes.Reference(symbols.DataSymbol("fake", symbols.INTEGER_TYPE))) assert result is False grid_type = symbols.DataTypeSymbol("grid_type", symbols.DeferredType()) sym1 = symbols.DataSymbol("grid_var", grid_type) sym2 = symbols.DataSymbol("grid_var2", grid_type) ref1 = nodes.StructureReference.create(sym1, ["data"]) # Reference is to a different symbol ref2 = nodes.StructureReference.create(sym2, [("data", [one.copy()])]) assert ref2.member._matching_access(ref1) is False # Reference is to a different member of the same symbol ref2 = nodes.StructureReference.create(sym1, [("xvals", [one.copy()])]) assert ref2.member._matching_access(ref1) is False ref1 = nodes.StructureReference.create(sym1, [("data", [one.copy()]), ("xobs", [one.copy()])]) ref2 = nodes.StructureReference.create(sym1, [("data", [one.copy()])]) assert ref2.member._matching_access(ref1) is True ref2 = nodes.StructureReference.create(sym1, [("data", [one.copy()]), ("yobs", [one.copy()])]) amem = ref2.member.member # "yobs" assert amem._matching_access(ref1) is False # The same 'signature' (a%b%c) but where b is an array access in one # case. This may not be possible in Fortran but we need to exercise # all conditions. ref1 = nodes.StructureReference.create(sym1, [("a", [one.copy()]), "b", "c"]) ref2 = nodes.StructureReference.create(sym1, [("a", [one.copy()]), ("b", [one.copy()]), ("c", [one.copy()])]) amem = ref2.walk(nodes.ArrayMember)[0] assert amem._matching_access(ref1) is False # Same 'signature' but with one array access having more dimensions. ref1 = nodes.StructureReference.create(sym1, [("a", [one.copy()]), ("b", [one.copy()]), ("c", [one.copy()])]) ref2 = nodes.StructureReference.create( sym1, [("a", [one.copy()]), ("b", [one.copy(), one.copy()]), ("c", [one.copy()])]) amem = ref2.walk(nodes.ArrayMember)[0] assert amem._matching_access(ref1) is False # Same 'signature' but with one array access having a different index. ref1 = nodes.StructureReference.create( sym1, [("a", [one.copy()]), ("b", [one.copy(), one.copy()]), ("c", [one.copy()])]) ref2 = nodes.StructureReference.create( sym1, [("a", [one.copy()]), ("b", [one.copy(), two.copy()]), ("c", [one.copy()])]) amem = ref2.walk(nodes.ArrayMember)[0] assert amem._matching_access(ref1) is False # Reference to an element of the same array ref1 = nodes.StructureReference.create(sym1, ["data"]) ref2 = nodes.StructureReference.create(sym1, [("data", [one.copy()])]) assert ref2.member._matching_access(ref1) is True # Reference to an ArrayOfStructures array_sym = symbols.DataSymbol("grids", symbols.ArrayType(grid_type, [two.copy()])) ref1 = nodes.ArrayOfStructuresReference.create(array_sym, [one.copy()], ["data"]) assert ref1._matching_access(nodes.Reference(array_sym)) # member being compared is not at the bottom of a derived-type access ref1 = nodes.StructureReference.create(sym1, [("a", [one.copy()]), ("b", [one.copy()]), ("d", [one.copy()])]) ref2 = nodes.StructureReference.create(sym1, [("a", [one.copy()]), ("b", [one.copy()]), ("c", [one.copy()])]) amem = ref2.member.member assert amem.name == "b" assert amem._matching_access(ref1)