Repository: stfc/PSyclone (python)

Issue:
SymbolTable view() output needs sorting/ordering
It's a nice-to-have but it would be good if view() output the symbols grouped by type and in alpha-order within each group.

Pull request description:
(Closes #2195) SymbolTable().view() grouping and alpha-ordering
Gives outputs like
```
Symbol Table of Routine 'func':
-------------------------------
DataSymbol:
  var1: DataSymbol<Scalar<REAL, UNDEFINED>, Automatic>
  var2: DataSymbol<Scalar<INTEGER, UNDEFINED>, Automatic>
RoutineSymbol:
  func: RoutineSymbol<NoType, pure=unknown, elemental=unknown>
```

where Symbol subclasses are alpha-sorted and symbols are as well.

I hope that's what you had in mind?

Patch:
diff --git a/src/psyclone/psyir/symbols/symbol_table.py b/src/psyclone/psyir/symbols/symbol_table.py
index bb253970e..3b50de37c 100644
--- a/src/psyclone/psyir/symbols/symbol_table.py
+++ b/src/psyclone/psyir/symbols/symbol_table.py
@@ -1798,7 +1798,19 @@ class SymbolTable():
         header += ":"
         header += "\n" + "-" * len(header) + "\n"
 
-        return header + "\n".join(map(str, self._symbols.values())) + "\n"
+        # Unique types of symbols, alpha-sorted.
+        symbol_types = list({type(symbol)
+                             for symbol in self._symbols.values()})
+        symbol_types.sort(key=lambda t: t.__name__)
+        for symbol_type in symbol_types:
+            header += symbol_type.__name__ + ":\n"
+            # _symbols is an OrderDict so these are alpha-sorted.
+            for symbol in self._symbols.values():
+                # pylint: disable=unidiomatic-typecheck
+                if type(symbol) is symbol_type:
+                    header += f"  {symbol}\n"
+
+        return header
 
     @property
     def scope(self):


Test patch:
diff --git a/src/psyclone/tests/psyir/symbols/symbol_table_test.py b/src/psyclone/tests/psyir/symbols/symbol_table_test.py
index d604cc352..5add7456c 100644
--- a/src/psyclone/tests/psyir/symbols/symbol_table_test.py
+++ b/src/psyclone/tests/psyir/symbols/symbol_table_test.py
@@ -1399,15 +1399,61 @@ def test_wildcard_imports():
 
 def test_view():
     '''Test the view method of the SymbolTable class, it should return a
-    representation of the full SymbolTable.'''
+    representation of the full SymbolTable, sorted by symbol type and
+    alphabetically ordered.'''
     sym_table = symbols.SymbolTable()
     sym_table.add(symbols.DataSymbol("var1", symbols.REAL_TYPE))
     sym_table.add(symbols.DataSymbol("var2", symbols.INTEGER_TYPE))
     output = sym_table.view()
     assert "Symbol Table:\n" in output
+    assert "DataSymbol:\n" in output
     assert "var1" in output
     assert "var2" in output
 
+    sym_table_2 = sym_table.deep_copy()
+
+    sym_table.add(symbols.RoutineSymbol("func", symbols.REAL_TYPE))
+    output = sym_table.view()
+    assert "Symbol Table:\n" in output
+    assert "DataSymbol:\n" in output
+    assert "var1" in output
+    assert "var2" in output
+    assert "RoutineSymbol:\n" in output
+    assert "func" in output
+    assert output.index("DataSymbol:\n") < output.index("RoutineSymbol:\n")
+    assert output.index("var1") < output.index("var2")
+    assert output == ("Symbol Table:\n"
+                      "-------------\n"
+                      "DataSymbol:\n"
+                      "  var1: DataSymbol<Scalar<REAL, UNDEFINED>, "
+                      "Automatic>\n"
+                      "  var2: DataSymbol<Scalar<INTEGER, UNDEFINED>, "
+                      "Automatic>\n"
+                      "RoutineSymbol:\n"
+                      "  func: RoutineSymbol<Scalar<REAL, UNDEFINED>, "
+                      "pure=unknown, elemental=unknown>\n")
+
+    Routine("func", symbol_table=sym_table_2)
+    output = sym_table_2.view()
+    assert "Symbol Table of Routine 'func':\n" in output
+    assert "DataSymbol:\n" in output
+    assert "var1" in output
+    assert "var2" in output
+    assert "RoutineSymbol:\n" in output
+    assert "func" in output
+    assert output.index("DataSymbol:\n") < output.index("RoutineSymbol:\n")
+    assert output.index("var1") < output.index("var2")
+    assert output == ("Symbol Table of Routine 'func':\n"
+                      "-------------------------------\n"
+                      "DataSymbol:\n"
+                      "  var1: DataSymbol<Scalar<REAL, UNDEFINED>, "
+                      "Automatic>\n"
+                      "  var2: DataSymbol<Scalar<INTEGER, UNDEFINED>, "
+                      "Automatic>\n"
+                      "RoutineSymbol:\n"
+                      "  func: RoutineSymbol<NoType, pure=unknown, "
+                      "elemental=unknown>\n")
+
 
 def test_can_be_printed():
     '''Test that a SymbolTable instance can always be printed. (i.e. is