render.py 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. import argparse
  2. import sys
  3. from lib.os_tools import *
  4. from lib.builder import Builder, dropext
  5. from sccd.compiler.utils import FormattedWriter
  6. from sccd.runtime.statecharts_core import *
  7. if __name__ == '__main__':
  8. parser = argparse.ArgumentParser(
  9. description="Render statecharts as SVG images.")
  10. 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.")
  11. parser.add_argument('--build-dir', metavar='BUILD_DIR', type=str, default='build', help="Directory for output files. Defaults to 'build'")
  12. args = parser.parse_args()
  13. builder = Builder(args.build_dir)
  14. srcs = get_files(args.path, filter=xml_filter)
  15. for src in srcs:
  16. module = builder.build_and_load(src)
  17. model = module.Model()
  18. for class_name, _class in model.classes.items():
  19. f = open(dropext(src)+'_'+class_name+'.smcat', 'w')
  20. w = FormattedWriter(f)
  21. sc = _class().statechart
  22. def name_to_label(name):
  23. label = name.split('/')[-1]
  24. return label if len(label) else "root"
  25. def name_to_name(name):
  26. return name.replace('/','_')
  27. class PseudoState:
  28. def __init__(self, name):
  29. self.name = name
  30. class PseudoTransition:
  31. def __init__(self, source, targets):
  32. self.source = source
  33. self.targets = targets
  34. self.trigger = None
  35. transitions = []
  36. def write_state(s, hide=False):
  37. if not hide:
  38. w.write(name_to_name(s.name))
  39. w.extendWrite(' [label="')
  40. w.extendWrite(name_to_label(s.name))
  41. w.extendWrite('"')
  42. if isinstance(s, ParallelState):
  43. w.extendWrite(' type=parallel')
  44. elif isinstance(s, HistoryState):
  45. w.extendWrite(' type=history')
  46. elif isinstance(s, DeepHistoryState):
  47. w.extendWrite(' type=deephistory')
  48. else:
  49. w.extendWrite(' type=regular')
  50. w.extendWrite(']')
  51. if s.children:
  52. if not hide:
  53. w.extendWrite(' {')
  54. w.indent()
  55. if s.default_state:
  56. w.write(name_to_name(s.name)+'_initial [type=initial],')
  57. transitions.append(PseudoTransition(source=PseudoState(s.name+'/initial'), targets=[s.default_state]))
  58. for i, c in enumerate(s.children):
  59. write_state(c)
  60. w.extendWrite(',' if i < len(s.children)-1 else ';')
  61. if not hide:
  62. w.dedent()
  63. w.write('}')
  64. transitions.extend(s.transitions)
  65. write_state(sc.root, hide=True)
  66. for t in transitions:
  67. w.write(name_to_name(t.source.name) + ' -> ' + name_to_name(t.targets[0].name))
  68. label = ""
  69. if t.trigger and t.trigger.name:
  70. label = (t.trigger.port + '.' if t.trigger.port else '') + t.trigger.name
  71. if label:
  72. w.extendWrite(': '+label)
  73. w.extendWrite(';')
  74. f.close()