38 ''' This module contains the implementation of the StructureReference node. '''
46 ArrayOfStructuresMember)
49 DataTypeSymbol, UnresolvedType, ScalarType,
50 StructureType, UnsupportedType)
56 Node representing a reference to a component of a structure. As such
57 it must have a single child representing the component being accessed.
59 :param symbol: the symbol being referenced.
60 :type symbol: :py:class:`psyclone.psyir.symbols.Symbol`
61 :param kwargs: additional keyword arguments provided to the super class.
62 :type kwargs: unwrapped dict.
66 _children_valid_format =
"Member"
67 _text_name =
"StructureReference"
69 def __init__(self, symbol, **kwargs):
70 super().__init__(symbol=symbol, **kwargs)
74 def _validate_child(position, child):
76 :param int position: the position to be validated.
77 :param child: a child to be validated.
78 :type child: :py:class:`psyclone.psyir.nodes.Node`
80 :return: whether the given child and position are valid for this node.
85 return isinstance(child, Member)
89 def create(symbol, members, parent=None, overwrite_datatype=None):
91 Create a StructureReference instance given a symbol and a
92 list of components. e.g. for "field%bundle(2)%flag" this
93 list would be [("bundle", [Literal("2", INTEGER4_TYPE)]), "flag"].
95 :param symbol: the symbol that this reference is to.
96 :type symbol: :py:class:`psyclone.psyir.symbols.DataSymbol`
97 :param members: the component(s) of the structure that make up \
98 the full access. Any components that are array accesses must \
99 provide the name of the array and a list of DataNodes describing \
100 which part of it is accessed.
101 :type members: list of str or 2-tuples containing (str, \
102 list of nodes describing array access)
103 :param parent: the parent of this node in the PSyIR.
104 :type parent: sub-class of :py:class:`psyclone.psyir.nodes.Node`
105 :param overwrite_datatype: the datatype for the reference, which will \
106 overwrite the value determined by analysing the corresponding \
107 user defined type. This is useful when e.g. the module that \
108 declares the structure cannot be accessed.
109 :type overwrite_datatype: \
110 Optional[:py:class:`psyclone.psyir.symbols.DataType`]
112 :returns: a StructureReference instance.
113 :rtype: :py:class:`psyclone.psyir.nodes.StructureReference`
115 :raises TypeError: if the supplied symbol is not a DataSymbol.
118 if not isinstance(symbol, DataSymbol):
120 f
"The 'symbol' argument to StructureReference.create() "
121 f
"should be a DataSymbol but found '{type(symbol).__name__}'.")
123 if overwrite_datatype
and not isinstance(overwrite_datatype, DataType):
125 f
"The 'overwrite_datatype' argument to "
126 f
"StructureReference.create() should be a DataType but found "
127 f
"'{type(symbol).__name__}'.")
129 return StructureReference.\
130 _create(symbol, symbol.datatype, members, parent=parent,
131 overwrite_datatype=overwrite_datatype)
134 def _create(cls, symbol, symbol_type, members, parent=None,
135 overwrite_datatype=None):
138 Create an instance of `cls` given a symbol, a type and a
139 list of components. e.g. for "field%bundle(2)%flag" this list
140 would be [("bundle", [Literal("2", INTEGER4_TYPE)]), "flag"].
142 This 'internal' method is used by both ArrayOfStructuresReference
143 *and* this class which is why it is a class method with the symbol
144 type as a separate argument.
146 :param symbol: the symbol that this reference is to.
147 :type symbol: :py:class:`psyclone.psyir.symbols.DataSymbol`
148 :param symbol_type: the type of the symbol being referenced.
149 :type symbol_type: :py:class:`psyclone.psyir.symbols.DataTypeSymbol`
150 :param members: the component(s) of the structure that are being \
151 accessed. Any components that are array references must \
152 provide the name of the array and a list of DataNodes describing \
153 which part of it is accessed.
154 :type members: list of str or 2-tuples containing (str, \
155 list of nodes describing array access)
156 :param parent: the parent of this node in the PSyIR.
157 :type parent: sub-class of :py:class:`psyclone.psyir.nodes.Node`
158 :param overwrite_datatype: the datatype for the reference, which will \
159 overwrite the value determined by analysing the corresponding \
160 user defined type. This is useful when e.g. the module that \
161 declares the structure cannot be accessed.
162 :type overwrite_datatype: \
163 Optional[:py:class:`psyclone.psyir.symbols.DataType`]
165 :returns: a StructureReference instance.
166 :rtype: :py:class:`psyclone.psyir.nodes.StructureReference`
168 :raises TypeError: if the arguments to the create method are not of \
170 :raises ValueError: if no members are provided (since this would then \
171 be a Reference as opposed to a StructureReference).
172 :raises NotImplementedError: if any of the structures being referenced\
173 do not have full type information available.
176 if not isinstance(symbol_type, (StructureType, DataTypeSymbol,
177 UnresolvedType, UnsupportedType)):
179 f
"A StructureReference must refer to a symbol that is (or "
180 f
"could be) a structure, however symbol '{symbol.name}' has "
181 f
"type '{symbol_type}'.")
182 if not isinstance(members, list):
184 f
"The 'members' argument to StructureReference._create() "
185 f
"must be a list but found '{type(members).__name__}'.")
188 f
"A StructureReference must include one or more structure "
189 f
"'members' that are being accessed but got an empty list for "
190 f
"symbol '{symbol.name}'")
193 ref = cls(symbol, parent=parent)
197 if isinstance(members[-1], tuple):
199 subref = ArrayMember.create(members[-1][0], members[-1][1])
200 elif isinstance(members[-1], str):
202 subref =
Member(members[-1])
205 f
"The list of 'members' passed to StructureType._create() "
206 f
"must consist of either 'str' or 2-tuple entries but found "
207 f
"'{type(members[-1]).__name__}' in the last entry while "
208 f
"attempting to create reference to symbol '{symbol.name}'")
213 child_member = subref
215 for component
in reversed(members[:-1]):
216 if isinstance(component, tuple):
218 subref = ArrayOfStructuresMember.create(
219 component[0], component[1], subref)
220 elif isinstance(component, str):
222 subref = StructureMember.create(component, subref)
225 f
"The list of 'members' passed to StructureType._create() "
226 f
"must consist of either 'str' or 2-tuple entries but "
227 f
"found '{type(component).__name__}' while attempting to "
228 f
"create reference to symbol '{symbol.name}'")
229 child_member = subref
231 ref.addchild(child_member)
232 ref._overwrite_datatype = overwrite_datatype
236 result = super().__str__()
238 result +=
"\n" + str(entity)
244 :returns: the member of the structure that this reference is to.
245 :rtype: :py:class:`psyclone.psyir.nodes.Member`
247 :raises InternalError: if the first child of this node is not an \
252 f
"{type(self).__name__} malformed or incomplete. It must have "
253 f
"a single child that must be a (sub-class of) Member, but "
254 f
"found: {self.children}")
258 ''':returns: the Signature of this structure reference, and \
259 a list of the indices used for each component (empty list \
260 if an access is not an array).
261 :rtype: Tuple[:py:class:`psyclone.core.Signature`, \
262 List[List[:py:class:`psyclone.psyir.nodes.Node`]]]
270 return (
Signature(my_sig, sub_sig), my_index + indices)
275 Walks down the list of members making up this reference to determine
276 the type that it refers to. If an overwrite datatype was given to this
277 reference, this datatype will be returned instead of determining the
280 In order to minimise code duplication, this method also supports
281 ArrayOfStructuresReference by simply allowing for the case where
282 the starting reference is to an Array.
284 :returns: the datatype of this reference.
285 :rtype: :py:class:`psyclone.psyir.symbols.DataType`
287 :raises NotImplementedError: if the structure reference represents \
297 if isinstance(dtype, ArrayType):
298 dtype = dtype.intrinsic
300 if isinstance(dtype, DataTypeSymbol):
301 dtype = dtype.datatype
303 if isinstance(dtype, (UnresolvedType, UnsupportedType)):
306 dtype = UnresolvedType()
314 if isinstance(cursor, ArrayMixin):
316 shape = cursor._get_effective_shape()
322 while isinstance(cursor, (StructureMember, StructureReference)):
323 cursor = cursor.member
324 if isinstance(cursor_type, ArrayType):
325 cursor_type = cursor_type.intrinsic
326 if isinstance(cursor_type, DataTypeSymbol):
327 cursor_type = cursor_type.datatype
328 if not isinstance(cursor_type, (UnresolvedType, UnsupportedType)):
331 cursor_type = cursor_type.components[cursor.name].datatype
332 if isinstance(cursor, ArrayMixin):
334 shape.extend(cursor._get_effective_shape())
338 if isinstance(cursor_type, ArrayType):
346 cursor_shape = cursor._get_effective_shape()
349 cursor_shape = cursor_type.shape
350 if cursor_shape
and len(shape) != len(cursor_shape):
354 raise NotImplementedError(
355 f
"Array of arrays not supported: the ultimate member "
356 f
"'{cursor.name}' of the StructureAccess represents "
357 f
"an array but other array notation is present in the "
358 f
"full access expression: '{self.debug_string()}'")
360 return ArrayType(cursor_type, shape)
364 if isinstance(cursor_type, ArrayType):
365 if not cursor.children:
373 if isinstance(cursor_type.intrinsic, ScalarType.Intrinsic):
374 return ScalarType(cursor_type.intrinsic, cursor_type.precision)
375 return cursor_type.intrinsic
380 __all__ = [
'StructureReference']
def children(self, my_children)
def create(symbol, members, parent=None, overwrite_datatype=None)
def get_signature_and_indices(self)