Beispiel #1
0
    def swap(self, old_symbol, new_symbol):
        '''
        Remove the `old_symbol` from the table and replace it with the
        `new_symbol`.

        :param old_symbol: the symbol to remove from the table.
        :type old_symbol: :py:class:`psyclone.psyir.symbols.Symbol`
        :param new_symbol: the symbol to add to the table.
        :type new_symbol: :py:class:`psyclone.psyir.symbols.Symbol`

        :raises TypeError: if either old/new_symbol are not Symbols.
        :raises SymbolError: if `old_symbol` and `new_symbol` don't have \
                             the same name.
        '''
        if not isinstance(old_symbol, Symbol):
            raise TypeError("Symbol to remove must be of type Symbol but "
                            "got '{0}'".format(type(old_symbol).__name__))
        if not isinstance(new_symbol, Symbol):
            raise TypeError("Symbol to add must be of type Symbol but "
                            "got '{0}'".format(type(new_symbol).__name__))
        if old_symbol.name != new_symbol.name:
            raise SymbolError(
                "Cannot swap symbols that have different names, got: '{0}' "
                "and '{1}'".format(old_symbol.name, new_symbol.name))
        # TODO #898 remove() does not currently check for any uses of
        # old_symbol.
        self.remove(old_symbol)
        self.add(new_symbol)
Beispiel #2
0
    def scope(self):
        '''Schedule and Container nodes allow symbols to be scoped via an
        attached symbol table. This property returns the closest
        ancestor Schedule or Container node including self.

        :returns: the closest ancestor Schedule or Container node.
        :rtype: :py:class:`psyclone.psyir.node.Node`

        :raises SymbolError: if there is no Schedule or Container ancestor.

        '''
        # These imports have to be local to this method to avoid circular
        # dependencies.
        # pylint: disable=import-outside-toplevel
        from psyclone.psyir.nodes import Schedule, Container
        node = self.ancestor((Container, Schedule), include_self=True)
        if node:
            return node
        raise SymbolError(
            "Unable to find the scope of node '{0}' as none of its ancestors "
            "are Container or Schedule nodes.".format(self))
Beispiel #3
0
    def import_container(name):
        ''' Imports a Fortran module as a PSyIR container. The module is
        expected to be found in a Fortran source file with the same name
        as the module plus the '.[f|F]90' extension. The search
        locations are provided in-order by the Config include_paths
        attribute ('-I' in the psyclone script).

        :param str name: name of the module to be imported.

        :returns: container associated with the given name.
        :rtype: :py:class:`psyclone.psyir.nodes.Container`

        :raises SymbolError: the given Fortran module is not found on the \
            import path.

        '''
        # pylint: disable=import-outside-toplevel
        from psyclone.psyir.frontend.fortran import FortranReader
        for directory in Config.get().include_paths:
            for filename in [name+'.f90', name+'.F90']:
                if filename in listdir(directory):
                    # Parse the module source code
                    abspath = path.join(directory, filename)
                    fortran_reader = FortranReader()
                    file_container = fortran_reader.psyir_from_file(abspath)
                    # Check the expected container is in this file
                    for candidate in file_container.children:
                        if candidate.name.lower() == name.lower():
                            return candidate
                    raise ValueError(
                        "Error importing the Fortran module '{0}' into a "
                        "PSyIR container. The file with filename '{1}' "
                        "does not contain the expected module."
                        "".format(name, filename))

        raise SymbolError(
            "Module '{0}' (expected to be found in '{0}.[f|F]90') not found in"
            " any of the include_paths directories {1}."
            "".format(name, Config.get().include_paths))
