Reference Guide  2.5.0
typed_symbol.py
1 # -----------------------------------------------------------------------------
2 # BSD 3-Clause License
3 #
4 # Copyright (c) 2021-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 TypedSymbol class.
40 
41 '''
42 
43 import abc
44 from psyclone.psyir.symbols.data_type_symbol import DataTypeSymbol
45 from psyclone.psyir.symbols.symbol import Symbol
46 
47 
48 class TypedSymbol(Symbol, metaclass=abc.ABCMeta):
49  '''
50  Abstract base class for those Symbols that have an associated datatype.
51 
52  :param str name: name of the symbol.
53  :param datatype: data type of the symbol.
54  :type datatype: :py:class:`psyclone.psyir.symbols.DataType`
55  :param kwargs: additional keyword arguments provided by \
56  :py:class:`psyclone.psyir.symbols.Symbol`
57  :type kwargs: unwrapped dict.
58 
59  '''
60  def __init__(self, name, datatype, **kwargs):
61  self._datatype_datatype = None
62  super(TypedSymbol, self).__init__(name)
63  self._process_arguments_process_arguments_process_arguments(datatype=datatype, **kwargs)
64 
65  def _process_arguments(self, **kwargs):
66  ''' Process the arguments for the constructor and the specialise
67  methods. In this case the datatype argument.
68 
69  :param kwargs: keyword arguments which can be:\n
70  :param datatype: data type of the symbol.\n
71  :type datatype: :py:class:`psyclone.psyir.symbols.DataType`\n
72  and the arguments in :py:class:`psyclone.psyir.symbols.Symbol`
73  :type kwargs: unwrapped dict.
74 
75  :raises AttributeError: if the datatype argument is not given \
76  and it isn't already a property of this symbol.
77 
78  '''
79  if "datatype" in kwargs:
80  self.datatypedatatypedatatypedatatype = kwargs.pop("datatype")
81  elif not hasattr(self, '_datatype'):
82  raise AttributeError(f"Missing mandatory 'datatype' attribute for "
83  f"symbol '{self.name}'.")
84 
85  super(TypedSymbol, self)._process_arguments(**kwargs)
86 
87  @abc.abstractmethod
88  def __str__(self):
89  ''' Abstract method. Must be overridden in sub-class. '''
90 
91  @property
92  def datatype(self):
93  '''
94  :returns: datatype of the TypedSymbol.
95  :rtype: :py:class:`psyclone.psyir.symbols.DataType` or \
96  :py:class:`psyclone.psyir.symbols.DataTypeSymbol`
97  '''
98  return self._datatype_datatype
99 
100  @datatype.setter
101  def datatype(self, value):
102  ''' Setter for the datatype of a TypedSymbol.
103 
104  :param value: new value for datatype.
105  :type value: :py:class:`psyclone.psyir.symbols.DataType` or \
106  :py:class:`psyclone.psyir.symbols.DataTypeSymbol`
107 
108  :raises TypeError: if value is not of the correct type.
109 
110  '''
111  # We can't do this import at the toplevel as we get a circular
112  # dependency with the datatypes module.
113  # pylint: disable=import-outside-toplevel
114  from psyclone.psyir.symbols.datatypes import DataType
115  if not isinstance(value, (DataType, DataTypeSymbol)):
116  raise TypeError(
117  f"The datatype of a {type(self).__name__} must be specified "
118  f"using either a DataType or a DataTypeSymbol but got: "
119  f"'{type(value).__name__}'")
120  self._datatype_datatype = value
121 
122  def copy(self):
123  '''Create and return a copy of this object. Any references to the
124  original will not be affected so the copy will not be referred
125  to by any other object.
126 
127  :returns: A symbol object with the same properties as this \
128  symbol object.
129  :rtype: :py:class:`psyclone.psyir.symbols.TypedSymbol`
130 
131  '''
132  # The constructors for all Symbol-based classes have 'name' as the
133  # first positional argument.
134  return type(self)(self.namename, self.datatypedatatypedatatypedatatype, visibility=self.visibilityvisibilityvisibilityvisibility,
135  interface=self.interfaceinterfaceinterfaceinterfaceinterface)
136 
137  def copy_properties(self, symbol_in):
138  '''Replace all properties in this object with the properties from
139  symbol_in, apart from the name (which is immutable) and visibility.
140 
141  :param symbol_in: the symbol from which the properties are copied.
142  :type symbol_in: :py:class:`psyclone.psyir.symbols.DataSymbol`
143 
144  :raises TypeError: if the argument is not the expected type.
145 
146  '''
147  if not isinstance(symbol_in, TypedSymbol):
148  raise TypeError(f"Argument should be of type 'TypedSymbol' but "
149  f"found '{type(symbol_in).__name__}'.")
150  super(TypedSymbol, self).copy_properties(symbol_in)
151  self._datatype_datatype = symbol_in.datatype
152 
153  def resolve_type(self):
154  ''' If the symbol has an Unresolved datatype, find where it is defined
155  (i.e. an external container) and obtain the properties of the symbol.
156 
157  :returns: this TypedSymbol with its properties updated. This is for \
158  consistency with the equivalent method in the Symbol \
159  class which returns a new Symbol object.
160  :rtype: :py:class:`psyclone.psyir.symbols.TypedSymbol`
161 
162  '''
163  # This import has to be local to this method to avoid circular
164  # dependencies.
165  # pylint: disable=import-outside-toplevel
166  from psyclone.psyir.symbols.datatypes import UnresolvedType
167  if isinstance(self.datatypedatatypedatatypedatatype, UnresolvedType):
168  # Copy all the symbol properties but the interface and
169  # visibility (the latter is determined by the current
170  # scoping unit)
171  tmp = self.interfaceinterfaceinterfaceinterfaceinterface
172  extern_symbol = self.get_external_symbolget_external_symbol()
173  self.copy_propertiescopy_propertiescopy_properties(extern_symbol)
174  self.interfaceinterfaceinterfaceinterfaceinterface = tmp
175 
176  return self
177 
178  @property
179  def is_scalar(self):
180  '''
181  :returns: True if this symbol is a scalar and False otherwise.
182  :rtype: bool
183 
184  '''
185  # This import has to be local to this method to avoid circular
186  # dependencies.
187  # pylint: disable=import-outside-toplevel
188  from psyclone.psyir.symbols.datatypes import ScalarType
189  return isinstance(self.datatypedatatypedatatypedatatype, ScalarType)
190 
191  @property
192  def is_array(self):
193  '''
194  :returns: True if this symbol is an array and False if it is not or
195  there is not enough symbol information to determine it.
196  :rtype: bool
197 
198  '''
199  # This import has to be local to this method to avoid circular
200  # dependencies.
201  # pylint: disable=import-outside-toplevel
203  ArrayType, UnsupportedFortranType)
204  if isinstance(self.datatypedatatypedatatypedatatype, ArrayType):
205  return True
206  return (isinstance(self.datatypedatatypedatatypedatatype, UnsupportedFortranType) and
207  isinstance(self.datatypedatatypedatatypedatatype.partial_datatype, ArrayType))
208 
209  @property
210  def shape(self):
211  '''
212  :returns: shape of the symbol in column-major order (leftmost
213  index is contiguous in memory). Each entry represents
214  an array dimension. If it is 'None' the extent of that
215  dimension is unknown, otherwise it holds an integer
216  literal or a reference to an integer symbol with the
217  extent. If it is an empty list then the symbol
218  represents a scalar.
219  :rtype: List[Optional[:py:class:`psyclone.psyir.nodes.Literal` |
220  :py:class:`psyclone.psyir.nodes.Reference`]]
221 
222  '''
223  if self.is_arrayis_arrayis_array:
224  # pylint: disable=import-outside-toplevel
225  from psyclone.psyir.symbols.datatypes import UnsupportedFortranType
226  if isinstance(self.datatypedatatypedatatypedatatype, UnsupportedFortranType):
227  # An UnsupportedFortranType that has is_array True must have a
228  # partial_datatype.
229  return self._datatype_datatype.partial_datatype.shape
230  return self._datatype_datatype.shape
231  return []
def _process_arguments(self, visibility=None, interface=None)
Definition: symbol.py:115
def copy_properties(self, symbol_in)
Definition: symbol.py:152