render_priorities.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. import argparse
  2. import sys
  3. import subprocess
  4. import os
  5. from sccd.util.os_tools import *
  6. from sccd.util.indenting_writer import *
  7. from sccd.statechart.parser.xml import *
  8. from sccd.statechart.static import priority
  9. if __name__ == '__main__':
  10. parser = argparse.ArgumentParser(
  11. description="Render the priorities between transitions in a statechart as a graph.")
  12. parser.add_argument('path', metavar='PATH', type=str, nargs='*', help="Models to render. Can be a XML file or a directory. If a directory, it will be recursively scanned for XML files.")
  13. args = parser.parse_args()
  14. srcs = get_files(args.path,
  15. filter=lambda file: (file.startswith("statechart_") or file.startswith("test_") or file.startswith("model_")) and file.endswith(".xml"))
  16. if len(srcs) == 0:
  17. print("No input files specified.")
  18. print()
  19. parser.print_usage()
  20. exit()
  21. try:
  22. subprocess.run(["dot", "-?"], capture_output=True)
  23. except:
  24. print("Could not run command 'dot'. Make sure GraphViz dot is installed.")
  25. for src in srcs:
  26. path = os.path.dirname(src)
  27. parse_sc = statechart_parser_rules(Globals(), path, load_external=False)
  28. def find_statechart(el):
  29. def when_done(statechart):
  30. return statechart
  31. # When parsing <test>, only look for <statechart> node in it.
  32. # All other nodes will be ignored.
  33. return ({"statechart": parse_sc}, when_done)
  34. try:
  35. statechart = parse_f(src, {
  36. "test": find_statechart,
  37. "single_instance_cd": find_statechart,
  38. "statechart": parse_sc,
  39. }, ignore_unmatched=True)
  40. except SkipFile:
  41. continue
  42. assert isinstance(statechart, Statechart)
  43. if statechart.semantics.has_multiple_variants():
  44. print("Skipping statechart from " + src + ". Statechart has multiple semantic variants.")
  45. continue
  46. tree = statechart.tree
  47. semantics = statechart.semantics
  48. hierarchical = {
  49. HierarchicalPriority.NONE: priority.none,
  50. HierarchicalPriority.SOURCE_PARENT: priority.source_parent,
  51. HierarchicalPriority.SOURCE_CHILD: priority.source_child,
  52. HierarchicalPriority.ARENA_PARENT: priority.arena_parent,
  53. HierarchicalPriority.ARENA_CHILD: priority.arena_child,
  54. }[semantics.hierarchical_priority]
  55. same_state = {
  56. SameSourcePriority.NONE: priority.none,
  57. SameSourcePriority.EXPLICIT: priority.explicit_same_state,
  58. }[semantics.same_source_priority]
  59. orthogonal = {
  60. OrthogonalPriority.NONE: priority.none,
  61. OrthogonalPriority.EXPLICIT: priority.explicit_ortho,
  62. }[semantics.orthogonal_priority]
  63. same_state_edges = same_state(tree)
  64. hierarchical_edges = hierarchical(tree)
  65. orthogonal_edges = orthogonal(tree)
  66. dot_target = dropext(src)+'_priorities.dot'
  67. svg_target = dropext(src)+'_priorities.svg'
  68. with open(dot_target, 'w') as f:
  69. w = IndentingWriter(f)
  70. w.write("digraph priorities {")
  71. w.indent()
  72. pseudo_dict = {}
  73. def node_label(t):
  74. if isinstance(t, priority.PseudoVertex):
  75. try:
  76. label = pseudo_dict[t]
  77. except KeyError:
  78. pseudo_dict[t] = label = "pseudo"+str(len(pseudo_dict))
  79. w.write("%s [label=\"\" shape=circle style=filled fixedsize=true width=0.4 height=0.4 fillcolor=\"grey\"];" % label)
  80. return label
  81. elif isinstance(t, Transition):
  82. trigger = ""
  83. guard = ""
  84. if t.trigger is not None:
  85. trigger = t.trigger.render()
  86. if t.guard is not None:
  87. guard = "["+t.guard.render()+"]"
  88. return '"'+str(tree.transition_list.index(t)) + ". " + trigger + guard + " / " + t.source.short_name + "->" + t.target.short_name+'"'
  89. def draw_edges(edges, color):
  90. for high, low in edges:
  91. w.write("%s -> %s [color=%s];" % (node_label(high), node_label(low), color))
  92. draw_edges(same_state_edges, "green")
  93. draw_edges(hierarchical_edges, "red")
  94. draw_edges(orthogonal_edges, "blue")
  95. w.dedent()
  96. w.write("}")
  97. subprocess.run(["dot", "-Tsvg", dot_target, "-o", svg_target])
  98. print("Wrote", svg_target)
  99. os.remove(dot_target)