Beispiel #4
0
    def symbol_from_tag(self, tag, root_name=None, **new_symbol_args):
        ''' Lookup a tag, if it doesn't exist create a new symbol with the
        given tag. By default it creates a generic Symbol with the tag as the
        root of the symbol name. Optionally, a different root_name or any of
        the arguments available in the new_symbol() method can be given to
        refine the name and the type of the created Symbol.

        :param str tag: tag identifier.
        :param str root_name: optional name of the new symbol if it needs \
                              to be created. Otherwise it is ignored.
        :param new_symbol_args: arguments to create a new symbol.
        :type new_symbol_args: unwrapped Dict[str, object]

        :returns: symbol associated with the given tag.
        :rtype: :py:class:`psyclone.psyir.symbols.Symbol`

        :raises SymbolError: if the symbol already exists but the type_symbol \
                             argument does not match the type of the symbol \
                             found.

        '''
        try:
            symbol = self.lookup_with_tag(tag)
            # Check that the symbol found matches the requested description
            if 'symbol_type' in new_symbol_args:
                symbol_type = new_symbol_args['symbol_type']
                if not isinstance(symbol, new_symbol_args['symbol_type']):
                    raise SymbolError(
                        "Expected symbol with tag '{0}' to be of type '{1}' "
                        "but found type '{2}'.".format(tag,
                                                       symbol_type.__name__,
                                                       type(symbol).__name__))
            # TODO #1057: If the symbol is found and some unmatching arguments
            # were given it should also fail here.
            return symbol
        except KeyError:
            if not root_name:
                root_name = tag
            return self.new_symbol(root_name, tag, **new_symbol_args)
Beispiel #5
0
 def dummy_func():
     '''Simple Dummy function that raises SymbolError.'''
     from psyclone.psyir.symbols import SymbolError
     raise SymbolError("error")
Beispiel #6
0
    def lookup(self, name, visibility=None, scope_limit=None):
        '''Look up a symbol in the symbol table. The lookup can be limited
        by visibility (e.g. just show public methods) or by scope_limit (e.g.
        just show symbols up to a certain scope).

        :param str name: name of the symbol.
        :param visibilty: the visibility or list of visibilities that the \
                          symbol must have.
        :type visibility: [list of] :py:class:`psyclone.symbols.Visibility`
        :param scope_limit: optional Node which limits the symbol \
            search space to the symbol tables of the nodes within the \
            given scope. If it is None (the default), the whole \
            scope (all symbol tables in ancestor nodes) is searched \
            otherwise ancestors of the scope_limit node are not \
            searched.
        :type scope_limit: :py:class:`psyclone.psyir.nodes.Node` or \
            `NoneType`

        :returns: the symbol with the given name and, if specified, visibility.
        :rtype: :py:class:`psyclone.psyir.symbols.Symbol`

        :raises TypeError: if the name argument is not a string.
        :raises SymbolError: if the name exists in the Symbol Table but does \
                             not have the specified visibility.
        :raises TypeError: if the visibility argument has the wrong type.
        :raises KeyError: if the given name is not in the Symbol Table.

        '''
        if not isinstance(name, six.string_types):
            raise TypeError(
                "Expected the name argument to the lookup() method to be "
                "a str but found '{0}'."
                "".format(type(name).__name__))

        try:
            symbol = self.get_symbols(scope_limit)[self._normalize(name)]
            if visibility:
                if not isinstance(visibility, list):
                    vis_list = [visibility]
                else:
                    vis_list = visibility
                if symbol.visibility not in vis_list:
                    vis_names = []
                    # Take care here in case the 'visibility' argument
                    # is of the wrong type
                    for vis in vis_list:
                        if not isinstance(vis, Symbol.Visibility):
                            raise TypeError(
                                "the 'visibility' argument to lookup() must be"
                                " an instance (or list of instances) of "
                                "Symbol.Visibility but got '{0}' when "
                                "searching for symbol '{1}'".format(
                                    type(vis).__name__, name))
                        vis_names.append(vis.name)
                    raise SymbolError(
                        "Symbol '{0}' exists in the Symbol Table but has "
                        "visibility '{1}' which does not match with the "
                        "requested visibility: {2}".format(
                            name, symbol.visibility.name, vis_names))
            return symbol
        except KeyError as err:
            six.raise_from(
                KeyError("Could not find '{0}' in the Symbol Table."
                         "".format(name)), err)
Beispiel #7
0
 def fake_import(name):
     raise SymbolError("Oh dear")