36 '''This module contains the ModuleInfo class, which is used to store
37 and cache information about a module: the filename, source code (if requested)
38 and the fparser tree (if requested), and information about any routines it
39 includes, and external symbol usage.
44 from fparser.common.readfortran
import FortranStringReader
45 from fparser.two.Fortran2003
import (Function_Subprogram, Interface_Block,
46 Interface_Stmt, Procedure_Stmt,
47 Subroutine_Subprogram, Use_Stmt)
48 from fparser.two.parser
import ParserFactory
49 from fparser.two.utils
import FortranSyntaxError, walk
60 PSyclone-specific exception for use when an error with the module manager
61 happens - typically indicating that some module information cannot be
64 :param str value: the message associated with the error.
67 def __init__(self, value):
68 PSycloneError.__init__(self, value)
69 self.
valuevaluevalue =
"ModuleInfo error: "+str(value)
75 '''This class stores mostly cached information about modules: it stores
76 the original filename, if requested it will read the file and then caches
77 the plain text file, and if required it will parse the file, and then
78 cache the fparser AST.
80 :param str name: the module name.
81 :param str filename: the name of the source file that stores this module \
86 def __init__(self, name, filename):
87 self.
_name_name = name
125 ''':returns: the name of this module.
129 return self.
_name_name
134 ''':returns: the filename that contains the source code for this \
143 '''Returns the source code for the module. The first time, it
144 will be read from the file, but the data is then cached.
146 :returns: the source code.
149 :raises ModuleInfoError: when the file cannot be read.
154 with open(self.
_filename_filename,
"r", encoding=
'utf-8')
as file_in:
156 except FileNotFoundError
as err:
158 f
"Could not find file '{self._filename}' when trying to "
159 f
"read source code for module '{self._name}'")
from err
165 '''Returns the fparser AST for this module. The first time, the file
166 will be parsed by fparser using the Fortran 2008 standard. The AST is
167 then cached for any future uses.
169 :returns: the fparser AST for this module.
170 :rtype: :py:class:`fparser.two.Fortran2003.Program`
180 parser = ParserFactory().create(std=
"f2008")
188 all_generic_interfaces = []
189 for routine
in walk(self.
_parse_tree_parse_tree, (Function_Subprogram,
190 Subroutine_Subprogram,
192 if isinstance(routine, Interface_Block):
193 all_generic_interfaces.append(routine)
195 routine_name = str(routine.content[0].items[1])
200 for interface
in all_generic_interfaces:
204 name = str(walk(interface, Interface_Stmt)[0].items[0]).lower()
209 for proc_stmt
in walk(interface, Procedure_Stmt):
211 routine_names.extend([str(i)
for i
in
212 proc_stmt.items[0].items])
219 ''':returns: whether the specified routine name is part of this
220 module or not. It will also return False if the file could
232 except FortranSyntaxError:
238 def _extract_import_information(self):
239 '''This internal function analyses a given module source file and
240 caches which modules are imported (in self._used_modules), and which
241 symbol is imported from each of these modules (in
242 self._used_symbols_from_module).
251 except FortranSyntaxError:
254 print(f
"[ModuleInfo._extract_import_information] Syntax error "
255 f
"parsing '{self._filename} - ignored")
258 for use
in walk(parse_tree, Use_Stmt):
260 if str(use.items[0]) ==
"INTRINSIC":
263 mod_name = str(use.items[2])
267 only_list = use.items[4]
272 for symbol
in only_list.children:
273 all_symbols.add(str(symbol))
279 '''This function returns a set of all modules `used` in this
280 module. Fortran `intrinsic` modules will be ignored. The information
281 is based on the fparser parse tree of the module (since fparser can
282 handle more files than PSyir, like LFRic's `constants_mod` which has
283 pre-processor directives).
285 :returns: a set with all imported module names.
296 '''This function returns information about which modules are used by
297 this module, and also which symbols are imported. The return value is
298 a dictionary with the used module name as key, and a set of all
299 imported symbol names as value.
301 :returns: a dictionary that gives for each module name the set \
302 of symbols imported from it.
303 :rtype: dict[str, set[str]]
313 '''Returns the PSyIR representation of this module. This is based
314 on the fparser tree (see get_parse_tree), and the information is
315 cached. If the PSyIR must be modified, it needs to be copied,
316 otherwise the modified tree will be returned from the cache in the
318 If the conversion to PSyIR fails, a dummy FileContainer with an
319 empty Container (module) is returned, which avoids additional error
320 handling in many other subroutines.
321 #TODO 2120: This should be revisited when improving on the error
324 :param routine_name: optional the name of a routine.
325 :type routine_name: Optional[str]
327 :returns: PSyIR representing this module.
328 :rtype: list[:py:class:`psyclone.psyir.nodes.Node`]
331 if self.
_psyir_psyir
is None:
335 except (KeyError, SymbolError, InternalError,
336 FortranSyntaxError)
as err:
337 print(f
"Error trying to parse '{self.filename}': '{err}'")
344 self.
_psyir_psyir = FileContainer(os.path.basename(self.
_filename_filename))
345 module = Container(
"invalid-module")
346 self.
_psyir_psyir.children.append(module)
351 return self.
_psyir_psyir.children[0]
355 '''This function returns a list of function names that might be
356 actually called when the routine `name` is called. In most cases
357 this is exactly name, but in case of a generic subroutine the
358 name might change. For now (since we cannot resolve generic
359 interfaces yet), we return the list of all possible functions that
362 :param str routine_name: the name of the routine to resolve
364 :returns: list of routine name(s) that could be called.
369 if self.
_psyir_psyir
is None:
371 routine_name = routine_name.lower()
373 return [routine_name]
def resolve_routine(self, routine_name)
def contains_routine(self, routine_name)
def _extract_import_information(self)
def get_used_symbols_from_modules(self)
def get_source_code(self)
_used_symbols_from_module
def get_used_modules(self)