40 ''' This module contains the SymbolTable implementation. '''
44 from collections
import OrderedDict
45 from collections.abc
import Iterable
52 DataSymbol, ContainerSymbol, DataTypeSymbol, GenericInterfaceSymbol,
53 ImportInterface, RoutineSymbol, Symbol, SymbolError, UnresolvedInterface)
60 '''Encapsulates the symbol table and provides methods to add new
61 symbols and look up existing symbols. Nested scopes are supported
62 and, by default, the add and lookup methods take any ancestor
63 symbol tables into consideration (ones attached to nodes that are
64 ancestors of the node that this symbol table is attached to). If the
65 default visibility is not specified then it defaults to
66 Symbol.Visbility.PUBLIC.
68 :param node: reference to the Schedule or Container to which this \
70 :type node: :py:class:`psyclone.psyir.nodes.Schedule`, \
71 :py:class:`psyclone.psyir.nodes.Container` or NoneType
72 :param default_visibility: optional default visibility value for this \
73 symbol table, if not provided it defaults to PUBLIC visibility.
74 :type default_visibillity: \
75 :py:class:`psyclone.psyir.symbols.Symbol.Visibility`
77 :raises TypeError: if node argument is not a Schedule or a Container.
80 def __init__(self, node=None, default_visibility=Symbol.Visibility.PUBLIC):
84 self.
_symbols_symbols = OrderedDict()
91 self.
_node_node =
None
101 def default_visibility(self):
103 :returns: the default visibility of symbols in this table.
104 :rtype: :py:class:`psyclone.psyir.symbols.Symbol.Visibility`
108 @default_visibility.setter
109 def default_visibility(self, vis):
111 Sets the default visibility of symbols in this table.
113 :param vis: the default visibility.
114 :type vis: :py:class:`psyclone.psyir.symbols.Symbol.Visibility`
116 :raises TypeError: if the supplied value is of the wrong type.
121 f
"Default visibility must be an instance of psyir.symbols."
122 f
"Symbol.Visibility but got '{type(vis).__name__}'")
128 :returns: the Schedule or Container to which this symbol table belongs.
129 :rtype: :py:class:`psyclone.psyir.nodes.Schedule`, \
130 :py:class:`psyclone.psyir.nodes.Container` or NoneType
133 return self.
_node_node
137 :returns: True if the symbol table is empty, and False otherwise.
141 return len(self.
_symbols_symbols) == 0
144 '''If this symbol table is enclosed in another scope, return the
145 symbol table of the next outer scope. Otherwise return None.
147 :param scope_limit: optional Node which limits the symbol \
148 search space to the symbol tables of the nodes within the \
149 given scope. If it is None (the default), the whole \
150 scope (all symbol tables in ancestor nodes) is searched \
151 otherwise ancestors of the scope_limit node are not \
153 :type scope_limit: :py:class:`psyclone.psyir.nodes.Node` or \
156 :returns: the 'parent' SymbolTable of the current SymbolTable (i.e.
157 the one that encloses this one in the PSyIR hierarchy).
158 :rtype: :py:class:`psyclone.psyir.symbols.SymbolTable` or NoneType
162 if scope_limit
is not None:
165 if not isinstance(scope_limit, Node):
167 f
"The scope_limit argument '{scope_limit}', is not of "
173 search_next = self.
nodenode
174 while search_next
is not scope_limit
and search_next.parent:
175 search_next = search_next.parent
176 if hasattr(search_next,
'symbol_table'):
177 return search_next.symbol_table
181 '''Return symbols from this symbol table and all symbol tables
182 associated with ancestors of the node that this symbol table
183 is attached to. If there are name duplicates we only return the
184 one from the closest ancestor including self. It accepts an
185 optional scope_limit argument.
187 :param scope_limit: optional Node which limits the symbol \
188 search space to the symbol tables of the nodes within the \
189 given scope. If it is None (the default), the whole \
190 scope (all symbol tables in ancestor nodes) is searched \
191 otherwise ancestors of the scope_limit node are not \
193 :type scope_limit: Optional[:py:class:`psyclone.psyir.nodes.Node`]
195 :returns: ordered dictionary of symbols indexed by symbol name.
196 :rtype: OrderedDict[str] = :py:class:`psyclone.psyir.symbols.Symbol`
199 all_symbols = OrderedDict()
202 for symbol_name, symbol
in current.symbols_dict.items():
203 if symbol_name
not in all_symbols:
204 all_symbols[symbol_name] = symbol
205 current = current.parent_symbol_table(scope_limit)
209 '''Return tags from this symbol table and all symbol tables associated
210 with ancestors of the node that this symbol table is attached
211 to. If there are tag duplicates we only return the one from the closest
212 ancestor including self. It accepts an optional scope_limit argument.
214 :param scope_limit: optional Node which limits the symbol \
215 search space to the symbol tables of the nodes within the \
216 given scope. If it is None (the default), the whole \
217 scope (all symbol tables in ancestor nodes) is searched \
218 otherwise ancestors of the scope_limit node are not \
220 :type scope_limit: :py:class:`psyclone.psyir.nodes.Node` or \
223 :returns: ordered dictionary of symbols indexed by tag.
224 :rtype: OrderedDict[str] = :py:class:`psyclone.psyir.symbols.Symbol`
227 all_tags = OrderedDict()
230 for tag, symbol
in current.tags_dict.items():
231 if tag
not in all_tags:
232 all_tags[tag] = symbol
233 current = current.parent_symbol_table(scope_limit)
237 '''Create a copy of the symbol table with new instances of the
238 top-level data structures but keeping the same existing symbol
239 objects. Symbols added to the new symbol table will not be added
240 in the original but the existing objects are still the same.
242 :returns: a shallow copy of this symbol table.
243 :rtype: :py:class:`psyclone.psyir.symbols.SymbolTable`
247 new_st = type(self)()
248 new_st._symbols = copy.copy(self.
_symbols_symbols)
249 new_st._argument_list = copy.copy(self.
_argument_list_argument_list)
250 new_st._tags = copy.copy(self.
_tags_tags)
251 new_st._node = self.
nodenode
256 '''Create a copy of the symbol table with new instances of the
257 top-level data structures and also new instances of the symbols
258 contained in these data structures. Modifying a symbol attribute
259 will not affect the equivalent named symbol in the original symbol
262 The only attribute not copied is the _node reference to the scope,
263 since that scope can only have one symbol table associated to it.
265 :returns: a deep copy of this symbol table.
266 :rtype: :py:class:`psyclone.psyir.symbols.SymbolTable`
270 new_st = type(self)()
273 for symbol
in self.
symbolssymbols:
274 new_st.add(symbol.copy())
278 for name
in [arg.name
for arg
in self.
argument_listargument_list]:
279 new_arguments.append(new_st.lookup(name))
280 new_st.specify_argument_list(new_arguments)
283 for tag, symbol
in self.
_tags_tags.items():
284 new_st._tags[tag] = new_st.lookup(symbol.name)
287 for symbol
in new_st.imported_symbols:
288 name = symbol.interface.container_symbol.name
289 orig_name = symbol.interface.orig_name
290 new_container = new_st.lookup(name)
296 for symbol
in new_st.symbols:
297 if not isinstance(symbol, GenericInterfaceSymbol):
300 for routine
in symbol.routines:
301 new_routines.append((new_st.lookup(routine.symbol.name),
302 routine.from_container))
303 symbol.routines = new_routines
312 '''Normalises the symboltable key strings.
314 :param str key: an input key.
316 :returns: the normalized key.
321 new_key = key.lower()
325 def _has_same_name(cls, first, second):
326 ''' Compare if two symbols have the same normalized name. For
327 convenience it accepts symbols and strings.
329 :param first: first item of the comparison.
330 :type first: str | :py:class:`psyclone.psyir.symbols.Symbol`
331 :param second: second item of the comparison.
332 :type second: str | :py:class:`psyclone.psyir.symbols.Symbol`
334 :returns: whether the two symbols names are the same.
338 string1 = first
if isinstance(first, str)
else first.name
339 string2 = second
if isinstance(second, str)
else second.name
342 def new_symbol(self, root_name=None, tag=None, shadowing=False,
343 symbol_type=None, allow_renaming=True, **symbol_init_args):
344 ''' Create a new symbol. Optional root_name and shadowing
345 arguments can be given to choose the name following the rules of
346 next_available_name(). An optional tag can also be given.
347 By default it creates a generic symbol but a symbol_type argument
348 and any additional initialization keyword arguments of this
349 symbol_type can be provided to refine the created Symbol.
351 :param root_name: optional name to use when creating a
352 new symbol name. This will be appended
353 with an integer if the name
354 clashes with an existing symbol name.
355 :type root_name: Optional[str]
356 :param str tag: optional tag identifier for the new symbol.
357 :param bool shadowing: optional logical flag indicating whether the
358 name can be overlapping with a symbol in any of the ancestors
359 symbol tables. Defaults to False.
360 :param symbol_type: class type of the new symbol.
361 :type symbol_type: type object of class (or subclasses) of
362 :py:class:`psyclone.psyir.symbols.Symbol`
363 :param bool allow_renaming: whether to allow the newly created
364 symbol to be renamed from root_name.
366 :param symbol_init_args: arguments to create a new symbol.
367 :type symbol_init_args: unwrapped dict[str, Any]
369 :raises TypeError: if the type_symbol argument is not the type of a
370 Symbol object class or one of its subclasses.
371 :raises SymbolError: if the the symbol needs to be created but would
372 need to be renamed to be created and
373 allow_renaming is False.
378 if symbol_type
is not None:
379 if not (isinstance(symbol_type, type)
and
380 Symbol
in inspect.getmro(symbol_type)):
382 f
"The symbol_type parameter should be a type class of "
383 f
"Symbol or one of its sub-classes but found "
384 f
"'{type(symbol_type).__name__}' instead.")
390 if "visibility" not in symbol_init_args:
395 if (
not allow_renaming
and available_name != root_name):
397 f
"Cannot create symbol '{root_name}' as a symbol with that "
398 f
"name already exists in this scope, and renaming is "
401 if "interface" in symbol_init_args
and available_name != root_name:
402 interface = symbol_init_args[
"interface"]
403 if isinstance(interface, ImportInterface):
405 symbol_init_args[
"interface"].container_symbol,
408 symbol = symbol_type(available_name, **symbol_init_args)
409 self.
addadd(symbol, tag)
413 ''' Lookup a symbol by its name, if it doesn't exist create a new
414 symbol with the given properties.
416 :param str name: name of the symbol to lookup or create.
417 :param new_symbol_args: arguments to create a new symbol.
418 :type new_symbol_args: unwrapped Dict[str, object]
420 :raises SymbolError: if the symbol already exists but the type_symbol \
421 argument does not match the type of the symbol \
426 symbol = self.
lookuplookup(name)
428 if 'symbol_type' in new_symbol_args:
429 symbol_type = new_symbol_args[
'symbol_type']
430 if not isinstance(symbol, new_symbol_args[
'symbol_type']):
432 f
"Expected symbol with name '{name}' to be of type "
433 f
"'{symbol_type.__name__}' but found type "
434 f
"'{type(symbol).__name__}'.")
439 return self.
new_symbolnew_symbol(name, **new_symbol_args)
443 ''' Lookup a tag, if it doesn't exist create a new symbol with the
444 given tag. By default it creates a generic Symbol with the tag as the
445 root of the symbol name. Optionally, a different root_name or any of
446 the arguments available in the new_symbol() method can be given to
447 refine the name and the type of the created Symbol.
449 :param str tag: tag identifier.
450 :param str root_name: optional name of the new symbol if it needs \
451 to be created. Otherwise it is ignored.
452 :param bool shadowing: optional logical flag indicating whether the
453 name can be overlapping with a symbol in any of the ancestors
454 symbol tables. Defaults to False.
455 :param symbol_type: class type of the new symbol.
456 :type symbol_type: type object of class (or subclasses) of
457 :py:class:`psyclone.psyir.symbols.Symbol`
458 :param bool allow_renaming: whether to allow the newly created
459 :param bool allow_renaming: whether to allow the newly created
460 symbol to be renamed from root_name.
462 :param new_symbol_args: arguments to create a new symbol.
463 :type new_symbol_args: unwrapped dict[str, Any]
465 :returns: symbol associated with the given tag.
466 :rtype: :py:class:`psyclone.psyir.symbols.Symbol`
468 :raises SymbolError: if the symbol already exists but the type_symbol \
469 argument does not match the type of the symbol \
476 if 'symbol_type' in new_symbol_args:
477 symbol_type = new_symbol_args[
'symbol_type']
478 if not isinstance(symbol, new_symbol_args[
'symbol_type']):
480 f
"Expected symbol with tag '{tag}' to be of type "
481 f
"'{symbol_type.__name__}' but found type "
482 f
"'{type(symbol).__name__}'.")
489 return self.
new_symbolnew_symbol(root_name, tag, **new_symbol_args)
493 '''Return a name that is not in the symbol table and therefore can
494 be used to declare a new symbol.
495 If the `root_name` argument is not supplied or if it is
496 an empty string then the name is generated internally,
497 otherwise the `root_name` is used. If required, an additional
498 integer is appended to avoid clashes.
499 If the shadowing argument is True (is False by default), the names
500 in parent symbol tables will not be considered.
501 If `other_table` is supplied, the new name is constructed so as not
502 to clash with any entries in that table.
504 :param str root_name: optional name to use when creating a new \
505 symbol name. This will be appended with an integer if the name \
506 clashes with an existing symbol name.
507 :param bool shadowing: optional logical flag indicating whether the \
508 name can be overlapping with a symbol in any of the ancestors \
509 symbol tables. Defaults to False.
510 :param other_table: an optional, second symbol table to take into \
511 account when constructing a new name.
512 :type other_table: :py:class`psyclone.psyir.symbols.SymbolTable`
514 :returns: the new unique symbol name.
517 :raises TypeError: if any of the arguments are of the wrong type.
520 if not isinstance(shadowing, bool):
522 f
"Argument 'shadowing' should be of type bool"
523 f
" but found '{type(shadowing).__name__}'.")
525 if other_table
and not isinstance(other_table, SymbolTable):
527 f
"If supplied, argument 'other_table' should be of type "
528 f
"SymbolTable but found '{type(other_table).__name__}'.")
539 existing_names = set(symbols.keys())
544 other_names = set(other_table.symbols_dict.keys())
545 existing_names = existing_names.union(other_names)
547 if root_name
is not None:
548 if not isinstance(root_name, str):
550 f
"Argument root_name should be of type str or NoneType "
551 f
"but found '{type(root_name).__name__}'.")
553 root_name = Config.get().psyir_root_name
554 candidate_name = root_name
556 while self.
_normalize_normalize(candidate_name)
in existing_names:
557 candidate_name = f
"{root_name}_{idx}"
559 return candidate_name
561 def add(self, new_symbol, tag=None):
562 '''Add a new symbol to the symbol table if the symbol name is not
565 :param new_symbol: the symbol to add to the symbol table.
566 :type new_symbol: :py:class:`psyclone.psyir.symbols.Symbol`
567 :param str tag: a tag identifier for the new symbol, by default no \
570 :raises InternalError: if the new_symbol argument is not a \
572 :raises KeyError: if the symbol name is already in use.
573 :raises KeyError: if a tag is supplied and it is already in \
577 if not isinstance(new_symbol, Symbol):
578 raise InternalError(f
"Symbol '{new_symbol}' is not a symbol, but "
579 f
"'{type(new_symbol).__name__}'.'")
581 key = self.
_normalize_normalize(new_symbol.name)
583 raise KeyError(f
"Symbol table already contains a symbol with "
584 f
"name '{new_symbol.name}'.")
589 f
"This symbol table, or an outer scope ancestor symbol "
590 f
"table, already contains the tag '{tag}' for the symbol"
591 f
" '{self.lookup_with_tag(tag).name}', so it can not be "
592 f
"associated with symbol '{new_symbol.name}'.")
593 self.
_tags_tags[tag] = new_symbol
595 self.
_symbols_symbols[key] = new_symbol
599 Checks the symbols in the supplied table against those in
600 this table. If there is a name clash that cannot be resolved by
601 renaming then a SymbolError is raised. Any symbols appearing
602 in `symbols_to_skip` are excluded from the checks.
604 :param other_table: the table for which to check for clashes.
605 :type other_table: :py:class:`psyclone.psyir.symbols.SymbolTable`
606 :param symbols_to_skip: an optional list of symbols to exclude from
608 :type symbols_to_skip: Iterable[
609 :py:class:`psyclone.psyir.symbols.Symbol`]
611 :raises TypeError: if symbols_to_skip is supplied but is not an
612 instance of Iterable.
613 :raises SymbolError: if there would be an unresolvable name clash
614 when importing symbols from `other_table` into this table.
620 if not isinstance(symbols_to_skip, Iterable):
622 f
"check_for_clashes: 'symbols_to_skip' must be an instance of "
623 f
"Iterable but got '{type(symbols_to_skip).__name__}'")
627 other_imports = other_table.wildcard_imports()
628 shared_wildcard_imports = self_imports & other_imports
630 unique_wildcard_imports = self_imports ^ other_imports
632 for other_sym
in other_table.symbols:
633 if other_sym.name
not in self
or other_sym
in symbols_to_skip:
636 this_sym = self.
lookuplookup(other_sym.name)
640 if (isinstance(this_sym, ContainerSymbol)
and
641 isinstance(other_sym, ContainerSymbol)):
645 if (isinstance(this_sym, IntrinsicSymbol)
and
646 isinstance(other_sym, IntrinsicSymbol)):
649 if other_sym.is_import
and this_sym.is_import:
653 if this_sym.interface != other_sym.interface:
655 f
"This table has an import of '{this_sym.name}' via "
656 f
"interface '{this_sym.interface}' but the supplied "
657 f
"table imports it via '{other_sym.interface}'.")
660 if other_sym.is_unresolved
and this_sym.is_unresolved:
662 if shared_wildcard_imports
and not unique_wildcard_imports:
667 if not (self_imports
or other_imports):
671 _ = IntrinsicCall.Intrinsic[this_sym.name.upper()]
673 if not isinstance(this_sym, IntrinsicSymbol):
674 this_sym.specialise(IntrinsicSymbol)
675 if not isinstance(other_sym, IntrinsicSymbol):
676 other_sym.specialise(IntrinsicSymbol)
682 f
"A symbol named '{this_sym.name}' is present but "
683 f
"unresolved in one or both tables.")
688 except SymbolError
as err1:
690 other_table.rename_symbol(other_sym,
"", dry_run=
True)
691 except SymbolError
as err2:
694 f
"There is a name clash for symbol '{this_sym.name}' "
695 f
"that cannot be resolved by renaming "
696 f
"one of the instances because:\n- {err1}\n- {err2}")
698 def _add_container_symbols_from_table(self, other_table):
700 Takes container symbols from the supplied symbol table and adds them to
701 this table. All references to each container symbol are also updated.
702 (This is a preliminary step to adding all symbols from other_table to
705 :param other_table: the symbol table from which to take container
707 :type other_table: :py:class:`psyclone.psyir.symbols.SymbolTable`
710 for csym
in other_table.containersymbols:
711 if csym.name
in self:
713 self_csym = self.
lookuplookup(csym.name)
714 if not isinstance(self_csym, ContainerSymbol):
720 csym.name, other_table=other_table))
728 if csym.wildcard_import:
729 self_csym.wildcard_import =
True
734 imported_syms = other_table.symbols_imported_from(csym)
735 for isym
in imported_syms:
736 if isym.name
in self:
739 other_sym = self.
lookuplookup(isym.name)
740 if not other_sym.is_import:
749 other_sym.name, other_table=other_table))
751 self.
lookuplookup(csym.name),
752 orig_name=isym.interface.orig_name)
754 def _add_symbols_from_table(self, other_table, symbols_to_skip=()):
756 Takes symbols from the supplied symbol table and adds them to this
757 table (unless they appear in `symbols_to_skip`).
758 _add_container_symbols_from_table() MUST have been called
759 before this method in order to handle any Container Symbols and update
760 those Symbols imported from them.
762 :param other_table: the symbol table from which to add symbols.
763 :type other_table: :py:class:`psyclone.psyir.symbols.SymbolTable`
764 :param symbols_to_skip: an optional list of symbols to exclude from
766 :type symbols_to_skip: Iterable[
767 :py:class:`psyclone.psyir.symbols.Symbol`]
769 :raises InternalError: if an imported symbol is found that has not
770 already been updated to refer to a Container in this table.
773 for old_sym
in other_table.symbols:
775 if old_sym
in symbols_to_skip
or isinstance(old_sym,
787 def _handle_symbol_clash(self, old_sym, other_table):
789 Adds the supplied Symbol to the current table in the presence
790 of a name clash. `check_for_clashes` MUST have been called
791 prior to this method in order to check for any unresolvable cases.
793 :param old_sym: the Symbol to be added to self.
794 :type old_sym: :py:class:`psyclone.psyir.symbols.Symbol`
795 :param other_table: the other table containing the symbol that we are
796 trying to add to self.
797 :type other_table: :py:class:`psyclone.psyir.symbols.SymbolTable`
799 :raises InternalError: if the supplied symbol is imported from a
800 Container that is not represented in this table.
803 if old_sym.is_import:
807 self_csym = self.
lookuplookup(old_sym.interface.container_symbol.name)
808 if old_sym.interface.container_symbol
is self_csym:
811 f
"Symbol '{old_sym.name}' imported from '{self_csym.name}' "
812 f
"has not been updated to refer to the corresponding "
813 f
"container in the current table.")
815 self_sym = self.
lookuplookup(old_sym.name)
816 if old_sym.is_unresolved
and self_sym.is_unresolved:
826 old_sym.name, other_table=other_table)
828 other_table.rename_symbol(old_sym, new_name)
834 def merge(self, other_table, symbols_to_skip=()):
835 '''Merges all of the symbols found in `other_table` into this
836 table. Symbol objects in *either* table may be renamed in the
839 Any Symbols appearing in `symbols_to_skip` are excluded.
841 :param other_table: the symbol table from which to add symbols.
842 :type other_table: :py:class:`psyclone.psyir.symbols.SymbolTable`
843 :param symbols_to_skip: an optional list of Symbols to exclude from
845 :type symbols_to_skip: Iterable[
846 :py:class:`psyclone.psyir.symbols.Symbol`]
848 :raises TypeError: if `other_table` is not a SymbolTable.
849 :raises TypeError: if `symbols_to_skip` is not an Iterable.
850 :raises SymbolError: if name clashes prevent the merge.
853 if not isinstance(other_table, SymbolTable):
854 raise TypeError(f
"SymbolTable.merge() expects a SymbolTable "
855 f
"instance but got '{type(other_table).__name__}'")
856 if not isinstance(symbols_to_skip, Iterable):
858 f
"SymbolTable.merge() expects 'symbols_to_skip' to be an "
859 f
"Iterable but got '{type(symbols_to_skip).__name__}'")
863 symbols_to_skip=symbols_to_skip)
864 except SymbolError
as err:
866 f
"Cannot merge {other_table.view()} with {self.view()} due to "
867 f
"unresolvable name clashes.")
from err
875 symbols_to_skip=symbols_to_skip)
878 '''Swaps the properties of symbol1 and symbol2 apart from the symbol
879 name. Argument list positions are also updated appropriately.
881 :param symbol1: the first symbol.
882 :type symbol1: :py:class:`psyclone.psyir.symbols.Symbol`
883 :param symbol2: the second symbol.
884 :type symbol2: :py:class:`psyclone.psyir.symbols.Symbol`
886 :raises KeyError: if either of the supplied symbols are not in \
888 :raises TypeError: if the supplied arguments are not symbols, \
889 or the names of the symbols are the same in the SymbolTable \
893 for symbol
in [symbol1, symbol2]:
894 if not isinstance(symbol, Symbol):
895 raise TypeError(f
"Arguments should be of type 'Symbol' but "
896 f
"found '{type(symbol).__name__}'.")
897 if symbol.name
not in self.
_symbols_symbols:
898 raise KeyError(f
"Symbol '{symbol.name}' is not in the symbol "
901 raise ValueError(f
"The symbols should have different names, but "
902 f
"found '{symbol1.name}' for both.")
904 tmp_symbol = symbol1.copy()
905 symbol1.copy_properties(symbol2)
906 symbol2.copy_properties(tmp_symbol)
915 if index1
is not None:
917 if index2
is not None:
922 Sets-up the internal list storing the order of the arguments to this
925 :param list argument_symbols: ordered list of the DataSymbols \
926 representing the kernel arguments.
928 :raises ValueError: if the new argument_list is not consistent with \
929 the existing entries in the SymbolTable.
935 def lookup(self, name, visibility=None, scope_limit=None):
936 '''Look up a symbol in the symbol table. The lookup can be limited
937 by visibility (e.g. just show public methods) or by scope_limit (e.g.
938 just show symbols up to a certain scope).
940 :param str name: name of the symbol.
941 :param visibilty: the visibility or list of visibilities that the \
943 :type visibility: [list of] :py:class:`psyclone.symbols.Visibility`
944 :param scope_limit: optional Node which limits the symbol \
945 search space to the symbol tables of the nodes within the \
946 given scope. If it is None (the default), the whole \
947 scope (all symbol tables in ancestor nodes) is searched \
948 otherwise ancestors of the scope_limit node are not \
950 :type scope_limit: :py:class:`psyclone.psyir.nodes.Node` or \
953 :returns: the symbol with the given name and, if specified, visibility.
954 :rtype: :py:class:`psyclone.psyir.symbols.Symbol`
956 :raises TypeError: if the name argument is not a string.
957 :raises SymbolError: if the name exists in the Symbol Table but does \
958 not have the specified visibility.
959 :raises TypeError: if the visibility argument has the wrong type.
960 :raises KeyError: if the given name is not in the Symbol Table.
963 if not isinstance(name, str):
965 f
"Expected the name argument to the lookup() method to be "
966 f
"a str but found '{type(name).__name__}'.")
971 if not isinstance(visibility, list):
972 vis_list = [visibility]
974 vis_list = visibility
975 if symbol.visibility
not in vis_list:
982 f
"the 'visibility' argument to lookup() must "
983 f
"be an instance (or list of instances) of "
984 f
"Symbol.Visibility but got "
985 f
"'{type(vis).__name__}' when searching for "
987 vis_names.append(vis.name)
989 f
"Symbol '{name}' exists in the Symbol Table but has "
990 f
"visibility '{symbol.visibility.name}' which does not"
991 f
" match with the requested visibility: {vis_names}")
993 except KeyError
as err:
994 raise KeyError(f
"Could not find '{name}' in the Symbol Table.") \
998 '''Look up a symbol by its tag. The lookup can be limited by
999 scope_limit (e.g. just show symbols up to a certain scope).
1001 :param str tag: tag identifier.
1002 :param scope_limit: optional Node which limits the symbol \
1003 search space to the symbol tables of the nodes within the \
1004 given scope. If it is None (the default), the whole \
1005 scope (all symbol tables in ancestor nodes) is searched \
1006 otherwise ancestors of the scope_limit node are not \
1009 :returns: symbol with the given tag.
1010 :rtype: :py:class:`psyclone.psyir.symbols.Symbol`
1012 :raises TypeError: if the tag argument is not a string.
1013 :raises KeyError: if the given tag is not in the Symbol Table.
1016 if not isinstance(tag, str):
1018 f
"Expected the tag argument to the lookup_with_tag() method "
1019 f
"to be a str but found '{type(tag).__name__}'.")
1022 return self.
get_tagsget_tags(scope_limit)[tag]
1023 except KeyError
as err:
1024 raise KeyError(f
"Could not find the tag '{tag}' in the Symbol "
1028 '''Check if the given key is part of the Symbol Table.
1030 :param str key: key to check for existance.
1032 :returns: whether the Symbol Table contains the given key.
1039 Examines the contents of this symbol table to see which DataSymbols
1040 (if any) are imported from the supplied ContainerSymbol (which must
1041 be present in the SymbolTable).
1043 :param csymbol: the ContainerSymbol to search for imports from.
1044 :type csymbol: :py:class:`psyclone.psyir.symbols.ContainerSymbol`
1046 :returns: list of DataSymbols that are imported from the supplied \
1047 ContainerSymbol. If none are found then the list is empty.
1048 :rtype: list of :py:class:`psyclone.psyir.symbols.DataSymbol`
1050 :raises TypeError: if the supplied object is not a ContainerSymbol.
1051 :raises KeyError: if the supplied object is not in this SymbolTable.
1054 if not isinstance(csymbol, ContainerSymbol):
1056 f
"symbols_imported_from() expects a ContainerSymbol but got "
1057 f
"an object of type '{type(csymbol).__name__}'")
1060 if self.
lookuplookup(csymbol.name)
is not csymbol:
1061 raise KeyError(f
"The '{csymbol.name}' entry in this SymbolTable "
1062 f
"is not the supplied ContainerSymbol.")
1065 symbol.interface.container_symbol
is csymbol]
1067 def swap(self, old_symbol, new_symbol):
1069 Remove the `old_symbol` from the table and replace it with the
1072 :param old_symbol: the symbol to remove from the table.
1073 :type old_symbol: :py:class:`psyclone.psyir.symbols.Symbol`
1074 :param new_symbol: the symbol to add to the table.
1075 :type new_symbol: :py:class:`psyclone.psyir.symbols.Symbol`
1077 :raises TypeError: if either old/new_symbol are not Symbols.
1078 :raises SymbolError: if `old_symbol` and `new_symbol` don't have
1079 the same name (after normalising).
1081 if not isinstance(old_symbol, Symbol):
1082 raise TypeError(f
"Symbol to remove must be of type Symbol but "
1083 f
"got '{type(old_symbol).__name__}'")
1084 if not isinstance(new_symbol, Symbol):
1085 raise TypeError(f
"Symbol to add must be of type Symbol but "
1086 f
"got '{type(new_symbol).__name__}'")
1087 if not self.
_has_same_name_has_same_name(old_symbol, new_symbol):
1089 f
"Cannot swap symbols that have different names, got: "
1090 f
"'{old_symbol.name}' and '{new_symbol.name}'")
1093 self.
removeremove(old_symbol)
1094 self.
addadd(new_symbol)
1096 def _validate_remove_routinesymbol(self, symbol):
1098 Checks whether the supplied RoutineSymbol can be removed from this
1101 If the symbol is the target of a Call or is a member of an interface
1102 definition then removal is not possible.
1104 :param symbol: the Symbol to validate for removal.
1105 :type symbol: :py:class:`psyclone.psyir.symbols.RoutineSymbol`
1107 :raises ValueError: if the Symbol cannot be removed.
1115 all_calls = self.
nodenode.walk(Call)
if self.
nodenode
else []
1116 for call
in all_calls:
1117 if call.routine.symbol
is symbol:
1119 f
"Cannot remove RoutineSymbol '{symbol.name}' "
1120 f
"because it is referenced by '{call.debug_string()}'")
1122 for sym
in self.
_symbols_symbols.values():
1123 if not isinstance(sym, GenericInterfaceSymbol):
1125 for rt_info
in sym.routines:
1126 if rt_info.symbol
is symbol:
1128 f
"Cannot remove RoutineSymbol '{symbol.name}' "
1129 f
"because it is referenced in interface '{sym.name}'")
1133 Remove the supplied symbol from the Symbol Table. This has a high
1134 potential to leave broken links, so this method checks for some
1135 references to the removed symbol depending on the symbol type.
1137 Currently, generic Symbols, ContainerSymbols and RoutineSymbols are
1138 supported. Support for removing other types of Symbol will be added
1141 TODO #898. This method should check for any references/uses of
1144 :param symbol: the symbol to remove.
1145 :type symbol: :py:class:`psyclone.psyir.symbols.Symbol`
1147 :raises TypeError: if the supplied parameter is not of type Symbol.
1148 :raises NotImplementedError: the removal of this symbol type is not
1150 :raises KeyError: if the supplied symbol is not in the symbol table.
1151 :raises ValueError: if the supplied container symbol is referenced
1152 by one or more DataSymbols.
1153 :raises InternalError: if the supplied symbol is not the same as the
1154 entry with that name in this SymbolTable.
1156 if not isinstance(symbol, Symbol):
1157 raise TypeError(f
"remove() expects a Symbol argument but found: "
1158 f
"'{type(symbol).__name__}'.")
1161 if not (isinstance(symbol, (ContainerSymbol, RoutineSymbol))
or
1162 type(symbol)
is Symbol):
1163 raise NotImplementedError(
1164 f
"remove() currently only supports generic Symbol, "
1165 f
"ContainerSymbol and RoutineSymbol types but got: "
1166 f
"'{type(symbol).__name__}'")
1171 norm_name = self.
_normalize_normalize(symbol.name)
1173 if norm_name
not in self.
_symbols_symbols:
1174 raise KeyError(f
"Cannot remove Symbol '{symbol.name}' from symbol "
1175 f
"table because it does not exist.")
1178 if self.
_symbols_symbols[norm_name]
is not symbol:
1180 f
"The Symbol with name '{symbol.name}' in this symbol table "
1181 f
"is not the same Symbol object as the one that has been "
1182 f
"supplied to the remove() method.")
1186 if (isinstance(symbol, ContainerSymbol)
and
1189 f
"Cannot remove ContainerSymbol '{symbol.name}' since symbols"
1190 f
" {[sym.name for sym in self.symbols_imported_from(symbol)]} "
1191 f
"are imported from it - remove them first.")
1195 if isinstance(symbol, RoutineSymbol):
1199 for tag, tagged_symbol
in list(self.
_tags_tags.items()):
1200 if symbol
is tagged_symbol:
1201 del self.
_tags_tags[tag]
1203 self.
_symbols_symbols.pop(norm_name)
1208 Checks that the contents of the SymbolTable are self-consistent
1209 and then returns the list of kernel arguments.
1211 :returns: ordered list of arguments.
1212 :rtype: list of :py:class:`psyclone.psyir.symbols.DataSymbol`
1214 :raises InternalError: if the entries of the SymbolTable are not \
1221 except ValueError
as err:
1228 def _validate_arg_list(arg_list):
1230 Checks that the supplied list of Symbols are valid kernel arguments.
1232 :param arg_list: the proposed kernel arguments.
1233 :type param_list: list of :py:class:`psyclone.psyir.symbols.DataSymbol`
1235 :raises TypeError: if any item in the supplied list is not a \
1237 :raises ValueError: if any of the symbols does not have an argument \
1241 for symbol
in arg_list:
1242 if not isinstance(symbol, DataSymbol):
1243 raise TypeError(f
"Expected a list of DataSymbols but found an "
1244 f
"object of type '{type(symbol)}'.")
1245 if not symbol.is_argument:
1247 f
"DataSymbol '{symbol}' is listed as a kernel argument "
1248 f
"but has an interface of type '{type(symbol.interface)}' "
1249 f
"rather than ArgumentInterface")
1251 def _validate_non_args(self):
1253 Performs internal consistency checks on the current entries in the
1254 SymbolTable that do not represent kernel arguments.
1256 :raises ValueError: if a symbol that is not in the argument list \
1257 has an argument interface.
1264 if symbol.is_argument:
1266 f
"Symbol '{symbol}' is not listed as a kernel argument"
1267 f
" and yet has an ArgumentInterface interface.")
1272 :returns: ordered dictionary of symbols indexed by symbol name.
1273 :rtype: OrderedDict[str] = :py:class:`psyclone.psyir.symbols.Symbol`
1281 :returns: ordered dictionary of symbols indexed by tag.
1282 :rtype: OrderedDict[str] = :py:class:`psyclone.psyir.symbols.Symbol`
1285 return self.
_tags_tags
1289 Constructs and returns a reverse of the map returned by tags_dict
1292 :returns: ordered dictionary of tags indexed by symbol.
1293 :rtype: OrderedDict[:py:class:`psyclone.psyir.symbols.Symbol`, str]
1296 tags_dict_reversed = OrderedDict()
1300 for tag, sym
in self.
_tags_tags.items():
1301 tags_dict_reversed[sym] = tag
1302 return tags_dict_reversed
1307 :returns: list of symbols.
1308 :rtype: List[:py:class:`psyclone.psyir.symbols.Symbol`]
1310 return list(self.
_symbols_symbols.values())
1315 :returns: list of symbols representing data variables.
1316 :rtype: List[:py:class:`psyclone.psyir.symbols.DataSymbol`]
1318 return [sym
for sym
in self.
_symbols_symbols.values()
if
1319 isinstance(sym, DataSymbol)]
1324 :returns: list of symbols representing automatic variables.
1325 :rtype: List[:py:class:`psyclone.psyir.symbols.DataSymbol`]
1327 return [sym
for sym
in self.
datasymbolsdatasymbols
if sym.is_automatic]
1332 :returns: list of symbols representing arguments.
1333 :rtype: List[:py:class:`psyclone.psyir.symbols.DataSymbol`]
1335 return [sym
for sym
in self.
datasymbolsdatasymbols
if sym.is_argument]
1340 :returns: list of symbols that have an imported interface (are \
1341 associated with data that exists outside the current scope).
1342 :rtype: List[:py:class:`psyclone.psyir.symbols.Symbol`]
1345 return [sym
for sym
in self.
symbolssymbols
if sym.is_import]
1350 :returns: list of symbols representing unresolved variables.
1351 :rtype: List[:py:class:`psyclone.psyir.symbols.DataSymbol`]
1353 return [sym
for sym
in self.
datasymbolsdatasymbols
if sym.is_unresolved]
1358 :returns: list of all symbols used to define the precision of \
1359 other symbols within the table.
1360 :rtype: List[:py:class:`psyclone.psyir.symbols.DataSymbol`]
1364 precision_symbols = set()
1368 if (hasattr(sym.datatype,
"precision")
and
1369 isinstance(sym.datatype.precision, DataSymbol)):
1370 precision_symbols.add(sym.datatype.precision)
1371 return list(precision_symbols)
1376 :returns: a list of the ContainerSymbols present in the Symbol Table.
1377 :rtype: List[:py:class:`psyclone.psyir.symbols.ContainerSymbol`]
1379 return [sym
for sym
in self.
symbolssymbols
if isinstance(sym,
1385 :returns: the DataTypeSymbols present in the Symbol Table.
1386 :rtype: List[:py:class:`psyclone.psyir.symbols.DataTypeSymbol`]
1388 return [sym
for sym
in self.
symbolssymbols
if isinstance(sym, DataTypeSymbol)]
1393 :returns: list of symbols representing kernel iteration indices.
1394 :rtype: List[:py:class:`psyclone.psyir.symbols.DataSymbol`]
1396 :raises NotImplementedError: this method is abstract.
1398 raise NotImplementedError(
1399 "Abstract property. Which symbols are iteration indices is"
1405 :returns: list of symbols representing kernel data arguments.
1406 :rtype: List[:py:class:`psyclone.psyir.symbols.DataSymbol`]
1408 :raises NotImplementedError: this method is abstract.
1410 raise NotImplementedError(
1411 "Abstract property. Which symbols are data arguments is"
1416 Copy the given imported variable (and its referenced ContainerSymbol if
1417 needed) into the SymbolTable.
1419 :param imported_var: the variable to be copied in.
1420 :type imported_var: :py:class:`psyclone.psyir.symbols.DataSymbol`
1421 :param str tag: a tag identifier for the new copy, by default no tag \
1424 :raises TypeError: if the given variable is not an imported variable.
1425 :raises KeyError: if the given variable name already exists in the \
1429 if not isinstance(imported_var, DataSymbol):
1431 f
"The imported_var argument of "
1432 f
"SymbolTable.copy_external_import method should be a "
1433 f
"DataSymbol, but found '{type(imported_var).__name__}'.")
1435 if not imported_var.is_import:
1437 f
"The imported_var argument of SymbolTable.copy_external_"
1438 f
"import method should have an ImportInterface interface, "
1439 f
"but found '{type(imported_var.interface).__name__}'.")
1441 external_container_name = imported_var.interface.container_symbol.name
1445 if external_container_name
not in self:
1447 container_ref = self.
lookuplookup(external_container_name)
1450 if imported_var.name
not in self:
1451 new_symbol = imported_var.copy()
1454 self.
addadd(new_symbol, tag)
1458 local_instance = self.
lookuplookup(imported_var.name)
1459 if not (local_instance.is_import
and
1461 local_instance.interface.container_symbol,
1462 external_container_name)):
1464 f
"Couldn't copy '{imported_var}' into the SymbolTable. The"
1465 f
" name '{imported_var.name}' is already used by another "
1474 self.
_tags_tags[tag] = self.
lookuplookup(imported_var.name)
1479 f
"Couldn't copy '{imported_var}' into the SymbolTable."
1480 f
" The tag '{tag}' is already used by another symbol.")
1483 ''' Try to resolve deferred and unknown information from imported
1484 symbols in this symbol table by searching for their definitions in
1485 referred external container. A single symbol to resolve can be
1486 specified for a more targeted import.
1488 :param container_symbols: list of container symbols to search in
1489 order to resolve imported symbols. Defaults to all container
1490 symbols in the symbol table.
1491 :type container_symbols: list[
1492 :py:class:`psyclone.psyir.symbols.ContainerSymbol`]
1493 :param symbol_target: If a symbol is given, this method will just
1494 resolve information for the given symbol. Otherwise it will
1495 resolve all possible symbols information. Defaults to None.
1496 :type symbol_target: Optional[
1497 :py:class:`psyclone.psyir.symbols.Symbol`]
1499 :raises SymbolError: if a symbol name clash is found between multiple \
1500 imports or an import and a local symbol.
1501 :raises TypeError: if the provided container_symbols is not a list of \
1503 :raises TypeError: if the provided symbol_target is not a Symbol.
1504 :raises KeyError: if a symbol_target has been specified but this has \
1505 not been found in any of the searched containers.
1508 if container_symbols
is not None:
1509 if not isinstance(container_symbols, list):
1511 f
"The resolve_imports container_symbols argument must be a"
1512 f
" list but found '{type(container_symbols).__name__}' "
1514 for item
in container_symbols:
1515 if not isinstance(item, ContainerSymbol):
1517 f
"The resolve_imports container_symbols argument list "
1518 f
"elements must be ContainerSymbols, but found a "
1519 f
"'{type(item).__name__}' instead.")
1524 if symbol_target
and not isinstance(symbol_target, Symbol):
1526 f
"The resolve_imports symbol_target argument must be a Symbol "
1527 f
"but found '{type(symbol_target).__name__}' instead.")
1529 for c_symbol
in container_symbols:
1531 external_container = c_symbol.container
1541 for symbol
in external_container.symbol_table.symbols:
1542 if symbol.visibility == Symbol.Visibility.PRIVATE:
1545 if isinstance(symbol, ContainerSymbol):
1554 symbol, symbol_target):
1571 for scoping_node
in self.
nodenode.walk(ScopingNode):
1572 symbol_table = scoping_node.symbol_table
1573 if symbol.name
in symbol_table:
1574 test_symbol = symbol_table.lookup(symbol.name)
1576 if (type(test_symbol)
is Symbol
1577 and test_symbol.is_unresolved):
1579 if not [sym
for sym
in
1580 symbol_table.containersymbols
if
1581 sym.wildcard_import]:
1582 symbol_table.remove(test_symbol)
1583 if test_symbol.name
not in self:
1584 self.
addadd(test_symbol)
1586 for ref
in symbol_table.node.walk(
1588 if SymbolTable._has_same_name(
1589 ref.symbol, symbol):
1590 mod_symbol = self.
lookuplookup(
1592 ref.symbol = mod_symbol
1595 if symbol.name
in self:
1597 symbol_match = self.
lookuplookup(symbol.name)
1598 interface = symbol_match.interface
1599 visibility = symbol_match.visibility
1604 if not c_symbol.wildcard_import:
1605 if not isinstance(interface, ImportInterface)
or \
1606 interface.container_symbol
is not c_symbol:
1611 if isinstance(interface, UnresolvedInterface):
1614 elif isinstance(interface, ImportInterface):
1620 f
"Found a name clash with symbol '{symbol.name}' "
1621 f
"when importing symbols from container "
1622 f
"'{c_symbol.name}'.")
1627 if isinstance(symbol, type(symbol_match)):
1629 if type(symbol)
is not type(symbol_match):
1630 if isinstance(symbol, TypedSymbol):
1633 symbol_match.specialise(
1634 type(symbol), datatype=symbol.datatype)
1636 symbol_match.specialise(type(symbol))
1638 symbol_match.copy_properties(symbol)
1641 symbol_match.interface = interface
1642 symbol_match.visibility = visibility
1648 if c_symbol.wildcard_import:
1651 new_symbol = symbol.copy()
1654 self.
addadd(new_symbol)
1662 f
"The target symbol '{symbol_target.name}' was not found in "
1663 f
"any of the searched containers: "
1664 f
"{[cont.name for cont in container_symbols]}.")
1668 Rename the given symbol which should belong to this symbol table
1669 with the new name provided.
1671 :param symbol: the symbol to be renamed.
1672 :type symbol: :py:class:`psyclone.psyir.symbols.Symbol`
1673 :param str name: the new name.
1674 :param bool dry_run: if True then only the validation checks are
1677 :raises TypeError: if the symbol is not a Symbol.
1678 :raises TypeError: if the name is not a str.
1679 :raises ValueError: if the given symbol does not belong to this
1681 :raises KeyError: if the given variable name already exists in the
1683 :raises SymbolError: if the specified Symbol is a ContainerSymbol, is
1684 imported/unresolved or is a formal routine argument.
1685 :raises SymbolError: if the specified Symbol is accessed within a
1686 CodeBlock in the scope of this table.
1687 :raises SymbolError: if the symbol has a common block interface.
1690 if not isinstance(symbol, Symbol):
1692 f
"The symbol argument of rename_symbol() must be a Symbol, but"
1693 f
" found: '{type(symbol).__name__}'.")
1695 if symbol
not in self.
symbolssymbols:
1697 f
"The symbol argument of rename_symbol() must belong to this "
1698 f
"symbol_table instance, but '{symbol}' does not.")
1700 if isinstance(symbol, ContainerSymbol):
1701 raise SymbolError(f
"Cannot rename symbol '{symbol.name}' because "
1702 f
"it is a ContainerSymbol.")
1704 if symbol.is_import:
1706 f
"Cannot rename symbol '{symbol.name}' because it is imported "
1707 f
"(from Container '{symbol.interface.container_symbol.name}')."
1710 if symbol.is_unresolved:
1712 f
"Cannot rename symbol '{symbol.name}' because it is "
1715 if symbol.is_argument:
1717 f
"Cannot rename symbol '{symbol.name}' because it is a routine"
1718 f
" argument and as such may be named in a Call.")
1720 if symbol.is_commonblock:
1722 f
"Cannot rename symbol '{symbol.name}' because it has a "
1723 f
"CommonBlock interface.")
1725 if not isinstance(name, str):
1727 f
"The name argument of rename_symbol() must be a str, but"
1728 f
" found: '{type(symbol).__name__}'.")
1732 f
"The name argument of rename_symbol() must not already exist "
1733 f
"in this symbol_table instance, but '{name}' does.")
1735 old_name = self.
_normalize_normalize(symbol.name)
1739 cblocks = self.
nodenode.walk(CodeBlock)
1740 for cblock
in cblocks:
1741 sym_names = [self.
_normalize_normalize(sname)
for sname
in
1742 cblock.get_symbol_names()]
1743 if old_name
in sym_names:
1744 cblk_txt =
"\n".join(str(anode)
for anode
in
1745 cblock.get_ast_nodes)
1747 f
"Cannot rename Symbol '{symbol.name}' because it is "
1748 f
"accessed in a CodeBlock:\n"
1755 del self.
_symbols_symbols[old_name]
1767 Searches this symbol table and then up through any parent symbol
1768 tables for a ContainerSymbol that has a wildcard import.
1770 :returns: the name(s) of containers which have wildcard imports
1771 into the current scope.
1776 current_table = self
1777 while current_table:
1778 for sym
in current_table.containersymbols:
1779 if sym.wildcard_import:
1780 wildcards.add(sym.name)
1781 current_table = current_table.parent_symbol_table()
1786 :returns: a representation of this Symbol Table.
1793 header =
"Symbol Table"
1795 header += f
" of {self.node.coloured_name(False)}"
1796 if hasattr(self.
nodenode,
'name'):
1797 header += f
" '{self.node.name}'"
1799 header +=
"\n" +
"-" * len(header) +
"\n"
1801 return header +
"\n".join(map(str, self.
_symbols_symbols.values())) +
"\n"
1806 :returns: the scope associated to this symbol table.
1807 :rtype: :py:class:`psyclone.psyir.nodes.ScopingNode`
1810 return self.
_node_node
1813 ''' Detach this symbol table from the associated scope and return self.
1815 :returns: this symbol table.
1816 :rtype: py:class:`psyclone.psyir.symbols.SymbolTable`
1821 self.
_node_node._symbol_table =
None
1822 self.
_node_node =
None
1826 ''' Attach this symbol table to the provided scope.
1828 :param node: the scoped node this symbol table will attach to.
1829 :type node: py:class:`psyclone.psyir.nodes.ScopingNode`
1834 if not isinstance(node, ScopingNode):
1836 f
"A SymbolTable must be attached to a ScopingNode"
1837 f
" but found '{type(node).__name__}'.")
1839 if node.symbol_table
is not None:
1841 "The provided scope already has a symbol table attached "
1842 "to it. You may need to detach that one first.")
1844 if self.
_node_node
is not None:
1846 f
"The symbol table is already bound to another "
1847 f
"scope ({self.node.node_str(False)}). Consider "
1848 f
"detaching or deepcopying the symbol table first.")
1850 self.
_node_node = node
1852 node._symbol_table = self
1856 Checks whether two SymbolTables are equal.
1858 # TODO 1698: Improve. Currently it uses a quick implementation
1859 # that only checks that the view() lines of each symbol_table
1860 # are exactly the same.
1861 # The current implementation does not check tags, order
1862 # of arguments or visibilities.
1864 :param object other: the object to check equality to.
1866 :returns: whether other is equal to self.
1870 if type(self)
is not type(other):
1872 this_lines = self.
viewview().split(
'\n')
1873 other_lines = other.view().split(
'\n')
1874 for line
in other_lines:
1875 if line
not in this_lines:
1877 this_lines.remove(line)
1878 return len(this_lines) == 0
def unresolved_datasymbols(self)
def _handle_symbol_clash(self, old_sym, other_table)
def swap(self, old_symbol, new_symbol)
def get_tags(self, scope_limit=None)
def __contains__(self, key)
def resolve_imports(self, container_symbols=None, symbol_target=None)
def next_available_name(self, root_name=None, shadowing=False, other_table=None)
def imported_symbols(self)
def _has_same_name(cls, first, second)
def rename_symbol(self, symbol, name, dry_run=False)
def add(self, new_symbol, tag=None)
def get_reverse_tags_dict(self)
def containersymbols(self)
def find_or_create_tag(self, tag, root_name=None, **new_symbol_args)
def _validate_non_args(self)
def symbols_imported_from(self, csymbol)
def check_for_clashes(self, other_table, symbols_to_skip=())
def merge(self, other_table, symbols_to_skip=())
def _add_container_symbols_from_table(self, other_table)
def argument_datasymbols(self)
def lookup(self, name, visibility=None, scope_limit=None)
def iteration_indices(self)
def datatypesymbols(self)
def swap_symbol_properties(self, symbol1, symbol2)
def _add_symbols_from_table(self, other_table, symbols_to_skip=())
def default_visibility(self)
def copy_external_import(self, imported_var, tag=None)
def default_visibility(self, vis)
def specify_argument_list(self, argument_symbols)
def automatic_datasymbols(self)
def parent_symbol_table(self, scope_limit=None)
def find_or_create(self, name, **new_symbol_args)
def new_symbol(self, root_name=None, tag=None, shadowing=False, symbol_type=None, allow_renaming=True, **symbol_init_args)
def precision_datasymbols(self)
def wildcard_imports(self)
def _validate_arg_list(arg_list)
def get_symbols(self, scope_limit=None)
def _validate_remove_routinesymbol(self, symbol)
def lookup_with_tag(self, tag, scope_limit=None)