Reference Guide  2.5.0
interfaces.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 # Author: S. Siso STFC Daresbury Lab
35 # Modified by: J. Henrichs, Bureau of Meteorology
36 # -----------------------------------------------------------------------------
37 
38 ''' This module contains the SymbolInterface class and its subclasses. '''
39 
40 from enum import Enum
41 
42 # pylint: disable=too-few-public-methods
43 
44 
46  ''' Abstract class of a Symbol Interface '''
47 
48  def copy(self):
49  '''
50  :returns: a copy of this object.
51  :rtype: :py:class:`psyclone.psyir.symbol.SymbolInterface`
52  '''
53  return self.__class__()
54 
55 
57  ''' The symbol is declared without attributes. Its data will live
58  during the local context.
59  '''
60 
61  def __str__(self):
62  return "Automatic"
63 
64 
66  ''' The symbol contains data that is kept alive through the execution
67  of the program.
68  '''
69 
70  def __str__(self):
71  return "Static"
72 
73 
75  ''' The symbol contains data declared in a module scope without additional
76  attributes.
77  '''
78 
79  def __str__(self):
80  return "DefaultModule"
81 
82 
84  ''' We have a symbol with a declaration but PSyclone does not support its
85  attributes. '''
86 
87  def __str__(self):
88  return "Unknown"
89 
90 
92  ''' A symbol declared in the local scope but acts as a global that
93  can be accessed by any scope referencing the same CommonBlock name.'''
94 
95  def __str__(self):
96  return "CommonBlock"
97 
98 
100  ''' We have a symbol but we don't know where it is declared. '''
101 
102  def __str__(self):
103  return "Unresolved"
104 
105 
107  '''Describes the interface to a Symbol that is imported from an
108  external PSyIR container. The symbol can be renamed on import and,
109  if so, its original name in the Container is specified using the
110  optional 'orig_name' argument.
111 
112  :param container_symbol: symbol representing the external container \
113  from which the symbol is imported.
114  :type container_symbol: \
115  :py:class:`psyclone.psyir.symbols.ContainerSymbol`
116  :param Optional[str] orig_name: the name of the symbol in the \
117  external container before it is renamed, or None (the default) if \
118  it is not renamed.
119 
120  :raises TypeError: if the orig_name argument is an unexpected type.
121 
122  '''
123  def __init__(self, container_symbol, orig_name=None):
124  super().__init__()
125  if not isinstance(orig_name, (str, type(None))):
126  raise TypeError(
127  f"ImportInterface orig_name parameter must be of type "
128  f"str or None, but found '{type(orig_name).__name__}'.")
129  self._orig_name_orig_name = orig_name
130  # Use error-checking setter
131  self.container_symbolcontainer_symbolcontainer_symbolcontainer_symbol = container_symbol
132 
133  @property
134  def orig_name(self):
135  '''
136  :returns: the symbol's original name if it is renamed on \
137  import, or None otherwise.
138  :rtype: Optional[str]
139 
140  '''
141  return self._orig_name_orig_name
142 
143  @property
144  def container_symbol(self):
145  '''
146  :return: symbol representing the container containing this Symbol.
147  :rtype: :py:class:`psyclone.psyir.symbols.ContainerSymbol`
148  '''
149  return self._container_symbol_container_symbol
150 
151  @container_symbol.setter
152  def container_symbol(self, value):
153  '''
154  :param value: the ContainerSymbol that imports the symbol with
155  this interface.
156  :type value: :py:class:`psyclone.psyir.symbols.ContainerSymbol`
157 
158  :raises TypeError: if the provided value is not a ContainerSymbol.
159 
160  '''
161  # Avoid circular import
162  # pylint: disable=import-outside-toplevel
163  from psyclone.psyir.symbols import ContainerSymbol
164 
165  if not isinstance(value, ContainerSymbol):
166  raise TypeError(
167  f"ImportInterface container_symbol parameter must be of type"
168  f" ContainerSymbol, but found "
169  f"'{type(value).__name__}'.")
170 
171  self._container_symbol_container_symbol = value
172 
173  def __str__(self):
174  orig_name_str = ""
175  if self.orig_nameorig_name:
176  orig_name_str = f", orig_name='{self.orig_name}'"
177  return (f"Import(container='{self.container_symbol.name}"
178  f"'{orig_name_str})")
179 
180  def __eq__(self, other):
181  if type(other) is not type(self):
182  return False
183  if (self.container_symbolcontainer_symbolcontainer_symbolcontainer_symbol.name.lower() !=
184  other.container_symbol.name.lower()):
185  return False
186  orig_name = self.orig_nameorig_name.lower() if self.orig_nameorig_name else ""
187  other_oname = other.orig_name.lower() if other.orig_name else ""
188  return orig_name == other_oname
189 
190  def copy(self):
191  '''
192  :returns: a copy of this object.
193  :rtype: :py:class:`psyclone.psyir.symbol.SymbolInterface`
194  '''
195  return self.__class__(self.container_symbolcontainer_symbolcontainer_symbolcontainer_symbol, orig_name=self.orig_nameorig_name)
196 
197 
199  '''
200  Captures the interface to a Symbol that is accessed as a routine
201  argument.
202 
203  :param access: specifies how the argument is used in the Schedule
204  :type access: :py:class:`psyclone.psyir.symbols.ArgumentInterface.Access`
205  '''
206 
207  class Access(Enum):
208  '''
209  Enumeration for the different types of access that an Argument
210  Symbol is permitted to have.
211 
212  '''
213 
214  READ = 1
215 
217  WRITE = 2
218 
220  READWRITE = 3
221 
223  UNKNOWN = 4
224 
225  def __init__(self, access=None):
226  super().__init__()
227  self._access = None
228  # Use the setter as that has error checking
229  if not access:
230  self.access = ArgumentInterface.Access.UNKNOWN
231  else:
232  self.access = access
233 
234  @property
235  def access(self):
236  '''
237  :returns: the access-type for this argument.
238  :rtype: :py:class:`psyclone.psyir.symbols.ArgumentInterface.Access`
239  '''
240  return self._access_access
241 
242  @access.setter
243  def access(self, value):
244  '''
245  :param value: the new access type.
246  :type value: :py:class:`psyclon.psyir.symbols.ArgumentInterface.Access`
247 
248  :raises TypeError: if the supplied value is not an \
249  ArgumentInterface.Access
250  '''
251  if not isinstance(value, ArgumentInterface.Access):
252  raise TypeError(
253  f"SymbolInterface.access must be an 'ArgumentInterface.Access'"
254  f" but got '{type(value).__name__}'.")
255  self._access_access = value
256 
257  def __str__(self):
258  return f"Argument({self.access})"
259 
260  def copy(self):
261  '''
262  :returns: a copy of this object.
263  :rtype: :py:class:`psyclone.psyir.symbol.SymbolInterface`
264  '''
265  return self.__class__(access=self.accessaccessaccessaccess)
266 
267 
269  '''The symbol exists in the file through compiler macros or preprocessor
270  directives.
271 
272  Note that this is different from UnresolvedInterface because the backend
273  will not check if is importing statements that could bring them into
274  scope.
275  '''
276  def __str__(self):
277  return "Preprocessor"