37 ''' This module contains the Call node implementation.'''
39 from collections.abc
import Iterable
50 ''' Node representing a Call. This can be found as a standalone statement
53 TODO #1437: The combined Statement and Expression implementation is simple
54 but it has some shortcomings that may need to be addressed.
56 :param kwargs: additional keyword arguments provided to the PSyIR node.
57 :type kwargs: unwrapped dict.
61 _children_valid_format =
"Reference, [DataNode]*"
65 def __init__(self, **kwargs):
66 super().__init__(**kwargs)
76 Checks whether two nodes are equal. Two Call nodes are equal
77 if their routine members are equal.
79 :param object other: the object to check equality to.
81 :returns: whether other is equal to self.
84 is_eq = super().
__eq__(other)
90 def create(cls, routine, arguments=()):
91 '''Create an instance of class cls given valid instances of a routine
92 symbol, and a list of child nodes (or name and node tuple) for
95 :param routine: the routine that class cls calls.
96 :type routine: py:class:`psyclone.psyir.symbols.RoutineSymbol` |
97 py:class:`psyclone.psyir.nodes.Reference`
98 :param arguments: optional list of arguments for this call, these
99 can be PSyIR nodes or tuples of string,Node for named arguments.
100 :type arguments: Optional[Iterable[\
101 Union[:py:class:`psyclone.psyir.nodes.DataNode`,\
102 Tuple[str, :py:class:`psyclone.psyir.nodes.DataNode`]]]]
104 :returns: an instance of cls.
105 :rtype: :py:class:`psyclone.psyir.nodes.Call` or a subclass thereof.
107 :raises TypeError: if the routine argument is not a RoutineSymbol.
108 :raises GenerationError: if the arguments argument is not an Iterable.
111 if not isinstance(routine, (Reference, RoutineSymbol)):
113 f
"The Call routine argument should be a Reference to a "
114 f
"RoutineSymbol or a RoutineSymbol, but "
115 f
"found '{type(routine).__name__}'.")
117 if not isinstance(arguments, Iterable):
119 f
"Call.create 'arguments' argument should be an Iterable but "
120 f
"found '{type(arguments).__name__}'.")
123 if isinstance(routine, Reference):
124 call.addchild(routine)
132 def _add_args(call, arguments):
133 '''Internal utility method to add arguments to a call node. These are
134 added as child nodes.
136 :param call: the supplied call node.
137 :type call: :py:class:`psyclone.psyir.nodes.Call`
138 :param arguments: list of arguments for this call, these
139 can be PSyIR nodes or tuples of string,Node for named arguments.
140 :type arguments: Iterable[
141 Union[:py:class:`psyclone.psyir.nodes.DataNode`,
142 Tuple[str, :py:class:`psyclone.psyir.nodes.DataNode`]]]
144 :raises GenerationError: if the contents of the arguments
145 argument are not in the expected form or of the expected
149 for arg
in arguments:
151 if isinstance(arg, tuple):
152 if not len(arg) == 2:
154 f
"If a child of the children argument in create "
155 f
"method of Call class is a tuple, it's "
156 f
"length should be 2, but found {len(arg)}.")
157 if not isinstance(arg[0], str):
159 f
"If a child of the children argument in create "
160 f
"method of Call class is a tuple, its first "
161 f
"argument should be a str, but found "
162 f
"{type(arg[0]).__name__}.")
164 call.append_named_arg(name, arg)
167 '''Append a named argument to this call.
169 :param name: the argument name.
170 :type name: Optional[str]
171 :param arg: the argument expression.
172 :type arg: :py:class:`psyclone.psyir.nodes.DataNode`
174 :raises ValueError: if the name argument is already used \
175 for an existing argument.
182 FortranReader.validate_name(name)
184 if check_name
and check_name.lower() == name.lower():
186 f
"The value of the name argument ({name}) in "
187 f
"'append_named_arg' in the 'Call' node is "
188 f
"already used for a named argument.")
193 '''Insert a named argument to the call.
195 :param name: the argument name.
196 :type name: Optional[str]
197 :param arg: the argument expression.
198 :type arg: :py:class:`psyclone.psyir.nodes.DataNode`
199 :param int index: where in the argument list to insert the \
202 :raises ValueError: if the name argument is already used \
203 for an existing argument.
204 :raises TypeError: if the index argument is the wrong type.
211 FortranReader.validate_name(name)
213 if check_name
and check_name.lower() == name.lower():
215 f
"The value of the name argument ({name}) in "
216 f
"'insert_named_arg' in the 'Call' node is "
217 f
"already used for a named argument.")
218 if not isinstance(index, int):
220 f
"The 'index' argument in 'insert_named_arg' in the "
221 f
"'Call' node should be an int but found "
222 f
"{type(index).__name__}.")
229 '''Replace one named argument node with another node keeping the
232 :param str existing_name: the argument name.
233 :param arg: the argument expression.
234 :type arg: :py:class:`psyclone.psyir.nodes.DataNode`
236 :raises TypeError: if the name argument is the wrong type.
237 :raises ValueError: if the name argument is already used \
238 for an existing argument.
239 :raises TypeError: if the index argument is the wrong type.
242 if not isinstance(existing_name, str):
244 f
"The 'name' argument in 'replace_named_arg' in the "
245 f
"'Call' node should be a string, but found "
246 f
"{type(existing_name).__name__}.")
249 if name
is not None and name.lower() == existing_name:
254 f
"The value of the existing_name argument ({existing_name}) "
255 f
"in 'replace_named_arg' in the 'Call' node was not found "
256 f
"in the existing arguments.")
263 def _validate_child(position, child):
265 :param int position: the position to be validated.
266 :param child: a child to be validated.
267 :type child: :py:class:`psyclone.psyir.nodes.Node`
269 :return: whether the given child and position are valid for this node.
274 return isinstance(child, Reference)
275 return isinstance(child, DataNode)
279 Updates the supplied var_accesses object with information on the
280 arguments passed to this call.
282 TODO #446 - all arguments that are passed by reference are currently
283 marked as having READWRITE access (unless we know that the routine is
284 PURE). We could do better than this if we have the PSyIR of the called
287 :param var_accesses: VariablesAccessInfo instance that stores the
288 information about variable accesses.
289 :type var_accesses: :py:class:`psyclone.core.VariablesAccessInfo`
295 default_access = AccessType.READ
298 default_access = AccessType.READWRITE
305 if isinstance(arg, Reference):
307 sig, indices_list = arg.get_signature_and_indices()
308 var_accesses.add_access(sig, default_access, arg)
310 for indices
in indices_list:
312 idx.reference_accesses(var_accesses)
318 arg.reference_accesses(var_accesses)
320 var_accesses.next_location()
325 :returns: the routine reference that this call calls.
326 :rtype: Optional[py:class:`psyclone.psyir.nodes.Reference`]
335 :returns: the children of this node that represent its arguments.
336 :rtype: list[py:class:`psyclone.psyir.nodes.DataNode`]
345 :returns: whether the routine being called is elemental (provided with
346 an input array it will apply the operation individually to each of
347 the array elements and return an array with the results). If this
348 information is not known then it returns None.
349 :rtype: NoneType | bool
352 return self.
routineroutine.symbol.is_elemental
358 :returns: whether the routine being called is pure (guaranteed to \
359 return the same result when provided with the same argument \
360 values). If this information is not known then it returns None.
361 :rtype: NoneType | bool
364 return self.
routineroutine.symbol.is_pure
369 :returns: whether this call is available on an accelerated device.
376 def argument_names(self):
378 :returns: a list with the name of each argument. If the entry is \
379 None then the argument is a positional argument.
380 :rtype: List[Optional[str]]
385 def _reconcile(self):
386 '''Update the _argument_names values in case child arguments have been
387 removed, added, or re-ordered.
390 new_argument_names = []
393 if id(child) == arg[0]:
394 new_argument_names.append(arg)
397 new_argument_names.append((id(child),
None))
402 Construct a text representation of this node, optionally containing
403 colour control codes.
405 :param bool colour: whether or not to include colour control codes.
407 :returns: description of this PSyIR node.
411 return (f
"{self.coloured_name(colour)}"
412 f
"[name='{self.routine.debug_string()}']")
418 '''Return a copy of this node. This is a bespoke implementation for
419 a Call node that ensures that any internal id's are
420 consistent before and after copying.
422 :returns: a copy of this node and its children.
423 :rtype: :py:class:`psyclone.psyir.node.Node`
430 new_copy = super().
copy()
434 for idx, child
in enumerate(new_copy.arguments):
435 my_tuple = (id(child), new_copy._argument_names[idx][1])
436 new_list.append(my_tuple)
437 new_copy._argument_names = new_list
def append_named_arg(self, name, arg)
def _add_args(call, arguments)
def is_available_on_device(self)
def node_str(self, colour=True)
def insert_named_arg(self, name, arg, index)
def replace_named_arg(self, existing_name, arg)
def create(cls, routine, arguments=())
def reference_accesses(self, var_accesses)
def children(self, my_children)
def node_str(self, colour=True)