LoLADraw.py 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. import subprocess
  2. import sys
  3. try:
  4. import pydot
  5. has_pydot = True
  6. except ImportError:
  7. has_pydot = False
  8. class LoLADraw:
  9. def get_net(self, filename):
  10. places = []
  11. markings = {}
  12. transitions = {}
  13. place_mode = False
  14. marking_mode = False
  15. transition_mode = False
  16. trans_consume_mode = True
  17. trans_name = ""
  18. trans_consume = {}
  19. trans_produce = {}
  20. with open(filename) as f:
  21. for line in f:
  22. if "PLACE" in line:
  23. place_mode = True
  24. continue
  25. elif "MARKING" in line:
  26. place_mode = False
  27. marking_mode = True
  28. continue
  29. elif "TRANSITION" in line:
  30. marking_mode = False
  31. transition_mode = True
  32. line = line.strip()
  33. if not line:
  34. continue
  35. print(line)
  36. if place_mode:
  37. if "SAFE" in line:
  38. continue
  39. for place in line.split(','):
  40. place = place.replace(";", "").strip()
  41. if place:
  42. places.append(place)
  43. elif marking_mode:
  44. for marking in line.split(','):
  45. if not marking:
  46. continue
  47. m = marking.split(":")
  48. markings[m[0].strip()] = m[1].replace(";", "").strip()
  49. elif transition_mode:
  50. if "TRANSITION" in line:
  51. if trans_name:
  52. transitions[trans_name] = (trans_consume, trans_produce)
  53. trans_consume = {}
  54. trans_produce = {}
  55. trans_name = line.split(" ")[1]
  56. elif trans_consume_mode:
  57. if "CONSUME" in line:
  58. continue
  59. elif "PRODUCE" in line:
  60. trans_consume_mode = False
  61. else:
  62. for consume in line.split(","):
  63. if not consume:
  64. continue
  65. place, marking = consume.split(":")
  66. trans_consume[place.strip()] = marking.replace(";", "").strip()
  67. elif not trans_consume_mode:
  68. if ";" in line:
  69. trans_consume_mode = True
  70. for produce in line.split(","):
  71. if not produce:
  72. continue
  73. place, marking = produce.split(":")
  74. trans_produce[place.strip()] = marking.replace(";", "").strip()
  75. # do end-of-file
  76. if trans_name:
  77. transitions[trans_name] = (trans_consume, trans_produce)
  78. return places, markings, transitions
  79. def draw(self, filename):
  80. name = filename.replace(".lola", "")
  81. nodes = {}
  82. graph = pydot.Dot(name, graph_type='digraph', layout='fdp')
  83. places, markings, transitions = self.get_net(filename)
  84. print("Places: " + str(places))
  85. print("Markings: " + str(markings))
  86. print("Transitions: " + str(transitions))
  87. for i, place in enumerate(places):
  88. v_attr = place
  89. if place in markings:
  90. v_attr += "\n" + markings[place]
  91. nodes[place] = pydot.Node(v_attr, style="filled", fillcolor='lightblue')
  92. graph.add_node(nodes[place])
  93. for t_name, _ in transitions.items():
  94. v_attr = t_name
  95. nodes[t_name] = pydot.Node(v_attr, style="filled")
  96. graph.add_node(nodes[t_name])
  97. for t_name, conpro in transitions.items():
  98. c, p = conpro
  99. for c_name, weight in c.items():
  100. graph.add_edge(pydot.Edge(nodes[c_name], nodes[t_name])) # , color=color))
  101. for p_name, weight in p.items():
  102. graph.add_edge(pydot.Edge(nodes[t_name], nodes[p_name], label=weight))
  103. # , color=color))
  104. dot_filename = filename.replace(".lola", ".dot")
  105. graph.write(dot_filename, prog='dot')
  106. svg_filename = filename.replace(".lola", ".svg")
  107. command = "dot -Tsvg " + dot_filename + " -o " + svg_filename
  108. returncode = subprocess.call(command, shell=True)
  109. if returncode != 0:
  110. print("ERROR: Please ensure that GraphViz is installed!")
  111. print("Exported drawing to file: " + svg_filename)
  112. # command = "rm " + dot_filename
  113. # subprocess.call(command, shell=True)
  114. if __name__ == "__main__":
  115. print("Starting LoLADraw...")
  116. if len(sys.argv) < 2:
  117. print("Error: Please pass a filename as the first argument.")
  118. exit(1)
  119. if not has_pydot:
  120. print("ERROR: Install pydot first!")
  121. exit(1)
  122. filename = sys.argv[1]
  123. ld = LoLADraw()
  124. ld.draw(filename)