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)
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))
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))
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)
def dummy_func(): '''Simple Dummy function that raises SymbolError.''' from psyclone.psyir.symbols import SymbolError raise SymbolError("error")
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)
def fake_import(name): raise SymbolError("Oh dear")