39 '''This module contains the SymbolError class and the generic Symbol class.
45 AutomaticInterface, SymbolInterface, ArgumentInterface,
46 UnresolvedInterface, ImportInterface, UnknownInterface,
47 CommonBlockInterface, DefaultModuleInterface, StaticInterface)
52 PSyclone-specific exception for use with errors relating to the Symbol and
53 SymbolTable in the PSyIR.
55 :param str value: the message associated with the error.
57 def __init__(self, value):
58 PSycloneError.__init__(self, value)
59 self.
valuevaluevalue =
"PSyclone SymbolTable error: "+str(value)
63 '''Generic Symbol item for the Symbol Table and PSyIR References.
64 It has an immutable name label because it must always match with the
65 key in the SymbolTable. If the symbol is private then it is only visible
66 to those nodes that are descendants of the Node to which its containing
69 :param str name: name of the symbol.
70 :param visibility: the visibility of the symbol.
71 :type visibility: :py:class:`psyclone.psyir.symbols.Symbol.Visibility`
72 :param interface: optional object describing the interface to this \
73 symbol (i.e. whether it is passed as a routine argument or \
74 accessed in some other way). Defaults to \
75 :py:class:`psyclone.psyir.symbols.AutomaticInterface`
76 :type interface: Optional[ \
77 :py:class:`psyclone.psyir.symbols.symbol.SymbolInterface`]
79 :raises TypeError: if the name is not a str.
84 ''' Enumeration of the different visibility attributes supported in
85 the PSyIR. If no visibility information is supplied for a Symbol then
86 it is given the DEFAULT_VISIBILITY value.
88 PUBLIC: the symbol is visible in any scoping region that has access to
89 the SymbolTable containing it.
90 PRIVATE: the symbol is only visibile inside the scoping region that
91 contains the SymbolTable to which it belongs.
98 DEFAULT_VISIBILITY = Visibility.PUBLIC
100 def __init__(self, name, visibility=DEFAULT_VISIBILITY, interface=None):
102 if not isinstance(name, str):
104 f
"{type(self).__name__} 'name' attribute should be of type "
105 f
"'str' but '{type(name).__name__}' found.")
110 self._visibility =
None
111 self._interface =
None
113 self._process_arguments(visibility=visibility, interface=interface)
115 def _process_arguments(self, visibility=None, interface=None):
116 ''' Process the visibility and interface arguments of the constructor
117 and the specialise methods.
119 :param visibility: the visibility of the symbol.
120 :type visibility: :py:class:`psyclone.psyir.symbols.Symbol.Visibility`
121 :param interface: optional object describing the interface to this \
122 symbol (i.e. whether it is passed as a routine argument or \
123 accessed in some other way). Defaults to \
124 :py:class:`psyclone.psyir.symbols.AutomaticInterface`
125 :type interface: Optional[ \
126 :py:class:`psyclone.psyir.symbols.symbol.SymbolInterface`]
130 self.interface = interface
131 elif not self.interface:
135 self.visibility = visibility
138 '''Create and return a copy of this object. Any references to the
139 original will not be affected so the copy will not be referred
140 to by any other object.
142 :returns: A symbol object with the same properties as this \
144 :rtype: :py:class:`psyclone.psyir.symbols.Symbol`
153 '''Replace all properties in this object with the properties from
154 symbol_in, apart from the name (which is immutable) and visibility.
156 :param symbol_in: the symbol from which the properties are copied.
157 :type symbol_in: :py:class:`psyclone.psyir.symbols.Symbol`
159 :raises TypeError: if the argument is not the expected type.
162 if not isinstance(symbol_in, Symbol):
163 raise TypeError(f
"Argument should be of type 'Symbol' but "
164 f
"found '{type(symbol_in).__name__}'.")
165 self.
_interface_interface = symbol_in.interface
168 '''Specialise this symbol so that it becomes an instance of the class
169 provided in the subclass argument. This allows this instance
170 to become a subclass without any references to it becoming
173 :param subclass: the class that this symbol will become.
174 :type subclass: type of sub-class of \
175 :py:class:`psyclone.psyir.symbols.Symbol`
177 :raises TypeError: if subclass is not a sub-class of Symbol.
181 is_subclass = issubclass(subclass, self.
__class____class__)
182 except TypeError
as info:
184 f
"The specialise method in '{self.name}' expects the "
185 f
"subclass argument to be a class.")
from info
187 if not is_subclass
or type(self)
is subclass:
189 f
"The specialise method in '{self.name}', an instance of "
190 f
"'{type(self).__name__}', expects the subclass argument to "
191 f
"be a subclass of '{type(self).__name__}', but found "
192 f
"'{subclass.__name__}'.")
199 Looks-up and returns the Symbol referred to by this Symbol's
202 :raises SymbolError: if the module pointed to by the symbol interface \
203 does not contain the symbol (or the symbol is \
205 :raises NotImplementedError: if this symbol does not have an \
209 raise NotImplementedError(
210 f
"Error trying to resolve symbol '{self.name}' properties, "
211 f
"the lazy evaluation of '{self.interface}' interfaces is "
216 return module.container.symbol_table.lookup(
218 except KeyError
as kerr:
220 f
"Error trying to resolve the properties of symbol "
221 f
"'{self.name}'. The interface points to module "
222 f
"'{module.name}' but could not find the definition of "
223 f
"'{self.name}' in that module.")
from kerr
224 except SymbolError
as err:
226 f
"Error trying to resolve the properties of symbol "
227 f
"'{self.name}' in module '{module.name}': {err.value}")
from err
231 Update the properties of this Symbol by using the definition imported
232 from the external Container. If this symbol does not have an
233 ImportInterface then there is no lookup needed and we just return this
236 :returns: a symbol object with the class and type determined by
237 examining the Container from which it is imported.
238 :rtype: subclass of :py:class:`psyclone.psyir.symbols.Symbol`
244 if extern_symbol.initial_value:
245 init_value = extern_symbol.initial_value.copy()
248 self.
specialisespecialise(type(extern_symbol),
249 datatype=extern_symbol.datatype,
250 is_constant=extern_symbol.is_constant,
251 initial_value=init_value)
257 :returns: name of the Symbol.
260 return self.
_name_name
263 def visibility(self):
265 :returns: the visibility of this Symbol.
266 :rtype: :py:class:`psyclone.psyir.symbol.Symbol.Visibility`
271 def visibility(self, value):
273 Setter for the visibility attribute.
275 :raises TypeError: if the supplied value is not an instance of \
280 f
"{type(self).__name__} 'visibility' attribute should be of "
281 f
"type psyir.symbols.Symbol.Visibility but got "
282 f
"'{type(value).__name__}'.")
288 :returns: the an object describing the interface to this Symbol.
289 :rtype: Sub-class of \
290 :py:class:`psyclone.psyir.symbols.symbol.SymbolInterface`
295 def interface(self, value):
297 Setter for the Interface associated with this Symbol.
299 :param value: an Interface object describing how the Symbol is \
301 :type value: Sub-class of \
302 :py:class:`psyclone.psyir.symbols.symbol.SymbolInterface`
304 :raises TypeError: if the supplied `value` is of the wrong type.
306 if not isinstance(value, SymbolInterface):
307 raise TypeError(f
"The interface to a Symbol must be a "
308 f
"SymbolInterface but got "
309 f
"'{type(value).__name__}'")
315 :returns: whether the Symbol has an AutomaticInterface.
319 return isinstance(self.
_interface_interface, AutomaticInterface)
324 :returns: whether the Symbol has a DefaultModuleInterface.
328 return isinstance(self.
_interface_interface, DefaultModuleInterface)
333 :returns: whether the Symbol has an ImportInterface.
337 return isinstance(self.
_interface_interface, ImportInterface)
342 :returns: whether the Symbol has an ArgumentInterface.
346 return isinstance(self.
_interface_interface, ArgumentInterface)
351 :returns: whether the Symbol has a CommonBlockInterface.
355 return isinstance(self.
_interface_interface, CommonBlockInterface)
360 :returns: whether the Symbol has a StaticInterface.
364 return isinstance(self.
_interface_interface, StaticInterface)
369 :returns: whether the Symbol has an UnresolvedInterface.
373 return isinstance(self.
_interface_interface, UnresolvedInterface)
378 :returns: whether the Symbol has an UnknownInterface.
382 return isinstance(self.
_interface_interface, UnknownInterface)
386 Searches back up the PSyIR tree for the SymbolTable that contains
389 :param node: the PSyIR node from which to search.
390 :type node: :py:class:`psyclone.psyir.nodes.Node`
392 :returns: the SymbolTable containing this Symbol or None.
393 :rtype: :py:class:`psyclone.psyir.symbols.SymbolTable` or NoneType
395 :raises TypeError: if the supplied `node` argument is not a PSyIR Node.
402 if not isinstance(node, Node):
404 f
"find_symbol_table: expected to be passed an instance of "
405 f
"psyir.nodes.Node but got '{type(node).__name__}'")
408 current = node.scope.symbol_table
410 if self.
namename
in current:
412 if current.node.parent:
413 current = current.node.parent.scope.symbol_table
423 return f
"{self.name}: Symbol<{self.interface}>"
428 :returns: True if this symbol is an array and False if it is not or
429 there is not enough symbol information to determine it.
436 '''This method detects if a variable is used as an array or not.
437 If available, it will use the access information, i.e. how the
438 variable is used (e.g. if it has indices somewhere, like `a(i)%b`).
439 This can be incorrect in case of implicit loops (e.g. `a=b+1`,
440 where `a` and `b` are arrays) where the variable usage information
441 will not have information about indices. In this case this function
442 will fallback to querying the symbol itself.
444 This can cause significant slowdown if this symbol is imported
445 from a module, since then these modules need to be parsed.
446 # TODO #1213: Parsing modules is not yet supported.
448 If a `loop_variable` is specified, a variable access will only be
449 considered an array access if the specified variable is used in
450 at least one of the indices. For example:
454 the access to `a` is not considered an array if `loop_variable` is
455 set to `i`. If `loop_variable` is specified, `access_information`
458 :param str index_variable: optional loop variable that is used to \
459 to determine if an access is an array access using this variable.
460 :param access_info: variable access information, optional.
462 :py:class:`psyclone.core.SingleVariableAccessInfo`
464 :returns: if the variable is an array.
467 :raises InternalError: if a loop_variable is specified, but no \
468 access information is given.
475 if index_variable
and not access_info:
476 raise InternalError(f
"In Symbol.is_array_access: index variable "
477 f
"'{index_variable}' specified, but no access "
478 f
"information given.")
491 is_array = access_info.is_array(index_variable=index_variable)
500 if is_array
or index_variable
is not None:
def visibility(self, value)
def specialise(self, subclass, **kwargs)
def is_array_access(self, index_variable=None, access_info=None)
def _process_arguments(self, visibility=None, interface=None)
def find_symbol_table(self, node)
def copy_properties(self, symbol_in)
def is_unknown_interface(self)
def get_external_symbol(self)
def interface(self, value)