def test_create_structuretype(): ''' Test the create() method of StructureType. ''' # One member will have its type defined by a DataTypeSymbol tsymbol = DataTypeSymbol("my_type", DeferredType()) stype = StructureType.create([ ("fred", INTEGER_TYPE, Symbol.Visibility.PUBLIC), ("george", REAL_TYPE, Symbol.Visibility.PRIVATE), ("barry", tsymbol, Symbol.Visibility.PUBLIC)]) assert len(stype.components) == 3 george = stype.lookup("george") assert isinstance(george, StructureType.ComponentType) assert george.name == "george" assert george.datatype == REAL_TYPE assert george.visibility == Symbol.Visibility.PRIVATE barry = stype.lookup("barry") assert isinstance(barry, StructureType.ComponentType) assert barry.datatype is tsymbol assert barry.visibility == Symbol.Visibility.PUBLIC with pytest.raises(TypeError) as err: StructureType.create([ ("fred", INTEGER_TYPE, Symbol.Visibility.PUBLIC), ("george", Symbol.Visibility.PRIVATE)]) assert ("Each component must be specified using a 3-tuple of (name, " "type, visibility) but found a tuple with 2 members: (" "'george', " in str(err.value))
def test_create_datatypesymbol(): ''' Check that a basic DataTypeSymbol can be created with the expected properties. ''' sym = DataTypeSymbol("my_type", DeferredType()) assert sym.name == "my_type" assert isinstance(sym.datatype, DeferredType) assert str(sym) == "my_type : DataTypeSymbol"
def test_create_datatypesymbol_wrong_datatype(): ''' Check that attempting to specify the type of a DataTypeSymbol with an invalid type results in the expected error. ''' sym = DataTypeSymbol("my_type", DeferredType()) with pytest.raises(TypeError) as err: sym.datatype = "integer" assert ("datatype of a DataTypeSymbol must be specified using a " "DataType but got: 'str'" in str(err.value))
def test_create_struct_reference(): ''' Tests for the _create_struct_reference() utility. ''' one = Literal("1", INTEGER_TYPE) with pytest.raises(InternalError) as err: _create_struct_reference(None, StructureReference, Symbol("fake"), ["hello", 1], []) assert ("List of members must contain only strings or tuples but found " "entry of type 'int'" in str(err.value)) with pytest.raises(NotImplementedError) as err: _create_struct_reference(None, StructureType, Symbol("fake"), ["hello"], []) assert "Cannot create structure reference for type '" in str(err.value) with pytest.raises(InternalError) as err: _create_struct_reference(None, StructureReference, DataSymbol("fake", DeferredType()), ["hello"], [one.copy()]) assert ("Creating a StructureReference but array indices have been " "supplied" in str(err.value)) with pytest.raises(InternalError) as err: _create_struct_reference(None, ArrayOfStructuresReference, DataSymbol("fake", DeferredType()), ["hello"], []) assert ("Cannot create an ArrayOfStructuresReference without one or more " "index expressions" in str(err.value)) ref = _create_struct_reference(None, StructureReference, DataSymbol("fake", DeferredType()), ["hello"], []) assert isinstance(ref, StructureReference) assert isinstance(ref.member, Member) assert ref.member.name == "hello" # Check that we can create an ArrayOfStructuresReference and that any # PSyIR nodes are copied. idx_var = one.copy() idx_var2 = one.copy() aref = _create_struct_reference(None, ArrayOfStructuresReference, DataSymbol("fake", DeferredType()), ["a", ("b", [idx_var2])], [idx_var]) assert isinstance(aref, ArrayOfStructuresReference) assert isinstance(aref.member, StructureMember) assert aref.member.name == "a" assert aref.member.member.name == "b" assert len(aref.member.member.indices) == 1 assert aref.member.member.indices[0] is not idx_var2 assert len(aref.indices) == 1 assert aref.indices[0] is not idx_var
def test_arraytype_datatypesymbol(): ''' Test that we can correctly create an ArrayType when the type of the elements is specified as a DataTypeSymbol. ''' tsym = DataTypeSymbol("my_type", DeferredType()) atype = ArrayType(tsym, [5]) assert isinstance(atype, ArrayType) assert len(atype.shape) == 1 assert atype.intrinsic is tsym assert atype.precision is None
def test_datatypesymbol_copy(): ''' Check that a DataTypeSymbol can be copied. ''' symbol = DataTypeSymbol("my_type", DeferredType(), visibility=Symbol.Visibility.PRIVATE, interface=UnresolvedInterface()) new_symbol = symbol.copy() assert new_symbol is not symbol assert new_symbol.name == "my_type" assert isinstance(new_symbol.datatype, DeferredType) assert new_symbol.visibility == Symbol.Visibility.PRIVATE assert isinstance(new_symbol.interface, UnresolvedInterface)
def test_datasymbol_constant_value_setter_invalid(): '''Test that a DataSymbol constant value setter raises the appropriate error if an invalid value and/or datatype are given.''' # Test with invalid constant values sym = DataSymbol('a', DeferredType()) with pytest.raises(ValueError) as error: sym.constant_value = 1.0 assert ("Error setting constant value for symbol 'a'. A DataSymbol with " "a constant value must be a scalar or an array but found " "'DeferredType'." in str(error.value)) # Test with invalid constant expressions ct_expr = Return() with pytest.raises(ValueError) as error: _ = DataSymbol('a', INTEGER_SINGLE_TYPE, constant_value=ct_expr) assert "Error setting constant value for symbol 'a'. PSyIR static " \ "expressions can only contain PSyIR literal, operation or reference" \ " nodes but found:" in str(error.value) with pytest.raises(ValueError) as error: DataSymbol('a', INTEGER_SINGLE_TYPE, interface=ArgumentInterface(), constant_value=9) assert ("Error setting constant value for symbol 'a'. A DataSymbol with " "an ArgumentInterface can not have a constant value." in str(error.value)) with pytest.raises(ValueError) as error: DataSymbol('a', INTEGER_SINGLE_TYPE, constant_value=9.81) assert ("Error setting constant value for symbol 'a'. This DataSymbol " "instance datatype is 'Scalar<INTEGER, SINGLE>' which " "means the constant value is expected to be") in str(error.value) assert "'int'>' but found " in str(error.value) assert "'float'>'." in str(error.value) with pytest.raises(ValueError) as error: DataSymbol('a', CHARACTER_TYPE, constant_value=42) assert ("Error setting constant value for symbol 'a'. This DataSymbol " "instance datatype is 'Scalar<CHARACTER, UNDEFINED>' which " "means the constant value is expected to be") in str(error.value) assert "'str'>' but found " in str(error.value) assert "'int'>'." in str(error.value) with pytest.raises(ValueError) as error: DataSymbol('a', BOOLEAN_TYPE, constant_value="hello") assert ("Error setting constant value for symbol 'a'. This DataSymbol " "instance datatype is 'Scalar<BOOLEAN, UNDEFINED>' which " "means the constant value is expected to be") in str(error.value) assert "'bool'>' but found " in str(error.value) assert "'str'>'." in str(error.value)
def test_datasymbol_initialisation(): '''Test that a DataSymbol instance can be created when valid arguments are given, otherwise raise relevant exceptions.''' # Test with valid arguments assert isinstance(DataSymbol('a', REAL_SINGLE_TYPE), DataSymbol) assert isinstance(DataSymbol('a', REAL_DOUBLE_TYPE), DataSymbol) assert isinstance(DataSymbol('a', REAL4_TYPE), DataSymbol) kind = DataSymbol('r_def', INTEGER_SINGLE_TYPE) real_kind_type = ScalarType(ScalarType.Intrinsic.REAL, kind) assert isinstance(DataSymbol('a', real_kind_type), DataSymbol) # real constants are not currently supported assert isinstance(DataSymbol('a', INTEGER_SINGLE_TYPE), DataSymbol) assert isinstance(DataSymbol('a', INTEGER_DOUBLE_TYPE, constant_value=0), DataSymbol) assert isinstance(DataSymbol('a', INTEGER4_TYPE), DataSymbol) assert isinstance(DataSymbol('a', CHARACTER_TYPE), DataSymbol) assert isinstance(DataSymbol('a', CHARACTER_TYPE, constant_value="hello"), DataSymbol) assert isinstance(DataSymbol('a', BOOLEAN_TYPE), DataSymbol) assert isinstance(DataSymbol('a', BOOLEAN_TYPE, constant_value=False), DataSymbol) array_type = ArrayType(REAL_SINGLE_TYPE, [ArrayType.Extent.ATTRIBUTE]) assert isinstance(DataSymbol('a', array_type), DataSymbol) array_type = ArrayType(REAL_SINGLE_TYPE, [3]) assert isinstance(DataSymbol('a', array_type), DataSymbol) array_type = ArrayType(REAL_SINGLE_TYPE, [3, ArrayType.Extent.ATTRIBUTE]) assert isinstance(DataSymbol('a', array_type), DataSymbol) assert isinstance(DataSymbol('a', REAL_SINGLE_TYPE), DataSymbol) assert isinstance(DataSymbol('a', REAL8_TYPE), DataSymbol) dim = DataSymbol('dim', INTEGER_SINGLE_TYPE, interface=UnresolvedInterface()) array_type = ArrayType(REAL_SINGLE_TYPE, [Reference(dim)]) assert isinstance(DataSymbol('a', array_type), DataSymbol) array_type = ArrayType(REAL_SINGLE_TYPE, [3, Reference(dim), ArrayType.Extent.ATTRIBUTE]) assert isinstance(DataSymbol('a', array_type), DataSymbol) assert isinstance( DataSymbol('a', REAL_SINGLE_TYPE, interface=ArgumentInterface( ArgumentInterface.Access.READWRITE)), DataSymbol) assert isinstance( DataSymbol('a', REAL_SINGLE_TYPE, visibility=Symbol.Visibility.PRIVATE), DataSymbol) assert isinstance(DataSymbol('field', DataTypeSymbol("field_type", DeferredType())), DataSymbol)
def test_datasymbol_resolve_deferred(monkeypatch): ''' Test the datasymbol resolve_deferred method ''' symbola = DataSymbol('a', INTEGER_SINGLE_TYPE) new_sym = symbola.resolve_deferred() # For a DataSymbol (unlike a Symbol), resolve_deferred should always # return the object on which it was called. assert new_sym is symbola module = ContainerSymbol("dummy_module") symbolb = DataSymbol('b', visibility=Symbol.Visibility.PRIVATE, datatype=DeferredType(), interface=GlobalInterface(module)) # Monkeypatch the get_external_symbol() method so that it just returns # a new DataSymbol monkeypatch.setattr(symbolb, "get_external_symbol", lambda: DataSymbol("b", INTEGER_SINGLE_TYPE)) new_sym = symbolb.resolve_deferred() assert new_sym is symbolb assert new_sym.datatype == INTEGER_SINGLE_TYPE assert new_sym.visibility == Symbol.Visibility.PRIVATE assert isinstance(new_sym.interface, GlobalInterface)
''' _, invoke_info = get_invoke("explicit_do.f90", api=API, idx=0) schedule = invoke_info.schedule assignments = schedule.walk(Assignment) assert len(assignments) == 1 assignment = assignments[0] array_ref = assignment.lhs with pytest.raises(IndexError): _ = get_outer_index(array_ref) @pytest.mark.parametrize( "datatype", [REAL_TYPE, ArrayType(INTEGER_TYPE, [10]), DeferredType()]) def test_loop_variable_name_error(datatype): '''Check that the expected exception is raised when the config file specifies a loop iteration name but it is already declared in the code as something that is not a scalar. ''' _, invoke_info = get_invoke("implicit_do.f90", api=API, idx=0) schedule = invoke_info.schedule assignment = schedule[0] array_ref = assignment.lhs trans = NemoArrayRange2LoopTrans() symbol_table = schedule.symbol_table symbol_table.add(DataSymbol("jk", datatype)) with pytest.raises(TransformationError) as info: trans.apply(array_ref.children[2])
SCALAR_TYPE = ScalarType(ScalarType.Intrinsic.REAL, REAL_KIND) # Derived-type definition in container GRID_TYPE = StructureType.create([ ("dx", SCALAR_TYPE, Symbol.Visibility.PUBLIC), ("dy", SCALAR_TYPE, Symbol.Visibility.PUBLIC)]) GRID_TYPE_SYMBOL = TypeSymbol("grid_type", GRID_TYPE) CONTAINER_SYMBOL_TABLE.add(GRID_TYPE_SYMBOL) # Kernel symbol table, symbols and scalar datatypes SYMBOL_TABLE = SymbolTable() CONT = ContainerSymbol("kernel_mod") SYMBOL_TABLE.add(CONT) DTYPE_SYMBOL = TypeSymbol("other_type", DeferredType(), interface=GlobalInterface(CONT)) SYMBOL_TABLE.add(DTYPE_SYMBOL) # Create the definition of the 'field_type' FIELD_TYPE_DEF = StructureType.create( [("data", ArrayType(SCALAR_TYPE, [10]), Symbol.Visibility.PUBLIC), ("grid", GRID_TYPE_SYMBOL, Symbol.Visibility.PUBLIC), ("sub_meshes", ArrayType(GRID_TYPE_SYMBOL, [3]), Symbol.Visibility.PUBLIC), ("flag", INTEGER4_TYPE, Symbol.Visibility.PUBLIC)]) FIELD_TYPE_SYMBOL = TypeSymbol("field_type", FIELD_TYPE_DEF) CONTAINER_SYMBOL_TABLE.add(FIELD_TYPE_SYMBOL) # Create an argument of this derived type. At this point we know only that # DTYPE_SYMBOL refers to a type defined in the CONT container.
def test_deferredtype_str(): '''Test that the DeferredType class str method works as expected.''' data_type = DeferredType() assert str(data_type) == "DeferredType"
def test_deferredtype(): '''Test that the DeferredType class can be created successfully.''' assert isinstance(DeferredType(), DeferredType)
def create(cls, children, symbol_table, ast=None, options=None): ''' Creates a new (sub-class of a) PSyData node with the supplied 'children' nodes as its children. The symbols used by the PSyData API are added to the supplied symbol table. This is a class method so that it acts as a factory for the various sub-classes of PSyDataNode. :param children: the PSyIR nodes that will become children of the \ new PSyData node. :type children: list of :py:class:`psyclone.psyir.nodes.Node` :param symbol_table: the associated SymbolTable to which symbols \ must be added. :type symbol_table: :py:class:`psyclone.psyir.symbols.SymbolTable` :parent ast: reference to fparser2 parse tree for the routine being \ instrumented with PSyData calls. :type ast: :py:class:`fparser.two.Fortran2003.Base` :param options: a dictionary with options for transformations. :type options: dictionary of string:values or None :param str options[prefix"]: a prefix to use for the PSyData module \ name (``prefix_psy_data_mod``) and the PSyDataType \ (``prefix_PSyDataType``) - a "_" will be added automatically. \ It defaults to "", which means the module name used will just be \ ``psy_data_mod``, and the data type ``PSyDataType``. :param (str,str) options["region_name"]: an optional name to use for \ this PSyDataNode, provided as a 2-tuple containing a module name \ followed by a local name. The pair of strings should uniquely \ identify a region unless aggregate information is required \ (and is supported by the runtime library). :raises TypeError: if the supplied children or symbol table are not \ of the correct type. ''' if not isinstance(children, list): raise TypeError("Error in PSyDataNode.create(). The 'children' " "argument must be a list (of PSyIR nodes) but got " "'{0}'".format(type(children).__name__)) if children and not all(isinstance(child, Node) for child in children): raise TypeError( "Error in PSyDataNode.create(). The 'children' argument must " "be a list of PSyIR nodes but it contains: {0}".format( [type(child).__name__ for child in children])) if not isinstance(symbol_table, SymbolTable): raise TypeError( "Error in PSyDataNode.create(). The 'symbol_table' argument " "must be an instance of psyir.symbols.SymbolTable but got " "'{0}'.".format(type(symbol_table).__name__)) data_node = cls(ast=ast, options=options) # Ensure that we have a container symbol for the API access try: csym = symbol_table.lookup_with_tag(data_node.fortran_module) except KeyError: # The tag doesn't exist which means that we haven't already added # this Container as part of a PSyData transformation. csym = ContainerSymbol(data_node.fortran_module) symbol_table.add(csym, tag=data_node.fortran_module) # A PSyData node always contains a Schedule # TODO 435 we can probably get rid of _insert_schedule() once we # do away with the ast argument? # pylint: disable=protected-access sched = data_node._insert_schedule(children=children, ast=ast) data_node.addchild(sched) # The use statement that will be inserted by the update() method. Any # use of a module of the same name that doesn't match this will result # in a NotImplementedError at code-generation time. # TODO #435 remove this when removing the update() method data_node.use_stmt = "use {0}, only: ".format( data_node.fortran_module) + ", ".join(symbol.name for symbol in data_node.imported_symbols) # Add the symbols that will be imported from the module. Use the # PSyData names as tags to ensure we don't attempt to add them more # than once if multiple transformations are applied. for sym in data_node.imported_symbols: symbol_table.symbol_from_tag(sym.name, symbol_type=sym.symbol_type, interface=GlobalInterface(csym), datatype=DeferredType()) # Store the name of the PSyData variable that is used for this # PSyDataNode. This allows the variable name to be shown in str # (and also, calling create_name in gen() would result in the name # being changed every time gen() is called). data_node._var_name = symbol_table.next_available_name( data_node._psy_data_symbol_with_prefix) psydata_type = UnknownFortranType( "type({0}), save, target :: {1}".format(data_node.type_name, data_node._var_name)) symbol_table.new_symbol(data_node._var_name, symbol_type=DataSymbol, datatype=psydata_type) return data_node