Beispiel #1
0
def test_unknown_fortran_type():
    ''' Check the constructor and 'declaration' property of the
    UnknownFortranType class. '''
    with pytest.raises(TypeError) as err:
        UnknownFortranType(1)
    assert ("constructor expects the original variable declaration as a "
            "string but got an argument of type 'int'" in str(err.value))
    decl = "type(some_type) :: var"
    utype = UnknownFortranType(decl)
    assert str(utype) == "UnknownFortranType('" + decl + "')"
    assert utype.declaration == decl
Beispiel #2
0
def test_name_clash_derived_type_def(f2008_parser):
    ''' Check that the frontend raises an error if it encounters a definition
    of a derived type with a name that clashes with another symbol. '''
    fake_parent = KernelSchedule("dummy_schedule")
    symtab = fake_parent.symbol_table
    # Add a RoutineSymbol to the symbol table that will clash with the name
    # of the derived type.
    symtab.add(RoutineSymbol("my_type"))
    # Add a DataTypeSymbol to the symbol table. Make it appear that we've
    # already seen a definition of this symbol by making it of
    # UnknownFortranType.
    symtab.new_symbol("my_type2",
                      symbol_type=DataTypeSymbol,
                      datatype=UnknownFortranType("huh"))
    processor = Fparser2Reader()
    fparser2spec = f2008_parser(
        FortranStringReader("subroutine my_sub()\n"
                            "  type :: my_type\n"
                            "    integer :: flag\n"
                            "  end type my_type\n"
                            "end subroutine my_sub\n"))
    # This should raise an error because the Container symbol table will
    # already contain a RoutineSymbol named 'my_type'
    with pytest.raises(SymbolError) as err:
        processor.process_declarations(fake_parent, fparser2spec.content, [])
    assert ("Error processing definition of derived type 'my_type'. The "
            "symbol table already contains an entry with this name but it is a"
            " 'RoutineSymbol' when it should be a 'DataTypeSymbol' (for the "
            "derived-type definition 'TYPE :: my_type\n  INTEGER :: flag\n"
            "END TYPE my_type')" in str(err.value))
    # Repeat but with a derived-type name that will clash with our existing
    # DataTypeSymbol
    fparser2spec = f2008_parser(
        FortranStringReader("subroutine my_sub2()\n"
                            "  type :: my_type2\n"
                            "    integer :: flag\n"
                            "  end type my_type2\n"
                            "end subroutine my_sub2\n"))
    with pytest.raises(SymbolError) as err:
        processor.process_declarations(fake_parent, fparser2spec.content, [])
    assert ("Error processing definition of derived type 'my_type2'. The "
            "symbol table already contains a DataTypeSymbol with this name but"
            " it is of type 'UnknownFortranType' when it should be of "
            "'DeferredType'" in str(err.value))
Beispiel #3
0
    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