Reference Guide  2.5.0
reference.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 and S. Siso, STFC Daresbury Lab
35 # I. Kavcic, Met Office
36 # J. Henrichs, Bureau of Meteorology
37 # Modified A. B. G. Chalk and N. Nobre, STFC Daresbury Lab
38 # -----------------------------------------------------------------------------
39 
40 ''' This module contains the implementation of the Reference node.'''
41 
42 
43 from psyclone.core import AccessType, Signature, VariablesAccessInfo
44 # We cannot import from 'nodes' directly due to circular import
45 from psyclone.psyir.nodes.datanode import DataNode
46 from psyclone.psyir.symbols import Symbol
47 from psyclone.psyir.symbols.datatypes import UnresolvedType
48 
49 
51  '''
52  Node representing a Reference Expression.
53 
54  :param symbol: the symbol being referenced.
55  :type symbol: :py:class:`psyclone.psyir.symbols.Symbol`
56  :param kwargs: additional keyword arguments provided to the super class.
57  :type kwargs: unwrapped dict.
58 
59  '''
60  # Textual description of the node.
61  _children_valid_format = "<LeafNode>"
62  _text_name = "Reference"
63  _colour = "yellow"
64 
65  def __init__(self, symbol, **kwargs):
66  super().__init__(**kwargs)
67  self.symbolsymbolsymbolsymbol = symbol
68 
69  def __eq__(self, other):
70  '''
71  Checks equivalence of two References. References are considered
72  equivalent if they are the same type of Reference and their symbol
73  name is the same.
74 
75  :param object other: the object to check equality to.
76 
77  :returns: whether other is equal to self.
78  :rtype: bool
79  '''
80  is_eq = super().__eq__(other)
81  # TODO #1698. Is reference equality enough comparing the symbols by
82  # name? (Currently it is needed because symbol equality is not fully
83  # implemented)
84  is_eq = is_eq and (self.symbolsymbolsymbolsymbol.name == other.symbol.name)
85  return is_eq
86 
87  @property
88  def is_array(self):
89  '''
90  :returns: whether this reference is an array, False if it can not be
91  determined.
92  :rtype: bool
93 
94  '''
95  return self.symbolsymbolsymbolsymbol.is_array
96 
97  @property
98  def symbol(self):
99  ''' Return the referenced symbol.
100 
101  :returns: the referenced symbol.
102  :rtype: :py:class:`psyclone.psyir.symbols.Symbol`
103 
104  '''
105  return self._symbol_symbol
106 
107  @symbol.setter
108  def symbol(self, symbol):
109  '''
110  :param symbol: the new symbol being referenced.
111  :type symbol: :py:class:`psyclone.psyir.symbols.Symbol`
112 
113  :raises TypeError: if the symbol argument is not of type Symbol.
114 
115  '''
116  if not isinstance(symbol, Symbol):
117  raise TypeError(
118  f"The {type(self).__name__} symbol setter expects a PSyIR "
119  f"Symbol object but found '{type(symbol).__name__}'.")
120  self._symbol_symbol = symbol
121 
122  @property
123  def name(self):
124  ''' Return the name of the referenced symbol.
125 
126  :returns: Name of the referenced symbol.
127  :rtype: str
128 
129  '''
130  return self._symbol_symbol.name
131 
132  def node_str(self, colour=True):
133  ''' Create a text description of this node in the schedule, optionally
134  including control codes for colour.
135 
136  :param bool colour: whether or not to include colour control codes.
137 
138  :return: text description of this node.
139  :rtype: str
140  '''
141  return f"{self.coloured_name(colour)}[name:'{self.name}']"
142 
143  def __str__(self):
144  return self.node_strnode_strnode_str(False)
145 
147  ''':returns: the Signature of this reference, and \
148  an empty list of lists as 'indices' since this reference does \
149  not represent an array access.
150  :rtype: tuple(:py:class:`psyclone.core.Signature`, list of \
151  list of indices)
152  '''
153  return (Signature(self.namename), [[]])
154 
155  def reference_accesses(self, var_accesses):
156  '''Get all variable access information from this node, i.e.
157  it sets this variable to be read. It relies on
158  `get_signature_and_indices` and will correctly handle
159  array expressions.
160 
161  :param var_accesses: VariablesAccessInfo instance that stores the \
162  information about variable accesses.
163  :type var_accesses: \
164  :py:class:`psyclone.core.VariablesAccessInfo`
165 
166  '''
167  sig, all_indices = self.get_signature_and_indicesget_signature_and_indices()
168  if self.symbolsymbolsymbolsymbol.is_import and \
169  var_accesses.options("USE-ORIGINAL-NAMES") and \
170  self.symbolsymbolsymbolsymbol.interface.orig_name:
171  # If the option is set to return the original (un-renamed)
172  # name of an imported symbol, get the original name from
173  # the interface and use it. The rest of the signature is
174  # used from the original access, it does not change.
175  sig = Signature(self.symbolsymbolsymbolsymbol.interface.orig_name, sig[1:])
176  for indices in all_indices:
177  for index in indices:
178  index.reference_accesses(var_accesses)
179  var_accesses.add_access(sig, AccessType.READ, self, all_indices)
180 
181  @property
182  def datatype(self):
183  '''
184  :returns: the datatype of this reference.
185  :rtype: :py:class:`psyclone.psyir.symbols.DataType`
186 
187  '''
188  # pylint: disable=unidiomatic-typecheck
189  # Use type() directly as we need to ignore inheritance.
190  if type(self.symbolsymbolsymbolsymbol) is Symbol:
191  # We don't even have a DataSymbol
192  return UnresolvedType()
193  return self.symbolsymbolsymbolsymbol.datatype
194 
195  def previous_access(self):
196  '''
197  :returns: the previous reference to the same symbol.
198  :rtype: Optional[:py:class:`psyclone.psyir.nodes.Node`]
199  '''
200  # Avoid circular import
201  # pylint: disable=import-outside-toplevel
202  from psyclone.psyir.nodes.routine import Routine
203  # The scope is as far as the Routine that contains this
204  # Reference.
205  routine = self.ancestorancestor(Routine)
206  # Handle the case when this is a subtree without an ancestor
207  # Routine
208  if routine is None:
209  routine = self.rootroot
210  var_access = VariablesAccessInfo(nodes=routine)
211  signature, _ = self.get_signature_and_indicesget_signature_and_indices()
212  all_accesses = var_access[signature].all_accesses
213  index = -1
214  # Find my position in the VariablesAccesInfo
215  for i, access in enumerate(all_accesses):
216  if access.node is self:
217  index = i
218  break
219 
220  if index > 0:
221  return all_accesses[index-1].node
222  return None
223 
224  def next_access(self):
225  '''
226  :returns: the next reference to the same symbol.
227  :rtype: Optional[:py:class:`psyclone.psyir.nodes.Node`]
228  '''
229  # Avoid circular import
230  # pylint: disable=import-outside-toplevel
231  from psyclone.psyir.nodes.routine import Routine
232  # The scope is as far as the Routine that contains this
233  # Reference.
234  routine = self.ancestorancestor(Routine)
235  # Handle the case when this is a subtree without an ancestor
236  # Routine
237  if routine is None:
238  routine = self.rootroot
239  var_access = VariablesAccessInfo(nodes=routine)
240  signature, _ = self.get_signature_and_indicesget_signature_and_indices()
241  all_accesses = var_access[signature].all_accesses
242  index = len(all_accesses)
243  # Find my position in the VariablesAccesInfo
244  for i, access in enumerate(all_accesses):
245  if access.node is self:
246  index = i
247  break
248 
249  if len(all_accesses) > index+1:
250  return all_accesses[index+1].node
251  return None
252 
253 
254 # For AutoAPI documentation generation
255 __all__ = ['Reference']
def node_str(self, colour=True)
Definition: node.py:483
def ancestor(self, my_type, excluding=None, include_self=False, limit=None, shared_with=None)
Definition: node.py:1161
def reference_accesses(self, var_accesses)
Definition: reference.py:155