Reference Guide  2.5.0
containersymbol.py
1 # -----------------------------------------------------------------------------
2 # BSD 3-Clause License
3 #
4 # Copyright (c) 2017-2024, Science and Technology Facilities Council.
5 # All rights reserved.
6 #
7 # Redistribution and use in source and binary forms, with or without
8 # modification, are permitted provided that the following conditions are met:
9 #
10 # * Redistributions of source code must retain the above copyright notice, this
11 # list of conditions and the following disclaimer.
12 #
13 # * Redistributions in binary form must reproduce the above copyright notice,
14 # this list of conditions and the following disclaimer in the documentation
15 # and/or other materials provided with the distribution.
16 #
17 # * Neither the name of the copyright holder nor the names of its
18 # contributors may be used to endorse or promote products derived from
19 # this software without specific prior written permission.
20 #
21 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 # POSSIBILITY OF SUCH DAMAGE.
33 # -----------------------------------------------------------------------------
34 # Authors R. W. Ford, A. R. Porter, S. Siso and N. Nobre, STFC Daresbury Lab
35 # I. Kavcic, Met Office
36 # J. Henrichs, Bureau of Meteorology
37 # -----------------------------------------------------------------------------
38 
39 ''' This module contains the ContainerSymbol and its interfaces.'''
40 
41 from os import listdir, path
42 from psyclone.psyir.symbols.symbol import Symbol, SymbolError
43 from psyclone.psyir.symbols.interfaces import SymbolInterface
44 from psyclone.configuration import Config
45 
46 
48  ''' Symbol that represents a reference to a Container. The reference
49  is lazy evaluated, this means that the Symbol will be created without
50  parsing and importing the referenced container, but this can be imported
51  when needed.
52 
53  :param str name: name of the symbol.
54  :param bool wildcard_import: if all public Symbols of the Container are \
55  imported into the current scope. Defaults to False.
56  :param kwargs: additional keyword arguments provided by \
57  :py:class:`psyclone.psyir.symbols.Symbol`.
58  :type kwargs: unwrapped dict.
59 
60  '''
61  def __init__(self, name, wildcard_import=False, **kwargs):
62  super(ContainerSymbol, self).__init__(name)
63 
64  self._reference_reference = None
65  self._has_wildcard_import_has_wildcard_import = False
66 
67  self._process_arguments_process_arguments_process_arguments(wildcard_import=wildcard_import, **kwargs)
68 
69  def _process_arguments(self, **kwargs):
70  ''' Process the arguments for the constructor and the specialise
71  methods. In this case the wildcard_import and a change in default
72  value for the interface.
73 
74  :param kwargs: keyword arguments which can be:\n
75  :param bool wildcard_import: if all public Symbols of the \
76  Container are imported into the current scope. Defaults to \
77  False.\n
78  and the arguments in :py:class:`psyclone.psyir.symbols.Symbol`
79  :type kwargs: unwrapped dict.
80 
81  :raises TypeError: if it is provided with an interface argument other \
82  then FortranModuleInterface.
83 
84  '''
85  if not hasattr(self, '_reference'):
86  self._reference_reference = None
87 
88  if "wildcard_import" in kwargs:
89  self.wildcard_importwildcard_importwildcard_importwildcard_import = kwargs.pop("wildcard_import")
90  elif not hasattr(self, '_has_wildcard_import'):
91  self._has_wildcard_import_has_wildcard_import = False
92 
93  # TODO #1298: ContainerSymbol currently defaults to
94  # FortranModuleInterface expecting externally defined containers
95  # which can be imported, but this is not always true.
96  if "interface" not in kwargs or kwargs["interface"] is None:
97  kwargs["interface"] = FortranModuleInterface()
98  elif not isinstance(kwargs["interface"], FortranModuleInterface):
99  raise TypeError(f"A ContainerSymbol interface must be of type '"
100  f"FortranModuleInterface' but found "
101  f"'{type(kwargs['interface']).__name__}' for "
102  f"Container '{self.name}'.")
103  super(ContainerSymbol, self)._process_arguments(**kwargs)
104 
105  def copy(self):
106  '''Create and return a copy of this object. Any references to the
107  original will not be affected so the copy will not be referred
108  to by any other object.
109 
110  :returns: A symbol object with the same properties as this \
111  symbol object.
112  :rtype: :py:class:`psyclone.psyir.symbols.Symbol`
113 
114  '''
115  # Use the generic Symbol copy and add the wildcard import value
116  new_symbol = super(ContainerSymbol, self).copy()
117  new_symbol.wildcard_import = self.wildcard_importwildcard_importwildcard_importwildcard_import
118  return new_symbol
119 
120  @property
121  def container(self):
122  ''' Returns the referenced container. If it is not available, use
123  the interface to import the container
124 
125  :returns: referenced container.
126  :rtype: :py:class:`psyclone.psyir.nodes.Container`
127  '''
128  if not self._reference_reference:
129  self._reference_reference = self._interface_interface.import_container(self._name_name)
130  return self._reference_reference
131 
132  def __str__(self):
133  string = self._name_name + ": ContainerSymbol<"
134  if self._reference_reference:
135  string += "linked>"
136  else:
137  string += "not linked>"
138  return string
139 
140  @property
141  def wildcard_import(self):
142  '''
143  :returns: whether or not there is a wildcard import of all public \
144  symbols from this Container.
145  :rtype: bool
146 
147  '''
148  return self._has_wildcard_import_has_wildcard_import
149 
150  @wildcard_import.setter
151  def wildcard_import(self, value):
152  '''
153  Set whether or not there is a wildcard import of all public symbols
154  from this Container symbol.
155 
156  :param bool value: whether there is or is not a wildcard import.
157 
158  :raises TypeError: if the supplied `value` is not a bool.
159 
160  '''
161  if not isinstance(value, bool):
162  raise TypeError(f"wildcard_import must be a bool but got: "
163  f"'{type(value).__name__}'")
164  self._has_wildcard_import_has_wildcard_import = value
165 
166 
168  ''' Abstract implementation of the ContainerSymbol Interface '''
169 
170  @staticmethod
171  def import_container(name):
172  ''' Abstract method to import an external container, the specific
173  implementation depends on the language used.
174 
175  :param str name: name of the external entity to be imported.
176 
177  :raises NotImplementedError: this is an abstract method.
178  '''
179  raise NotImplementedError("Abstract method")
180 
181 
183  ''' Implementation of ContainerSymbolInterface for Fortran modules '''
184 
185  @staticmethod
186  def import_container(name):
187  ''' Imports a Fortran module as a PSyIR container. The module is
188  expected to be found in a Fortran source file with the same name
189  as the module plus the '.[f|F]90' extension. The search
190  locations are provided in-order by the Config include_paths
191  attribute ('-I' in the psyclone script).
192 
193  :param str name: name of the module to be imported.
194 
195  :returns: container associated with the given name.
196  :rtype: :py:class:`psyclone.psyir.nodes.Container`
197 
198  :raises SymbolError: the given Fortran module is not found on the \
199  import path.
200 
201  '''
202  # pylint: disable=import-outside-toplevel
203  from psyclone.psyir.frontend.fortran import FortranReader
204  for directory in Config.get().include_paths:
205  for filename in [name+'.f90', name+'.F90']:
206  if filename in listdir(directory):
207  # Parse the module source code
208  abspath = path.join(directory, filename)
209  fortran_reader = FortranReader()
210  file_container = fortran_reader.psyir_from_file(abspath)
211  # Check the expected container is in this file
212  for candidate in file_container.children:
213  if candidate.name.lower() == name.lower():
214  return candidate
215  raise ValueError(
216  f"Error importing the Fortran module '{name}' into a "
217  f"PSyIR container. The file with filename "
218  f"'{filename}' does not contain the expected module.")
219 
220  raise SymbolError(
221  f"Module '{name}' (expected to be found in '{name}.[f|F]90') not "
222  f"found in any of the include_paths directories "
223  f"{Config.get().include_paths}.")
224 
225 
226 # For Sphinx AutoAPI documentation generation
227 __all__ = ['ContainerSymbol', 'ContainerSymbolInterface',
228  'FortranModuleInterface']
def _process_arguments(self, visibility=None, interface=None)
Definition: symbol.py:115