소스 검색

Overhaul of directory structure.

Joeri Exelmans 5 년 전
부모
커밋
650cb9334c
100개의 변경된 파일1599개의 추가작업 그리고 5297개의 파일을 삭제
  1. 0 0
      src/sccd/compiler/__init__.py
  2. 0 17
      src/sccd/compiler/compiler_exceptions.py
  3. 0 811
      src/sccd/compiler/generic_generator.py
  4. 0 1020
      src/sccd/compiler/generic_language_constructs.py
  5. 0 287
      src/sccd/compiler/javascript_writer.py
  6. 0 171
      src/sccd/compiler/lexer.py
  7. 0 83
      src/sccd/compiler/path_calculator.py
  8. 0 357
      src/sccd/compiler/python_writer.py
  9. 0 1169
      src/sccd/compiler/sccd_constructs.py
  10. 0 137
      src/sccd/compiler/sccdc.py
  11. 0 157
      src/sccd/compiler/state_linker.py
  12. 0 221
      src/sccd/compiler/stateful_writer.py
  13. 0 52
      src/sccd/compiler/super_class_linker.py
  14. 0 30
      src/sccd/compiler/visitor.py
  15. 6 5
      src/sccd/runtime/controller.py
  16. 0 0
      src/sccd/controller/event_queue.py
  17. 1 3
      src/sccd/runtime/object_manager.py
  18. 0 0
      src/sccd/controller/test_event_queue.py
  19. 6 17
      src/sccd/runtime/event.py
  20. 14 0
      src/sccd/execution/instance.py
  21. 4 4
      src/sccd/runtime/round.py
  22. 9 11
      src/sccd/runtime/statechart_instance.py
  23. 13 12
      src/sccd/runtime/statechart_state.py
  24. 33 0
      src/sccd/execution/timestamp.py
  25. 0 0
      src/sccd/legacy/socket2event.py
  26. 10 10
      src/sccd/runtime/xml_loader.py
  27. 28 0
      src/sccd/model/model.py
  28. 23 0
      src/sccd/model/namespace.py
  29. 46 112
      src/sccd/runtime/xml_loader2.py
  30. 0 0
      src/sccd/runtime/__init__.py
  31. 0 1
      src/sccd/runtime/libs/__init__.py
  32. 0 64
      src/sccd/runtime/libs/drawing.py
  33. 0 198
      src/sccd/runtime/libs/ordered_set.py
  34. 0 121
      src/sccd/runtime/libs/ui.py
  35. 0 19
      src/sccd/runtime/libs/utils.py
  36. 0 62
      src/sccd/runtime/model.py
  37. 0 48
      src/sccd/runtime/tkinter_eventloop.py
  38. 33 0
      src/sccd/syntax/action.py
  39. 9 0
      src/sccd/syntax/datamodel.py
  40. 1 54
      src/sccd/runtime/expression.py
  41. 10 4
      src/sccd/runtime/semantic_options.py
  42. 46 0
      src/sccd/syntax/statement.py
  43. 13 38
      src/sccd/runtime/statechart_syntax.py
  44. 2 2
      src/sccd/runtime/test.py
  45. 67 0
      src/sccd/test/xml_loader.py
  46. 0 0
      src/sccd/util/bitmap.py
  47. 0 0
      src/sccd/util/debug.py
  48. 64 0
      src/sccd/util/indenting_writer.py
  49. 0 0
      src/sccd/util/utils.py
  50. 907 0
      src/sccd_runtime.svg
  51. 150 0
      test/legacy_render.py
  52. 104 0
      test/legacy_test.py
  53. 0 0
      test/legacy_test_files/compiler/stateref/flat_absolute+c.svg
  54. 0 0
      test/legacy_test_files/compiler/stateref/flat_absolute.xml
  55. 0 0
      test/legacy_test_files/compiler/stateref/flat_relative+c.svg
  56. 0 0
      test/legacy_test_files/compiler/stateref/flat_relative.xml
  57. 0 0
      test/legacy_test_files/compiler/stateref/nested_absolute+c.svg
  58. 0 0
      test/legacy_test_files/compiler/stateref/nested_absolute.xml
  59. 0 0
      test/legacy_test_files/compiler/stateref/nested_relative+c.svg
  60. 0 0
      test/legacy_test_files/compiler/stateref/nested_relative.xml
  61. 0 0
      test/legacy_test_files/pssm/PSSM_TestSuite.xmi
  62. 0 0
      test/legacy_test_files/scxml/schemas/scxml-attribs.xsd
  63. 0 0
      test/legacy_test_files/scxml/schemas/scxml-contentmodels.xsd
  64. 0 0
      test/legacy_test_files/scxml/schemas/scxml-copyright.xsd
  65. 0 0
      test/legacy_test_files/scxml/schemas/scxml-core-strict.xsd
  66. 0 0
      test/legacy_test_files/scxml/schemas/scxml-data-strict.xsd
  67. 0 0
      test/legacy_test_files/scxml/schemas/scxml-datatypes.xsd
  68. 0 0
      test/legacy_test_files/scxml/schemas/scxml-external-strict.xsd
  69. 0 0
      test/legacy_test_files/scxml/schemas/scxml-strict.xsd
  70. 0 0
      test/legacy_test_files/scxml/tests/test144.txml
  71. 0 0
      test/legacy_test_files/scxml/tests/test147.txml
  72. 0 0
      test/legacy_test_files/scxml/tests/test148.txml
  73. 0 0
      test/legacy_test_files/scxml/tests/test149.txml
  74. 0 0
      test/legacy_test_files/scxml/tests/test150.txml
  75. 0 0
      test/legacy_test_files/scxml/tests/test151.txml
  76. 0 0
      test/legacy_test_files/scxml/tests/test152.txml
  77. 0 0
      test/legacy_test_files/scxml/tests/test153.txml
  78. 0 0
      test/legacy_test_files/scxml/tests/test155.txml
  79. 0 0
      test/legacy_test_files/scxml/tests/test156.txml
  80. 0 0
      test/legacy_test_files/scxml/tests/test158.txml
  81. 0 0
      test/legacy_test_files/scxml/tests/test159.txml
  82. 0 0
      test/legacy_test_files/scxml/tests/test172.txml
  83. 0 0
      test/legacy_test_files/scxml/tests/test173.txml
  84. 0 0
      test/legacy_test_files/scxml/tests/test174.txml
  85. 0 0
      test/legacy_test_files/scxml/tests/test175.txml
  86. 0 0
      test/legacy_test_files/scxml/tests/test176.txml
  87. 0 0
      test/legacy_test_files/scxml/tests/test178.txml
  88. 0 0
      test/legacy_test_files/scxml/tests/test179.txml
  89. 0 0
      test/legacy_test_files/scxml/tests/test183.txml
  90. 0 0
      test/legacy_test_files/scxml/tests/test185.txml
  91. 0 0
      test/legacy_test_files/scxml/tests/test186.txml
  92. 0 0
      test/legacy_test_files/scxml/tests/test187.txml
  93. 0 0
      test/legacy_test_files/scxml/tests/test189.txml
  94. 0 0
      test/legacy_test_files/scxml/tests/test190.txml
  95. 0 0
      test/legacy_test_files/scxml/tests/test191.txml
  96. 0 0
      test/legacy_test_files/scxml/tests/test192.txml
  97. 0 0
      test/legacy_test_files/scxml/tests/test193.txml
  98. 0 0
      test/legacy_test_files/scxml/tests/test194.txml
  99. 0 0
      test/legacy_test_files/scxml/tests/test198.txml
  100. 0 0
      test/test_files/scxml/tests/test199.txml

+ 0 - 0
src/sccd/compiler/__init__.py


+ 0 - 17
src/sccd/compiler/compiler_exceptions.py

@@ -1,17 +0,0 @@
-class CompilerException(Exception):
-	def __init__(self, message):
-		self.message = message
-	def __str__(self):
-		return repr(self.message)
-	
-class TransitionException(CompilerException):
-	pass
-
-class UnprocessedException(CompilerException):
-	pass
-
-class CodeBlockException(CompilerException):
-	pass
-
-class TargetLanguageException(CompilerException):
-  pass

+ 0 - 811
src/sccd/compiler/generic_generator.py

@@ -1,811 +0,0 @@
-# Generic Generator by Joeri Exelmans
-#
-# Visits SCCD-domain constructs (see sccd_constructs.py) and converts them
-# to a generic language AST (see generic_language_constructs.py), that can
-# then be visited by a target language writer.
-
-import traceback
-import time
-
-from sccd.compiler.utils import Enum, Logger
-from sccd.compiler.visitor import Visitor
-from sccd.compiler.sccd_constructs import FormalParameter
-from sccd.compiler.stateful_writer import StatefulWriter
-import sccd.compiler.generic_language_constructs as GLC
-
-Platforms = Enum("Threads","GameLoop","EventLoop")
-
-def compiled_class_name(class_name):
-    return "Class_"+class_name
-
-class GenericGenerator(Visitor):
-    
-    def __init__(self, platform):
-        self.platform = platform
-        self.writer = StatefulWriter()
-
-    def generic_visit(self, node):
-        Logger.showWarning("GenericGenerator has no visit method for node of type '" + str(type(node)) + "'.")
-
-    def get(self):
-        return self.writer.get()
-
-    def visit_ClassDiagram(self, class_diagram):
-        header = ("Generated by Statechart compiler by Glenn De Jonghe, Joeri Exelmans, Simon Van Mierlo, and Yentl Van Tendeloo (for the inspiration)\n")
-        if class_diagram.name or class_diagram.author or class_diagram.description:
-            header += "\n"
-        if class_diagram.author:
-            header += "Model author: " + class_diagram.author + "\n"
-        if class_diagram.name:
-            header += "Model name:   " + class_diagram.name + "\n"
-        if class_diagram.description.strip():
-            header += "Model description:\n"
-            header += class_diagram.description.strip()
-
-        self.writer.addMultiLineComment(header)
-        self.writer.addVSpace()
-        self.writer.addInclude(([GLC.RuntimeModuleIdentifier(), "event"]))
-        self.writer.addInclude(([GLC.RuntimeModuleIdentifier(), "statechart_syntax"]))
-        self.writer.addInclude(([GLC.RuntimeModuleIdentifier(), "statechart_instance"]))
-        if class_diagram.top.strip():
-            self.writer.addRawCode(class_diagram.top)
-        self.writer.addVSpace()
-
-        self.writer.beginPackage(class_diagram.name)
-
-        for c in class_diagram.classes:
-            c.accept(self)
-
-        self.writer.beginClass("Model")
-        self.writer.beginConstructor()
-        self.writer.beginMethodBody()
-        self.writer.addAssignment(GLC.SelfProperty("inports"), GLC.ArrayExpression([GLC.String(i) for i in class_diagram.inports]))
-        self.writer.addAssignment(GLC.SelfProperty("outports"), GLC.ArrayExpression([GLC.String(o) for o in class_diagram.outports]))
-        self.writer.addAssignment(GLC.SelfProperty("classes"), GLC.MapExpression(
-            { GLC.String(c.name) : GLC.Identifier(compiled_class_name(c.name)) for c in class_diagram.classes }))
-        self.writer.addAssignment(GLC.SelfProperty("default_class"), GLC.String(class_diagram.default_class.name))
-        self.writer.endMethodBody()
-        self.writer.endConstructor()
-        self.writer.endClass()
-
-        # visit test node if there is one
-        if class_diagram.test:
-            class_diagram.test.accept(self)
-
-        self.writer.endPackage()
-
-    ### TESTS
-    def visit_DiagramTest(self, test):
-        # helper class
-        self.writer.beginClass("InputEvent")
-        self.writer.beginConstructor()
-        self.writer.addFormalParameter("name")
-        self.writer.addFormalParameter("port")
-        self.writer.addFormalParameter("parameters")
-        self.writer.addFormalParameter("time_offset")
-        self.writer.beginMethodBody()
-        self.writer.addAssignment(GLC.SelfProperty("name"), "name")
-        self.writer.addAssignment(GLC.SelfProperty("port"), "port")
-        self.writer.addAssignment(GLC.SelfProperty("parameters"), "parameters")
-        self.writer.addAssignment(GLC.SelfProperty("time_offset"), "time_offset")
-        self.writer.endMethodBody()
-        self.writer.endConstructor()
-        self.writer.endClass()
-        self.writer.beginClass("Test")
-        if test.input:
-            test.input.accept(self)
-        else:
-            self.writer.addStaticAttribute("input_events", GLC.ArrayExpression())
-        if test.expected:
-            test.expected.accept(self)
-        else:
-            self.writer.addStaticAttribute("expected_events", GLC.ArrayExpression())
-        self.writer.endClass()
-
-    def visit_DiagramTestInput(self, test_input):
-        # write array of input events
-        self.writer.startRecordingExpression()
-        self.writer.beginArray()
-        for e in test_input.input_events:
-            e.accept(self)
-        self.writer.endArray()
-        array_expr = self.writer.stopRecordingExpression()
-        self.writer.addStaticAttribute("input_events", array_expr)
-
-    def visit_DiagramTestInputEvent(self, event):
-        self.writer.add(GLC.NewExpression("InputEvent", [GLC.String(event.name), GLC.String(event.port), GLC.ArrayExpression(event.parameters), event.time]))
-
-    def visit_DiagramTestExpected(self, test_expected):
-        # write array of slots containing expected events
-        self.writer.startRecordingExpression()
-        self.writer.beginArray()
-        for s in test_expected.slots:
-            s.accept(self)
-        self.writer.endArray()
-        array_expr = self.writer.stopRecordingExpression()
-        self.writer.addStaticAttribute("expected_events", array_expr)
-
-    def visit_DiagramTestExpectedSlot(self, slot):
-        # write slot
-        self.writer.beginArray()
-        for e in slot.expected_events:
-            e.accept(self)
-        self.writer.endArray()
-
-    def visit_DiagramTestEvent(self, event):
-        self.writer.add(GLC.NewExpression("Event", [GLC.String(event.name), GLC.String(event.port), GLC.ArrayExpression(event.parameters)]))
-
-    def visit_Class(self, class_node):
-        if class_node.statechart:
-            self.writer.beginClass("Statechart_"+class_node.name)
-            class_node.statechart.accept(self)
-            self.writer.endClass()
-
-        self.writer.beginClass(compiled_class_name(class_node.name))
-        self.writer.beginConstructor()
-        self.writer.beginMethodBody()
-        self.writer.addAssignment(GLC.SelfProperty("name"), GLC.String(class_node.name))
-        if class_node.statechart:
-            self.writer.addAssignment(GLC.SelfProperty("statechart"), GLC.NewExpression("Statechart_"+class_node.name, [GLC.SelfExpression()]))
-        self.writer.endMethodBody()
-        self.writer.endConstructor()
-        self.writer.endClass()
-
-    def visit_StateChart(self, statechart):
-        # We are in the Statechart_ClassName class here:
-        self.writer.beginConstructor()
-        self.writer.addFormalParameter("_class")
-        self.writer.beginMethodBody()
-
-        self.writer.addAssignment(GLC.SelfProperty("_class"), GLC.Identifier("_class"))
-        self.writer.addVSpace()
-
-        self.writer.addAssignment(GLC.SelfProperty("semantics"), GLC.NewExpression("StatechartSemantics"))
-        if statechart.big_step_maximality == "take_one":
-            self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "big_step_maximality"), GLC.Property("StatechartSemantics", "TakeOne"))
-        elif statechart.big_step_maximality == "take_many":
-            self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "big_step_maximality"), GLC.Property("StatechartSemantics", "TakeMany"))
-        if statechart.combo_step_maximality == "take_one":
-            self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "combo_step_maximality"), GLC.Property("StatechartSemantics", "ComboTakeOne"))
-        elif statechart.combo_step_maximality == "take_many":
-            self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "combo_step_maximality"), GLC.Property("StatechartSemantics", "ComboTakeMany"))
-        if statechart.internal_event_lifeline == "queue":
-            self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "internal_event_lifeline"), GLC.Property("StatechartSemantics", "Queue"))
-        elif statechart.internal_event_lifeline == "next_small_step":
-            self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "internal_event_lifeline"), GLC.Property("StatechartSemantics", "NextSmallStep"))
-        elif statechart.internal_event_lifeline == "next_combo_step":
-            self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "internal_event_lifeline"), GLC.Property("StatechartSemantics", "NextComboStep"))
-        if statechart.input_event_lifeline == "first_small_step":
-            self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "input_event_lifeline"), GLC.Property("StatechartSemantics", "FirstSmallStep"))
-        elif statechart.input_event_lifeline == "first_combo_step":
-            self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "input_event_lifeline"), GLC.Property("StatechartSemantics", "FirstComboStep"))
-        elif statechart.input_event_lifeline == "whole":
-            self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "input_event_lifeline"), GLC.Property("StatechartSemantics", "Whole"))
-        if statechart.priority == "source_parent":
-            self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "priority"), GLC.Property("StatechartSemantics", "SourceParent"))
-        elif statechart.priority == "source_child":
-            self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "priority"), GLC.Property("StatechartSemantics", "SourceChild"))
-        if statechart.concurrency == "single":
-            self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "concurrency"), GLC.Property("StatechartSemantics", "Single"))
-        elif statechart.concurrency == "many":
-            self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "concurrency"), GLC.Property("StatechartSemantics", "Many"))
-
-        self.writer.addVSpace()
-
-        def writeState(s):
-            # self.writer.addComment("state %s" % ("<root>" if s.is_root else s.new_full_name))
-            index_expr = GLC.MapIndexedExpression(GLC.SelfProperty("states"), GLC.String(s.new_full_name))
-            clazz = "State"
-            if s.is_parallel_state:
-                clazz = "ParallelState"
-            elif s.is_history:
-                if s.is_history_deep:
-                    clazz = "DeepHistoryState"
-                else:
-                    clazz = "ShallowHistoryState"
-            self.writer.addAssignment(
-                index_expr,
-                GLC.NewExpression(clazz, [GLC.String(s.new_name)])
-            )
-            if not s.is_root:
-                if s.enter_action.action or s.has_timers:
-                    self.writer.add(
-                        GLC.FunctionCall(
-                            GLC.Property(
-                                index_expr,
-                                "setEnter"
-                            ),
-                            [GLC.SelfProperty(s.friendly_name + "_enter")]
-                        )
-                    )
-                if s.exit_action.action or s.has_timers:
-                    self.writer.add(
-                        GLC.FunctionCall(
-                            GLC.Property(
-                                index_expr,
-                                "setExit"
-                            ),
-                            [GLC.SelfProperty(s.friendly_name + "_exit")]
-                        )
-                    )
-        
-        # write all states
-        self.writer.addAssignment(GLC.SelfProperty("states"), GLC.MapExpression())
-        for s in statechart.states:
-            writeState(s)
-
-        # statechart structure
-        self.writer.addVSpace()
-        self.writer.addComment("structure")
-        self.writer.addAssignment(GLC.SelfProperty("root"), GLC.MapIndexedExpression(GLC.SelfProperty("states"), GLC.String(statechart.root.new_full_name)))
-        for (i, s) in enumerate(statechart.composites):
-            for c in s.children:
-                self.writer.add(
-                    GLC.FunctionCall(
-                        GLC.Property(
-                            GLC.MapIndexedExpression(
-                                GLC.SelfProperty("states"),
-                                GLC.String(s.new_full_name)
-                            ),
-                        "addChild"),
-                        [GLC.MapIndexedExpression(GLC.SelfProperty("states"), GLC.String(c.new_full_name))]
-                    )
-                )
-                
-        # fix tree at root, such that 'descendants' and 'ancestors' fields are filled in
-        self.writer.add(
-            GLC.FunctionCall(
-                GLC.Property(
-                    GLC.SelfProperty("root"),
-                    "init_tree"
-                )
-            )
-        )
-        
-        # defaults
-        for (i, s) in enumerate(statechart.composites):
-            if not s.is_parallel_state:
-                self.writer.addAssignment(
-                    GLC.Property(
-                        GLC.MapIndexedExpression(
-                            GLC.SelfProperty("states"),
-                            GLC.String(s.new_full_name)
-                        ),
-                        "default_state"
-                    ),
-                    GLC.MapIndexedExpression(
-                        GLC.SelfProperty("states"),
-                        GLC.String(s.initial)
-                    )
-                )
-        
-        # transitions
-        self.writer.addVSpace()
-        self.writer.addComment("transitions")
-        for s in statechart.basics + statechart.composites:
-            # if s.transitions:
-            #     self.writer.addVSpace()
-                # self.writer.addComment("transition %s" % s.new_full_name)
-            for (i, t) in enumerate(s.transitions + s.else_transitions):
-                # instantiate new Transition instance
-                self.writer.addAssignment(
-                    GLC.LocalVariableDeclaration(
-                        "%s_%i" % (s.friendly_name, i)
-                    ),
-                    GLC.NewExpression(
-                        "Transition",
-                        [
-                            # GLC.SelfExpression(),
-                            GLC.MapIndexedExpression(
-                                GLC.SelfProperty("states"),
-                                GLC.String(s.new_full_name),
-                            ),
-                            GLC.ArrayExpression(
-                                [
-                                    GLC.MapIndexedExpression(
-                                        GLC.SelfProperty("states"),
-                                        GLC.String(target_node.new_full_name)
-                                    )
-                                    for target_node in t.target.target_nodes
-                                ]
-                            )
-                        ]
-                    )
-                )
-                # if any action associated with transition: set executable_content to correct function (generated later)
-                if t.action.sub_actions:
-                    self.writer.add(
-                        GLC.FunctionCall(
-                            GLC.Property(
-                                "%s_%i" % (s.friendly_name, i),
-                                "setAction"
-                            ),
-                            [GLC.SelfProperty("%s_%i_exec" % (s.friendly_name, i))]
-                        )
-                    )
-                # if any trigger associated with transition: instantiate correct Event instance
-                trigger = None
-                if t.trigger.is_after:
-                    trigger = GLC.NewExpression("Event", [GLC.String("_after_%i" % (t.trigger.getAfterIndex()))])
-                elif t.trigger.event:
-                    trigger = GLC.NewExpression("Event",
-                                                    [
-                                                        GLC.String(t.trigger.event),
-                                                        GLC.NoneExpression() if t.trigger.port is None else GLC.String(t.trigger.port)
-                                                    ]
-                                                )
-                else:
-                    trigger = GLC.NoneExpression()
-                if trigger:
-                    self.writer.add(
-                        GLC.FunctionCall(
-                            GLC.Property(
-                                "%s_%i" % (s.friendly_name, i),
-                                "setTrigger"
-                            ),
-                            [trigger]
-                        )
-                    )
-                # if any guard associated with transition: set guard to correct function (generated later)
-                if t.guard:
-                    self.writer.add(
-                        GLC.FunctionCall(
-                            GLC.Property(
-                                "%s_%i" % (s.friendly_name, i),
-                                "setGuard"
-                            ),
-                            [GLC.SelfProperty("%s_%i_guard" % (s.friendly_name, i))]
-                        )
-                    )
-                self.writer.add(
-                    GLC.FunctionCall(
-                        GLC.Property(
-                            GLC.MapIndexedExpression(
-                                GLC.SelfProperty("states"),
-                                GLC.String(s.new_full_name)
-                            ),
-                            "addTransition"
-                        ),
-                        ["%s_%i" % (s.friendly_name, i)]
-                    )
-                )
-        self.writer.endMethodBody()
-        self.writer.endConstructor()
-        
-        # enter/exit actions
-        for (i, s) in enumerate(statechart.composites + statechart.basics):
-            if not s.is_root:
-                if s.enter_action.action or s.has_timers:
-                    s.enter_action.accept(self)
-                if s.exit_action.action or s.has_timers:
-                    s.exit_action.accept(self)
-        
-        # transition actions and guards
-        for s in statechart.composites + statechart.basics:
-            for (i, t) in enumerate(s.transitions):
-                if t.action.sub_actions:
-                    self.writeTransitionAction(t, i)
-                if t.hasGuard():
-                    self.writeTransitionGuard(t, i)
-
-
-    def visit_EnterAction(self, enter_method):
-        parent_node = enter_method.parent_node
-        self.writer.beginMethod(parent_node.friendly_name + "_enter")
-        self.writer.addFormalParameter("instance")
-        self.writer.beginMethodBody()
-
-        if enter_method.action:
-            enter_method.action.accept(self)
-
-        # take care of any AFTER events
-        for transition in parent_node.transitions :
-            trigger = transition.getTrigger()
-            if trigger.isAfter() :
-                self.writer.startRecordingExpression()
-                trigger.after.accept(self)
-                after = self.writer.stopRecordingExpression()
-                self.writer.addComment("schedule timer")
-                # self.writer.add(GLC.AssignmentExpression(GLC.Identifier("timer_event"), GLC.NewExpression("Event", [GLC.FunctionCall(GLC.Property("instance", "next_timer_id"))])))
-                # self.writer.add(GLC.FunctionCall())
-                self.writer.add(GLC.FunctionCall(GLC.Property(GLC.Property("instance", "_big_step"), "addOutputEvent"),
-                    # function call parameter:
-                    [
-                        GLC.NewExpression("OutputEvent", [
-                            GLC.NewExpression("Event", [GLC.String("_after_"+str(trigger.getAfterIndex()))]),
-                            GLC.NewExpression("InstancesTarget", [GLC.ArrayExpression([GLC.Identifier("instance")])]),
-                            after
-                        ])
-                    ]))
-                # self.writer.add(GLC.FunctionCall(GLC.SelfProperty("addTimer"), [str(trigger.getAfterIndex()), after]))
-                
-        self.writer.endMethodBody()
-        self.writer.endMethod()
-         
-    def visit_ExitAction(self, exit_method):
-        parent_node = exit_method.parent_node
-        self.writer.beginMethod(parent_node.friendly_name + "_exit")
-        self.writer.addFormalParameter("instance")
-        self.writer.beginMethodBody()
-        
-        # take care of any AFTER events
-        for transition in parent_node.transitions:
-            trigger = transition.getTrigger()
-            if trigger.isAfter():
-                self.writer.add(GLC.IncrementExpression(GLC.MapIndexedExpression(GLC.Property("instance", "ignore_events"), GLC.String("_after_"+str(trigger.getAfterIndex()))), GLC.Literal("1")))
-                # self.writer.add(GLC.FunctionCall(GLC.SelfProperty("removeTimer"), [str(trigger.getAfterIndex())]))
-                
-        # execute user-defined exit action if present
-        if exit_method.action:
-            exit_method.action.accept(self)
-        
-        self.writer.endMethodBody()
-        self.writer.endMethod()        
-
-    def visit_RaiseEvent(self, raise_event):
-        self.writer.startRecordingExpression()
-        self.writer.begin(GLC.NewExpression("Event"))
-
-        self.writer.addActualParameter(GLC.String(raise_event.getEventName()))
-        if raise_event.isOutput():
-            self.writer.addActualParameter(GLC.String(raise_event.getPort()))
-        else:
-            self.writer.addActualParameter(GLC.NoneExpression())
-
-        self.writer.end()
-        new_event_expr = self.writer.stopRecordingExpression()
-
-        self.writer.startRecordingExpression()
-        self.writer.beginArray()
-        if raise_event.isCD():
-            self.writer.add(GLC.Identifier("instance"))
-        for param in raise_event.getParameters() :
-            param.accept(self) # -> visit_Expression will cause expressions to be added to array
-        self.writer.endArray()
-        parameters_array_expr = self.writer.stopRecordingExpression()
-        new_event_expr.getActualParameters().add(parameters_array_expr)
-
-        if raise_event.isNarrow():
-            self.writer.add(GLC.FunctionCall(
-                GLC.Property(GLC.Property("instance", "_big_step"), "outputEventOM"), [
-                    GLC.NewExpression("Event", [
-                        GLC.String("narrow_cast"),
-                        GLC.NoneExpression(),
-                        GLC.ArrayExpression([
-                            GLC.SelfExpression(),
-                            raise_event.getTarget(),
-                            new_event_expr])])]))
-        elif raise_event.isLocal():
-            self.writer.add(GLC.FunctionCall(
-                GLC.Property("instance", "_raiseInternalEvent"),
-                [new_event_expr]))
-        elif raise_event.isOutput():
-            # event to output port
-            output_event = GLC.NewExpression("OutputEvent", [new_event_expr, GLC.NewExpression("OutputPortTarget", [GLC.String(raise_event.getPort())])])
-            self.writer.add(GLC.FunctionCall(
-                GLC.Property(GLC.Property("instance", "_big_step"), "addOutputEvent"),
-                [output_event]))
-        elif raise_event.isCD():
-            output_event = GLC.NewExpression("OutputEvent", [new_event_expr, GLC.NewExpression("InstancesTarget", [GLC.ArrayExpression([GLC.Property("instance", "object_manager")])])])
-            self.writer.add(GLC.FunctionCall(
-                GLC.Property(GLC.Property("instance", "_big_step"), "addOutputEvent"),
-                [output_event]))
-        elif raise_event.isBroad():
-            self.writer.add(GLC.FunctionCall(
-                GLC.Property(GLC.Property("instance", "_big_step"), "outputEventOM"),
-                [GLC.NewExpression("Event", [
-                    GLC.String("broad_cast"),
-                    GLC.NoneExpression(),
-                    GLC.ArrayExpression([
-                        GLC.SelfExpression(),
-                        new_event_expr])])]))
-
-    # ### CLASS
-    # def visit_Class(self, class_node):
-    #     """
-    #     Generate code for Class construct
-    #     """
-    #     super_classes = []
-    #     if not class_node.super_class_objs:
-    #         # if none of the class' super classes is defined in the diagram,
-    #         # we have to inherit RuntimeClassBase
-    #         if class_node.statechart:
-    #             # only inherit RuntimeClassBase if class has a statechart
-    #             super_classes.append("RuntimeClassBase")
-    #     if class_node.super_classes:
-    #         for super_class in class_node.super_classes:
-    #             super_classes.append(super_class)
-
-    #     self.writer.beginClass(compiled_class_name(class_node.name), super_classes)
-
-    #     # visit constructor
-    #     class_node.constructors[0].accept(self)
-
-    #     # visit destructor
-    #     class_node.destructors[0].accept(self)
-        
-    #     # visit methods
-    #     for i in class_node.methods:
-    #         i.accept(self)
-
-    #     # compile and initialize Statechart
-    #     if class_node.statechart:
-    #         class_node.statechart.accept(self)
-        
-    #     self.writer.endClass()
-        
-    ### CLASS -- CONSTRUCTOR
-    def visit_Constructor(self, constructor):
-        self.writer.beginConstructor()
-        if constructor.parent_class.statechart:
-            self.writer.addFormalParameter("controller")
-        for p in constructor.getParams():
-            self.writer.addFormalParameter(p.getIdent(), p.getDefault())
-        self.writer.beginMethodBody() # constructor body
-
-        if constructor.parent_class.statechart:
-            self.writer.beginSuperClassConstructorCall("RuntimeClassBase")
-            # self.writer.addActualParameter("controller")
-            self.writer.endSuperClassConstructorCall()
-
-            self.writer.addVSpace()
-            
-            for p in constructor.parent_class.inports:
-                self.writer.addAssignment(
-                    GLC.MapIndexedExpression(GLC.SelfProperty("inports"), GLC.String(p)),
-                    GLC.FunctionCall(GLC.Property("controller", "createInputPort"), [GLC.String(p), GLC.SelfExpression()]))
-
-            for p in constructor.parent_class.outports:
-                self.writer.addAssignment(
-                    GLC.MapIndexedExpression(GLC.SelfProperty("outports"), GLC.String(p)),
-                    GLC.FunctionCall(GLC.Property("controller", "createOutputPort"), [GLC.String(p), GLC.SelfExpression()]))
-
-            self.writer.addVSpace()
-            self.writer.addComment("build Statechart structure")
-            self.writer.add(GLC.FunctionCall(GLC.SelfProperty("build_statechart_structure"), []))
-
-        if constructor.parent_class.attributes:
-            self.writer.addVSpace()
-            self.writer.addComment("user defined attributes")
-            for attribute in constructor.parent_class.attributes:
-                if attribute.init_value is None :
-                    self.writer.addAssignment(GLC.SelfProperty(attribute.name), GLC.NoneExpression())
-                else :
-                    self.writer.addAssignment(GLC.SelfProperty(attribute.name), attribute.init_value)
-
-        self.writer.addVSpace()
-        self.writer.addComment("call user defined constructor")
-        self.writer.beginSuperClassMethodCall(compiled_class_name( constructor.parent_class.name ), "user_defined_constructor")
-        for p in constructor.getParams():
-            # we can't do p.accept(self) here because 'p' is a FormalParameter
-            # and we want to write it as an actual parameter
-            self.writer.addActualParameter(p.getIdent())
-        self.writer.endSuperClassMethodCall()
-        self.writer.endMethodBody()
-        self.writer.endConstructor()
-
-        # user defined constructor
-        self.writer.beginMethod("user_defined_constructor")
-        for p in constructor.getParams():
-            p.accept(self)
-        self.writer.beginMethodBody()
-        for super_class in constructor.parent_class.super_classes:
-            # begin call
-            if super_class in constructor.parent_class.super_class_objs:
-                self.writer.beginSuperClassMethodCall(super_class, "user_defined_constructor")
-            else:
-                self.writer.beginSuperClassConstructorCall(super_class)
-            # write actual parameters
-            if super_class in constructor.super_class_parameters:
-                for p in constructor.super_class_parameters[super_class]:
-                    self.writer.addActualParameter(p)
-            # end call
-            if super_class in constructor.parent_class.super_class_objs:
-                self.writer.endSuperClassMethodCall()
-            else:
-                self.writer.endSuperClassConstructorCall()
-        self.writer.addRawCode(constructor.body)
-        self.writer.endMethodBody()
-        self.writer.endMethod()
-
-    def visit_FormalParameter(self, formal_parameter):
-        self.writer.addFormalParameter(formal_parameter.getIdent(), formal_parameter.getDefault())
-
-    ### CLASS -- DESTRUCTOR
-    def visit_Destructor(self, destructor):
-        self.writer.beginMethod("user_defined_destructor")
-        self.writer.beginMethodBody()
-        if destructor.body.strip():
-            self.writer.addRawCode(destructor.body)
-        if destructor.parent_class.super_classes:
-            self.writer.addComment("call super class destructors")
-            for super_class in destructor.parent_class.super_classes:
-                # begin call
-                if super_class in destructor.parent_class.super_class_objs:
-                    self.writer.beginSuperClassMethodCall(super_class, "user_defined_destructor")
-                    self.writer.endSuperClassMethodCall()
-                else:
-                    self.writer.beginSuperClassDestructorCall(super_class)
-                    self.writer.endSuperClassDestructorCall()
-                    pass
-
-                # self.writer.beginSuperClassMethodCall(super_class, "user_defined_destructor")
-                # self.writer.endSuperClassMethodCall()
-        self.writer.endMethodBody()
-        self.writer.endMethod()
-        
-    ### CLASS -- METHOD
-    def visit_Method(self, method):
-        self.writer.addVSpace()
-        self.writer.beginMethod(method.name, "user defined method")
-        for p in method.parameters:
-            p.accept(self)
-        self.writer.beginMethodBody()
-        self.writer.addRawCode(method.body)
-        self.writer.endMethodBody()
-        self.writer.endMethod()
-        
-    ### CLASS -- ASSOCIATION
-    def visit_Association(self, association):
-        self.writer.addAssignment(
-            GLC.MapIndexedExpression(
-                GLC.Property("instance", "associations"),
-                GLC.String(association.name)),
-            GLC.NewExpression("Association", [GLC.String(association.to_class), str(association.min), str(association.max)]))
-        
-    def visit_FormalEventParameter(self, formal_event_parameter):
-        self.writer.add(formal_event_parameter.name)
-        
-    def writeFormalEventParameters(self, transition):
-        parameters = transition.getTrigger().getParameters()
-        if(len(parameters) > 0) :
-            for index, parameter in enumerate(parameters):
-                self.writer.startRecordingExpression()
-                parameter.accept(self)
-                parameter_expr = self.writer.stopRecordingExpression()
-                self.writer.addAssignment(
-                    GLC.LocalVariableDeclaration(parameter_expr),
-                    GLC.ArrayIndexedExpression("parameters", str(index)))        
-        
-    def writeTransitionAction(self, transition, index):
-        self.writer.beginMethod("%s_%i_exec" % (transition.parent_node.friendly_name, index))
-        
-        # parameters, start method
-        self.writer.addFormalParameter("instance")
-        self.writer.addFormalParameter("parameters")
-        self.writer.beginMethodBody()
-
-        # handle parameters to actually use them
-        self.writeFormalEventParameters(transition)
-        
-        # write action
-        transition.getAction().accept(self)
-        
-        # end method
-        self.writer.endMethodBody()
-        self.writer.endMethod()
-        
-    def writeTransitionGuard(self, transition, index):
-        self.writer.beginMethod("%s_%i_guard" % (transition.parent_node.friendly_name, index))
-        
-        # parameters, start method
-        self.writer.addFormalParameter("instance")
-        self.writer.addFormalParameter("parameters")
-        self.writer.beginMethodBody()
-        
-        # handle parameters to actually use them
-        self.writeFormalEventParameters(transition)
-        
-        # get guard condition
-        self.writer.startRecordingExpression()
-        transition.getGuard().accept(self) # --> visit_Expression
-        expr = self.writer.stopRecordingExpression()
-        
-        # return statement, end method
-        self.writer.add(GLC.ReturnStatement(expr))
-        self.writer.endMethodBody()
-        self.writer.endMethod()
-                
-    # helper method
-    def writeEnterHistory(self, entered_node, is_deep):
-        ### OLD CODE (TODO)
-        self.writer.beginMethod("enterHistory" + ("Deep" if is_deep else "Shallow") + "_" + entered_node.full_name)
-        self.writer.beginMethodBody()
-
-        self.writer.beginIf(GLC.EqualsExpression(
-            GLC.ArrayLength(
-                GLC.MapIndexedExpression(
-                    GLC.SelfProperty("history_state"),
-                    GLC.SelfProperty(entered_node.full_name))),
-            "0"))
-        defaults = entered_node.defaults
-
-        for node in defaults:
-            if node.is_basic :
-                self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enter_"+node.full_name)))
-            elif node.is_composite :
-                self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enterDefault_"+node.full_name)))
-
-        self.writer.endIf()
-        self.writer.beginElse()
-        children = entered_node.children
-        if entered_node.is_parallel_state:
-            for child in children:
-                if not child.is_history :
-                    self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enter_"+child.full_name)))
-                    self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enterHistory"+("Deep" if is_deep else "Shallow")+"_"+child.full_name)))
-        else:
-            for child in children:
-                if not child.is_history :
-                    self.writer.beginIf(GLC.ArrayContains(
-                        GLC.MapIndexedExpression(
-                            GLC.SelfProperty("history_state"),
-                            GLC.SelfProperty(entered_node.full_name)),
-                        GLC.SelfProperty(child.full_name)))
-                    if child.is_composite:
-                        if is_deep :
-                            self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enter_"+child.full_name)))
-                            self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enterHistoryDeep_"+child.full_name)))
-                        else :
-                            self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enterDefault_"+child.full_name)))
-                    else:
-                        self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enter_"+child.full_name)))
-                    self.writer.endIf()
-        self.writer.endElse()
-
-        self.writer.endMethodBody()
-        self.writer.endMethod()
-
-    def visit_SelfReference(self, self_reference):
-        self.writer.add(GLC.SelfExpression())
-
-    def visit_StateReference(self, state_ref):
-        self.writer.beginArray()
-        for node in state_ref.getNodes():
-            self.writer.add(GLC.SelfProperty(node.full_name))
-        self.writer.endArray()
-
-    def visit_InStateCall(self, in_state_call):
-        self.writer.add(
-            GLC.FunctionCall(
-                GLC.Property("instance", "inState"),
-                [
-                    GLC.ArrayExpression(
-                        [GLC.String(target_node.new_full_name) for target in in_state_call.targets for target_node in target.target_nodes]
-                    )
-                ]
-            )
-        )
-        
-    def visit_ElseGuard(self, else_guard):
-        self.writer.add(
-            GLC.String("ELSE_GUARD")
-        )
-
-    def visit_Expression(self, expression):
-        self.writer.startRecordingExpression()
-        self.writer.beginGlue()
-        for part in expression.expression_parts:
-            part.accept(self)
-        self.writer.endGlue()
-        expr = self.writer.stopRecordingExpression()
-        self.writer.add(expr)
-
-    def visit_ExpressionPartString(self, e):
-        self.writer.add(e.string)
-                    
-    def visit_Script(self, script):
-        self.writer.addRawCode(script.code)
-        
-    def visit_Log(self, log):
-        self.writer.add(GLC.LogStatement(log.message))
-        
-    def visit_Assign(self, assign):
-        self.writer.startRecordingExpression()
-        assign.lvalue.accept(self) # --> visit_Expression
-        lvalue = self.writer.stopRecordingExpression()
-        self.writer.startRecordingExpression()
-        assign.expression.accept(self) # --> visit_Expression
-        rvalue = self.writer.stopRecordingExpression()
-        self.writer.addAssignment(lvalue, rvalue)
-

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 0 - 1020
src/sccd/compiler/generic_language_constructs.py


+ 0 - 287
src/sccd/compiler/javascript_writer.py

@@ -1,287 +0,0 @@
-from sccd.compiler.visitor import Visitor
-from sccd.compiler.generic_language_constructs import *
-
-class JavascriptWriter(CLikeWriterBase):
-    def __init__(self, outputter):
-        self.out = outputter
-
-    ### VISIT METHODS ###
-
-    def visit_ArrayContains(self, a):
-        array = a.getArrayExpression()
-        el = a.getElementExpression()
-
-        self.out.extendWrite("(")
-        array.accept(self)
-        self.out.extendWrite(".indexOf(")
-        el.accept(self)
-        self.out.extendWrite(") !== -1)")
-
-    def visit_ArrayExpression(self, a):
-        elements = a.getElements()
-        if len(elements) == 0:
-            self.out.extendWrite("new Array()")
-        else:
-            self.out.extendWrite("[")
-            self.writeCommaSeparated(elements)
-            self.out.extendWrite("]")
-
-    def visit_ArrayIndexOf(self, a):
-        array = a.getArrayExpression()
-        el = a.getElementExpression()
-
-        array.accept(self)
-        self.out.extendWrite(".indexOf(")
-        el.accept(self)
-        self.out.extendWrite(")")
-
-    def visit_ArrayLength(self, a):
-        a.getArrayExpression().accept(self)
-        self.out.extendWrite(".length")
-
-    def visit_ArrayPushBack(self, a):
-        array = a.getArrayExpression()
-        el = a.getElementExpression()
-
-        array.accept(self)
-        self.out.extendWrite(".push(")
-        el.accept(self)
-        self.out.extendWrite(")")
-
-    def visit_AST(self, ast):
-        self.writeAll(ast.getEntries())
-
-    def visit_Class(self, c):
-        class_name = c.getIdentifier()
-        constructor = c.getConstructor()
-        super_classes = c.getSuperClassIdentifierList()
-        description = c.getDescription()
-
-        self.out.write()
-        if description:
-            self.writeComment(description)
-        constructor.accept(self)
-        if super_classes:
-            self.out.write(class_name + ".prototype = new Object();")
-            self.out.write("(function() {")
-            self.out.indent()
-            for s in super_classes:
-                # workaround for multiple inheritance
-                self.out.write("var proto = new " + s + "();")
-                self.out.write("for (prop in proto) {")
-                self.out.indent()
-                self.out.write(class_name + ".prototype[prop] = proto[prop];")
-                self.out.dedent()
-                self.out.write("}")
-            self.out.dedent()
-            self.out.write("})();")
-        self.writeAll(c.getMembers())
-
-    def visit_Constructor(self, constructor):
-        class_name = constructor.getClass().getIdentifier()
-        parameters = constructor.getFormalParameters()
-        body = constructor.getBody()
-
-        self.out.write("var " + class_name + " = function")
-        parameters.accept(self)
-        body.accept(self)
-        self.out.extendWrite(";")
-
-    def visit_EqualsOperator(self, e):
-        self.out.extendWrite(" === ")
-
-    def visit_ForLoopBody(self, body):
-        for_loop = body.getForLoop()
-        collection_expr = for_loop.getCollectionExpression()
-        iterator_identifier = for_loop.getIteratorIdentifier()
-
-        self.out.extendWrite(" {")
-        self.out.indent()
-        self.out.write("if (!")
-        collection_expr.accept(self)
-        self.out.extendWrite(".hasOwnProperty(" + iterator_identifier + "_idx)) continue;")
-        self.out.write("var " + iterator_identifier + " = ")
-        collection_expr.accept(self)
-        self.out.extendWrite("[" + iterator_identifier + "_idx]")
-        self.writeAll(body.getEntries())
-        self.out.dedent()
-        self.out.write("}")
-
-    def visit_ForLoopCurrentElement(self, el):
-        collection = el.getCollectionExpression()
-        iterator = el.getIteratorIdentifier()
-
-        collection.accept(self)
-        self.out.extendWrite("[" + iterator + "]")
-
-    def visit_ForLoopIterateArray(self, loop):
-        collection = loop.getCollectionExpression()
-        iterator = loop.getIteratorIdentifier()
-        body = loop.getBody()
-
-        self.out.write("for (var " + iterator + "_idx in ")
-        collection.accept(self)
-        self.out.extendWrite(")")
-        body.accept(self)
-
-    def visit_ForLoopIterateMapValues(self, loop):
-        collection = loop.getCollectionExpression()
-        iterator = loop.getIteratorIdentifier()
-        body = loop.getBody()
-
-        self.out.write("for (var " + iterator + "_idx in ")
-        collection.accept(self)
-        self.out.extendWrite(")")
-        body.accept(self)
-
-    def visit_FormalParameter(self, parameter):
-        self.out.extendWrite(parameter.getIdentifier())
-
-    def visit_IncludeStatement(self, i):
-        pass # javascript doesn't have an include mechanism
-
-    def visit_LocalVariableDeclaration(self, decl):
-        identifier = decl.getIdentifier()
-        init_value = decl.getInitValue()
-
-        self.out.extendWrite("var " + identifier)
-        if init_value:
-            self.out.extendWrite(" = ")
-            init_value.accept(self)
-
-    def visit_LogStatement(self, l):
-        self.out.write("console.log(\"" + l.getMessage() + "\");")
-
-    def visit_MapExpression(self, m):
-        elements = m.getElements()
-        if len(elements) == 0:
-            self.out.extendWrite("new Object()")
-        else:
-            self.out.extendWrite("{")
-            keys = list(elements.keys())
-            for i in range(len(keys)):
-                if i != 0:
-                    self.out.extendWrite(", ")            
-                self.out.extendWrite(keys[i] + " : ")
-                self.out.extendWrite(" : ")
-                elements[keys[i]].accept(self)
-            self.out.extendWrite("}")
-
-    def visit_MapIndexedExpression(self, i):
-        m = i.getMapExpression()
-        key = i.getKeyExpression()
-
-        m.accept(self)
-        self.out.extendWrite("[")
-        key.accept(self)
-        self.out.extendWrite("]")
-
-    def visit_MapRemoveElement(self, stmt):
-        map_expr = stmt.getMapExpression()
-        key_expr = stmt.getKeyExpression()
-
-        self.out.write("delete ") # this is a statement, not an expression
-        map_expr.accept(self)
-        self.out.extendWrite("[")
-        key_expr.accept(self)
-        self.out.extendWrite("];")        
-
-    def visit_Method(self, method):
-        class_name = method.getClass().getIdentifier()
-        method_name = method.getIdentifier()
-        description = method.getDescription()
-        body = method.getBody()
-        parameters = method.getFormalParameters()
-
-        self.out.write()
-        if description:
-            self.writeComment(description)
-        self.out.write(class_name + ".prototype." + method_name + " = function")
-        parameters.accept(self)
-        body.accept(self)
-        self.out.extendWrite(";")
-
-    def visit_MethodBody(self, body):
-        method = body.getMethod()
-        formal_parameters = method.getFormalParameters()
-        formal_parameter_list = formal_parameters.getParameterList()
-
-        self.out.extendWrite(" {")
-        self.out.indent()
-        # check for undefined parameters and replace them with default values
-        for p in formal_parameter_list:
-            p_id = p.getIdentifier()
-            p_default = p.getDefaultValue()
-            if p_default:
-                self.out.write("if (" + p_id + " === undefined) " + p_id + " = ")
-                p_default.accept(self)
-                self.out.extendWrite(";")
-        self.writeAll(body.getEntries())
-        self.out.dedent()
-        self.out.write("}")
-
-    def visit_NoneExpression(self, n):
-        self.out.extendWrite("null")
-
-    def visit_Package(self, package):
-        name = package.getIdentifier()
-        description = package.getDescription()
-
-        self.writeComment("package \"" + name + "\"")
-        if description:
-            self.writeComment(description)
-        self.out.write("var " + name + " = {};")
-        self.out.write("(function() {")
-        for d in package.getDeclarations():
-            d_id = d.getIdentifier()
-            d.accept(self)
-            self.out.write()
-            self.out.write("// add symbol '" + d_id + "' to package '" + name + "'")
-            self.out.write(name + "." + d_id + " = " + d_id + ";")
-        self.out.write("})();")
-
-    def visit_RuntimeModuleIdentifier(self, r):
-        self.out.extendWrite("javascript_runtime")
-
-    def visit_StaticAttribute(self, attr):
-        name = attr.getIdentifier()
-        init_value = attr.getInitValue()
-        class_name = attr.getClass().getIdentifier()
-
-        if init_value:
-            self.out.write(class_name + ".prototype." + name + " = ")
-            init_value.accept(self)
-            self.out.extendWrite(";")
-        else:
-            self.out.write(class_name + ".prototype." + name + " = null;")
-
-    def visit_SuperClassConstructorCall(self, call):
-        super_class = call.getSuperClassIdentifier()
-        params = call.getActualParameters()
-        param_list = [Literal("this")] + params.getParameterList()
-        params = ActualParameters(param_list)
-
-        self.out.extendWrite(super_class)
-        self.out.extendWrite(".call")
-        params.accept(self)
-
-    def visit_SuperClassDestructorCall(self, call):
-        pass # Javascript doesn't have destructors
-
-    def visit_SuperClassMethodCall(self, call):
-        super_class = call.getSuperClassIdentifier()
-        method_name = call.getMethodIdentifier()
-        params = call.getActualParameters()
-        param_list = [Literal("this")] + params.getParameterList()
-        params = ActualParameters(param_list)
-
-        self.out.extendWrite(super_class)
-        self.out.extendWrite(".prototype." + method_name + ".call")
-        params.accept(self)
-
-    def visit_ThrowExceptionStatement(self, stmt):
-        self.out.write("throw new Error(")
-        stmt.getExpression().accept(self)
-        self.out.extendWrite(");")
-
-

+ 0 - 171
src/sccd/compiler/lexer.py

@@ -1,171 +0,0 @@
-from sccd.compiler.utils import Enum
-
-TokenType = Enum("SLASH",
-                                 "LBRACKET",
-                                 "RBRACKET",
-                                 "COMMA",
-                                 "DOT",
-                                 "NUMBER",
-                                 "WORD",
-                                 "QUOTED",
-                                 "WHITESPACE",
-                                 "BINARYOPERATOR",
-                                 "UNARYOPERATOR",
-                                 "UNKNOWN"
-                                )
-
-class Token(object):
-        """ A simple Token structure. Token type, value and position.
-        """
-        def __init__(self, token_type, val, pos):
-                self.type = token_type
-                self.val = val
-                self.pos = pos
-
-        def __str__(self):
-                return '%s(%s) at %s' % (TokenType.name_of(self.type), self.val, self.pos)
-
-
-class LexerError(Exception):
-        def __init__(self, pos):
-                self.pos = pos
-                
-class Lexer(object):
-        single_rules = {
-                        '/': TokenType.SLASH,
-                        '(': TokenType.LBRACKET,
-                        ')': TokenType.RBRACKET,
-                        ',': TokenType.COMMA,
-                        '.': TokenType.DOT,
-                        '+': TokenType.BINARYOPERATOR,
-                        '-': TokenType.BINARYOPERATOR,
-                        '<': TokenType.BINARYOPERATOR,
-                        '>': TokenType.BINARYOPERATOR,
-                        '==': TokenType.BINARYOPERATOR,
-                        '<=': TokenType.BINARYOPERATOR,
-                        '>=': TokenType.BINARYOPERATOR,
-                        '=': TokenType.BINARYOPERATOR,
-                        '+=': TokenType.BINARYOPERATOR,
-                        '-=': TokenType.BINARYOPERATOR,
-                        '&&': TokenType.BINARYOPERATOR,
-                        '||': TokenType.BINARYOPERATOR,
-                        '!': TokenType.UNARYOPERATOR}
-        
-        def __init__(self, skip_white_space = True, accept_unknown_tokens = False):
-                self.skip_white_space = skip_white_space
-                self.accept_unknown_tokens = accept_unknown_tokens
-
-        def input(self, buf):
-                """ Initialize the lexer with a buffer as input.
-                """
-                self.buf = buf
-                self.pos = 0
-                self.buflen = len(buf)
-
-        def nextToken(self):
-                """ Return the next token (a Token object) found in the
-                        input buffer. None is returned if the end of the
-                        buffer was reached.
-                        In case of a lexing error (the current chunk of the
-                        buffer matches no rule), a LexerError is raised.
-                """
-                if self.skip_white_space :
-                        self.skipWhiteSpace() 
-                if self.pos >= self.buflen:
-                        return None
-
-                #c part of next token
-                c = self.buf[self.pos]
-                
-                #check if it is an operator
-                result_type = self.single_rules.get(c,None)
-                if result_type is not None :
-                        if self.pos < self.buflen-1:
-                                c2 = c+self.buf[self.pos+1]
-                                result_type2 = self.single_rules.get(c2, None)
-                                if result_type2 is not None:
-                                        c = c2
-                                        result_type = result_type2
-                                        self.pos += 1
-                        token = Token(result_type, c, self.pos)
-                        self.pos += 1
-                        return token
-                else : #not an operator
-                        if (self.isAlpha(c)) :
-                                return self.processIdentifier()
-                        elif (self.isDigit(c)) :
-                                return self.processNumber()
-                        elif ( c == "'" or c == '"') :
-                                return self.processQuote()
-                        elif (self.isWhiteSpace(c)) :
-                                return self.processWhiteSpace()
-
-                # if we're here, no rule matched
-                if self.accept_unknown_tokens :
-                        token = Token(TokenType.UNKNOWN, c, self.pos)
-                        self.pos += 1
-                        return token
-                raise LexerError("Invalid character at position " + str(self.pos) + ".")
-
-        def tokens(self):
-                """ Returns an iterator to the tokens found in the buffer.
-                """
-                while True:
-                        tok = self.nextToken()
-                        if tok is None: break
-                        yield tok
-                        
-        def skipWhiteSpace(self):
-                while (self.pos < self.buflen) : 
-                        if self.isWhiteSpace(self.buf[self.pos]) :
-                                self.pos += 1
-                        else :
-                                break     
-                        
-        def isAlpha(self, c):
-                return c.isalpha() or c == '_';
-        
-        def isAlphaNum(self, c):
-                return c.isalnum() or c == '_';
-        
-        def isDigit(self, c):
-                return c.isdigit()
-        
-        def isWhiteSpace(self, c):
-                return c == ' ' or c == '\t' or c == '\r' or c == '\n'
-        
-        def processNumber(self):
-                nextpos = self.pos + 1
-                while (nextpos < self.buflen) and (self.isDigit(self.buf[nextpos])) :
-                        nextpos += 1;
-                token = Token(TokenType.NUMBER, self.buf[self.pos:nextpos], self.pos)
-                self.pos = nextpos
-                return token
-        
-        def processIdentifier(self):
-                nextpos = self.pos + 1
-                while (nextpos < self.buflen) and (self.isAlphaNum(self.buf[nextpos])) :
-                        nextpos += 1;
-                token = Token(TokenType.WORD, self.buf[self.pos:nextpos], self.pos)
-                self.pos = nextpos
-                return token
-        
-        def processQuote(self):
-                # self.pos points at the opening quote. Find the ending quote.
-                end_index = self.buf.find(self.buf[self.pos], self.pos + 1)
-        
-                if (end_index == -1) :
-                        print("Buffer: " + str(self.buf))
-                        raise LexerError("Missing matching quote for the quote at position " + str(self.pos) + ".")
-                token = Token(TokenType.QUOTED, self.buf[self.pos:end_index+1], self.pos)
-
-                self.pos = end_index + 1;
-                return token;
-        
-        def processWhiteSpace(self):
-                nextpos = self.pos + 1
-                while (nextpos < self.buflen) and (self.isWhiteSpace(self.buf[nextpos])) :
-                        nextpos += 1;
-                token = Token(TokenType.WHITESPACE, self.buf[self.pos:nextpos], self.pos)
-                self.pos = nextpos
-                return token

+ 0 - 83
src/sccd/compiler/path_calculator.py

@@ -1,83 +0,0 @@
-from sccd.compiler.compiler_exceptions import *
-from sccd.compiler.visitor import Visitor
-
-class PathCalculator(Visitor):
-    """ Computes the states that must be exited and entered for a specific transition if the system is to make
-        that transition. 
-    """
-    
-    def visit_ClassDiagram(self, class_diagram): 
-        for c in class_diagram.classes :
-            c.accept(self)
-
-    def visit_Class(self, c):
-        if c.statechart:
-            c.statechart.accept(self)
-        
-    def visit_StateChart(self, statechart):
-        for node in statechart.basics + statechart.composites:
-            node.accept(self)
-                     
-    def visit_StateChartNode(self, node):
-        for transition in node.transitions :
-            transition.accept(self)
-            
-    def visit_StateChartTransition(self, transition):
-        #Find the scope of the transition (lowest common proper ancestor)
-        #TODO: Could it be made more efficient if we calculated the LCA from the source node and just one of the target nodes?
-        LCA = self.calculateLCA(transition)
-        
-        if LCA == None:
-            #raise CompilerException("Transision with source " + transition.parent_node.name + " and target " + transition.target_nodes + " has no lowest common ancestor node.")
-            raise CompilerException("Transision with source '" + transition.parent_node.name + "' and target '" + transition.target_string + "' has no lowest common ancestor node.")
-
-        #Calculate exit nodes
-        transition.exit_nodes = [transition.parent_node]
-        for node in transition.parent_node.getAncestors() :
-            if (node == LCA) :
-                break
-            transition.exit_nodes.append(node)
-            if node.is_parallel_state:
-                raise CompilerException("Transision with source '" + transition.parent_node.name + "' and target '" + transition.target_string + "' exits a parallel component.")
-       
-        #Calculate enter nodes
-        transition.enter_nodes = []
-        
-        #we then add the branching paths to the other nodes
-        for target_node in transition.target.target_nodes :
-            to_append_list = [(target_node, True)]
-            for anc in target_node.getAncestors() :
-                if anc == LCA : #If we reach the LCA in the ancestor hierarchy we break
-                    break;
-                to_add = True;  #boolean value to see if the current ancestor should be added to the result
-                for enter_node_entry in transition.enter_nodes :
-                    if anc == enter_node_entry[0] :
-                        to_add = False #If we reach an ancestor in the hierarchy that is already listed as enter node, we don't add and break
-                        break
-                if to_add:
-                    to_append_list.append((anc, False)) #Only the first from the ancestor list should get True
-                else :
-                    break
-                    
-            to_append_list.reverse() #the enter sequence should be in the reverse order of the ancestor hierarchy
-            transition.enter_nodes.extend(to_append_list)
-
-        # Calculate arena
-        current = LCA
-        while not current.is_composite:
-            current = current.parent
-        transition.arena = current
-
-    def calculateLCA(self, transition):
-        """
-        Calculates the lowest common ancestor of a transition
-        """ 
-        for anc in transition.parent_node.getAncestors() :
-            all_descendants = True 
-            for node in transition.target.getNodes() :
-                if not node.isDescendantOf(anc) :
-                    all_descendants = False
-                    break
-            if all_descendants :
-                return anc
-        return None

+ 0 - 357
src/sccd/compiler/python_writer.py

@@ -1,357 +0,0 @@
-from sccd.compiler.generic_language_constructs import *
-
-class PythonWriter(GenericWriterBase):
-	def __init__(self, outputter):
-		self.out = outputter
-
-
-	def writeComment(self, text):
-		self.out.write("# " + text)
-
-	def writeMultiLineComment(self, text):
-		self.out.write("\"\"\"\n" + text + "\n\"\"\"")
-
-	def visit_AndOperator(self, a):
-		self.out.extendWrite(" and ")
-
-	def visit_ArrayContains(self, a):
-		array = a.getArrayExpression()
-		el = a.getElementExpression()
-
-		el.accept(self)
-		self.out.extendWrite(" in ")
-		array.accept(self)
-
-	def visit_ArrayExpression(self, a):
-		self.out.extendWrite("[")
-		self.writeCommaSeparated(a.getElements())
-		self.out.extendWrite("]")
-
-	def visit_ArrayIndexOf(self, a):
-		array = a.getArrayExpression()
-		el = a.getElementExpression()
-
-		array.accept(self)
-		self.out.extendWrite(".index(")
-		el.accept(self)
-		self.out.extendWrite(")")
-
-	def visit_ArrayLength(self, a):
-		self.out.extendWrite("len(")
-		a.getArrayExpression().accept(self)
-		self.out.extendWrite(")")
-
-	def visit_ArrayPushBack(self, a):
-		array = a.getArrayExpression()
-		el = a.getElementExpression()
-
-		array.accept(self)
-		self.out.extendWrite(".append(")
-		el.accept(self)
-		self.out.extendWrite(")")
-
-	def visit_AST(self, ast):
-		self.writeAll(ast.getEntries())
-
-	def visit_Block(self, b):
-		self.out.indent()
-		self.writeAll(b.getEntries())
-		if b.isEmpty():
-			self.out.write("pass")
-		self.out.dedent()
-
-	def visit_BreakStatement(self, b):
-		self.out.write("break")
-
-	def visit_Class(self, c):
-		class_name = c.getIdentifier()
-		constructor = c.getConstructor()
-		super_classes = c.getSuperClassIdentifierList()
-		description = c.getDescription()
-
-		self.out.write()
-		if description:
-			self.writeComment(description)
-		self.out.write("class " + class_name)
-		if super_classes:
-			self.out.extendWrite("(" + ", ".join(super_classes) + ")")
-		self.out.extendWrite(":")
-		self.out.indent()
-		constructor.accept(self)
-		self.writeAll(c.getMembers())
-		self.out.dedent()
-
-	def visit_Constructor(self, constructor):
-		#class_name = constructor.getClass().getIdentifier()
-		parameters = constructor.getFormalParameters()
-		body = constructor.getBody()
-
-		self.out.write("def __init__")
-		parameters.accept(self)
-		self.out.extendWrite(":")
-		body.accept(self)
-
-	def visit_Destructor(self, destructor):
-		#class_name = destructor.getClass().getIdentifier()
-		parameters = destructor.getFormalParameters()
-		body = destructor.getBody()
-
-		self.out.write("def __del__")
-		parameters.accept(self)
-		self.out.extendWrite(":")
-		body.accept(self)
-
-	def visit_ElseStatement(self, else_stmt):
-		self.out.write("else:")
-		else_stmt.getBody().accept(self)
-
-	def visit_ElseIfStatement(self, else_if):
-		condition = else_if.getCondition()
-		body = else_if.getBody()
-
-		if else_if.isFirst():
-			self.out.write("if ")
-		else:
-			self.out.write("elif ")
-		condition.accept(self)
-		self.out.extendWrite(":")
-		body.accept(self)
-
-	def visit_EqualsOperator(self, e):
-		self.out.extendWrite(" == ")
-
-	def visit_ExpressionStatement(self, stmt):
-		self.out.write() # expressions don't begin with a newline
-		stmt.expression.accept(self)
-
-	def visit_FalseExpression(self, f):
-		self.out.extendWrite("False")
-
-	def visit_FormalParameter(self, parameter):
-		self.out.extendWrite(parameter.getIdentifier())
-		if parameter.getDefaultValue():
-			self.out.extendWrite(" = None") # correct default value will be assigned in function body
-
-	def visit_FormalParameters(self, p):
-		params = [Literal("self")] + p.getParameterList()
-		self.writeTuple(params)
-
-	def visit_ForLoopCurrentElement(self, el):
-		#collection = el.getCollectionExpression()
-		iterator = el.getIteratorIdentifier()
-
-		self.out.extendWrite(iterator)
-
-	def visit_ForLoopIterateArray(self, loop):
-		collection = loop.getCollectionExpression()
-		iterator = loop.getIteratorIdentifier()
-		body = loop.getBody()
-
-		self.out.write("for " + iterator + " in ")
-		collection.accept(self)
-		self.out.extendWrite(":")
-		body.accept(self)
-
-	def visit_ForLoopIterateMapValues(self, loop):
-		collection = loop.getCollectionExpression()
-		iterator = loop.getIteratorIdentifier()
-		body = loop.getBody()
-
-		self.out.write("for " + iterator + " in ")
-		collection.accept(self)
-		self.out.extendWrite(".itervalues():")
-		body.accept(self)
-
-	def visit_Identifier(self, identifier):
-		self.out.extendWrite(identifier.identifier)
-
-	def visit_IfStatement(self, if_stmt):
-		condition = if_stmt.getCondition()
-		body = if_stmt.getBody()
-
-		self.out.write("if ")
-		condition.accept(self)
-		self.out.extendWrite(":")
-		body.accept(self)
-
-	def visit_IncludeStatement(self, i):
-		module_path = i.getModulePath()
-		imported_symbols = i.getImportedSymbols()
-
-		self.out.write("from ")
-		for j in range(len(module_path)):
-			if j != 0:
-				self.out.extendWrite(".")
-			module_path[j].accept(self)
-		self.out.extendWrite(" import ")
-		if imported_symbols:
-			self.writeCommaSeparated(imported_symbols)
-		else:
-			self.out.extendWrite("*")
-
-	def visit_LocalVariableDeclaration(self, decl):
-		identifier = decl.getIdentifier()
-		init_value = decl.getInitValue()
-
-		self.out.extendWrite(decl.getIdentifier())
-		if init_value:
-			self.out.extendWrite(" = ")
-			init_value.accept(self)
-
-	def visit_LogStatement(self, l):
-		self.out.write("print(\"" + l.getMessage() + "\")")
-
-	def visit_MapExpression(self, m):
-		elements = m.getElements()
-		self.out.extendWrite("{")
-		keys = list(elements.keys())
-		for i in range(len(keys)):
-			if i != 0:
-				self.out.extendWrite(", ")
-			keys[i].accept(self)
-			self.out.extendWrite(" : ")
-			# self.out.extendWrite(" : ")
-			elements[keys[i]].accept(self)
-		self.out.extendWrite("}")
-
-	def visit_MapIndexedExpression(self, i):
-		m = i.getMapExpression()
-		key = i.getKeyExpression()
-
-		m.accept(self)
-		self.out.extendWrite("[")
-		key.accept(self)
-		self.out.extendWrite("]")
-
-	def visit_MapRemoveElement(self, stmt):
-		map_expr = stmt.getMapExpression()
-		key_expr = stmt.getKeyExpression()
-
-		self.out.write() # this is a statement, not an expression
-		map_expr.accept(self)
-		self.out.extendWrite(".pop(")
-		key_expr.accept(self)
-		self.out.extendWrite(", None)")
-
-	def visit_Method(self, method):
-		class_name = method.getClass().getIdentifier()
-		method_name = method.getIdentifier()
-		description = method.getDescription()
-		body = method.getBody()
-		parameters = method.getFormalParameters()
-
-		self.out.write()
-		if description:
-			self.writeComment(description)
-		self.out.write("def " + method_name + "")
-		parameters.accept(self)
-		self.out.extendWrite(":")
-		body.accept(self)
-
-	def visit_MethodBody(self, body):
-		method = body.getMethod()
-		formal_parameters = method.getFormalParameters()
-		formal_parameter_list = formal_parameters.getParameterList()
-
-		self.out.indent()
-		# check for undefined parameters and replace them with default values
-		for p in formal_parameter_list:
-			p_id = p.getIdentifier()
-			p_default = p.getDefaultValue()
-			if p_default:
-				self.out.write("if " + p_id + " == None: " + p_id + " = ")
-				p_default.accept(self)
-		self.writeAll(body.getEntries())
-		if body.isEmpty():
-			self.out.write("pass")
-		self.out.dedent()
-
-	def visit_NewExpression(self, new):
-		type_expr = new.getTypeExpression()
-		params = new.getActualParameters()
-
-		type_expr.accept(self)
-		params.accept(self)
-
-	def visit_NoneExpression(self, n):
-		self.out.extendWrite("None")
-
-	def visit_NotOperator(self, n):
-		self.out.extendWrite("not ")
-
-	def visit_OrOperator(self, o):
-		self.out.extendWrite(" or ")
-
-	def visit_Package(self, package):
-		name = package.getIdentifier()
-		description = package.getDescription()
-
-		self.writeComment("package \"" + name + "\"")
-		if description:
-			self.writeComment(description)
-		self.writeAll(package.getDeclarations())
-
-	def visit_ReturnStatement(self, r):
-		self.out.write("return ")
-		r.getExpression().accept(self)
-
-	def visit_RuntimeModuleIdentifier(self, r):
-		self.out.extendWrite("sccd.runtime")
-
-	def visit_SelfExpression(self, s):
-		self.out.extendWrite("self")
-
-	def visit_StaticAttribute(self, attr):
-		name = attr.getIdentifier()
-		init_value = attr.getInitValue()
-		#class_name = attr.getClass().getIdentifier()
-
-		if init_value:
-			self.out.write(name + " = ")
-			init_value.accept(self)
-		else:
-			self.out.write(name + " = None")
-
-	def visit_SuperClassConstructorCall(self, call):
-		super_class = call.getSuperClassIdentifier()
-		params = call.getActualParameters()
-		param_list = [Literal("self")] + params.getParameterList()
-		params = ActualParameters(param_list)
-
-		self.out.extendWrite(super_class)
-		self.out.extendWrite(".__init__")
-		params.accept(self)
-
-	def visit_SuperClassDestructorCall(self, call):
-		super_class = call.getSuperClassIdentifier()
-		params = call.getActualParameters()
-		param_list = [Literal("self")] + params.getParameterList()
-		params = ActualParameters(param_list)
-
-		self.out.extendWrite("if hasattr(")
-		self.out.extendWrite(super_class)
-		self.out.extendWrite(", \"__del__\"):")
-		self.out.indent()
-		self.out.write(super_class)
-		self.out.extendWrite(".__del__")
-		params.accept(self)
-		self.out.dedent()
-
-	def visit_SuperClassMethodCall(self, call):
-		super_class = call.getSuperClassIdentifier()
-		method_name = call.getMethodIdentifier()
-		params = call.getActualParameters()
-		param_list = [Literal("self")] + params.getParameterList()
-		params = ActualParameters(param_list)
-
-		self.out.extendWrite(super_class + "." + method_name)
-		params.accept(self)
-
-	def visit_ThrowExceptionStatement(self, stmt):
-		self.out.write("raise Exception(")
-		stmt.getExpression().accept(self)
-		self.out.extendWrite(")")
-
-	def visit_TrueExpression(self, t):
-		self.out.extendWrite("True")
-

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 0 - 1169
src/sccd/compiler/sccd_constructs.py


+ 0 - 137
src/sccd/compiler/sccdc.py

@@ -1,137 +0,0 @@
-import argparse
-import os
-import sys
-import lxml.etree as ET
-
-from sccd.compiler.generic_generator import GenericGenerator, Platforms
-from sccd.compiler.utils import Enum, Logger, FileWriter
-from sccd.compiler.super_class_linker import SuperClassLinker
-from sccd.compiler.state_linker import StateLinker
-from sccd.compiler.path_calculator import PathCalculator
-from sccd.compiler.sccd_constructs import ClassDiagram
-from sccd.compiler.generic_language_constructs import GenericConstruct
-from sccd.compiler.compiler_exceptions import CompilerException, TargetLanguageException
-
-from sccd.compiler.javascript_writer import JavascriptWriter
-from sccd.compiler.python_writer import PythonWriter
-
-COMPILER_SRC_DIR = os.path.dirname(os.path.abspath(__file__))
-
-def generate(input_file, output_file, target_language, platform):
-
-	schema = ET.XMLSchema(ET.parse(os.path.join(COMPILER_SRC_DIR, "schema", "sccd.xsd")))
-	tree = ET.parse(input_file)
-	schema.assertValid(tree)
-	
-	language = tree.getroot().get("language")
-	if not target_language:
-		if language:
-			target_language = language
-		else:
-			target_language = "python" # default
-	elif language and target_language != language:
-		raise TargetLanguageException("Diagram specifies target language as \"" + language + "\", but language option of compiler has been set to \"" + target_language + "\". No output has been generated.")
-
-	if target_language == "python" and not output_file.endswith(".py") :
-		output_file += ".py"
-	elif target_language == "javascript" and not output_file.endswith(".js") :
-		output_file += ".js"
-
-	sccd = xmlToSccd(tree)
-	generic = sccdToGeneric(sccd, platform)
-	genericToTarget(generic, target_language, output_file)
-
-def xmlToSccd(tree):
-	cd = ClassDiagram(tree) # create AST
-	cd.accept(SuperClassLinker())
-	# SuperClassLinker().visit(cd) # visitor linking super classs references
-	StateLinker().visit(cd) # visitor fixing state references
-	PathCalculator().visit(cd) # visitor calculating paths
-	return cd
-	
-def sccdToGeneric(sccd, platform):
-	succesfull_generation = False
-	generator = GenericGenerator(platform)
-	sccd.accept(generator)
-	generic = generator.get()
-	Logger.showInfo("Classes <" + ", ".join(sccd.class_names) + "> have been converted to generic language constructs.")
-	return generic
-
-def genericToTarget(generic, target_language, output_file):
-	f = FileWriter(output_file)
-	try:
-		if target_language == "javascript":
-			writer = JavascriptWriter(f)
-		elif target_language == "python":
-			writer = PythonWriter(f)
-		else:
-			raise Exception("Language not supported")
-		generic.accept(writer)
-		Logger.showInfo("Generic language constructs have been converted to target language constructs and have been written to file '" + output_file + "'.")
-	finally:
-		f.close()
-		
-def main():
-	parser = argparse.ArgumentParser(prog="python -m sccd.compiler.sccdc")
-	parser.add_argument('input', help='The path to the XML file to be compiled.')
-	parser.add_argument('-o', '--output', type=str, help='The path to the generated code. Defaults to the same name as the input file but with matching extension.')
-	parser.add_argument('-v', '--verbose', type=int, help='2 = all output; 1 = only warnings and errors; 0 = only errors; -1 = no output.  Defaults to 2.', default = 2)
-	parser.add_argument('-p', '--platform', type=str, help="Let the compiled code run on top of threads, gameloop or eventloop. The default is eventloop.")
-	parser.add_argument('-l', '--language', type=str, help='Target language, either "javascript" or "python". Defaults to the latter.')
-	
-	args = vars(parser.parse_args())
-	#Set verbose
-	if args['verbose'] is not None:
-		if args['verbose'] in [-1, 0,1,2] :
-			Logger.verbose = args['verbose']
-		else :
-			Logger.showError("Invalid verbose argument.")
-	else :
-		Logger.verbose = 2
-
-	#Set source file
-	source = args['input']
-	if not source.endswith(".xml") :
-		Logger.showError("Input file not valid.")
-		return
-	
-	#Set target language
-	if args['language'] :
-		target_language = args['language']
-	else :
-		target_language = ""
-
-	#Set output file
-	if args['output'] :
-		output = args['output']
-	else:
-		output = os.path.splitext(os.path.split(source)[1])[0]
-		
-	#Set platform	
-	if args['platform'] :
-		args['platform'] = args['platform'].lower()
-		if args['platform'] == "threads" :
-			platform = Platforms.Threads
-		elif args['platform'] == "gameloop" :
-			platform = Platforms.GameLoop
-		elif args['platform'] == "eventloop" :
-			platform = Platforms.EventLoop
-		else :
-			Logger.showError("Invalid platform.")
-			return		  
-	else :
-		platform = Platforms.EventLoop
-		
-	#Compile	
-	try :
-		generate(source, output, target_language, platform)
-	except CompilerException as exception :
-		Logger.showError(str(exception));
-		return 1
-
-	return 0
-
-if __name__ == "__main__":
-	sys.exit(main())
-
-

+ 0 - 157
src/sccd/compiler/state_linker.py

@@ -1,157 +0,0 @@
-from sccd.compiler.visitor import Visitor
-from sccd.compiler.sccd_constructs import INSTATE_SEQ
-from sccd.compiler.compiler_exceptions import CompilerException
-from sccd.compiler.lexer import Lexer, Token, TokenType
-
-class StateReferenceException(CompilerException):
-    pass
-
-class StateLinker(Visitor):
-    
-    def __init__(self):
-        self.visiting_statechart = None
-        self.visiting_node = None
-        self.lexer = Lexer()
-    
-    def visit_ClassDiagram(self, class_diagram): 
-        for c in class_diagram.classes :
-            c.accept(self)
-
-    def visit_Class(self, c):
-        if c.statechart:
-            c.statechart.accept(self)
-        
-    def visit_StateChart(self, statechart):
-        self.visiting_statechart = statechart
-        for node in statechart.basics + statechart.composites:
-            node.accept(self)
-                     
-    def visit_StateChartNode(self, node):
-        self.visiting_node = node
-        node.enter_action.accept(self)
-        node.exit_action.accept(self)
-        for transition in node.transitions :
-            transition.accept(self)
-            
-    def visit_StateChartTransition(self, transition):
-        try :
-            transition.target.accept(self)
-        except StateReferenceException as exception :
-            raise StateReferenceException("Transition from <" + self.visiting_node.full_name + "> has invalid target. " + exception.message)
-        try :
-            transition.action.accept(self)
-        except StateReferenceException as exception :
-            raise StateReferenceException("Transition from <" + self.visiting_node.full_name + "> has invalid action. " + exception.message)
-        try :
-            if transition.guard :
-                transition.guard.accept(self)
-        except StateReferenceException as exception :
-            raise StateReferenceException("Transition from <" + self.visiting_node.full_name  + "> has invalid guard. " + exception.message)
-        
-    def visit_StateReference(self, state_reference):
-        state_reference.target_nodes = []
-        
-        current_node = None #Will be used to find the target state(s)
-        split_stack = [] #used for branching
-
-        self.lexer.input(state_reference.path_string)
-
-        for token in self.lexer.tokens() :
-            
-            if current_node == None : #current_node is not set yet or has been reset, the CHILD token can now have a special meaning
-                if token.type == TokenType.SLASH :
-                    #Root detected
-                    current_node = self.visiting_statechart.root
-                    #Token consumed so continue
-                    continue
-                else :
-                    current_node = self.visiting_node
-                    
-            if token.type == TokenType.DOT :
-                #Advance to next token
-                token = self.lexer.nextToken()
-                
-                if token is None or token.type == TokenType.SLASH :
-                    #CURRENT operator "." detected
-                    continue
-                elif token.type == TokenType.DOT :
-                    #Advance to next token
-                    token = self.lexer.nextToken()
-                    if token is None or token.type == TokenType.SLASH :
-                        #PARENT operator ".." detected
-                        current_node = current_node.parent
-                        if current_node is None :
-                            raise StateReferenceException("Illegal use of PARENT \"..\" operator at position " + str(token.pos) + " in state reference. Root of statechart reached.")
-                    
-                    else :
-                        raise StateReferenceException("Illegal use of PARENT \"..\" operator at position " + str(token.pos) + " in state reference.")
-    
-                else :
-                    raise StateReferenceException("Illegal use of CURRENT \".\" operator at position " + str(token.pos) + " in state reference.")
-                    
-            elif token.type == TokenType.SLASH :
-                continue
-            elif token.type == TokenType.WORD :
-                #try to advance to next child state
-                cname = token.val
-                found = False
-                for child in current_node.children :
-                    if child.name == cname : 
-                        found = True
-                        current_node = child
-                        break
-                if not found :
-                    raise StateReferenceException("Refering to non existing node " + cname + " at position " + str(token.pos) + " in state reference.")
-            elif token.type == TokenType.LBRACKET :
-                split_stack.append(current_node)
-            elif token.type == TokenType.RBRACKET :
-                if len(split_stack) > 0 :
-                    split_stack.pop()
-                else :
-                    raise StateReferenceException("Invalid token at position " + str(token.pos) + " in state reference.")
-            elif token.type == TokenType.COMMA :
-                state_reference.target_nodes.append(current_node)
-                if len(split_stack) > 0 :
-                    current_node = split_stack[-1]
-                else :
-                    current_node = None
-            
-            else :
-                raise StateReferenceException("Invalid token at position " + str(token.pos) + " in state reference.")
-        
-        if (len(split_stack) != 0) or (current_node is None) : #RB missing or extra COMMA
-            raise StateReferenceException("State reference ends unexpectedly.")
-        
-        #TODO better validation of the target! When is it a valid state configuration?
-        for node in state_reference.target_nodes :
-            if current_node == node :
-                raise StateReferenceException("A state reference can't reference the same node more than once.")
-            if node.isDescendantOrAncestorOf(current_node) :
-                raise StateReferenceException("A state reference can't reference a node and one of its descendants.");
-        
-        state_reference.target_nodes.append(current_node)
-            
-        if len(state_reference.target_nodes) == 0 :
-            raise StateReferenceException("Meaningless state reference.")
-
-    def visit_Expression(self, expression):
-        for part in expression.expression_parts :
-            part.accept(self)
-
-    def visit_EnterExitAction(self, action):
-        if action.action :
-            action.action.accept(self)
-            
-    def visit_Action(self, action):
-        for subaction in action.sub_actions :
-            subaction.accept(self)
-            
-    def visit_InStateCall(self, call):
-        try:
-            for target in call.targets:
-                target.accept(self)
-        except StateReferenceException:
-            raise StateReferenceException("Invalid state reference for " + INSTATE_SEQ + " call.")
-        
-    def visit_Assign(self, assign):
-        assign.expression.accept(self)

+ 0 - 221
src/sccd/compiler/stateful_writer.py

@@ -1,221 +0,0 @@
-# Used by generic_generator to create an AST of generic language constructs
-# while visiting an AST of SCCD constructs
-
-from sccd.compiler.generic_language_constructs import *
-
-class ExpressionWrapper(SimpleExpression, AbstractList):
-	def __init__(self, expr = None):
-		self.expr = expr
-
-	def add(self, expr):
-		if self.expr:
-			raise Exception("Expression can only be set once.")
-		self.expr = expr
-
-	def get(self):
-		return self.expr
-
-
-class StatefulWriter:
-	def __init__(self):
-		self.ast = AST()
-		self.last = None
-		self.stack = [self.ast]
-
-	def get(self):
-		return self.stack[-1]
-
-	def startRecordingExpression(self):
-		self.stack.append(ExpressionWrapper())
-
-	def stopRecordingExpression(self):
-		self.last = self.stack.pop()
-		if not isinstance(self.last, ExpressionWrapper):
-			raise Exception("Assymetry detected.")
-		return self.last.get()
-
-	def add(self, block_entry):
-		self.get().add(block_entry)
-        
-
-	#### SHORTHANDS ####
-
-	def addActualParameter(self, expr):
-		self.get().getActualParameters().add(expr)
-
-	def addAssignment(self, lhs, rhs):
-		self.add(AssignmentExpression(lhs, rhs))
-
-	def addInclude(self, module_path, symbols = None):
-		self.add(IncludeStatement(module_path, symbols))
-
-	def addComment(self, comment):
-		self.add(SingleLineComment(comment))
-
-	def addFormalParameter(self, parameter, default_value = None):
-		self.get().getFormalParameters().add(FormalParameter(parameter, default_value))
-
-	def addMultiLineComment(self, comment):
-		self.add(MultiLineComment(comment))
-
-	def addRawCode(self, raw):
-		self.add(RawCode(raw))
-
-	def addStaticAttribute(self, identifier, init_value):
-		self.add(StaticAttribute(self.get(), identifier, init_value))
-
-	def addVSpace(self):
-		self.add(VSpace())
-
-
-	#### STATEFUL OPERATIONS ####
-
-	def begin(self, generic_construct):
-		self.add(generic_construct)
-		self.stack.append(generic_construct)
-
-	def beginArray(self):
-		self.begin(ArrayExpression())
-
-	def beginClass(self, class_name, super_class_names = None, comment = None):
-		self.begin(Class(class_name, super_class_names, comment))
-
-	def beginConstructor(self):
-		c = self.get().getConstructor()
-		self.stack.append(c)
-
-	def beginDestructor(self):
-		d = self.get().getDestructor()
-		self.stack.append(d)
-
-	def beginElse(self):
-		self.begin(ElseStatement())
-
-	def beginElseIf(self, condition):
-		self.begin(ElseIfStatement(condition, not isinstance(self.last, ElseIfStatement)))
-
-	def beginForLoopIterateArray(self, array_expr, iterator_identifier):
-		f = ForLoopIterateArray(array_expr, iterator_identifier)
-		self.get().add(f)
-		self.stack.append(f.getBody())
-
-	def beginForLoopIterateMapValues(self, map_expr, iterator_identifier):
-		f = ForLoopIterateMapValues(map_expr, iterator_identifier)
-		self.get().add(f)
-		self.stack.append(f.getBody())
-
-	def beginFunctionCall(self, function_expr):
-		f = FunctionCall(function_expr)
-		self.get().add(f)
-		self.stack.append(f)
-
-	def beginGlue(self):
-		g = Glue()
-		self.get().add(g)
-		self.stack.append(g)
-
-	def beginIf(self, condition):
-		self.begin(IfStatement(condition))
-
-
-	def beginMethod(self, name, comment = None):
-		m = Method(self.get(), name, comment)
-		self.get().add(m)
-		self.stack.append(m)
-
-	def beginMethodBody(self):
-		b = self.get().getBody()
-		self.stack.append(b)
-
-	def beginPackage(self, package_name):
-		p = Package(package_name)
-		self.get().add(p)
-		self.stack.append(p)
-
-	def beginSuperClassConstructorCall(self, super_class_identifier):
-		c = SuperClassConstructorCall(super_class_identifier)
-		self.get().add(c)
-		self.stack.append(c)
-
-	def beginSuperClassDestructorCall(self, super_class_identifier):
-		c = SuperClassDestructorCall(super_class_identifier)
-		self.get().add(c)
-		self.stack.append(c)
-
-	def beginSuperClassMethodCall(self, super_class_identifier, method_identifier):
-		c = SuperClassMethodCall(super_class_identifier, method_identifier)
-		self.get().add(c)
-		self.stack.append(c)
-
-
-	def end(self):
-		self.stack.pop()
-
-	def endArray(self):
-		self.last = self.stack.pop()
-		assert isinstance(self.last, ArrayExpression)
-
-	def endClass(self):
-		self.last = self.stack.pop()
-		assert isinstance(self.last, Class)
-
-	def endConstructor(self):
-		self.last = self.stack.pop()
-		assert isinstance(self.last, Constructor)
-
-	def endDestructor(self):
-		self.last = self.stack.pop()
-		assert isinstance(self.last, Destructor)
-
-	def endElse(self):
-		self.last = self.stack.pop()
-		assert isinstance(self.last, ElseStatement)
-
-	def endElseIf(self):
-		self.last = self.stack.pop()
-		assert isinstance(self.last, ElseIfStatement)
-
-	def endForLoopIterateArray(self):
-		self.last = self.stack.pop()
-		assert isinstance(self.last, ForLoopBody)
-
-	def endForLoopIterateMapValues(self):
-		self.last = self.stack.pop()
-		assert isinstance(self.last, ForLoopBody)
-
-	def endFunctionCall(self):
-		self.last = self.stack.pop()
-		assert isinstance(self.last, FunctionCall)
-
-	def endGlue(self):
-		self.last = self.stack.pop()
-		assert isinstance(self.last, Glue)
-
-	def endIf(self):
-		self.last = self.stack.pop()
-		assert isinstance(self.last, IfStatement)
-
-	def endMethod(self):
-		self.last = self.stack.pop()
-		assert isinstance(self.last, Method)
-
-	def endMethodBody(self):
-		self.last = self.stack.pop()
-		assert isinstance(self.last, MethodBody)
-
-	def endPackage(self):
-		self.last = self.stack.pop()
-		assert isinstance(self.last, Package)
-
-	def endSuperClassConstructorCall(self):
-		self.last = self.stack.pop()
-		assert isinstance(self.last, SuperClassConstructorCall)
-
-	def endSuperClassDestructorCall(self):
-		self.last = self.stack.pop()
-		assert isinstance(self.last, SuperClassDestructorCall)
-
-	def endSuperClassMethodCall(self):
-		self.last = self.stack.pop()
-		assert isinstance(self.last, SuperClassMethodCall)
-

+ 0 - 52
src/sccd/compiler/super_class_linker.py

@@ -1,52 +0,0 @@
-from sccd.compiler.compiler_exceptions import *
-from sccd.compiler.utils import Logger
-from sccd.compiler.visitor import Visitor
-
-class SuperClassLinker(Visitor):
-	""" Computes the states that must be exited and entered for a specific transition if the system is to make
-		that transition. 
-	"""
-	
-	def visit_ClassDiagram(self, class_diagram): 
-		for c in class_diagram.classes :
-			c.accept(self)
-
-	def visit_Class(self, c):
-		# replace super class names by super class objects
-		for s in c.super_classes:
-			super_class = None
-			for clas in c.class_diagram.classes:
-				if clas.name == s:
-					super_class = clas
-			if super_class == None:
-				Logger.showWarning("Class <" + c.name + "> has undefined super class <" + s + ">.")
-			else:
-				c.super_class_objs[s] = super_class
-
-		# calculate list of abstract methods
-		c.abstract_method_names = getClassAbstractMethodNames(c)
-
-		# check if <super> tags exist for all inherited classes
-		for name,obj in list(c.super_class_objs.items()):
-			if obj:
-				if name not in c.constructors[0].super_class_parameters:
-					num_params = len(obj.constructors[0].parameters)
-					if num_params > 0:
-						raise CompilerException("Class <" + c.name + "> inherits <" + name + "> and <" + name + ">'s constructor has " + str(num_params) + " parameter(s), but there's no <super> entry for that class in <" + c.name + ">'s constructor.")
-
-def getClassAbstractMethodNames(c):
-	abstract_method_names = []
-	non_abstract_method_names = []
-	for m in c.methods:
-		if m.isAbstract():
-			abstract_method_names.append(m.name)
-		else:
-			non_abstract_method_names.append(m.name)
-	for s in c.super_classes:
-		if s in c.super_class_objs:
-			super_abstract_method_names = getClassAbstractMethodNames(c.super_class_objs[s])
-			for m_name in super_abstract_method_names:
-				if m_name not in non_abstract_method_names:
-					abstract_method_names.append(m_name)
-	return abstract_method_names
-

+ 0 - 30
src/sccd/compiler/visitor.py

@@ -1,30 +0,0 @@
-class Visitor(object):
-	def _visit(self, node, prepend, *args):
-		prepend = prepend + "_"
-		meth = None
-		for cls in node.__class__.__mro__:
-			meth_name = prepend + cls.__name__
-			meth = getattr(self, meth_name, None)
-			if meth:
-				break
-
-		if not meth:
-			meth = self.generic_visit
-		return meth(node, *args)
-	
-	def visit(self, node, *args):
-		self._visit(node, "visit", *args)
-	
-	def enter(self, node, *args):
-		self._visit(node, "enter", *args)
-		
-	def exit(self, node, *args):
-		self._visit(node, "exit", *args)
-
-	def generic_visit(self, node):
-		#print 'generic_visit '+node.__class__.__name__
-		pass
-		
-class Visitable(object):
-	def accept(self, visitor):
-		visitor.visit(self) 

+ 6 - 5
src/sccd/runtime/controller.py

@@ -1,11 +1,12 @@
 import queue
 import dataclasses
 from typing import Dict, List, Optional
-from sccd.runtime.event_queue import EventQueue, EventQueueDeque, Timestamp
-from sccd.runtime.event import *
-from sccd.runtime.object_manager import ObjectManager
-from sccd.runtime.debug import print_debug
-from sccd.runtime.model import *
+from sccd.controller.event_queue import *
+from sccd.execution.event import *
+from sccd.controller.object_manager import *
+from sccd.util.debug import print_debug
+# from sccd.syntax.model import *
+from sccd.model.model import *
 
 @dataclasses.dataclass
 class InputEvent:

src/sccd/runtime/event_queue.py → src/sccd/controller/event_queue.py


+ 1 - 3
src/sccd/runtime/object_manager.py

@@ -1,9 +1,7 @@
 import re
 import abc
 from typing import List, Tuple
-from sccd.runtime.event import Instance, Event, OutputEvent, InstancesTarget
-from sccd.runtime.event_queue import Timestamp
-from sccd.runtime.statechart_instance import StatechartInstance
+from sccd.execution.statechart_instance import *
 
 # TODO: Clean this mess up. Look at all object management operations and see how they can be improved.
 class ObjectManager(Instance):

src/sccd/runtime/test_event_queue.py → src/sccd/controller/test_event_queue.py


+ 6 - 17
src/sccd/runtime/event.py

@@ -1,16 +1,15 @@
 import termcolor
-import dataclasses
-from abc import ABC, abstractmethod
-from typing import List, Any, Tuple
-from sccd.runtime.event_queue import Timestamp
+from dataclasses import *
+from abc import *
+from typing import *
 
 # A raised event.
-@dataclasses.dataclass(frozen=True)
+@dataclass(frozen=True)
 class Event:
     id: int
     name: str
     port: str = ""
-    parameters: List[Any] = dataclasses.field(default_factory=list)
+    parameters: List[Any] = field(default_factory=list)
 
     def __str__(self):
         if self.port:
@@ -38,20 +37,10 @@ class OutputEvent:
         self.target = target
         self.time_offset = time_offset
 
-# Interface for all instances and also the Object Manager
-class Instance(ABC):
-    @abstractmethod
-    def initialize(self, timestamp: Timestamp) -> Tuple[bool, List[OutputEvent]]:
-        pass
-
-    @abstractmethod
-    def big_step(self, timestamp: Timestamp, input_events: List[Event]) -> Tuple[bool, List[OutputEvent]]:
-        pass
-
 class OutputPortTarget(EventTarget):
     def __init__(self, outport: str):
         self.outport = outport
 
 class InstancesTarget(EventTarget):
-    def __init__(self, instances: List[Instance]):
+    def __init__(self, instances):
         self.instances = instances

+ 14 - 0
src/sccd/execution/instance.py

@@ -0,0 +1,14 @@
+from abc import *
+from typing import *
+from sccd.execution.event import *
+from sccd.execution.timestamp import *
+
+# Interface for all instances and also the Object Manager
+class Instance(ABC):
+    @abstractmethod
+    def initialize(self, timestamp: Timestamp) -> Tuple[bool, List[OutputEvent]]:
+        pass
+
+    @abstractmethod
+    def big_step(self, timestamp: Timestamp, input_events: List[Event]) -> Tuple[bool, List[OutputEvent]]:
+        pass

+ 4 - 4
src/sccd/runtime/round.py

@@ -1,8 +1,8 @@
 from typing import *
-from sccd.runtime.event import *
-from sccd.runtime.bitmap import *
-from sccd.runtime.statechart_syntax import *
-from sccd.runtime.debug import print_debug
+from sccd.execution.event import *
+from sccd.util.bitmap import *
+from sccd.syntax.tree import *
+from sccd.util.debug import print_debug
 
 class CandidatesGenerator:
     def __init__(self, reverse: bool):

+ 9 - 11
src/sccd/runtime/statechart_instance.py

@@ -1,17 +1,15 @@
 import termcolor
 import functools
 from typing import List, Tuple, Iterable
-from sccd.runtime.event_queue import Timestamp
-from sccd.runtime.statechart_syntax import *
-from sccd.runtime.event import *
-from sccd.runtime.semantic_options import *
-from sccd.runtime.debug import print_debug
-from sccd.runtime.bitmap import *
-from sccd.runtime.model import *
-from sccd.runtime.round import *
-from sccd.runtime.statechart_state import *
-
-ELSE_GUARD = "ELSE_GUARD"
+from sccd.execution.instance import *
+from sccd.syntax.statechart import *
+# from sccd.execution.event import *
+# from sccd.runtime.semantic_options import *
+from sccd.util.debug import print_debug
+from sccd.util.bitmap import *
+# from sccd.model.model import *
+from sccd.execution.round import *
+from sccd.execution.statechart_state import *
 
 class StatechartInstance(Instance):
     def __init__(self, statechart: Statechart, object_manager):

+ 13 - 12
src/sccd/runtime/statechart_state.py

@@ -1,8 +1,9 @@
 from typing import *
-from sccd.runtime.statechart_syntax import *
-from sccd.runtime.model import Statechart
-from sccd.runtime.event import *
-from sccd.runtime.debug import print_debug
+from sccd.syntax.statechart import *
+# from sccd.syntax.model import Statechart
+from sccd.execution.event import *
+from sccd.util.debug import print_debug
+from sccd.util.bitmap import *
 
 # Set of current states etc.
 class StatechartState:
@@ -37,8 +38,8 @@ class StatechartState:
     for state in states:
         print_debug(termcolor.colored('  ENTER %s'%state.name, 'green'))
         self.eventless_states += state.has_eventless_transitions
-        self.perform_actions([], state.enter)
-        self.start_timers(state.after_triggers)
+        self._perform_actions([], state.enter)
+        self._start_timers(state.after_triggers)
 
   def fire_transition(self, events, t: Transition) -> Bitmap:
     def __exitSet():
@@ -77,11 +78,11 @@ class StatechartState:
         print_debug(termcolor.colored('  EXIT %s' % s.name, 'green'))
         self.eventless_states -= s.has_eventless_transitions
         # execute exit action(s)
-        self.perform_actions(events, s.exit)
+        self._perform_actions(events, s.exit)
         self.configuration_bitmap &= ~Bit(s.state_id)
             
     # execute transition action(s)
-    self.perform_actions(events, t.actions)
+    self._perform_actions(events, t.actions)
         
     # enter states...
     targets = __getEffectiveTargetStates()
@@ -91,8 +92,8 @@ class StatechartState:
         self.eventless_states += s.has_eventless_transitions
         self.configuration_bitmap |= Bit(s.state_id)
         # execute enter action(s)
-        self.perform_actions(events, s.enter)
-        self.start_timers(s.after_triggers)
+        self._perform_actions(events, s.enter)
+        self._start_timers(s.after_triggers)
     try:
         self.configuration = self.config_mem[self.configuration_bitmap]
     except:
@@ -115,7 +116,7 @@ class StatechartState:
   def check_source(self, t) -> bool:
       return self.configuration_bitmap.has(t.source.state_id)
 
-  def perform_actions(self, events, actions: List[Action]):
+  def _perform_actions(self, events, actions: List[Action]):
       for a in actions:
           if isinstance(a, RaiseInternalEvent):
               self.raise_internal(Event(id=a.event_id, name=a.name, port="", parameters=[]))
@@ -127,7 +128,7 @@ class StatechartState:
           elif isinstance(a, Code):
               a.block.exec(events, self.data_model)
 
-  def start_timers(self, triggers: List[AfterTrigger]):
+  def _start_timers(self, triggers: List[AfterTrigger]):
       for after in triggers:
           delay = after.delay.eval([], self.data_model)
           self.output.append(OutputEvent(

+ 33 - 0
src/sccd/execution/timestamp.py

@@ -0,0 +1,33 @@
+
+class Timestamp(int):
+  def __new__(cls, value=0, *args, **kwargs):
+    return super(cls, cls).__new__(cls, value)
+
+  def __repr__(self):
+    return "timestamp("+format(self, 'b')+")"
+
+  def __str__(self):
+    return self.__repr__()
+
+  def __add__(self, other):
+    assert isinstance(other, Timedelta)
+    return self.__class__(super().__add__(other))
+
+  def __sub__(self, other):
+    diff = super().__sub(other)
+    if isinstance(other, Timedelta):
+      return self.__class__(diff)
+    elif isinstance(other, Timestamp):
+      return Timedelta(diff)
+    else:
+      raise TypeError("Can't subtract '%s' object from Timestamp", str(type(other)))
+
+class Timedelta(int):
+  def __new__(cls, value=0, *args, **kwargs):
+    return super(cls, cls).__new__(cls, value)
+
+  def __repr__(self):
+    return "timedelta("+format(self, 'b')+")"
+
+  def __str__(self):
+    return self.__repr__()

src/sccd/runtime/socket2event.py → src/sccd/legacy/socket2event.py


+ 10 - 10
src/sccd/runtime/xml_loader.py

@@ -1,14 +1,13 @@
+# Legacy model and test loader
+
 import os
 import dataclasses
 from typing import List, Any, Optional
 import lxml.etree as ET
 from lark import Lark
 
-from sccd.runtime.statechart_syntax import *
-from sccd.runtime.event import Event
-from sccd.runtime.semantic_options import SemanticConfiguration
-from sccd.runtime.controller import InputEvent
-from sccd.runtime.model import *
+from sccd.syntax.statechart import *
+from sccd.controller.controller import *
 import sccd.schema
 
 schema_dir = os.path.dirname(sccd.schema.__file__)
@@ -31,7 +30,7 @@ def load_model(src_file) -> Tuple[MultiInstanceModel, Optional[Test]]:
   schema.assertValid(tree)
   root = tree.getroot()
 
-  namespace = ModelNamespace()
+  namespace = Namespace()
   model = MultiInstanceModel(namespace, classes={}, default_class=None)
 
   classes = root.findall(".//class", root.nsmap)
@@ -83,7 +82,7 @@ def load_model(src_file) -> Tuple[MultiInstanceModel, Optional[Test]]:
 
   return (model, test)
 
-def load_statechart(scxml_node, namespace: ModelNamespace) -> Statechart:
+def load_statechart(scxml_node, namespace: Namespace) -> Statechart:
 
   def load_action(action_node) -> Optional[Action]:
     tag = ET.QName(action_node).localname
@@ -180,7 +179,7 @@ def load_statechart(scxml_node, namespace: ModelNamespace) -> Statechart:
     if after is not None:
       event = "_after%d" % next_after_id # transition gets unique event name
       next_after_id += 1
-      trigger = AfterTrigger(namespace.assign_event_id(event), event, Timestamp(after))
+      trigger = AfterTrigger(namespace.assign_event_id(event), event, IntLiteral(int(after)))
     elif event is not None:
       trigger = Trigger(namespace.assign_event_id(event), event, port)
     else:
@@ -210,8 +209,8 @@ def load_statechart(scxml_node, namespace: ModelNamespace) -> Statechart:
     t.optimize()
 
   # Semantics - We use reflection to find the xml attribute names and values
-  semantics = SemanticConfiguration()
-  for aspect in dataclasses.fields(SemanticConfiguration):
+  semantics = Semantics()
+  for aspect in dataclasses.fields(Semantics):
     key = scxml_node.get(aspect.name)
     if key is not None:
       value = aspect.type[key.upper()]
@@ -219,6 +218,7 @@ def load_statechart(scxml_node, namespace: ModelNamespace) -> Statechart:
 
   return Statechart(
     tree=StateTree(root=root, states=states, state_list=state_list, transition_list=transition_list),
+    datamodel=DataModel(),
     semantics=semantics)
 
 class ParseError(Exception):

+ 28 - 0
src/sccd/model/model.py

@@ -0,0 +1,28 @@
+from abc import *
+from dataclasses import *
+from typing import *
+from sccd.syntax.statechart import *
+from sccd.model.namespace import *
+
+@dataclass
+class AbstractModel(ABC):
+  namespace: Namespace
+
+  @abstractmethod
+  def get_default_class(self) -> Statechart:
+    pass
+
+@dataclass
+class MultiInstanceModel(AbstractModel):
+  classes: Dict[str, Statechart]
+  default_class: Optional[str]
+
+  def get_default_class(self) -> Statechart:
+    return self.classes[self.default_class]
+
+@dataclass
+class SingleInstanceModel(AbstractModel):
+  statechart: Statechart
+
+  def get_default_class(self) -> Statechart:
+    return self.statechart

+ 23 - 0
src/sccd/model/namespace.py

@@ -0,0 +1,23 @@
+from dataclasses import *
+from typing import *
+
+@dataclass
+class Namespace:
+  def __init__(self):
+    self.events: Dict[str, int] = {}
+    self.inports: List[str] = []
+    self.outports: List[str] = []
+
+  def assign_event_id(self, name: str) -> int:
+    return self.events.setdefault(name, len(self.events))
+
+  def get_event_id(self, name: str) -> int:
+    return self.events[name]
+
+  def add_inport(self, port: str):
+    if port not in self.inports:
+      self.inports.append(port)
+
+  def add_outport(self, port: str):
+    if port not in self.outports:
+      self.outports.append(port)

+ 46 - 112
src/sccd/runtime/xml_loader2.py

@@ -1,58 +1,49 @@
 import os
 import lxml.etree as ET
-from lark import Lark, Transformer
-from sccd.runtime.test import *
-from sccd.runtime.model import *
-from sccd.runtime.statechart_syntax import *
+import dataclasses
 from copy import deepcopy
+from lark import Lark, Transformer
+
+from sccd.syntax.statechart import *
+from sccd.model.namespace import *
+
+import sccd.schema
+
+with open(os.path.join(os.path.dirname(sccd.schema.__file__),"grammar.g")) as file:
+  _grammar = file.read()
 
 # Lark transformer for parsetree-less parsing of expressions
-class ExpressionTransformer(Transformer):
+class _ExpressionTransformer(Transformer):
+  array = Array
+  block = Block
   def string(self, node):
     return StringLiteral(node[0][1:-1])
-
   def int(self, node):
     return IntLiteral(int(node[0].value))
-
   def func_call(self, node):
     return FunctionCall(node[0], node[1].children)
-
   def identifier(self, node):
     return Identifier(node[0].value)
-
   def binary_expr(self, node):
     return BinaryExpression(node[0], node[1].value, node[2])
-
   def unary_expr(self, node):
     return UnaryExpression(node[0].value, node[1])
-
   def bool(self, node):
     return BoolLiteral({
       "True": True,
       "False": False,
       }[node[0].value])
-
   def group(self, node):
     return Group(node[0])
-
   def assignment(self, node):
     return Assignment(node[0], node[1].value, node[2])
 
-  array = Array
-
-  block = Block
-
-import sccd.schema
-schema_dir = os.path.dirname(sccd.schema.__file__)
-with open(os.path.join(schema_dir,"grammar.g")) as file:
-  grammar = file.read()
+_expr_parser = Lark(_grammar, parser="lalr", start=["expr", "block"], transformer=_ExpressionTransformer())
+_state_ref_parser = Lark(_grammar, parser="lalr", start=["state_ref"])
 
-expr_parser = Lark(grammar, parser="lalr", start=["expr", "block"], transformer=ExpressionTransformer())
-state_ref_parser = Lark(grammar, parser="lalr", start=["state_ref"])
 
-# Load state tree from XML <tree> node.
-# Namespace is required for building event namespace and in/outport discovery.
-def load_state_tree(namespace: ModelNamespace, tree_node) -> StateTree:
+# parent_node: XML node containing any number of action nodes as direct children
+def load_actions(namespace: Namespace, parent_node) -> List[Action]:
   def load_action(action_node) -> Optional[Action]:
       tag = ET.QName(action_node).localname
       if tag == "raise":
@@ -67,16 +58,18 @@ def load_state_tree(namespace: ModelNamespace, tree_node) -> StateTree:
       elif tag == "code":
         code = action_node.text
         try:
-          stmt_block = expr_parser.parse(code, start="block")
+          stmt_block = _expr_parser.parse(code, start="block")
           return Code(stmt_block)
         except:
           raise Exception("Line %d: <%s>: Error parsing code." % (action_node.sourceline, tag))
       else:
         raise Exception("Line %d: <%s>: Unsupported action tag." % (action_node.sourceline, tag))
+  return [load_action(child) for child in parent_node]
 
-  # parent_node: XML node containing any number of action nodes as direct children
-  def load_actions(parent_node) -> List[Action]:
-    return list(filter(lambda x: x is not None, map(lambda child: load_action(child), parent_node)))
+
+# Load state tree from XML <tree> node.
+# Namespace is required for building event namespace and in/outport discovery.
+def load_tree(namespace: Namespace, tree_node) -> StateTree:
 
   transition_nodes: List[Tuple[Any, State]] = [] # List of (<transition>, State) tuples
 
@@ -119,7 +112,7 @@ def load_state_tree(namespace: ModelNamespace, tree_node) -> StateTree:
     def _get_enter_exit(tag, setter):
       node = state_node.find(tag, state_node.nsmap)
       if node is not None:
-        actions = load_actions(node)
+        actions = load_actions(namespace, node)
         setter(actions)
 
     _get_enter_exit("onentry", state.setEnter)
@@ -137,7 +130,7 @@ def load_state_tree(namespace: ModelNamespace, tree_node) -> StateTree:
     try:
       # Parse and find target state
       target_string = t_node.get("target", "")
-      parse_tree = state_ref_parser.parse(target_string, start="state_ref")
+      parse_tree = _state_ref_parser.parse(target_string, start="state_ref")
       def find_state(sequence) -> State:
         if sequence.data == "relative_path":
           el = source
@@ -162,7 +155,7 @@ def load_state_tree(namespace: ModelNamespace, tree_node) -> StateTree:
     port = t_node.get("port")
     after = t_node.get("after")
     if after is not None:
-      after_expr = expr_parser.parse(after, start="expr")
+      after_expr = _expr_parser.parse(after, start="expr")
       # print(after_expr)
       name = "_after%d" % next_after_id # transition gets unique event name
       next_after_id += 1
@@ -174,17 +167,17 @@ def load_state_tree(namespace: ModelNamespace, tree_node) -> StateTree:
       trigger = None
     transition.setTrigger(trigger)
     # Actions
-    actions = load_actions(t_node)
+    actions = load_actions(namespace, t_node)
     transition.setActions(actions)
     # Guard
     cond = t_node.get("cond")
     if cond is not None:
       try:
-        # expr_parser2 = Lark(grammar, parser="lalr", start=["expr"])
-        # tree2 = expr_parser2.parse(cond, start="expr")
+        # _expr_parser2 = Lark(grammar, parser="lalr", start=["expr"])
+        # tree2 = _expr_parser2.parse(cond, start="expr")
         # print(tree2.pretty())
 
-        expr = expr_parser.parse(cond, start="expr")
+        expr = _expr_parser.parse(cond, start="expr")
         # print(expr)
         transition.setGuard(expr)
       except:
@@ -203,24 +196,10 @@ def load_state_tree(namespace: ModelNamespace, tree_node) -> StateTree:
 
   return StateTree(root=root, states=states, state_list=state_list, transition_list=transition_list)
 
-# Namespace is required for building event namespace and in/outport discovery.
-def load_statechart(namespace: ModelNamespace, sc_node) -> Statechart:
-  tree_node = sc_node.find("tree")
-  state_tree = load_state_tree(namespace, tree_node)
-
-  semantics_node = sc_node.find("semantics")
-  semantics = SemanticConfiguration() # start with default semantics
-  load_semantics(semantics, semantics_node)
-
-  datamodel_node = sc_node.find("datamodel")
-  datamodel = load_datamodel(datamodel_node)
-
-  return Statechart(tree=state_tree, semantics=semantics, datamodel=datamodel)
-
-def load_semantics(semantics: SemanticConfiguration, semantics_node):
+def load_semantics(semantics: Semantics, semantics_node):
   if semantics_node is not None:
     # Use reflection to find the possible XML attributes and their values
-    for aspect in dataclasses.fields(SemanticConfiguration):
+    for aspect in dataclasses.fields(Semantics):
       key = semantics_node.get(aspect.name)
       if key is not None:
         if key == "*":
@@ -229,71 +208,26 @@ def load_semantics(semantics: SemanticConfiguration, semantics_node):
           value = aspect.type[key.upper()]
           setattr(semantics, aspect.name, value)
 
-def load_datamodel(d_node) -> DataModel:
+def load_datamodel(datamodel_node) -> DataModel:
   datamodel = DataModel()
-  if d_node is not None:
-    for var_node in d_node.findall("var"):
+  if datamodel_node is not None:
+    for var_node in datamodel_node.findall("var"):
       id = var_node.get("id")
       expr = var_node.get("expr")
-      val = expr_parser.parse(expr, start="expr")
+      val = _expr_parser.parse(expr, start="expr")
       datamodel.names[id] = Variable(val.eval([], datamodel))
   return datamodel
 
-# Returned list contains more than one test if the semantic configuration contains wildcard values.
-def load_test(src_file) -> List[Test]:
-  namespace = ModelNamespace()
-
-  test_node = ET.parse(src_file).getroot()
-  sc_node = test_node.find("statechart")
-  src = sc_node.get("src")
-  if src is None:
-    statechart = load_statechart(namespace, sc_node)
-  else:
-    external_node = ET.parse(os.path.join(os.path.dirname(src_file), src)).getroot()
-    statechart = load_statechart(namespace, external_node)
-    semantics_node = sc_node.find("override_semantics")
-    load_semantics(statechart.semantics, semantics_node)
-
-  input_node = test_node.find("input")
-  output_node = test_node.find("output")
-  input = load_input(input_node)
-  output = load_output(output_node)
-
-  def variant_description(i, variant) -> str:
-    if not variant:
-      return ""
-    return " (variant %d: %s)" % (i, ",".join(str(val) for val in variant.values()))
+# Namespace is required for building event namespace and in/outport discovery.
+def load_statechart(namespace: Namespace, sc_node) -> Statechart:
+  tree_node = sc_node.find("tree")
+  state_tree = load_tree(namespace, tree_node)
 
-  return [
-    Test(
-      src_file + variant_description(i, variant),
-      SingleInstanceModel(
-        namespace,
-        Statechart(tree=statechart.tree, datamodel=deepcopy(statechart.datamodel), semantics=dataclasses.replace(statechart.semantics, **variant))),
-      input,
-      output)
-    for i, variant in enumerate(statechart.semantics.wildcard_cart_product())
-  ]
+  semantics_node = sc_node.find("semantics")
+  semantics = Semantics() # start with default semantics
+  load_semantics(semantics, semantics_node)
 
-def load_input(input_node) -> TestInput:
-  input = []
-  if input_node is not None:
-    for event_node in input_node:
-      name = event_node.get("name")
-      port = event_node.get("port")
-      time = int(event_node.get("time"))
-      input.append(InputEvent(name, port, [], time))
-  return input
+  datamodel_node = sc_node.find("datamodel")
+  datamodel = load_datamodel(datamodel_node)
 
-def load_output(output_node) -> TestOutput:
-  output = []
-  if output_node is not None: 
-    for big_step_node in output_node:
-      big_step = []
-      for event_node in big_step_node:
-        name = event_node.get("name")
-        port = event_node.get("port")
-        parameters = [] # todo: read params
-        big_step.append(Event(id=0, name=name, port=port, parameters=parameters))
-      output.append(big_step)
-  return output
+  return Statechart(tree=state_tree, semantics=semantics, datamodel=datamodel)

+ 0 - 0
src/sccd/runtime/__init__.py


+ 0 - 1
src/sccd/runtime/libs/__init__.py

@@ -1 +0,0 @@
-

+ 0 - 64
src/sccd/runtime/libs/drawing.py

@@ -1,64 +0,0 @@
-"""
- *REALLY* Small framework for creating/manipulating/deleting Tkinter Canvas elements.
- 
- NOTE: keep this synced with svg.js
- 
- Author: Raphael Mannadiar
- Date: 2014/08/21
-"""
-
-from sccd.runtime.libs.utils import utils
-
-class drawing:
-    class canvas_wrapper:
-        def __init__(self, element):
-            self.element = element
-            self.width = int(element.cget("width"))
-            self.height = int(element.cget("height"))
-
-        def add_circle(self, x, y, r, style):
-            new_element_id = self.element.create_oval(x-r, y-r, x+r, y+r, **style)
-            return drawing.ui_element_wrapper(self, new_element_id, x, y)
-
-        def add_rectangle(self, x, y, w, h, style):
-            new_element_id = self.element.create_rectangle(x-w/2.0, y-h/2.0, x+w/2.0, y+h/2.0, **style)
-            return drawing.ui_element_wrapper(self, new_element_id, x, y)
-
-        def remove_element(self, element):
-            self.element.delete(element.element_id)
-            
-        def get_width(self):
-            return self.element.winfo_width()
-            
-        def get_height(self):
-            return self.element.winfo_height()
-
-
-    class ui_element_wrapper:
-        def __init__(self, canvas_wrapper, element_id, x, y):
-            self.canvas_wrapper = canvas_wrapper
-            self.element_id = element_id
-            self.a = 0
-            self.x = x
-            self.y = y
-
-        def set_position(self, x, y):
-            self.move(x-self.x, y-self.y)
-
-        def get_position(self):
-            return utils._bunch(x=self.x, y=self.y)
-
-        def move(self, dx, dy):
-            self.x += dx
-            self.y += dy
-            self.canvas_wrapper.element.move(self.element_id, dx, dy)
-
-        def set_rotation(self, a):
-            raise Exception("Not implemented yet")
-
-        def rotate(self, a):
-            raise Exception("Not implemented yet")
-
-        def set_color(self, color):
-            self.canvas_wrapper.element.itemconfig(self.element_id, fill=color)
-

+ 0 - 198
src/sccd/runtime/libs/ordered_set.py

@@ -1,198 +0,0 @@
-"""
-An OrderedSet is a custom MutableSet that remembers its order, so that every
-entry has an index that can be looked up.
-
-Based on a recipe originally posted to ActiveState Recipes by Raymond Hettiger,
-and released under the MIT license.
-
-Rob Speer's changes are as follows:
-
-    - changed the content from a doubly-linked list to a regular Python list.
-      Seriously, who wants O(1) deletes but O(N) lookups by index?
-    - add() returns the index of the added item
-    - index() just returns the index of an item
-    - added a __getstate__ and __setstate__ so it can be pickled
-    - added __getitem__
-"""
-import collections
-
-SLICE_ALL = slice(None)
-__version__ = '2.0.1'
-
-
-def is_iterable(obj):
-    """
-    Are we being asked to look up a list of things, instead of a single thing?
-    We check for the `__iter__` attribute so that this can cover types that
-    don't have to be known by this module, such as NumPy arrays.
-
-    Strings, however, should be considered as atomic values to look up, not
-    iterables. The same goes for tuples, since they are immutable and therefore
-    valid entries.
-
-    We don't need to check for the Python 2 `unicode` type, because it doesn't
-    have an `__iter__` attribute anyway.
-    """
-    return hasattr(obj, '__iter__') and not isinstance(obj, str) and not isinstance(obj, tuple)
-
-
-class OrderedSet(collections.MutableSet):
-    """
-    An OrderedSet is a custom MutableSet that remembers its order, so that
-    every entry has an index that can be looked up.
-    """
-    def __init__(self, iterable=None):
-        self.items = []
-        self.map = {}
-        if iterable is not None:
-            self |= iterable
-
-    def __len__(self):
-        return len(self.items)
-
-    def __getitem__(self, index):
-        """
-        Get the item at a given index.
-
-        If `index` is a slice, you will get back that slice of items. If it's
-        the slice [:], exactly the same object is returned. (If you want an
-        independent copy of an OrderedSet, use `OrderedSet.copy()`.)
-
-        If `index` is an iterable, you'll get the OrderedSet of items
-        corresponding to those indices. This is similar to NumPy's
-        "fancy indexing".
-        """
-        if index == SLICE_ALL:
-            return self
-        elif hasattr(index, '__index__') or isinstance(index, slice):
-            result = self.items[index]
-            if isinstance(result, list):
-                return OrderedSet(result)
-            else:
-                return result
-        elif is_iterable(index):
-            return OrderedSet([self.items[i] for i in index])
-        else:
-            raise TypeError("Don't know how to index an OrderedSet by %r" %
-                    index)
-
-    def copy(self):
-        return OrderedSet(self)
-
-    def __getstate__(self):
-        if len(self) == 0:
-            # The state can't be an empty list.
-            # We need to return a truthy value, or else __setstate__ won't be run.
-            #
-            # This could have been done more gracefully by always putting the state
-            # in a tuple, but this way is backwards- and forwards- compatible with
-            # previous versions of OrderedSet.
-            return (None,)
-        else:
-            return list(self)
-
-    def __setstate__(self, state):
-        if state == (None,):
-            self.__init__([])
-        else:
-            self.__init__(state)
-
-    def __contains__(self, key):
-        return key in self.map
-
-    def add(self, key):
-        """
-        Add `key` as an item to this OrderedSet, then return its index.
-
-        If `key` is already in the OrderedSet, return the index it already
-        had.
-        """
-        if key not in self.map:
-            self.map[key] = len(self.items)
-            self.items.append(key)
-        return self.map[key]
-    append = add
-
-    def update(self, sequence):
-        """
-        Update the set with the given iterable sequence, then return the index
-        of the last element inserted.
-        """
-        item_index = None
-        try:
-            for item in sequence:
-                item_index = self.add(item)
-        except TypeError:
-            raise ValueError('Argument needs to be an iterable, got %s' % type(sequence))
-        return item_index
-
-    def index(self, key):
-        """
-        Get the index of a given entry, raising an IndexError if it's not
-        present.
-
-        `key` can be an iterable of entries that is not a string, in which case
-        this returns a list of indices.
-        """
-        if is_iterable(key):
-            return [self.index(subkey) for subkey in key]
-        return self.map[key]
-
-    def pop(self):
-        """
-        Remove and return the last element from the set.
-
-        Raises KeyError if the set is empty.
-        """
-        if not self.items:
-            raise KeyError('Set is empty')
-
-        elem = self.items[-1]
-        del self.items[-1]
-        del self.map[elem]
-        return elem
-
-    def discard(self, key):
-        """
-        Remove an element.  Do not raise an exception if absent.
-
-        The MutableSet mixin uses this to implement the .remove() method, which
-        *does* raise an error when asked to remove a non-existent item.
-        """
-        if key in self:
-            i = self.items.index(key)
-            del self.items[i]
-            del self.map[key]
-            for k, v in list(self.map.items()):
-                if v >= i:
-                    self.map[k] = v - 1
-
-    def clear(self):
-        """
-        Remove all items from this OrderedSet.
-        """
-        del self.items[:]
-        self.map.clear()
-
-    def __iter__(self):
-        return iter(self.items)
-
-    def __reversed__(self):
-        return reversed(self.items)
-
-    def __repr__(self):
-        if not self:
-            return '%s()' % (self.__class__.__name__,)
-        return '%s(%r)' % (self.__class__.__name__, list(self))
-
-    def __eq__(self, other):
-        if isinstance(other, OrderedSet):
-            return len(self) == len(other) and self.items == other.items
-        try:
-            other_as_set = set(other)
-        except TypeError:
-            # If `other` can't be converted into a set, it's not equal.
-            return False
-        else:
-            return set(self) == other_as_set
-

+ 0 - 121
src/sccd/runtime/libs/ui.py

@@ -1,121 +0,0 @@
-"""
- *REALLY* Small framework for creating/manipulating/deleting gui elements in Tkinter.
-
- NOTE: keep this synced with ui.js
-
- Author: Raphael Mannadiar
- Date: 2014/08/21
-"""
-
-import sys
-try:
-    import Tkinter as tk
-except ImportError:
-    import tkinter as tk
-
-from sccd.runtime.libs.drawing import drawing
-from sccd.runtime.libs.utils import utils
-
-from sccd.runtime.statecharts_core import Event
-
-
-class ui:
-    window = None
-    __nextWindowId = 0
-
-    EVENTS = utils._bunch(
-        KEY_PRESS =             '<Key>',
-        MOUSE_CLICK =             '<Button>',
-        MOUSE_MOVE =             '<Motion>',
-        MOUSE_PRESS =            '<ButtonPress>',
-        MOUSE_RELEASE =        '<ButtonRelease>',
-        MOUSE_RIGHT_CLICK =    '<Button-2>' if sys.platform == "darwin" else '<Button-3>',
-        WINDOW_CLOSE =         'WM_DELETE_WINDOW');
-
-    if sys.platform == "darwin":
-        MOUSE_BUTTONS = utils._bunch(
-            LEFT        = 1,
-            MIDDLE    = 3,
-            RIGHT        = 2);
-    else:
-        MOUSE_BUTTONS = utils._bunch(
-            LEFT        = 1,
-            MIDDLE    = 2,
-            RIGHT        = 3);
-
-    KEYCODES    = utils._bunch(
-        DELETE    = 46);
-
-    @staticmethod
-    def append_button(_window,text):
-        button = tk.Button(_window, text=text)
-        button.pack(fill=tk.BOTH, expand=1)
-        return ui.wrap_element(button)
-
-
-    @staticmethod
-    def append_canvas(_window,width,height,style):
-        canvas = tk.Canvas(_window,width=width,height=height)
-        canvas.config(**style)
-        canvas.pack(fill=tk.BOTH, expand=1)
-        return drawing.canvas_wrapper(canvas)
-
-
-    @staticmethod
-    def bind_event(source,event,controller,raise_name,port="ui"):
-
-        def __handle_event(ev=None):
-            if event == ui.EVENTS.KEY_PRESS :
-                controller.addInput(Event(raise_name, port, [ev.keycode,source]))
-
-            elif event == ui.EVENTS.MOUSE_CLICK or \
-                  event == ui.EVENTS.MOUSE_MOVE or \
-                  event == ui.EVENTS.MOUSE_PRESS or \
-                  event == ui.EVENTS.MOUSE_RELEASE or \
-                    event == ui.EVENTS.MOUSE_RIGHT_CLICK :
-                controller.addInput(Event(raise_name, port, [ev.x, ev.y, ev.num]))
-
-            elif event == ui.EVENTS.WINDOW_CLOSE :
-                controller.addInput(Event(raise_name, port, [source]))
-
-            else :
-                raise Exception('Unsupported event');
-
-        if event == ui.EVENTS.WINDOW_CLOSE :
-            source.protocol(event, __handle_event)
-
-        elif issubclass(drawing.ui_element_wrapper,source.__class__) :
-            source.canvas_wrapper.element.tag_bind(source.element_id, event, __handle_event)
-
-        else :
-            source.bind(event, __handle_event)
-
-
-    @staticmethod
-    def close_window(_window):
-        _window.destroy()
-
-
-    @staticmethod
-    def log(value):
-        print(value)
-
-
-    @staticmethod
-    def new_window(width,height,title=None):
-        _window = tk.Toplevel(ui.window)
-        if title:
-            _window.title(title)
-        _window.geometry(str(width)+"x"+str(height)+"+300+300")
-        return _window
-
-
-    @staticmethod
-    def println(value,target):
-        raise Exception('Not implemented yet');
-
-
-    @staticmethod
-    def wrap_element(element):
-        return utils._bunch(element=element)
-

+ 0 - 19
src/sccd/runtime/libs/utils.py

@@ -1,19 +0,0 @@
-import random
-
-class utils:
-
-	@staticmethod
-	def random():
-		return random.random()
-
-
-	"""
-		provide "." access to dictionaries
-
-		example: d = {'a':1}
-			before: d['a'] => 1, d.a => error
-			after:  d['a'] = d.a
-	"""
-	class _bunch:
-		def __init__(self, **kwds):
-			self.__dict__.update(kwds)

+ 0 - 62
src/sccd/runtime/model.py

@@ -1,62 +0,0 @@
-from abc import *
-from dataclasses import *
-from typing import *
-from sccd.runtime.statechart_syntax import *
-from sccd.runtime.semantic_options import *
-
-@dataclass
-class ModelNamespace:
-  def __init__(self):
-    self.events: Dict[str, int] = {}
-    self.inports: List[str] = []
-    self.outports: List[str] = []
-
-  def assign_event_id(self, name: str) -> int:
-    return self.events.setdefault(name, len(self.events))
-
-  def get_event_id(self, name: str) -> int:
-    return self.events[name]
-
-  def add_inport(self, port: str):
-    if port not in self.inports:
-      self.inports.append(port)
-
-  def add_outport(self, port: str):
-    if port not in self.outports:
-      self.outports.append(port)
-
-@dataclass
-class StateTree:
-  root: State
-  states: Dict[str, State] # mapping from state "full name" (e.g. "/parallel/ortho1/a") to state
-  state_list: List[State] # depth-first order
-  transition_list: List[Transition] # source state depth-first order, then document order
-
-@dataclass
-class Statechart:
-  tree: StateTree
-  semantics: SemanticConfiguration
-  datamodel: DataModel
-
-@dataclass
-class AbstractModel(ABC):
-  namespace: ModelNamespace
-
-  @abstractmethod
-  def get_default_class(self) -> Statechart:
-    pass
-
-@dataclass
-class MultiInstanceModel(AbstractModel):
-  classes: Dict[str, Statechart]
-  default_class: Optional[str]
-
-  def get_default_class(self) -> Statechart:
-    return self.classes[self.default_class]
-
-@dataclass
-class SingleInstanceModel(AbstractModel):
-  statechart: Statechart
-
-  def get_default_class(self) -> Statechart:
-    return self.statechart

+ 0 - 48
src/sccd/runtime/tkinter_eventloop.py

@@ -1,48 +0,0 @@
-"""
-Yentl added many patches to make this code TkInter compatible.
-TkInter is NOT thread-safe, and this applies to the after operations as well.
-Therefore, calling tk.after (or after_cancel) should NOT be done from any thread apart from the thread running TkInter itself.
-See https://mail.python.org/pipermail/tkinter-discuss/2013-November/003522.html for a discussion...
-What actually happens in this code, is that we check whether we are on the main thread or not.
-If we are on the main thread, we invoke the code as usual.
-If we are not on the main thread, we force the *run* operation to execute, even though it might not have been scheduled.
-This operation, however, will run on the main thread, and from there we can then call this schedule function again.
-"""
-
-# If we are not on the main thread, we force the *run* operation
-
-from sccd.runtime.statecharts_core import EventLoop
-
-import math
-import thread
-
-class TkEventLoop(EventLoop):
-    def __init__(self, tk):
-        self.ctr = 0
-        self.tk = tk
-        self.main_thread = thread.get_ident()
-
-        # bind scheduler callback
-        def schedule(callback, timeout, behind = False):
-            if self.main_thread != thread.get_ident():
-                # Use events, as Tk operations are far from thread safe...
-                # Should there be a timeout, event_generate will automatically schedule this for real from inside the main loop
-                tk.event_generate("<<TriggerSCCDEvent>>", when="tail")
-            else:
-                # As usual, use Tk after events
-                if behind:
-                    tk.update_idletasks()
-                return tk.after(timeout, callback)
-
-        def cancel(evt):
-            if self.main_thread != thread.get_ident():
-                # This will also remove the pending events, while also triggering a run first
-                # That initial run, however, will not execute anything
-                tk.event_generate("<<TriggerSCCDEvent>>", when="tail")
-            else:
-                tk.after_cancel(evt)
-
-        EventLoop.__init__(self, schedule, cancel)
-
-    def bind_controller(self, controller):
-        self.tk.bind("<<TriggerSCCDEvent>>", controller.run)

+ 33 - 0
src/sccd/syntax/action.py

@@ -0,0 +1,33 @@
+from typing import *
+from dataclasses import *
+from sccd.syntax.expression import *
+from sccd.syntax.statement import *
+
+@dataclass
+class Action:
+    pass
+
+@dataclass
+class RaiseEvent(Action):
+    name: str
+    parameters: List[Expression]
+
+    # just a simple string representation for rendering a transition label
+    def render(self) -> str:
+        return '^'+self.name
+
+@dataclass
+class RaiseInternalEvent(RaiseEvent):
+    event_id: int
+
+@dataclass
+class RaiseOutputEvent(RaiseEvent):
+    outport: str
+    time_offset: int
+
+    def render(self) -> str:
+        return '^'+self.outport + '.' + self.name
+
+@dataclass
+class Code(Action):
+    block: Block

+ 9 - 0
src/sccd/syntax/datamodel.py

@@ -0,0 +1,9 @@
+from typing import *
+
+class Variable:
+    def __init__(self, value):
+        self.value = value
+
+class DataModel:
+    def __init__(self):
+        self.names: Dict[str, Variable] = {}

+ 1 - 54
src/sccd/runtime/expression.py

@@ -1,15 +1,7 @@
 from abc import *
 from typing import *
 from dataclasses import *
-
-class Variable:
-    def __init__(self, value):
-        self.value = value
-
-class DataModel:
-    def __init__(self):
-        self.names: Dict[str, Variable] = {}
-
+from sccd.syntax.datamodel import *
 
 class Expression(ABC):
     # Evaluation should NOT have side effects.
@@ -27,14 +19,6 @@ class LHS(Expression):
     def eval(self, events, datamodel):
         return self.lhs(events, datamodel).value
 
-# A statement is NOT an expression.
-class Statement(ABC):
-    # Execution typically has side effects.
-    @abstractmethod
-    def exec(self, events, datamodel):
-        pass
-
-
 @dataclass
 class Identifier(LHS):
     name: str
@@ -168,40 +152,3 @@ class UnaryExpression(Expression):
 
     def render(self):
         return self.operator + ' ' + self.expr.render()
-
-@dataclass
-class Assignment(Statement):
-    lhs: LHS
-    operator: str # token value from the grammar.
-    rhs: Expression
-
-    def exec(self, events, datamodel):
-        rhs = self.rhs.eval(events, datamodel)
-        lhs = self.lhs.lhs(events, datamodel)
-
-        def assign(x,y):
-            x.value = y
-        def increment(x,y):
-            x.value += y
-        def decrement(x,y):
-            x.value -= y
-        def multiply(x,y):
-            x.value *= y
-        def divide(x,y):
-            x.value /= y
-
-        {
-            "=": assign,
-            "+=": increment,
-            "-=": decrement,
-            "*=": multiply,
-            "/=": divide,
-        }[self.operator](lhs, rhs)
-
-@dataclass
-class Block(Statement):
-    stmts: List[Statement]
-
-    def exec(self, events, datamodel):
-        for stmt in self.stmts:
-            stmt.exec(events, datamodel)

+ 10 - 4
src/sccd/runtime/semantic_options.py

@@ -1,7 +1,8 @@
-from enum import Enum
-from dataclasses import dataclass, fields
+from enum import *
+from dataclasses import *
 from typing import *
 import itertools
+from sccd.syntax.tree import *
 
 class BigStepMaximality(Enum):
   TAKE_ONE = 0
@@ -29,9 +30,8 @@ class Concurrency(Enum):
   SINGLE = 0
   MANY = 1
 
-
 @dataclass
-class SemanticConfiguration:
+class Semantics:
   big_step_maximality: BigStepMaximality = BigStepMaximality.TAKE_MANY
   combo_step_maximality: ComboStepMaximality = ComboStepMaximality.COMBO_TAKE_ONE
   internal_event_lifeline: InternalEventLifeline = InternalEventLifeline.NEXT_COMBO_STEP
@@ -56,3 +56,9 @@ class SemanticConfiguration:
         wildcard_fields.append(field)
     types = (field.type for field in wildcard_fields)
     return ({wildcard_fields[i].name: option for i,option in enumerate(configuration)} for configuration in itertools.product(*types))
+
+@dataclass
+class Statechart:
+  tree: StateTree
+  semantics: Semantics
+  datamodel: DataModel

+ 46 - 0
src/sccd/syntax/statement.py

@@ -0,0 +1,46 @@
+from typing import *
+from sccd.syntax.expression import *
+
+# A statement is NOT an expression.
+class Statement(ABC):
+    # Execution typically has side effects.
+    @abstractmethod
+    def exec(self, events, datamodel):
+        pass
+
+@dataclass
+class Assignment(Statement):
+    lhs: LHS
+    operator: str # token value from the grammar.
+    rhs: Expression
+
+    def exec(self, events, datamodel):
+        rhs = self.rhs.eval(events, datamodel)
+        lhs = self.lhs.lhs(events, datamodel)
+
+        def assign(x,y):
+            x.value = y
+        def increment(x,y):
+            x.value += y
+        def decrement(x,y):
+            x.value -= y
+        def multiply(x,y):
+            x.value *= y
+        def divide(x,y):
+            x.value /= y
+
+        {
+            "=": assign,
+            "+=": increment,
+            "-=": decrement,
+            "*=": multiply,
+            "/=": divide,
+        }[self.operator](lhs, rhs)
+
+@dataclass
+class Block(Statement):
+    stmts: List[Statement]
+
+    def exec(self, events, datamodel):
+        for stmt in self.stmts:
+            stmt.exec(events, datamodel)

+ 13 - 38
src/sccd/runtime/statechart_syntax.py

@@ -1,14 +1,7 @@
 import termcolor
-from dataclasses import dataclass, field
 from typing import *
-from sccd.runtime.event_queue import Timestamp
-from sccd.runtime.expression import *
-from sccd.compiler.utils import FormattedWriter
-from sccd.runtime.bitmap import *
-
-@dataclass
-class Action:
-    pass
+from sccd.syntax.action import *
+from sccd.util.bitmap import *
 
 class State:
     def __init__(self, short_name):
@@ -67,12 +60,12 @@ class State:
             self.descendant_bitmap |= Bit(d.state_id)
         return next_id
 
-    def print(self, w = FormattedWriter()):
-        w.write(self.name)
-        w.indent()
-        for c in self.children:
-            c.print(w)
-        w.dedent()
+    # def print(self, w = FormattedWriter()):
+    #     w.write(self.name)
+    #     w.indent()
+    #     for c in self.children:
+    #         c.print(w)
+    #     w.dedent()
             
     def addChild(self, child):
         child.parent = self
@@ -199,26 +192,8 @@ class Transition:
         return termcolor.colored("%s 🡪 %s" % (self.source.name, self.targets[0].name), 'green')
 
 @dataclass
-class RaiseEvent(Action):
-    name: str
-    parameters: List[Expression]
-
-    # just a simple string representation for rendering a transition label
-    def render(self) -> str:
-        return '^'+self.name
-
-@dataclass
-class RaiseInternalEvent(RaiseEvent):
-    event_id: int
-
-@dataclass
-class RaiseOutputEvent(RaiseEvent):
-    outport: str
-    time_offset: Timestamp
-
-    def render(self) -> str:
-        return '^'+self.outport + '.' + self.name
-
-@dataclass
-class Code(Action):
-    block: Block
+class StateTree:
+  root: State
+  states: Dict[str, State] # mapping from state "full name" (e.g. "/parallel/ortho1/a") to state
+  state_list: List[State] # depth-first order
+  transition_list: List[Transition] # source state depth-first order, then document order

+ 2 - 2
src/sccd/runtime/test.py

@@ -1,7 +1,7 @@
 import unittest
 from dataclasses import *
-from sccd.runtime.model import *
-from sccd.runtime.controller import *
+from sccd.model.model import *
+from sccd.controller.controller import *
 
 import threading
 import queue

+ 67 - 0
src/sccd/test/xml_loader.py

@@ -0,0 +1,67 @@
+import os
+import lxml.etree as ET
+from lark import Lark, Transformer
+from sccd.test.test import *
+from sccd.model.model import *
+from sccd.model.xml_loader import *
+from sccd.syntax.statechart import *
+from copy import deepcopy
+
+# Returned list contains more than one test if the semantic configuration contains wildcard values.
+def load_test(src_file) -> List[Test]:
+  namespace = Namespace()
+
+  test_node = ET.parse(src_file).getroot()
+  sc_node = test_node.find("statechart")
+  src = sc_node.get("src")
+  if src is None:
+    statechart = load_statechart(namespace, sc_node)
+  else:
+    external_node = ET.parse(os.path.join(os.path.dirname(src_file), src)).getroot()
+    statechart = load_statechart(namespace, external_node)
+    semantics_node = sc_node.find("override_semantics")
+    load_semantics(statechart.semantics, semantics_node)
+
+  input_node = test_node.find("input")
+  output_node = test_node.find("output")
+  input = load_input(input_node)
+  output = load_output(output_node)
+
+  def variant_description(i, variant) -> str:
+    if not variant:
+      return ""
+    return " (variant %d: %s)" % (i, ",".join(str(val) for val in variant.values()))
+
+  return [
+    Test(
+      src_file + variant_description(i, variant),
+      SingleInstanceModel(
+        namespace,
+        Statechart(tree=statechart.tree, datamodel=deepcopy(statechart.datamodel), semantics=dataclasses.replace(statechart.semantics, **variant))),
+      input,
+      output)
+    for i, variant in enumerate(statechart.semantics.wildcard_cart_product())
+  ]
+
+def load_input(input_node) -> TestInput:
+  input = []
+  if input_node is not None:
+    for event_node in input_node:
+      name = event_node.get("name")
+      port = event_node.get("port")
+      time = int(event_node.get("time"))
+      input.append(InputEvent(name, port, [], time))
+  return input
+
+def load_output(output_node) -> TestOutput:
+  output = []
+  if output_node is not None: 
+    for big_step_node in output_node:
+      big_step = []
+      for event_node in big_step_node:
+        name = event_node.get("name")
+        port = event_node.get("port")
+        parameters = [] # todo: read params
+        big_step.append(Event(id=0, name=name, port=port, parameters=parameters))
+      output.append(big_step)
+  return output

src/sccd/runtime/bitmap.py → src/sccd/util/bitmap.py


src/sccd/runtime/debug.py → src/sccd/util/debug.py


+ 64 - 0
src/sccd/util/indenting_writer.py

@@ -0,0 +1,64 @@
+import sys
+
+class IndentingWriter:
+
+  def __init__(self, out = sys.stdout):
+    self.out = out
+    self.indentLevel = 0
+    self.indentSpace = "    "
+    self.first_write = True
+
+  def write(self, text = ""):
+    if self.first_write :
+      self.first_write = False
+      if text == "":
+        self.out.write(self.indentLevel*self.indentSpace)
+      else:
+        self.out.write(self.indentLevel*self.indentSpace + text)  
+    else:
+      if text == "":
+        self.out.write("\n" + self.indentLevel*self.indentSpace)
+      else:
+        self.out.write("\n" + self.indentLevel*self.indentSpace + text)
+  
+  def extendWrite(self, text = ""):
+    self.out.write(text)
+        
+  def indent(self):
+    self.indentLevel+=1
+
+  def dedent(self):
+    self.indentLevel-=1
+
+  def writeCodeCorrectIndent(self, body):
+    lines = body.split('\n')
+    while( len(lines) > 0 and lines[-1].strip() == "") :
+      del(lines[-1])
+  
+    index = 0;
+    while( len(lines) > index and lines[index].strip() == "") :    
+      index += 1
+      
+    if index >= len(lines) :
+      return
+    #first index where valid code is present
+    to_strip_index = len(lines[index].rstrip()) - len(lines[index].strip()) 
+    indent_type = NOT_SET;
+      
+    while index < len(lines):
+      strip_part = lines[index][:to_strip_index]
+      
+      if( ('\t' in strip_part and ' ' in strip_part) or
+        (indent_type == SPACES_USED and '\t' in strip_part) or
+        (indent_type == TABS_USED and ' ' in strip_part)
+      ) :
+        raise Exception("Mixed tab and space indentation!")
+      
+      if indent_type == NOT_SET :
+        if ' ' in strip_part :
+          indent_type = SPACES_USED
+        elif '\t' in strip_part :
+          indent_type = TABS_USED
+          
+      self.write(lines[index][to_strip_index:])
+      index += 1

src/sccd/compiler/utils.py → src/sccd/util/utils.py


+ 907 - 0
src/sccd_runtime.svg

@@ -0,0 +1,907 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by graphviz version 2.40.1 (20161225.0304)
+ -->
+<!-- Title: G Pages: 1 -->
+<svg width="1991pt" height="1052pt"
+ viewBox="0.00 0.00 1991.11 1052.48" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 1048.4794)">
+<title>G</title><style>.edge>path:hover{stroke-width:8}</style>
+<polygon fill="#ffffff" stroke="transparent" points="-4,4 -4,-1048.4794 1987.1101,-1048.4794 1987.1101,4 -4,4"/>
+<!-- lxml -->
+<g id="node1" class="node">
+<title>lxml</title><style>.edge>path:hover{stroke-width:8}</style>
+<ellipse fill="#85db2f" stroke="#000000" cx="831.3406" cy="-1007.7098" rx="27" ry="18"/>
+<text text-anchor="middle" x="831.3406" y="-1005.2098" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">lxml</text>
+</g>
+<!-- sccd_runtime_xml_loader2 -->
+<g id="node13" class="node">
+<title>sccd_runtime_xml_loader2</title><style>.edge>path:hover{stroke-width:8}</style>
+<ellipse fill="#347979" stroke="#000000" cx="594.3406" cy="-28.9914" rx="48.5816" ry="28.9828"/>
+<text text-anchor="middle" x="594.3406" y="-37.4914" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#ffffff">sccd.</text>
+<text text-anchor="middle" x="594.3406" y="-26.4914" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#ffffff">runtime.</text>
+<text text-anchor="middle" x="594.3406" y="-15.4914" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#ffffff">xml_loader2</text>
+</g>
+<!-- lxml&#45;&gt;sccd_runtime_xml_loader2 -->
+<g id="edge6" class="edge">
+<title>lxml&#45;&gt;sccd_runtime_xml_loader2</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M755.3406,-788.6316C751.9496,-681.5799 802.4588,-663.2998 842.3406,-563.8965 853.9875,-534.8673 863.3684,-529.6082 869.3406,-498.9052"/>
+<path fill="none" stroke="#000000" d="M869.3406,-498.9052C873.8173,-457.3756 858.4989,-445.261 869.3406,-404.9224"/>
+</g>
+<!-- sccd_compiler_sccd_constructs -->
+<g id="node15" class="node">
+<title>sccd_compiler_sccd_constructs</title><style>.edge>path:hover{stroke-width:8}</style>
+<ellipse fill="#1b9c9c" stroke="#000000" cx="1382.3406" cy="-686.8707" rx="62.8651" ry="28.9828"/>
+<text text-anchor="middle" x="1382.3406" y="-695.3707" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#ffffff">sccd.</text>
+<text text-anchor="middle" x="1382.3406" y="-684.3707" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#ffffff">compiler.</text>
+<text text-anchor="middle" x="1382.3406" y="-673.3707" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#ffffff">sccd_constructs</text>
+</g>
+<!-- lxml&#45;&gt;sccd_compiler_sccd_constructs -->
+<g id="edge3" class="edge">
+<title>lxml&#45;&gt;sccd_compiler_sccd_constructs</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M858.6106,-1006.764C948.9501,-1003.1505 1236.8693,-987.6487 1310.3406,-934.9403 1325.287,-924.2177 1319.2878,-913.5756 1329.3406,-898.1707"/>
+<path fill="none" stroke="#000000" d="M1329.3406,-898.1707C1355.9465,-857.3998 1321.8626,-836.7379 1329.3406,-788.6316"/>
+<path fill="none" stroke="#000000" d="M1329.3406,-788.6316C1332.9857,-765.1827 1344.716,-741.5207 1356.217,-722.9221"/>
+<polygon fill="#85db2f" stroke="#000000" points="1359.1746,-724.7937 1361.631,-714.4876 1353.2837,-721.0124 1359.1746,-724.7937"/>
+</g>
+<!-- sccd_compiler_sccdc -->
+<g id="node32" class="node">
+<title>sccd_compiler_sccdc</title><style>.edge>path:hover{stroke-width:8}</style>
+<ellipse fill="#2e6b6b" stroke="#000000" cx="1154.3406" cy="-498.9052" rx="39.6962" ry="28.9828"/>
+<text text-anchor="middle" x="1154.3406" y="-507.4052" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#ffffff">sccd.</text>
+<text text-anchor="middle" x="1154.3406" y="-496.4052" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#ffffff">compiler.</text>
+<text text-anchor="middle" x="1154.3406" y="-485.4052" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#ffffff">sccdc</text>
+</g>
+<!-- lxml&#45;&gt;sccd_compiler_sccdc -->
+<g id="edge4" class="edge">
+<title>lxml&#45;&gt;sccd_compiler_sccdc</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M831.3406,-989.533C831.3406,-951.9953 831.3406,-863.179 831.3406,-788.6316 831.3406,-788.6316 831.3406,-788.6316 831.3406,-686.8707 831.3406,-623.311 853.5389,-602.0937 904.3406,-563.8965 935.8326,-540.2181 1041.8779,-518.4252 1105.293,-507.0852"/>
+<polygon fill="#85db2f" stroke="#000000" points="1106.2277,-510.4744 1115.4673,-505.29 1105.0113,-503.5809 1106.2277,-510.4744"/>
+</g>
+<!-- sccd_runtime_xml_loader -->
+<g id="node39" class="node">
+<title>sccd_runtime_xml_loader</title><style>.edge>path:hover{stroke-width:8}</style>
+<ellipse fill="#2e6b6b" stroke="#000000" cx="667.3406" cy="-122.9741" rx="45.011" ry="28.9828"/>
+<text text-anchor="middle" x="667.3406" y="-131.4741" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#ffffff">sccd.</text>
+<text text-anchor="middle" x="667.3406" y="-120.4741" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#ffffff">runtime.</text>
+<text text-anchor="middle" x="667.3406" y="-109.4741" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#ffffff">xml_loader</text>
+</g>
+<!-- lxml&#45;&gt;sccd_runtime_xml_loader -->
+<g id="edge5" class="edge">
+<title>lxml&#45;&gt;sccd_runtime_xml_loader</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M817.0266,-992.2399C804.9903,-978.32 788.347,-956.7564 779.3406,-934.9403 754.1955,-874.0314 755.3406,-854.5267 755.3406,-788.6316"/>
+<path fill="none" stroke="#000000" d="M755.3406,-788.6316C749.7117,-700.1892 707.0054,-680.9046 717.3406,-592.8879"/>
+</g>
+<!-- termcolor -->
+<g id="node2" class="node">
+<title>termcolor</title><style>.edge>path:hover{stroke-width:8}</style>
+<ellipse fill="#853bce" stroke="#000000" cx="353.3406" cy="-1007.7098" rx="33.6077" ry="18"/>
+<text text-anchor="middle" x="353.3406" y="-1005.2098" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#ffffff">termcolor</text>
+</g>
+<!-- sccd_runtime_statechart_syntax -->
+<g id="node8" class="node">
+<title>sccd_runtime_statechart_syntax</title><style>.edge>path:hover{stroke-width:8}</style>
+<ellipse fill="#04b3b3" stroke="#000000" cx="378.3406" cy="-686.8707" rx="67.3507" ry="28.9828"/>
+<text text-anchor="middle" x="378.3406" y="-695.3707" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#ffffff">sccd.</text>
+<text text-anchor="middle" x="378.3406" y="-684.3707" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#ffffff">runtime.</text>
+<text text-anchor="middle" x="378.3406" y="-673.3707" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#ffffff">statechart_syntax</text>
+</g>
+<!-- termcolor&#45;&gt;sccd_runtime_statechart_syntax -->
+<g id="edge96" class="edge">
+<title>termcolor&#45;&gt;sccd_runtime_statechart_syntax</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M232.3406,-898.1707C225.4991,-881.0955 240.5908,-876.3281 251.3406,-861.4012 264.3815,-843.2929 273.2997,-843.5095 286.3406,-825.4012 297.0904,-810.4742 296.9776,-805.0155 305.3406,-788.6316"/>
+<path fill="none" stroke="#000000" d="M305.3406,-788.6316C313.7036,-772.2477 314.1812,-767.1969 324.3406,-751.862 331.1134,-741.639 339.2209,-731.1626 347.0693,-721.6882"/>
+<polygon fill="#853bce" stroke="#000000" points="349.7894,-723.892 353.566,-713.9931 344.4406,-719.3762 349.7894,-723.892"/>
+</g>
+<!-- sccd_runtime_statechart_instance -->
+<g id="node12" class="node">
+<title>sccd_runtime_statechart_instance</title><style>.edge>path:hover{stroke-width:8}</style>
+<ellipse fill="#267373" stroke="#000000" cx="296.3406" cy="-404.9224" rx="72.25" ry="28.9828"/>
+<text text-anchor="middle" x="296.3406" y="-413.4224" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#ffffff">sccd.</text>
+<text text-anchor="middle" x="296.3406" y="-402.4224" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#ffffff">runtime.</text>
+<text text-anchor="middle" x="296.3406" y="-391.4224" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#ffffff">statechart_instance</text>
+</g>
+<!-- termcolor&#45;&gt;sccd_runtime_statechart_instance -->
+<g id="edge95" class="edge">
+<title>termcolor&#45;&gt;sccd_runtime_statechart_instance</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M369.5243,-991.7773C402.2792,-957.7437 473.3406,-874.0634 473.3406,-788.6316 473.3406,-788.6316 473.3406,-788.6316 473.3406,-686.8707 473.3406,-603.3198 511.1576,-574.856 476.3406,-498.9052"/>
+</g>
+<!-- sccd_runtime_event -->
+<g id="node25" class="node">
+<title>sccd_runtime_event</title><style>.edge>path:hover{stroke-width:8}</style>
+<ellipse fill="#05dbdb" stroke="#000000" cx="155.3406" cy="-592.8879" rx="36.5405" ry="28.9828"/>
+<text text-anchor="middle" x="155.3406" y="-601.3879" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">sccd.</text>
+<text text-anchor="middle" x="155.3406" y="-590.3879" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">runtime.</text>
+<text text-anchor="middle" x="155.3406" y="-579.3879" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">event</text>
+</g>
+<!-- termcolor&#45;&gt;sccd_runtime_event -->
+<g id="edge94" class="edge">
+<title>termcolor&#45;&gt;sccd_runtime_event</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M329.4106,-995.0583C307.0027,-982.2722 273.7063,-960.7501 251.3406,-934.9403 239.2941,-921.0387 239.1821,-915.2459 232.3406,-898.1707"/>
+<path fill="none" stroke="#000000" d="M232.3406,-898.1707C218.7704,-864.302 205.9465,-859.9922 194.3406,-825.4012 172.2503,-759.5618 162.3103,-678.8612 158.1183,-631.9189"/>
+<polygon fill="#853bce" stroke="#000000" points="161.5985,-631.5356 157.2631,-621.8684 154.6237,-632.1292 161.5985,-631.5356"/>
+</g>
+<!-- sccd_runtime_controller -->
+<g id="node3" class="node">
+<title>sccd_runtime_controller</title><style>.edge>path:hover{stroke-width:8}</style>
+<ellipse fill="#269b9b" stroke="#000000" cx="325.3406" cy="-216.9569" rx="39.6962" ry="28.9828"/>
+<text text-anchor="middle" x="325.3406" y="-225.4569" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#ffffff">sccd.</text>
+<text text-anchor="middle" x="325.3406" y="-214.4569" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#ffffff">runtime.</text>
+<text text-anchor="middle" x="325.3406" y="-203.4569" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#ffffff">controller</text>
+</g>
+<!-- sccd_runtime_test -->
+<g id="node35" class="node">
+<title>sccd_runtime_test</title><style>.edge>path:hover{stroke-width:8}</style>
+<ellipse fill="#38a8a8" stroke="#000000" cx="529.3406" cy="-122.9741" rx="36.5405" ry="28.9828"/>
+<text text-anchor="middle" x="529.3406" y="-131.4741" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">sccd.</text>
+<text text-anchor="middle" x="529.3406" y="-120.4741" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">runtime.</text>
+<text text-anchor="middle" x="529.3406" y="-109.4741" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">test</text>
+</g>
+<!-- sccd_runtime_controller&#45;&gt;sccd_runtime_test -->
+<g id="edge51" class="edge">
+<title>sccd_runtime_controller&#45;&gt;sccd_runtime_test</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M359.027,-201.4375C394.3936,-185.1442 450.039,-159.5083 488.0312,-142.0054"/>
+<polygon fill="#269b9b" stroke="#000000" points="489.6688,-145.1045 497.2868,-137.7413 486.7398,-138.7468 489.6688,-145.1045"/>
+</g>
+<!-- sccd_runtime_controller&#45;&gt;sccd_runtime_xml_loader -->
+<g id="edge52" class="edge">
+<title>sccd_runtime_controller&#45;&gt;sccd_runtime_xml_loader</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M363.1983,-207.753C412.311,-195.6671 500.5597,-173.4532 575.3406,-151.9655 588.9398,-148.0579 603.5839,-143.5716 617.1018,-139.3143"/>
+<polygon fill="#269b9b" stroke="#000000" points="618.2404,-142.6251 626.7149,-136.2663 616.1247,-135.9524 618.2404,-142.6251"/>
+</g>
+<!-- sccd_compiler_compiler_exceptions -->
+<g id="node4" class="node">
+<title>sccd_compiler_compiler_exceptions</title><style>.edge>path:hover{stroke-width:8}</style>
+<ellipse fill="#10f9f9" stroke="#000000" cx="1571.3406" cy="-1007.7098" rx="74.9067" ry="28.9828"/>
+<text text-anchor="middle" x="1571.3406" y="-1016.2098" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">sccd.</text>
+<text text-anchor="middle" x="1571.3406" y="-1005.2098" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">compiler.</text>
+<text text-anchor="middle" x="1571.3406" y="-994.2098" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">compiler_exceptions</text>
+</g>
+<!-- sccd_compiler_super_class_linker -->
+<g id="node10" class="node">
+<title>sccd_compiler_super_class_linker</title><style>.edge>path:hover{stroke-width:8}</style>
+<ellipse fill="#35a1a1" stroke="#000000" cx="1736.3406" cy="-788.6316" rx="69.0935" ry="28.9828"/>
+<text text-anchor="middle" x="1736.3406" y="-797.1316" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">sccd.</text>
+<text text-anchor="middle" x="1736.3406" y="-786.1316" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">compiler.</text>
+<text text-anchor="middle" x="1736.3406" y="-775.1316" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">super_class_linker</text>
+</g>
+<!-- sccd_compiler_compiler_exceptions&#45;&gt;sccd_compiler_super_class_linker -->
+<g id="edge16" class="edge">
+<title>sccd_compiler_compiler_exceptions&#45;&gt;sccd_compiler_super_class_linker</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M1634.9288,-992.1108C1707.387,-972.633 1817.8361,-937.1033 1833.3406,-898.1707"/>
+<path fill="none" stroke="#000000" d="M1833.3406,-898.1707C1846.1285,-866.0596 1817.9189,-837.1378 1788.6809,-817.0866"/>
+<polygon fill="#10f9f9" stroke="#000000" points="1790.3123,-813.971 1780.0308,-811.4135 1786.4733,-819.8245 1790.3123,-813.971"/>
+</g>
+<!-- sccd_compiler_compiler_exceptions&#45;&gt;sccd_compiler_sccd_constructs -->
+<g id="edge13" class="edge">
+<title>sccd_compiler_compiler_exceptions&#45;&gt;sccd_compiler_sccd_constructs</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M1506.6957,-992.7263C1458.4881,-977.7212 1396.1932,-949.2802 1367.3406,-898.1707"/>
+<path fill="none" stroke="#000000" d="M1367.3406,-898.1707C1342.0083,-853.2971 1321.4254,-839.5504 1329.3406,-788.6316"/>
+</g>
+<!-- sccd_compiler_utils -->
+<g id="node20" class="node">
+<title>sccd_compiler_utils</title><style>.edge>path:hover{stroke-width:8}</style>
+<ellipse fill="#05e5e5" stroke="#000000" cx="1571.3406" cy="-898.1707" rx="39.6962" ry="28.9828"/>
+<text text-anchor="middle" x="1571.3406" y="-906.6707" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">sccd.</text>
+<text text-anchor="middle" x="1571.3406" y="-895.6707" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">compiler.</text>
+<text text-anchor="middle" x="1571.3406" y="-884.6707" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">utils</text>
+</g>
+<!-- sccd_compiler_compiler_exceptions&#45;&gt;sccd_compiler_utils -->
+<g id="edge17" class="edge">
+<title>sccd_compiler_compiler_exceptions&#45;&gt;sccd_compiler_utils</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M1571.3406,-978.6429C1571.3406,-966.0161 1571.3406,-951.0321 1571.3406,-937.4369"/>
+<polygon fill="#10f9f9" stroke="#000000" points="1574.8407,-937.3734 1571.3406,-927.3734 1567.8407,-937.3735 1574.8407,-937.3734"/>
+</g>
+<!-- sccd_compiler_compiler_exceptions&#45;&gt;sccd_compiler_sccdc -->
+<g id="edge14" class="edge">
+<title>sccd_compiler_compiler_exceptions&#45;&gt;sccd_compiler_sccdc</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M1833.3406,-788.6316C1821.5149,-744.9779 1837.4413,-731.9115 1833.3406,-686.8707"/>
+</g>
+<!-- sccd_compiler_path_calculator -->
+<g id="node37" class="node">
+<title>sccd_compiler_path_calculator</title><style>.edge>path:hover{stroke-width:8}</style>
+<ellipse fill="#38a8a8" stroke="#000000" cx="1416.3406" cy="-788.6316" rx="58.8803" ry="28.9828"/>
+<text text-anchor="middle" x="1416.3406" y="-797.1316" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">sccd.</text>
+<text text-anchor="middle" x="1416.3406" y="-786.1316" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">compiler.</text>
+<text text-anchor="middle" x="1416.3406" y="-775.1316" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">path_calculator</text>
+</g>
+<!-- sccd_compiler_compiler_exceptions&#45;&gt;sccd_compiler_path_calculator -->
+<g id="edge12" class="edge">
+<title>sccd_compiler_compiler_exceptions&#45;&gt;sccd_compiler_path_calculator</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M1367.3406,-898.1707C1353.6276,-873.8796 1367.6634,-845.0332 1384.1725,-823.0415"/>
+<polygon fill="#10f9f9" stroke="#000000" points="1387.0994,-824.9833 1390.5682,-814.9724 1381.6136,-820.6352 1387.0994,-824.9833"/>
+</g>
+<!-- sccd_compiler_state_linker -->
+<g id="node38" class="node">
+<title>sccd_compiler_state_linker</title><style>.edge>path:hover{stroke-width:8}</style>
+<ellipse fill="#339999" stroke="#000000" cx="1419.3406" cy="-592.8879" rx="47.2526" ry="28.9828"/>
+<text text-anchor="middle" x="1419.3406" y="-601.3879" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#ffffff">sccd.</text>
+<text text-anchor="middle" x="1419.3406" y="-590.3879" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#ffffff">compiler.</text>
+<text text-anchor="middle" x="1419.3406" y="-579.3879" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#ffffff">state_linker</text>
+</g>
+<!-- sccd_compiler_compiler_exceptions&#45;&gt;sccd_compiler_state_linker -->
+<g id="edge15" class="edge">
+<title>sccd_compiler_compiler_exceptions&#45;&gt;sccd_compiler_state_linker</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M1833.3406,-898.1707C1851.3527,-852.9413 1837.8274,-837.1084 1833.3406,-788.6316"/>
+<path fill="none" stroke="#000000" d="M1833.3406,-788.6316C1831.6453,-770.315 1827.9464,-764.2416 1814.3406,-751.862 1715.1394,-661.6018 1558.1473,-619.4298 1475.1069,-602.5202"/>
+<polygon fill="#10f9f9" stroke="#000000" points="1475.6022,-599.0502 1465.1119,-600.5345 1474.2382,-605.9161 1475.6022,-599.0502"/>
+</g>
+<!-- sccd_runtime_event_queue -->
+<g id="node5" class="node">
+<title>sccd_runtime_event_queue</title><style>.edge>path:hover{stroke-width:8}</style>
+<ellipse fill="#16f3f3" stroke="#000000" cx="92.3406" cy="-788.6316" rx="50.8235" ry="28.9828"/>
+<text text-anchor="middle" x="92.3406" y="-797.1316" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">sccd.</text>
+<text text-anchor="middle" x="92.3406" y="-786.1316" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">runtime.</text>
+<text text-anchor="middle" x="92.3406" y="-775.1316" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">event_queue</text>
+</g>
+<!-- sccd_runtime_event_queue&#45;&gt;sccd_runtime_controller -->
+<g id="edge63" class="edge">
+<title>sccd_runtime_event_queue&#45;&gt;sccd_runtime_controller</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M89.0681,-759.4965C87.4278,-739.0473 86.5089,-711.1316 90.3406,-686.8707"/>
+<path fill="none" stroke="#000000" d="M90.3406,-686.8707C103.3731,-604.3533 57.5655,-575.7476 90.3406,-498.9052"/>
+<path fill="none" stroke="#000000" d="M90.3406,-498.9052C108.0438,-460.8119 91.7112,-445.3601 80.3406,-404.9224"/>
+<path fill="none" stroke="#000000" d="M80.3406,-404.9224C68.849,-364.0544 27.3111,-378.8444 10.3406,-339.931 .039,-316.3095 -5.9368,-301.9269 10.3406,-281.9483 43.2093,-241.6057 195.1874,-225.5568 275.4162,-219.8114"/>
+<polygon fill="#16f3f3" stroke="#000000" points="276.0354,-223.2772 285.7714,-219.0986 275.5546,-216.2937 276.0354,-223.2772"/>
+</g>
+<!-- sccd_runtime_event_queue&#45;&gt;sccd_runtime_statechart_syntax -->
+<g id="edge67" class="edge">
+<title>sccd_runtime_event_queue&#45;&gt;sccd_runtime_statechart_syntax</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M135.4973,-773.0046C153.6562,-766.4474 175.0162,-758.7579 194.3406,-751.862 234.8811,-737.3954 280.5035,-721.2798 316.1776,-708.7155"/>
+<polygon fill="#16f3f3" stroke="#000000" points="317.6931,-711.8926 325.9632,-705.2702 315.3683,-705.2898 317.6931,-711.8926"/>
+</g>
+<!-- sccd_runtime_event_queue&#45;&gt;sccd_runtime_statechart_instance -->
+<g id="edge66" class="edge">
+<title>sccd_runtime_event_queue&#45;&gt;sccd_runtime_statechart_instance</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M90.3406,-498.9052C96.9032,-483.519 100.6411,-479.512 114.3406,-469.9138 146.7413,-447.2129 187.9064,-431.636 222.8882,-421.4365"/>
+<polygon fill="#16f3f3" stroke="#000000" points="223.9055,-424.7861 232.5784,-418.7008 222.0036,-418.0495 223.9055,-424.7861"/>
+</g>
+<!-- sccd_runtime_object_manager -->
+<g id="node21" class="node">
+<title>sccd_runtime_object_manager</title><style>.edge>path:hover{stroke-width:8}</style>
+<ellipse fill="#35a1a1" stroke="#000000" cx="80.3406" cy="-310.9396" rx="60.623" ry="28.9828"/>
+<text text-anchor="middle" x="80.3406" y="-319.4396" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">sccd.</text>
+<text text-anchor="middle" x="80.3406" y="-308.4396" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">runtime.</text>
+<text text-anchor="middle" x="80.3406" y="-297.4396" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">object_manager</text>
+</g>
+<!-- sccd_runtime_event_queue&#45;&gt;sccd_runtime_object_manager -->
+<g id="edge65" class="edge">
+<title>sccd_runtime_event_queue&#45;&gt;sccd_runtime_object_manager</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M80.3406,-404.9224C75.4029,-387.3621 74.7778,-367.2155 75.6404,-350.0905"/>
+<polygon fill="#16f3f3" stroke="#000000" points="79.1489,-350.0853 76.3444,-339.8684 72.1655,-349.6042 79.1489,-350.0853"/>
+</g>
+<!-- sccd_runtime_event_queue&#45;&gt;sccd_runtime_event -->
+<g id="edge64" class="edge">
+<title>sccd_runtime_event_queue&#45;&gt;sccd_runtime_event</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M90.3406,-686.8707C94.1785,-662.5704 109.5503,-639.7596 124.3814,-622.6972"/>
+<polygon fill="#16f3f3" stroke="#000000" points="126.9861,-625.0351 131.1142,-615.2776 121.8023,-620.3311 126.9861,-625.0351"/>
+</g>
+<!-- sccd_runtime_statechart_state -->
+<g id="node6" class="node">
+<title>sccd_runtime_statechart_state</title><style>.edge>path:hover{stroke-width:8}</style>
+<ellipse fill="#339999" stroke="#000000" cx="386.3406" cy="-498.9052" rx="61.5366" ry="28.9828"/>
+<text text-anchor="middle" x="386.3406" y="-507.4052" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#ffffff">sccd.</text>
+<text text-anchor="middle" x="386.3406" y="-496.4052" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#ffffff">runtime.</text>
+<text text-anchor="middle" x="386.3406" y="-485.4052" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#ffffff">statechart_state</text>
+</g>
+<!-- sccd_runtime_statechart_state&#45;&gt;sccd_runtime_statechart_instance -->
+<g id="edge84" class="edge">
+<title>sccd_runtime_statechart_state&#45;&gt;sccd_runtime_statechart_instance</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M361.0311,-472.4756C351.2306,-462.2415 339.8781,-450.3865 329.4447,-439.4914"/>
+<polygon fill="#339999" stroke="#000000" points="331.843,-436.9354 322.3988,-432.1337 326.7873,-441.7769 331.843,-436.9354"/>
+</g>
+<!-- sccd_compiler_javascript_writer -->
+<g id="node7" class="node">
+<title>sccd_compiler_javascript_writer</title><style>.edge>path:hover{stroke-width:8}</style>
+<ellipse fill="#38a8a8" stroke="#000000" cx="1163.3406" cy="-686.8707" rx="62.4516" ry="28.9828"/>
+<text text-anchor="middle" x="1163.3406" y="-695.3707" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">sccd.</text>
+<text text-anchor="middle" x="1163.3406" y="-684.3707" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">compiler.</text>
+<text text-anchor="middle" x="1163.3406" y="-673.3707" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">javascript_writer</text>
+</g>
+<!-- sccd_compiler_javascript_writer&#45;&gt;sccd_compiler_sccdc -->
+<g id="edge24" class="edge">
+<title>sccd_compiler_javascript_writer&#45;&gt;sccd_compiler_sccdc</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M1210.5328,-667.8481C1266.216,-644.6573 1350.5604,-606.8331 1344.3406,-592.8879"/>
+<path fill="none" stroke="#000000" d="M1344.3406,-592.8879C1320.1993,-538.7616 1251.2403,-515.5419 1203.4055,-505.7635"/>
+<polygon fill="#38a8a8" stroke="#000000" points="1204.0223,-502.318 1193.5424,-503.8746 1202.7056,-509.1931 1204.0223,-502.318"/>
+</g>
+<!-- sccd_runtime_statechart_syntax&#45;&gt;sccd_runtime_statechart_state -->
+<g id="edge88" class="edge">
+<title>sccd_runtime_statechart_syntax&#45;&gt;sccd_runtime_statechart_state</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M401.096,-659.254C414.1176,-641.5106 429.0764,-617.2859 435.3406,-592.8879"/>
+<path fill="none" stroke="#000000" d="M435.3406,-592.8879C440.6889,-572.0574 430.9405,-550.658 418.7654,-533.5509"/>
+<polygon fill="#04b3b3" stroke="#000000" points="421.4921,-531.3544 412.6491,-525.5189 415.9229,-535.5953 421.4921,-531.3544"/>
+</g>
+<!-- sccd_runtime_round -->
+<g id="node9" class="node">
+<title>sccd_runtime_round</title><style>.edge>path:hover{stroke-width:8}</style>
+<ellipse fill="#339999" stroke="#000000" cx="231.3406" cy="-498.9052" rx="36.5405" ry="28.9828"/>
+<text text-anchor="middle" x="231.3406" y="-507.4052" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#ffffff">sccd.</text>
+<text text-anchor="middle" x="231.3406" y="-496.4052" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#ffffff">runtime.</text>
+<text text-anchor="middle" x="231.3406" y="-485.4052" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#ffffff">round</text>
+</g>
+<!-- sccd_runtime_statechart_syntax&#45;&gt;sccd_runtime_round -->
+<g id="edge86" class="edge">
+<title>sccd_runtime_statechart_syntax&#45;&gt;sccd_runtime_round</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M337.5299,-663.823C320.6815,-652.7932 301.9532,-638.3827 288.3406,-621.8793 267.5618,-596.688 252.5612,-562.6724 243.18,-536.8017"/>
+<polygon fill="#04b3b3" stroke="#000000" points="246.4682,-535.6017 239.8594,-527.3207 239.8617,-537.9156 246.4682,-535.6017"/>
+</g>
+<!-- sccd_runtime_statechart_syntax&#45;&gt;sccd_runtime_statechart_instance -->
+<g id="edge87" class="edge">
+<title>sccd_runtime_statechart_syntax&#45;&gt;sccd_runtime_statechart_instance</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M435.3406,-592.8879C446.6736,-548.7478 495.3311,-540.3316 476.3406,-498.9052"/>
+<path fill="none" stroke="#000000" d="M476.3406,-498.9052C469.9208,-484.9009 469.2499,-479.6863 457.3406,-469.9138 431.3731,-448.6054 397.5047,-433.533 367.5349,-423.3052"/>
+<polygon fill="#04b3b3" stroke="#000000" points="368.5493,-419.9545 357.9563,-420.153 366.3611,-426.6037 368.5493,-419.9545"/>
+</g>
+<!-- sccd_runtime_statechart_syntax&#45;&gt;sccd_runtime_xml_loader2 -->
+<g id="edge90" class="edge">
+<title>sccd_runtime_statechart_syntax&#45;&gt;sccd_runtime_xml_loader2</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M411.572,-661.544C424.5715,-650.4245 438.8476,-636.5631 449.3406,-621.8793 507.7929,-540.082 573.2518,-325.3741 594.3406,-216.9569"/>
+<path fill="none" stroke="#000000" d="M594.3406,-216.9569C597.3364,-165.59 596.6419,-106.1926 595.6664,-68.1436"/>
+<polygon fill="#04b3b3" stroke="#000000" points="599.1612,-67.902 595.3867,-58.0023 592.1638,-68.095 599.1612,-67.902"/>
+</g>
+<!-- sccd_runtime_model -->
+<g id="node29" class="node">
+<title>sccd_runtime_model</title><style>.edge>path:hover{stroke-width:8}</style>
+<ellipse fill="#05dbdb" stroke="#000000" cx="652.3406" cy="-592.8879" rx="36.5405" ry="28.9828"/>
+<text text-anchor="middle" x="652.3406" y="-601.3879" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">sccd.</text>
+<text text-anchor="middle" x="652.3406" y="-590.3879" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">runtime.</text>
+<text text-anchor="middle" x="652.3406" y="-579.3879" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">model</text>
+</g>
+<!-- sccd_runtime_statechart_syntax&#45;&gt;sccd_runtime_model -->
+<g id="edge85" class="edge">
+<title>sccd_runtime_statechart_syntax&#45;&gt;sccd_runtime_model</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M438.3341,-673.4287C483.9871,-662.2411 547.8607,-644.5057 601.3406,-621.8793 605.5703,-620.0898 609.8923,-618.0312 614.1429,-615.8538"/>
+<polygon fill="#04b3b3" stroke="#000000" points="616.114,-618.7682 623.2705,-610.9557 612.8041,-612.6002 616.114,-618.7682"/>
+</g>
+<!-- sccd_runtime_statechart_syntax&#45;&gt;sccd_runtime_xml_loader -->
+<g id="edge89" class="edge">
+<title>sccd_runtime_statechart_syntax&#45;&gt;sccd_runtime_xml_loader</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M435.052,-671.1029C464.5143,-660.7575 499.6296,-644.8254 525.3406,-621.8793 583.7373,-569.7626 567.8568,-532.8866 614.3406,-469.9138 636.31,-440.1512 672.2924,-441.4333 666.3406,-404.9224"/>
+<path fill="none" stroke="#000000" d="M666.3406,-404.9224C651.6799,-321.302 589.818,-290.4358 632.3406,-216.9569"/>
+</g>
+<!-- sccd_runtime_round&#45;&gt;sccd_runtime_statechart_instance -->
+<g id="edge79" class="edge">
+<title>sccd_runtime_round&#45;&gt;sccd_runtime_statechart_instance</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M249.1021,-473.224C255.9239,-463.3605 263.8447,-451.9079 271.2283,-441.2319"/>
+<polygon fill="#339999" stroke="#000000" points="274.1938,-443.0973 277.0035,-432.8818 268.4365,-439.1155 274.1938,-443.0973"/>
+</g>
+<!-- sccd_compiler_super_class_linker&#45;&gt;sccd_compiler_sccdc -->
+<g id="edge34" class="edge">
+<title>sccd_compiler_super_class_linker&#45;&gt;sccd_compiler_sccdc</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M1779.9487,-765.8462C1807.1383,-748.1436 1836.4388,-720.9 1833.3406,-686.8707"/>
+<path fill="none" stroke="#000000" d="M1833.3406,-686.8707C1828.6659,-635.526 1799.0155,-631.928 1765.3406,-592.8879"/>
+</g>
+<!-- sccd_compiler_generic_generator -->
+<g id="node11" class="node">
+<title>sccd_compiler_generic_generator</title><style>.edge>path:hover{stroke-width:8}</style>
+<ellipse fill="#309191" stroke="#000000" cx="979.3406" cy="-592.8879" rx="66.4361" ry="28.9828"/>
+<text text-anchor="middle" x="979.3406" y="-601.3879" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#ffffff">sccd.</text>
+<text text-anchor="middle" x="979.3406" y="-590.3879" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#ffffff">compiler.</text>
+<text text-anchor="middle" x="979.3406" y="-579.3879" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#ffffff">generic_generator</text>
+</g>
+<!-- sccd_compiler_generic_generator&#45;&gt;sccd_compiler_sccdc -->
+<g id="edge18" class="edge">
+<title>sccd_compiler_generic_generator&#45;&gt;sccd_compiler_sccdc</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M1021.2575,-570.3767C1049.1477,-555.3984 1085.6105,-535.8163 1113.3154,-520.9375"/>
+<polygon fill="#309191" stroke="#000000" points="1115.1963,-523.9002 1122.3503,-516.0854 1111.8844,-517.7333 1115.1963,-523.9002"/>
+</g>
+<!-- sccd_runtime_statechart_instance&#45;&gt;sccd_runtime_object_manager -->
+<g id="edge83" class="edge">
+<title>sccd_runtime_statechart_instance&#45;&gt;sccd_runtime_object_manager</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M247.3269,-383.5963C213.8773,-369.0422 169.5381,-349.7499 134.9556,-334.7029"/>
+<polygon fill="#267373" stroke="#000000" points="136.0435,-331.3594 125.4774,-330.5789 133.2506,-337.7781 136.0435,-331.3594"/>
+</g>
+<!-- sccd_compiler_python_writer -->
+<g id="node14" class="node">
+<title>sccd_compiler_python_writer</title><style>.edge>path:hover{stroke-width:8}</style>
+<ellipse fill="#3ab0b0" stroke="#000000" cx="1154.3406" cy="-592.8879" rx="53.066" ry="28.9828"/>
+<text text-anchor="middle" x="1154.3406" y="-601.3879" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">sccd.</text>
+<text text-anchor="middle" x="1154.3406" y="-590.3879" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">compiler.</text>
+<text text-anchor="middle" x="1154.3406" y="-579.3879" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">python_writer</text>
+</g>
+<!-- sccd_compiler_python_writer&#45;&gt;sccd_compiler_sccdc -->
+<g id="edge28" class="edge">
+<title>sccd_compiler_python_writer&#45;&gt;sccd_compiler_sccdc</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M1154.3406,-563.6664C1154.3406,-555.6216 1154.3406,-546.7619 1154.3406,-538.2467"/>
+<polygon fill="#3ab0b0" stroke="#000000" points="1157.8407,-538.1086 1154.3406,-528.1086 1150.8407,-538.1087 1157.8407,-538.1086"/>
+</g>
+<!-- sccd_compiler_sccd_constructs&#45;&gt;sccd_compiler_generic_generator -->
+<g id="edge29" class="edge">
+<title>sccd_compiler_sccd_constructs&#45;&gt;sccd_compiler_generic_generator</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M1325.2684,-674.6218C1266.6979,-661.9244 1172.986,-641.2564 1092.3406,-621.8793 1077.3978,-618.2889 1061.3856,-614.2799 1046.2508,-610.4159"/>
+<polygon fill="#1b9c9c" stroke="#000000" points="1047.0078,-606.9968 1036.4518,-607.9035 1045.2692,-613.7775 1047.0078,-606.9968"/>
+</g>
+<!-- sccd_compiler_sccd_constructs&#45;&gt;sccd_compiler_sccdc -->
+<g id="edge30" class="edge">
+<title>sccd_compiler_sccd_constructs&#45;&gt;sccd_compiler_sccdc</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M1371.3841,-658.2732C1364.057,-639.5362 1354.0188,-614.587 1344.3406,-592.8879"/>
+</g>
+<!-- sccd_compiler_sccd_constructs&#45;&gt;sccd_compiler_state_linker -->
+<g id="edge31" class="edge">
+<title>sccd_compiler_sccd_constructs&#45;&gt;sccd_compiler_state_linker</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M1393.6429,-658.1621C1397.0814,-649.428 1400.9129,-639.6956 1404.5457,-630.4681"/>
+<polygon fill="#1b9c9c" stroke="#000000" points="1407.8281,-631.6848 1408.2347,-621.0978 1401.3147,-629.1205 1407.8281,-631.6848"/>
+</g>
+<!-- sccd_runtime_libs_drawing -->
+<g id="node16" class="node">
+<title>sccd_runtime_libs_drawing</title><style>.edge>path:hover{stroke-width:8}</style>
+<ellipse fill="#38a8a8" stroke="#000000" cx="1914.3406" cy="-898.1707" rx="36.5405" ry="36.5405"/>
+<text text-anchor="middle" x="1914.3406" y="-912.1707" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">sccd.</text>
+<text text-anchor="middle" x="1914.3406" y="-901.1707" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">runtime.</text>
+<text text-anchor="middle" x="1914.3406" y="-890.1707" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">libs.</text>
+<text text-anchor="middle" x="1914.3406" y="-879.1707" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">drawing</text>
+</g>
+<!-- sccd_runtime_libs_ui -->
+<g id="node34" class="node">
+<title>sccd_runtime_libs_ui</title><style>.edge>path:hover{stroke-width:8}</style>
+<ellipse fill="#409696" stroke="#000000" cx="1930.3406" cy="-788.6316" rx="36.5405" ry="36.5405"/>
+<text text-anchor="middle" x="1930.3406" y="-802.6316" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#ffffff">sccd.</text>
+<text text-anchor="middle" x="1930.3406" y="-791.6316" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#ffffff">runtime.</text>
+<text text-anchor="middle" x="1930.3406" y="-780.6316" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#ffffff">libs.</text>
+<text text-anchor="middle" x="1930.3406" y="-769.6316" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#ffffff">ui</text>
+</g>
+<!-- sccd_runtime_libs_drawing&#45;&gt;sccd_runtime_libs_ui -->
+<g id="edge69" class="edge">
+<title>sccd_runtime_libs_drawing&#45;&gt;sccd_runtime_libs_ui</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M1919.6684,-861.6958C1920.8967,-853.2861 1922.2201,-844.2263 1923.5027,-835.4452"/>
+<polygon fill="#38a8a8" stroke="#000000" points="1926.9994,-835.7216 1924.9815,-825.3207 1920.0729,-834.7098 1926.9994,-835.7216"/>
+</g>
+<!-- sccd_runtime_expression -->
+<g id="node17" class="node">
+<title>sccd_runtime_expression</title><style>.edge>path:hover{stroke-width:8}</style>
+<ellipse fill="#47c2c2" stroke="#000000" cx="378.3406" cy="-788.6316" rx="45.011" ry="28.9828"/>
+<text text-anchor="middle" x="378.3406" y="-797.1316" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">sccd.</text>
+<text text-anchor="middle" x="378.3406" y="-786.1316" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">runtime.</text>
+<text text-anchor="middle" x="378.3406" y="-775.1316" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">expression</text>
+</g>
+<!-- sccd_runtime_expression&#45;&gt;sccd_runtime_statechart_syntax -->
+<g id="edge68" class="edge">
+<title>sccd_runtime_expression&#45;&gt;sccd_runtime_statechart_syntax</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M378.3406,-759.471C378.3406,-749.1454 378.3406,-737.3506 378.3406,-726.3131"/>
+<polygon fill="#47c2c2" stroke="#000000" points="381.8407,-726.0355 378.3406,-716.0355 374.8407,-726.0356 381.8407,-726.0355"/>
+</g>
+<!-- sccd_runtime_libs_utils -->
+<g id="node18" class="node">
+<title>sccd_runtime_libs_utils</title><style>.edge>path:hover{stroke-width:8}</style>
+<ellipse fill="#3bcece" stroke="#000000" cx="1946.3406" cy="-1007.7098" rx="36.5405" ry="36.5405"/>
+<text text-anchor="middle" x="1946.3406" y="-1021.7098" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">sccd.</text>
+<text text-anchor="middle" x="1946.3406" y="-1010.7098" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">runtime.</text>
+<text text-anchor="middle" x="1946.3406" y="-999.7098" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">libs.</text>
+<text text-anchor="middle" x="1946.3406" y="-988.7098" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">utils</text>
+</g>
+<!-- sccd_runtime_libs_utils&#45;&gt;sccd_runtime_libs_drawing -->
+<g id="edge70" class="edge">
+<title>sccd_runtime_libs_utils&#45;&gt;sccd_runtime_libs_drawing</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M1935.9511,-972.1456C1933.2693,-962.9654 1930.3467,-952.961 1927.5424,-943.3617"/>
+<polygon fill="#3bcece" stroke="#000000" points="1930.8417,-942.1738 1924.678,-933.5565 1924.1226,-944.1367 1930.8417,-942.1738"/>
+</g>
+<!-- sccd_runtime_libs_utils&#45;&gt;sccd_runtime_libs_ui -->
+<g id="edge71" class="edge">
+<title>sccd_runtime_libs_utils&#45;&gt;sccd_runtime_libs_ui</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M1955.5045,-971.9432C1961.7724,-942.1416 1967.7268,-898.6969 1960.3406,-861.4012 1958.3296,-851.2471 1954.8821,-840.7307 1951.0242,-830.9556"/>
+<polygon fill="#3bcece" stroke="#000000" points="1954.1471,-829.3506 1947.0675,-821.4684 1947.6864,-832.0451 1954.1471,-829.3506"/>
+</g>
+<!-- sccd_compiler_stateful_writer -->
+<g id="node19" class="node">
+<title>sccd_compiler_stateful_writer</title><style>.edge>path:hover{stroke-width:8}</style>
+<ellipse fill="#3ab0b0" stroke="#000000" cx="990.3406" cy="-686.8707" rx="55.3091" ry="28.9828"/>
+<text text-anchor="middle" x="990.3406" y="-695.3707" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">sccd.</text>
+<text text-anchor="middle" x="990.3406" y="-684.3707" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">compiler.</text>
+<text text-anchor="middle" x="990.3406" y="-673.3707" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">stateful_writer</text>
+</g>
+<!-- sccd_compiler_stateful_writer&#45;&gt;sccd_compiler_generic_generator -->
+<g id="edge33" class="edge">
+<title>sccd_compiler_stateful_writer&#45;&gt;sccd_compiler_generic_generator</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M986.9505,-657.9059C985.9886,-649.6876 984.9252,-640.6024 983.906,-631.894"/>
+<polygon fill="#3ab0b0" stroke="#000000" points="987.3773,-631.4442 982.7385,-621.9189 980.4248,-632.258 987.3773,-631.4442"/>
+</g>
+<!-- sccd_compiler_utils&#45;&gt;sccd_runtime_statechart_syntax -->
+<g id="edge40" class="edge">
+<title>sccd_compiler_utils&#45;&gt;sccd_runtime_statechart_syntax</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M1533.3258,-889.5924C1495.1096,-881.2579 1434.4154,-868.8069 1381.3406,-861.4012 1197.1028,-835.6937 1145.7417,-866.6092 964.3406,-825.4012 874.017,-804.8828 858.8271,-775.7685 769.3406,-751.862 673.1955,-726.1768 646.5027,-732.2271 548.3406,-715.862 516.3683,-710.5318 481.0349,-704.525 450.9011,-699.3671"/>
+<polygon fill="#05e5e5" stroke="#000000" points="451.3409,-695.8915 440.8935,-697.6526 450.1589,-702.791 451.3409,-695.8915"/>
+</g>
+<!-- sccd_compiler_utils&#45;&gt;sccd_compiler_super_class_linker -->
+<g id="edge39" class="edge">
+<title>sccd_compiler_utils&#45;&gt;sccd_compiler_super_class_linker</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M1600.8393,-878.5873C1625.7887,-862.024 1661.9532,-838.0154 1690.6463,-818.9668"/>
+<polygon fill="#05e5e5" stroke="#000000" points="1692.8951,-821.675 1699.2905,-813.2282 1689.0234,-815.8432 1692.8951,-821.675"/>
+</g>
+<!-- sccd_compiler_utils&#45;&gt;sccd_compiler_generic_generator -->
+<g id="edge35" class="edge">
+<title>sccd_compiler_utils&#45;&gt;sccd_compiler_generic_generator</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M1503.3406,-788.6316C1471.9034,-735.1246 1503.5304,-695.7165 1454.3406,-657.8793 1390.2632,-608.5904 1171.9453,-635.965 1092.3406,-621.8793 1076.8804,-619.1437 1060.4218,-615.4065 1044.987,-611.5251"/>
+<polygon fill="#05e5e5" stroke="#000000" points="1045.5692,-608.0611 1035.0128,-608.9627 1043.8274,-614.8409 1045.5692,-608.0611"/>
+</g>
+<!-- sccd_compiler_utils&#45;&gt;sccd_compiler_sccd_constructs -->
+<g id="edge37" class="edge">
+<title>sccd_compiler_utils&#45;&gt;sccd_compiler_sccd_constructs</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M1552.9033,-872.3703C1543.3831,-858.6645 1531.8107,-841.3883 1522.3406,-825.4012 1512.9656,-809.5746 1512.6589,-804.4916 1503.3406,-788.6316"/>
+<path fill="none" stroke="#000000" d="M1503.3406,-788.6316C1494.0223,-772.7716 1496.747,-765.4434 1484.3406,-751.862 1470.4117,-736.6141 1452.1296,-723.4893 1434.8952,-713.1069"/>
+<polygon fill="#05e5e5" stroke="#000000" points="1436.4098,-709.9387 1426.0069,-707.9309 1432.8871,-715.9878 1436.4098,-709.9387"/>
+</g>
+<!-- sccd_compiler_lexer -->
+<g id="node31" class="node">
+<title>sccd_compiler_lexer</title><style>.edge>path:hover{stroke-width:8}</style>
+<ellipse fill="#2fbcbc" stroke="#000000" cx="1571.3406" cy="-788.6316" rx="39.6962" ry="28.9828"/>
+<text text-anchor="middle" x="1571.3406" y="-797.1316" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">sccd.</text>
+<text text-anchor="middle" x="1571.3406" y="-786.1316" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">compiler.</text>
+<text text-anchor="middle" x="1571.3406" y="-775.1316" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">lexer</text>
+</g>
+<!-- sccd_compiler_utils&#45;&gt;sccd_compiler_lexer -->
+<g id="edge36" class="edge">
+<title>sccd_compiler_utils&#45;&gt;sccd_compiler_lexer</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M1571.3406,-869.1038C1571.3406,-856.477 1571.3406,-841.493 1571.3406,-827.8978"/>
+<polygon fill="#05e5e5" stroke="#000000" points="1574.8407,-827.8343 1571.3406,-817.8343 1567.8407,-827.8343 1574.8407,-827.8343"/>
+</g>
+<!-- sccd_compiler_utils&#45;&gt;sccd_compiler_sccdc -->
+<g id="edge38" class="edge">
+<title>sccd_compiler_utils&#45;&gt;sccd_compiler_sccdc</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M1589.7779,-872.3703C1599.2981,-858.6645 1610.8705,-841.3883 1620.3406,-825.4012 1639.0906,-793.7481 1639.5938,-783.517 1658.3406,-751.862 1701.7397,-678.5804 1820.9691,-657.3794 1765.3406,-592.8879"/>
+<path fill="none" stroke="#000000" d="M1765.3406,-592.8879C1725.7724,-553.1315 1343.3757,-515.633 1204.4555,-503.2168"/>
+<polygon fill="#05e5e5" stroke="#000000" points="1204.3745,-499.6959 1194.1042,-502.2979 1203.7555,-506.6685 1204.3745,-499.6959"/>
+</g>
+<!-- sccd_runtime_object_manager&#45;&gt;sccd_runtime_controller -->
+<g id="edge78" class="edge">
+<title>sccd_runtime_object_manager&#45;&gt;sccd_runtime_controller</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M127.941,-292.5091C137.035,-288.9967 146.4801,-285.3545 155.3406,-281.9483 197.7528,-265.6439 246.1593,-247.1492 280.4425,-234.0697"/>
+<polygon fill="#35a1a1" stroke="#000000" points="282.0668,-237.1961 290.1628,-230.3619 279.572,-230.6558 282.0668,-237.1961"/>
+</g>
+<!-- lark -->
+<g id="node22" class="node">
+<title>lark</title><style>.edge>path:hover{stroke-width:8}</style>
+<ellipse fill="#c24747" stroke="#000000" cx="611.3406" cy="-404.9224" rx="27" ry="18"/>
+<text text-anchor="middle" x="611.3406" y="-402.4224" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#ffffff">lark</text>
+</g>
+<!-- lark&#45;&gt;sccd_runtime_xml_loader2 -->
+<g id="edge2" class="edge">
+<title>lark&#45;&gt;sccd_runtime_xml_loader2</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M606.0362,-387.0782C600.9458,-368.3006 594.0649,-337.7998 594.3406,-310.9396"/>
+<path fill="none" stroke="#000000" d="M594.3406,-310.9396C594.7693,-269.1717 586.3651,-257.9585 594.3406,-216.9569"/>
+</g>
+<!-- lark&#45;&gt;sccd_runtime_xml_loader -->
+<g id="edge1" class="edge">
+<title>lark&#45;&gt;sccd_runtime_xml_loader</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M594.3406,-310.9396C594.803,-265.8868 603.6558,-251.7011 632.3406,-216.9569"/>
+</g>
+<!-- sccd_compiler -->
+<g id="node23" class="node">
+<title>sccd_compiler</title><style>.edge>path:hover{stroke-width:8}</style>
+<ellipse fill="#10f9f9" stroke="#000000" cx="305.3406" cy="-898.1707" rx="45.1548" ry="18"/>
+<text text-anchor="middle" x="305.3406" y="-895.6707" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">sccd.compiler</text>
+</g>
+<!-- sccd_compiler&#45;&gt;sccd_runtime_statechart_syntax -->
+<g id="edge11" class="edge">
+<title>sccd_compiler&#45;&gt;sccd_runtime_statechart_syntax</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M300.5373,-879.9395C295.5815,-857.1983 290.4696,-817.7653 305.3406,-788.6316"/>
+</g>
+<!-- lxml_etree -->
+<g id="node24" class="node">
+<title>lxml_etree</title><style>.edge>path:hover{stroke-width:8}</style>
+<ellipse fill="#85db2f" stroke="#000000" cx="1329.3406" cy="-1007.7098" rx="34.9638" ry="18"/>
+<text text-anchor="middle" x="1329.3406" y="-1005.2098" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">lxml.etree</text>
+</g>
+<!-- lxml_etree&#45;&gt;sccd_runtime_xml_loader2 -->
+<g id="edge10" class="edge">
+<title>lxml_etree&#45;&gt;sccd_runtime_xml_loader2</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M1302.3037,-996.0891C1276.5407,-983.9177 1237.9829,-962.7058 1212.3406,-934.9403 1199.8604,-921.4267 1207.9964,-909.2873 1193.3406,-898.1707"/>
+<path fill="none" stroke="#000000" d="M1193.3406,-898.1707C1089.8692,-819.6868 996.1713,-922.8648 910.3406,-825.4012 813.6847,-715.6451 853.6664,-644.3118 869.3406,-498.9052"/>
+</g>
+<!-- lxml_etree&#45;&gt;sccd_compiler_sccd_constructs -->
+<g id="edge7" class="edge">
+<title>lxml_etree&#45;&gt;sccd_compiler_sccd_constructs</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M1323.7744,-989.723C1317.7557,-966.5277 1311.2569,-925.8822 1329.3406,-898.1707"/>
+</g>
+<!-- lxml_etree&#45;&gt;sccd_compiler_sccdc -->
+<g id="edge8" class="edge">
+<title>lxml_etree&#45;&gt;sccd_compiler_sccdc</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M1193.3406,-898.1707C1147.5381,-863.8108 1256.4641,-706.7246 1286.3406,-657.8793 1306.5415,-624.8526 1359.5037,-628.5098 1344.3406,-592.8879"/>
+</g>
+<!-- lxml_etree&#45;&gt;sccd_runtime_xml_loader -->
+<g id="edge9" class="edge">
+<title>lxml_etree&#45;&gt;sccd_runtime_xml_loader</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M1295.1627,-1003.848C1209.6836,-992.4529 984.263,-951.4519 855.3406,-825.4012 733.214,-705.9948 789.2867,-620.8489 709.3406,-469.9138 693.1291,-439.3071 672.4816,-439.0086 666.3406,-404.9224"/>
+</g>
+<!-- sccd_runtime_event&#45;&gt;sccd_runtime_controller -->
+<g id="edge57" class="edge">
+<title>sccd_runtime_event&#45;&gt;sccd_runtime_controller</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M158.3406,-404.9224C163.4843,-363.1829 150.5228,-348.5499 169.3406,-310.9396"/>
+<path fill="none" stroke="#000000" d="M169.3406,-310.9396C190.5748,-268.4998 240.5318,-243.519 278.2335,-230.1132"/>
+<polygon fill="#05dbdb" stroke="#000000" points="279.6734,-233.3206 288.0179,-226.7923 277.4236,-226.692 279.6734,-233.3206"/>
+</g>
+<!-- sccd_runtime_event&#45;&gt;sccd_runtime_statechart_state -->
+<g id="edge61" class="edge">
+<title>sccd_runtime_event&#45;&gt;sccd_runtime_statechart_state</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M186.6888,-577.7075C196.4448,-573.1244 207.2813,-568.1764 217.3406,-563.8965 222.8713,-561.5434 282.1283,-538.7994 328.9333,-520.872"/>
+<polygon fill="#05dbdb" stroke="#000000" points="330.3211,-524.0885 338.4081,-517.2436 327.8177,-517.5514 330.3211,-524.0885"/>
+</g>
+<!-- sccd_runtime_event&#45;&gt;sccd_runtime_round -->
+<g id="edge59" class="edge">
+<title>sccd_runtime_event&#45;&gt;sccd_runtime_round</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M175.3087,-568.1951C184.385,-556.9712 195.2479,-543.5379 204.9826,-531.4999"/>
+<polygon fill="#05dbdb" stroke="#000000" points="207.9394,-533.4096 211.5059,-523.4331 202.4964,-529.0081 207.9394,-533.4096"/>
+</g>
+<!-- sccd_runtime_event&#45;&gt;sccd_runtime_statechart_instance -->
+<g id="edge60" class="edge">
+<title>sccd_runtime_event&#45;&gt;sccd_runtime_statechart_instance</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M128.3406,-498.9052C139.6312,-457.4356 181.9738,-433.9134 221.3213,-420.772"/>
+<polygon fill="#05dbdb" stroke="#000000" points="222.7519,-423.991 231.2396,-417.65 220.6501,-417.314 222.7519,-423.991"/>
+</g>
+<!-- sccd_runtime_event&#45;&gt;sccd_runtime_object_manager -->
+<g id="edge58" class="edge">
+<title>sccd_runtime_event&#45;&gt;sccd_runtime_object_manager</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M139.6921,-566.2066C130.6343,-547.4245 122.1416,-521.6736 128.3406,-498.9052"/>
+<path fill="none" stroke="#000000" d="M128.3406,-498.9052C139.8591,-456.5986 152.9778,-448.4398 158.3406,-404.9224"/>
+<path fill="none" stroke="#000000" d="M158.3406,-404.9224C161.4633,-379.5825 144.3924,-357.288 125.4333,-340.7801"/>
+<polygon fill="#05dbdb" stroke="#000000" points="127.486,-337.9368 117.5373,-334.2936 123.0426,-343.3458 127.486,-337.9368"/>
+</g>
+<!-- sccd_runtime_event&#45;&gt;sccd_runtime_xml_loader -->
+<g id="edge62" class="edge">
+<title>sccd_runtime_event&#45;&gt;sccd_runtime_xml_loader</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M158.3406,-404.9224C161.8168,-376.7139 189.107,-386.8672 215.3406,-375.931 385.1486,-305.1421 456.4359,-349.7306 608.3406,-245.9483 622.1522,-236.5121 621.691,-229.8561 632.3406,-216.9569"/>
+<path fill="none" stroke="#000000" d="M632.3406,-216.9569C642.3281,-199.6986 650.3841,-179.0729 656.238,-161.5466"/>
+<polygon fill="#05dbdb" stroke="#000000" points="659.6961,-162.2258 659.4282,-151.6344 653.0327,-160.0812 659.6961,-162.2258"/>
+</g>
+<!-- sccd_schema -->
+<g id="node26" class="node">
+<title>sccd_schema</title><style>.edge>path:hover{stroke-width:8}</style>
+<ellipse fill="#3bcece" stroke="#000000" cx="797.3406" cy="-310.9396" rx="44.3" ry="18"/>
+<text text-anchor="middle" x="797.3406" y="-308.4396" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">sccd.schema</text>
+</g>
+<!-- sccd_schema&#45;&gt;sccd_runtime_xml_loader2 -->
+<g id="edge93" class="edge">
+<title>sccd_schema&#45;&gt;sccd_runtime_xml_loader2</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M831.3406,-216.9569C823.6511,-175.9007 858.1335,-155.0191 831.3406,-122.9741"/>
+<path fill="none" stroke="#000000" d="M831.3406,-122.9741C786.5706,-69.4282 707.0345,-46.1889 652.5472,-36.2366"/>
+<polygon fill="#3bcece" stroke="#000000" points="653.1292,-32.7853 642.6788,-34.5286 651.9353,-39.6828 653.1292,-32.7853"/>
+</g>
+<!-- sccd_schema&#45;&gt;sccd_runtime_xml_loader -->
+<g id="edge92" class="edge">
+<title>sccd_schema&#45;&gt;sccd_runtime_xml_loader</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M809.8195,-293.4063C821.5254,-274.8823 836.5152,-244.5857 831.3406,-216.9569"/>
+<path fill="none" stroke="#000000" d="M831.3406,-216.9569C822.1017,-167.6278 765.3726,-143.696 721.1914,-132.4216"/>
+<polygon fill="#3bcece" stroke="#000000" points="721.949,-129.0041 711.4084,-130.0752 720.3164,-135.8111 721.949,-129.0041"/>
+</g>
+<!-- sccd_runtime_bitmap -->
+<g id="node27" class="node">
+<title>sccd_runtime_bitmap</title><style>.edge>path:hover{stroke-width:8}</style>
+<ellipse fill="#2fdbdb" stroke="#000000" cx="240.3406" cy="-788.6316" rx="36.5405" ry="28.9828"/>
+<text text-anchor="middle" x="240.3406" y="-797.1316" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">sccd.</text>
+<text text-anchor="middle" x="240.3406" y="-786.1316" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">runtime.</text>
+<text text-anchor="middle" x="240.3406" y="-775.1316" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">bitmap</text>
+</g>
+<!-- sccd_runtime_bitmap&#45;&gt;sccd_runtime_statechart_syntax -->
+<g id="edge50" class="edge">
+<title>sccd_runtime_bitmap&#45;&gt;sccd_runtime_statechart_syntax</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M267.276,-768.7695C286.8204,-754.3575 313.6458,-734.5765 336.0369,-718.0653"/>
+<polygon fill="#2fdbdb" stroke="#000000" points="338.4057,-720.6673 344.3769,-711.9154 334.2513,-715.0334 338.4057,-720.6673"/>
+</g>
+<!-- sccd_runtime_bitmap&#45;&gt;sccd_runtime_round -->
+<g id="edge48" class="edge">
+<title>sccd_runtime_bitmap&#45;&gt;sccd_runtime_round</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M231.3406,-592.8879C228.3404,-575.032 227.9412,-554.9971 228.4518,-538.0272"/>
+<polygon fill="#2fdbdb" stroke="#000000" points="231.9542,-538.0407 228.8722,-527.9041 224.9602,-537.7502 231.9542,-538.0407"/>
+</g>
+<!-- sccd_runtime_bitmap&#45;&gt;sccd_runtime_statechart_instance -->
+<g id="edge49" class="edge">
+<title>sccd_runtime_bitmap&#45;&gt;sccd_runtime_statechart_instance</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M241.1757,-759.5465C241.7854,-721.1124 241.1771,-651.4308 231.3406,-592.8879"/>
+<path fill="none" stroke="#000000" d="M231.3406,-592.8879C223.8182,-558.3085 196.0675,-561.6198 185.3406,-527.8965 177.5291,-503.3389 172.5236,-492.2705 185.3406,-469.9138 195.792,-451.6833 213.558,-438.0738 231.8489,-428.1513"/>
+<polygon fill="#2fdbdb" stroke="#000000" points="233.5177,-431.2292 240.8405,-423.5723 230.3412,-424.9914 233.5177,-431.2292"/>
+</g>
+<!-- sccd_compiler_visitor -->
+<g id="node28" class="node">
+<title>sccd_compiler_visitor</title><style>.edge>path:hover{stroke-width:8}</style>
+<ellipse fill="#10f9f9" stroke="#000000" cx="1261.3406" cy="-898.1707" rx="39.6962" ry="28.9828"/>
+<text text-anchor="middle" x="1261.3406" y="-906.6707" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">sccd.</text>
+<text text-anchor="middle" x="1261.3406" y="-895.6707" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">compiler.</text>
+<text text-anchor="middle" x="1261.3406" y="-884.6707" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">visitor</text>
+</g>
+<!-- sccd_compiler_visitor&#45;&gt;sccd_compiler_javascript_writer -->
+<g id="edge43" class="edge">
+<title>sccd_compiler_visitor&#45;&gt;sccd_compiler_javascript_writer</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M1272.3479,-869.877C1280.0276,-848.0677 1289.2597,-816.9485 1291.3406,-788.6316"/>
+<path fill="none" stroke="#000000" d="M1291.3406,-788.6316C1294.1577,-750.2959 1258.1877,-724.0454 1223.6721,-707.8203"/>
+<polygon fill="#10f9f9" stroke="#000000" points="1225.04,-704.598 1214.4825,-703.7093 1222.1815,-710.9878 1225.04,-704.598"/>
+</g>
+<!-- sccd_compiler_visitor&#45;&gt;sccd_compiler_super_class_linker -->
+<g id="edge47" class="edge">
+<title>sccd_compiler_visitor&#45;&gt;sccd_compiler_super_class_linker</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M1294.7459,-882.5088C1311.9159,-875.0574 1333.3784,-866.6501 1353.3406,-861.4012 1469.1447,-830.9514 1503.499,-851.5895 1620.3406,-825.4012 1637.8319,-821.4807 1656.4713,-816.1199 1673.5763,-810.7042"/>
+<polygon fill="#10f9f9" stroke="#000000" points="1675.0071,-813.9203 1683.4499,-807.5196 1672.8583,-807.2583 1675.0071,-813.9203"/>
+</g>
+<!-- sccd_compiler_visitor&#45;&gt;sccd_compiler_generic_generator -->
+<g id="edge41" class="edge">
+<title>sccd_compiler_visitor&#45;&gt;sccd_compiler_generic_generator</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M1234.6639,-876.525C1226.3454,-870.763 1216.8486,-865.1157 1207.3406,-861.4012 1105.6469,-821.6721 1048.4066,-895.064 964.3406,-825.4012 905.5556,-776.6879 900.7322,-729.8019 926.3406,-657.8793 930.2689,-646.8465 936.9611,-636.3305 944.2925,-627.0958"/>
+<polygon fill="#10f9f9" stroke="#000000" points="947.0719,-629.2292 950.8464,-619.3295 941.7222,-624.7146 947.0719,-629.2292"/>
+</g>
+<!-- sccd_compiler_visitor&#45;&gt;sccd_compiler_sccd_constructs -->
+<g id="edge45" class="edge">
+<title>sccd_compiler_visitor&#45;&gt;sccd_compiler_sccd_constructs</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M1291.3406,-788.6316C1293.5064,-759.1595 1315.1502,-734.2563 1336.7843,-716.4629"/>
+<polygon fill="#10f9f9" stroke="#000000" points="1339.0141,-719.1621 1344.7182,-710.2338 1334.6913,-713.6562 1339.0141,-719.1621"/>
+</g>
+<!-- sccd_compiler_generic_language_constructs -->
+<g id="node36" class="node">
+<title>sccd_compiler_generic_language_constructs</title><style>.edge>path:hover{stroke-width:8}</style>
+<ellipse fill="#0bdfdf" stroke="#000000" cx="1074.3406" cy="-788.6316" rx="101.2327" ry="28.9828"/>
+<text text-anchor="middle" x="1074.3406" y="-797.1316" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">sccd.</text>
+<text text-anchor="middle" x="1074.3406" y="-786.1316" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">compiler.</text>
+<text text-anchor="middle" x="1074.3406" y="-775.1316" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">generic_language_constructs</text>
+</g>
+<!-- sccd_compiler_visitor&#45;&gt;sccd_compiler_generic_language_constructs -->
+<g id="edge42" class="edge">
+<title>sccd_compiler_visitor&#45;&gt;sccd_compiler_generic_language_constructs</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M1232.8153,-877.9894C1224.6894,-872.4489 1215.7569,-866.5523 1207.3406,-861.4012 1183.2538,-846.6591 1155.995,-831.4919 1132.454,-818.8453"/>
+<polygon fill="#10f9f9" stroke="#000000" points="1134.0972,-815.7551 1123.6281,-814.128 1130.7975,-821.9286 1134.0972,-815.7551"/>
+</g>
+<!-- sccd_compiler_visitor&#45;&gt;sccd_compiler_path_calculator -->
+<g id="edge44" class="edge">
+<title>sccd_compiler_visitor&#45;&gt;sccd_compiler_path_calculator</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M1290.1317,-877.824C1313.7523,-861.1311 1347.5248,-837.264 1374.191,-818.4189"/>
+<polygon fill="#10f9f9" stroke="#000000" points="1376.4307,-821.1219 1382.5773,-812.4923 1372.3907,-815.4054 1376.4307,-821.1219"/>
+</g>
+<!-- sccd_compiler_visitor&#45;&gt;sccd_compiler_state_linker -->
+<g id="edge46" class="edge">
+<title>sccd_compiler_visitor&#45;&gt;sccd_compiler_state_linker</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M1291.3406,-788.6316C1295.6443,-730.067 1277.7322,-706.716 1310.3406,-657.8793 1318.3845,-645.8322 1346.9237,-629.0138 1372.7807,-615.5041"/>
+<polygon fill="#10f9f9" stroke="#000000" points="1374.4852,-618.5633 1381.7769,-610.8768 1371.2833,-612.3385 1374.4852,-618.5633"/>
+</g>
+<!-- sccd_runtime_model&#45;&gt;sccd_runtime_controller -->
+<g id="edge72" class="edge">
+<title>sccd_runtime_model&#45;&gt;sccd_runtime_controller</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M647.5043,-564.1321C643.7044,-545.1073 637.5037,-519.8947 628.3406,-498.9052"/>
+<path fill="none" stroke="#000000" d="M628.3406,-498.9052C609.1726,-454.9976 578.478,-465.3681 542.3406,-433.9138 471.2641,-372.0482 394.8118,-292.0991 354.344,-248.59"/>
+<polygon fill="#05dbdb" stroke="#000000" points="356.8189,-246.1114 347.4529,-241.1588 351.6861,-250.8712 356.8189,-246.1114"/>
+</g>
+<!-- sccd_runtime_model&#45;&gt;sccd_runtime_statechart_state -->
+<g id="edge74" class="edge">
+<title>sccd_runtime_model&#45;&gt;sccd_runtime_statechart_state</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M618.2368,-581.6206C580.112,-568.9325 516.599,-547.5185 462.3406,-527.8965 456.3272,-525.7219 450.0633,-523.4095 443.8257,-521.0761"/>
+<polygon fill="#05dbdb" stroke="#000000" points="444.6771,-517.6568 434.0852,-517.4089 442.2106,-524.2079 444.6771,-517.6568"/>
+</g>
+<!-- sccd_runtime_model&#45;&gt;sccd_runtime_statechart_instance -->
+<g id="edge73" class="edge">
+<title>sccd_runtime_model&#45;&gt;sccd_runtime_statechart_instance</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M628.8857,-570.0556C608.8618,-550.7555 579.1348,-522.5536 552.3406,-498.9052"/>
+</g>
+<!-- sccd_runtime_model&#45;&gt;sccd_runtime_xml_loader2 -->
+<g id="edge77" class="edge">
+<title>sccd_runtime_model&#45;&gt;sccd_runtime_xml_loader2</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M684.3931,-578.0831C736.3812,-551.9148 836.5764,-491.9117 869.3406,-404.9224"/>
+<path fill="none" stroke="#000000" d="M869.3406,-404.9224C891.7598,-280.4825 912.4462,-219.9783 831.3406,-122.9741"/>
+</g>
+<!-- sccd_runtime_model&#45;&gt;sccd_runtime_test -->
+<g id="edge75" class="edge">
+<title>sccd_runtime_model&#45;&gt;sccd_runtime_test</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M628.3406,-498.9052C614.8327,-464.1669 590.3852,-468.0147 575.3406,-433.9138 535.1328,-342.7768 528.877,-223.5168 528.5976,-162.5772"/>
+<polygon fill="#05dbdb" stroke="#000000" points="532.0978,-162.2527 528.6059,-152.2499 525.0978,-162.2471 532.0978,-162.2527"/>
+</g>
+<!-- sccd_runtime_model&#45;&gt;sccd_runtime_xml_loader -->
+<g id="edge76" class="edge">
+<title>sccd_runtime_model&#45;&gt;sccd_runtime_xml_loader</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M628.3406,-498.9052C612.012,-456.9129 671.8769,-449.6362 666.3406,-404.9224"/>
+</g>
+<!-- sccd_runtime_semantic_options -->
+<g id="node30" class="node">
+<title>sccd_runtime_semantic_options</title><style>.edge>path:hover{stroke-width:8}</style>
+<ellipse fill="#2fdbdb" stroke="#000000" cx="623.3406" cy="-686.8707" rx="65.5227" ry="28.9828"/>
+<text text-anchor="middle" x="623.3406" y="-695.3707" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">sccd.</text>
+<text text-anchor="middle" x="623.3406" y="-684.3707" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">runtime.</text>
+<text text-anchor="middle" x="623.3406" y="-673.3707" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">semantic_options</text>
+</g>
+<!-- sccd_runtime_semantic_options&#45;&gt;sccd_runtime_statechart_instance -->
+<g id="edge81" class="edge">
+<title>sccd_runtime_semantic_options&#45;&gt;sccd_runtime_statechart_instance</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M615.9767,-657.97C603.4072,-610.8351 576.7943,-520.4879 552.3406,-498.9052"/>
+<path fill="none" stroke="#000000" d="M552.3406,-498.9052C497.9797,-459.0374 424.8938,-434.4441 370.7297,-420.4674"/>
+<polygon fill="#2fdbdb" stroke="#000000" points="371.3969,-417.0263 360.8451,-417.98 369.6885,-423.8146 371.3969,-417.0263"/>
+</g>
+<!-- sccd_runtime_semantic_options&#45;&gt;sccd_runtime_model -->
+<g id="edge80" class="edge">
+<title>sccd_runtime_semantic_options&#45;&gt;sccd_runtime_model</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M632.2782,-657.9059C634.89,-649.4416 637.7856,-640.0575 640.5456,-631.1128"/>
+<polygon fill="#2fdbdb" stroke="#000000" points="643.9777,-631.8605 643.5819,-621.2731 637.2889,-629.7965 643.9777,-631.8605"/>
+</g>
+<!-- sccd_runtime_semantic_options&#45;&gt;sccd_runtime_xml_loader -->
+<g id="edge82" class="edge">
+<title>sccd_runtime_semantic_options&#45;&gt;sccd_runtime_xml_loader</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M666.5622,-664.7861C691.4985,-648.6508 717.8638,-624.153 717.3406,-592.8879"/>
+<path fill="none" stroke="#000000" d="M717.3406,-592.8879C715.8923,-506.3394 676.9771,-490.8271 666.3406,-404.9224"/>
+</g>
+<!-- sccd_compiler_lexer&#45;&gt;sccd_compiler_sccd_constructs -->
+<g id="edge25" class="edge">
+<title>sccd_compiler_lexer&#45;&gt;sccd_compiler_sccd_constructs</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M1542.9865,-768.1621C1534.8624,-762.6187 1525.8879,-756.7927 1517.3406,-751.862 1491.767,-737.1094 1462.3334,-722.663 1437.4894,-711.1512"/>
+<polygon fill="#2fbcbc" stroke="#000000" points="1438.7582,-707.8825 1428.2101,-706.8884 1435.836,-714.2434 1438.7582,-707.8825"/>
+</g>
+<!-- sccd_compiler_lexer&#45;&gt;sccd_compiler_state_linker -->
+<g id="edge26" class="edge">
+<title>sccd_compiler_lexer&#45;&gt;sccd_compiler_state_linker</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M1566.9415,-759.6283C1561.3817,-731.1443 1549.4609,-687.7353 1525.3406,-657.8793 1510.1652,-639.0953 1488.0115,-624.3175 1467.8762,-613.6316"/>
+<polygon fill="#2fbcbc" stroke="#000000" points="1469.2986,-610.4283 1458.7991,-609.01 1466.1225,-616.6663 1469.2986,-610.4283"/>
+</g>
+<!-- sccd_runtime_debug -->
+<g id="node33" class="node">
+<title>sccd_runtime_debug</title><style>.edge>path:hover{stroke-width:8}</style>
+<ellipse fill="#22e7e7" stroke="#000000" cx="334.3406" cy="-592.8879" rx="36.5405" ry="28.9828"/>
+<text text-anchor="middle" x="334.3406" y="-601.3879" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">sccd.</text>
+<text text-anchor="middle" x="334.3406" y="-590.3879" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">runtime.</text>
+<text text-anchor="middle" x="334.3406" y="-579.3879" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">debug</text>
+</g>
+<!-- sccd_runtime_debug&#45;&gt;sccd_runtime_controller -->
+<g id="edge53" class="edge">
+<title>sccd_runtime_debug&#45;&gt;sccd_runtime_controller</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M323.9503,-565.0085C316.7021,-546.1348 306.536,-520.7552 296.3406,-498.9052"/>
+<path fill="none" stroke="#000000" d="M296.3406,-498.9052C289.8264,-484.9445 288.5245,-480.5087 277.3406,-469.9138 254.2086,-447.9999 235.9005,-458.2571 215.3406,-433.9138 196.5145,-411.6233 156.0792,-336.9286 169.3406,-310.9396"/>
+</g>
+<!-- sccd_runtime_debug&#45;&gt;sccd_runtime_statechart_state -->
+<g id="edge56" class="edge">
+<title>sccd_runtime_debug&#45;&gt;sccd_runtime_statechart_state</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M349.1026,-566.2076C354.2981,-556.8175 360.235,-546.0875 365.8187,-535.9957"/>
+<polygon fill="#22e7e7" stroke="#000000" points="369.0371,-537.4083 370.8159,-526.9639 362.9121,-534.0194 369.0371,-537.4083"/>
+</g>
+<!-- sccd_runtime_debug&#45;&gt;sccd_runtime_round -->
+<g id="edge54" class="edge">
+<title>sccd_runtime_debug&#45;&gt;sccd_runtime_round</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M310.1917,-570.8531C296.2166,-558.1016 278.4562,-541.896 263.3306,-528.0946"/>
+<polygon fill="#22e7e7" stroke="#000000" points="265.4413,-525.2824 255.6951,-521.1275 260.723,-530.4533 265.4413,-525.2824"/>
+</g>
+<!-- sccd_runtime_debug&#45;&gt;sccd_runtime_statechart_instance -->
+<g id="edge55" class="edge">
+<title>sccd_runtime_debug&#45;&gt;sccd_runtime_statechart_instance</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M296.3406,-498.9052C288.4393,-481.9717 287.6074,-461.3802 289.1011,-443.7925"/>
+<polygon fill="#22e7e7" stroke="#000000" points="292.5816,-444.1613 290.2134,-433.8346 285.6248,-443.3842 292.5816,-444.1613"/>
+</g>
+<!-- sccd_runtime_test&#45;&gt;sccd_runtime_xml_loader2 -->
+<g id="edge91" class="edge">
+<title>sccd_runtime_test&#45;&gt;sccd_runtime_xml_loader2</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M547.1021,-97.2929C554.1018,-87.1722 562.2587,-75.3782 569.8051,-64.467"/>
+<polygon fill="#38a8a8" stroke="#000000" points="572.8828,-66.17 575.6924,-55.9545 567.1255,-62.1882 572.8828,-66.17"/>
+</g>
+<!-- sccd_compiler_generic_language_constructs&#45;&gt;sccd_compiler_javascript_writer -->
+<g id="edge20" class="edge">
+<title>sccd_compiler_generic_language_constructs&#45;&gt;sccd_compiler_javascript_writer</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M1099.1321,-760.2855C1109.6102,-748.305 1121.9153,-734.2356 1132.9346,-721.6364"/>
+<polygon fill="#0bdfdf" stroke="#000000" points="1135.6528,-723.8448 1139.6017,-714.0133 1130.3837,-719.2364 1135.6528,-723.8448"/>
+</g>
+<!-- sccd_compiler_generic_language_constructs&#45;&gt;sccd_compiler_generic_generator -->
+<g id="edge19" class="edge">
+<title>sccd_compiler_generic_language_constructs&#45;&gt;sccd_compiler_generic_generator</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M1074.3334,-759.236C1074.2593,-738.909 1074.022,-711.2425 1073.3406,-686.8707"/>
+<path fill="none" stroke="#000000" d="M1073.3406,-686.8707C1072.5686,-659.2566 1051.965,-636.9177 1030.2453,-620.9586"/>
+<polygon fill="#0bdfdf" stroke="#000000" points="1032.1132,-617.9944 1021.9054,-615.1567 1028.1157,-623.7407 1032.1132,-617.9944"/>
+</g>
+<!-- sccd_compiler_generic_language_constructs&#45;&gt;sccd_compiler_python_writer -->
+<g id="edge21" class="edge">
+<title>sccd_compiler_generic_language_constructs&#45;&gt;sccd_compiler_python_writer</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M1073.3406,-686.8707C1072.5966,-660.2587 1091.4508,-637.4367 1111.1531,-620.948"/>
+<polygon fill="#0bdfdf" stroke="#000000" points="1113.3414,-623.6796 1119.0001,-614.7225 1108.9908,-618.1958 1113.3414,-623.6796"/>
+</g>
+<!-- sccd_compiler_generic_language_constructs&#45;&gt;sccd_compiler_stateful_writer -->
+<g id="edge23" class="edge">
+<title>sccd_compiler_generic_language_constructs&#45;&gt;sccd_compiler_stateful_writer</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M1050.9419,-760.2855C1041.0661,-748.3215 1029.4707,-734.2745 1019.0815,-721.6885"/>
+<polygon fill="#0bdfdf" stroke="#000000" points="1021.5239,-719.1493 1012.4587,-713.6654 1016.1255,-723.6055 1021.5239,-719.1493"/>
+</g>
+<!-- sccd_compiler_generic_language_constructs&#45;&gt;sccd_compiler_sccdc -->
+<g id="edge22" class="edge">
+<title>sccd_compiler_generic_language_constructs&#45;&gt;sccd_compiler_sccdc</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M1073.3406,-686.8707C1071.795,-631.5886 1067.9092,-613.5111 1092.3406,-563.8965 1098.9927,-550.3876 1109.4477,-537.8229 1119.8903,-527.4122"/>
+<polygon fill="#0bdfdf" stroke="#000000" points="1122.6065,-529.6589 1127.4374,-520.2295 1117.7807,-524.5882 1122.6065,-529.6589"/>
+</g>
+<!-- sccd_compiler_path_calculator&#45;&gt;sccd_compiler_sccdc -->
+<g id="edge27" class="edge">
+<title>sccd_compiler_path_calculator&#45;&gt;sccd_compiler_sccdc</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M1436.826,-761.2415C1455.0632,-733.2262 1475.8039,-689.4521 1454.3406,-657.8793 1429.8881,-621.9094 1397.0596,-649.3526 1363.3406,-621.8793 1351.3974,-612.1483 1350.6159,-606.9575 1344.3406,-592.8879"/>
+</g>
+<!-- sccd_compiler_state_linker&#45;&gt;sccd_compiler_sccdc -->
+<g id="edge32" class="edge">
+<title>sccd_compiler_state_linker&#45;&gt;sccd_compiler_sccdc</title><style>.edge>path:hover{stroke-width:8}</style>
+<path fill="none" stroke="#000000" d="M1382.5973,-574.4432C1374.6832,-570.7481 1366.3021,-567.04 1358.3406,-563.8965 1305.5286,-543.0447 1243.1087,-523.9374 1201.3504,-511.9169"/>
+<polygon fill="#339999" stroke="#000000" points="1202.298,-508.5476 1191.7212,-509.1653 1200.3747,-515.2782 1202.298,-508.5476"/>
+</g>
+</g>
+</svg>

+ 150 - 0
test/legacy_render.py

@@ -0,0 +1,150 @@
+import argparse
+import sys
+import subprocess
+import multiprocessing
+from lib.os_tools import *
+from lib.loader import *
+from sccd.compiler.utils import FormattedWriter
+from sccd.syntax.statechart import *
+
+if __name__ == '__main__':
+    parser = argparse.ArgumentParser(
+        description="Render statecharts as SVG images.")
+    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.")
+    parser.add_argument('--build-dir', metavar='DIR', type=str, default='build', help="As a first step, input XML files first must be compiled to python files. Directory to store these files. Defaults to 'build'")
+    parser.add_argument('--output-dir', metavar='DIR', type=str, default='', help="Directory for SVG rendered output. Defaults to '.' (putting the SVG files with the XML source files)")
+    parser.add_argument('--keep-smcat', action='store_true', help="Whether to NOT delete intermediary SMCAT files after producing SVG output. Default = off (delete files)")
+    parser.add_argument('--no-svg', action='store_true', help="Don't produce SVG output. This option only makes sense in combination with the --keep-smcat option. Default = off")
+    parser.add_argument('--pool-size', metavar='INT', type=int, default=multiprocessing.cpu_count()+1, help="Number of worker processes. Default = CPU count + 1.")
+    args = parser.parse_args()
+
+
+    # builder = Builder(args.build_dir)
+    builder = Loader()
+    srcs = get_files(args.path, filter=filter_xml)
+
+    if len(srcs):
+      if not args.no_svg:
+        try:
+          subprocess.run(["state-machine-cat", "-h"], capture_output=True)
+        except:
+            print("Failed to run 'state-machine-cat'. Make sure this application is installed on your system.")
+            exit()
+    else:
+      print("No input files specified.")      
+      print()
+      parser.print_usage()
+      exit()
+
+
+    def process(src):
+      module = builder.build_and_load(src)
+      model = module.Model()
+
+      # Produce an output file for each class in the src file
+      for class_name, sc in model.classes.items():
+        target_path = lambda ext: os.path.join(args.output_dir, dropext(src)+'+'+class_name+ext)
+        smcat_target = target_path('.smcat')
+        svg_target = target_path('.svg')
+        
+        make_dirs(smcat_target)
+
+        f = open(smcat_target, 'w')
+        w = FormattedWriter(f)
+
+        def name_to_label(name):
+          label = name.split('/')[-1]
+          return label if len(label) else "root"
+        def name_to_name(name):
+          return name.replace('/','_')
+
+        # Used for drawing initial state
+        class PseudoState:
+          def __init__(self, name):
+            self.name = name
+        # Used for drawing initial state
+        class PseudoTransition:
+          def __init__(self, source, targets):
+            self.source = source
+            self.targets = targets
+            self.trigger = None
+            self.actions = []
+
+        transitions = []
+
+        def write_state(s, hide=False):
+          if not hide:
+            w.write(name_to_name(s.name))
+            w.extendWrite(' [label="')
+            w.extendWrite(name_to_label(s.name))
+            w.extendWrite('"')
+            if isinstance(s, ParallelState):
+              w.extendWrite(' type=parallel')
+            elif isinstance(s, ShallowHistoryState):
+              w.extendWrite(' type=history')
+            elif isinstance(s, DeepHistoryState):
+              w.extendWrite(' type=deephistory')
+            else:
+              w.extendWrite(' type=regular')
+            w.extendWrite(']')
+          if s.enter or s.exit:
+            w.extendWrite(' :')
+            for a in s.enter:
+              w.write("onentry/ "+a.render())
+            for a in s.exit:
+              w.write("onexit/ "+a.render())
+            w.write()
+          if s.children:
+            if not hide:
+              w.extendWrite(' {')
+              w.indent()
+            if s.default_state:
+              w.write(name_to_name(s.name)+'_initial [type=initial],')
+              transitions.append(PseudoTransition(source=PseudoState(s.name+'/initial'), targets=[s.default_state]))
+            for i, c in enumerate(s.children):
+              write_state(c)
+              w.extendWrite(',' if i < len(s.children)-1 else ';')
+            if not hide:
+              w.dedent()
+              w.write('}')
+          transitions.extend(s.transitions)
+
+        write_state(sc.tree.root, hide=True)
+
+        ctr = 0
+        for t in transitions:
+          label = ""
+          if t.trigger:
+            label += t.trigger.render()
+          if t.actions:
+            raises = [a for a in t.actions if isinstance(a, RaiseEvent)]
+            label += ','.join([r.render() for r in raises])
+
+          if len(t.targets) == 1:
+            w.write(name_to_name(t.source.name) + ' -> ' + name_to_name(t.targets[0].name))
+            if label:
+              w.extendWrite(': '+label)
+            w.extendWrite(';')
+          else:
+            w.write(name_to_name(t.source.name) + ' -> ' + ']split'+str(ctr))
+            if label:
+                w.extendWrite(': '+label)
+            w.extendWrite(';')
+            for tt in t.targets:
+              w.write(']split'+str(ctr) + ' -> ' + name_to_name(tt.name))
+              w.extendWrite(';')
+            ctr += 1
+
+        f.close()
+        if args.keep_smcat:
+          print("Wrote "+smcat_target)
+        if not args.no_svg:
+          subprocess.run(["state-machine-cat", smcat_target, "-o", svg_target])
+          print("Wrote "+svg_target)
+        if not args.keep_smcat:
+          os.remove(smcat_target)
+
+    pool_size = min(args.pool_size, len(srcs))
+    with multiprocessing.Pool(processes=pool_size) as pool:
+      print("Created a pool of %d processes."%pool_size)
+      pool.map(process, srcs)

+ 104 - 0
test/legacy_test.py

@@ -0,0 +1,104 @@
+import unittest
+import argparse
+import threading
+import queue
+from lib.os_tools import *
+from sccd.legacy.xml_loader import load_model
+from sccd.controller.controller import *
+
+class PyTestCase(unittest.TestCase):
+    def __init__(self, src_file):
+        unittest.TestCase.__init__(self)
+        self.src_file = src_file
+
+    def __str__(self):
+        return self.src_file
+
+    def runTest(self):
+        # Build & load
+        model, test = load_model(self.src_file)
+        inputs = test.input_events
+        expected = test.expected_events
+
+        controller = Controller(model)
+
+        # generate input
+        for i in inputs:
+            controller.add_input(i)
+
+        pipe = queue.Queue()
+
+        def model_thread():
+            try:
+                # Run as-fast-as-possible, always advancing time to the next item in event queue, no sleeping.
+                # The call returns when the event queue is empty and therefore the simulation is finished.
+                controller.run_until(None, pipe)
+            except Exception as e:
+                pipe.put(e, block=True, timeout=None)
+                return
+            pipe.put(None, block=True, timeout=None)
+
+        # start the controller
+        thread = threading.Thread(target=model_thread)
+        thread.start()
+
+        # check output
+        slot_index = 0
+        while True:
+            output = pipe.get(block=True, timeout=None)
+            if isinstance(output, Exception):
+                thread.join()
+                raise output # Exception was caught in Controller thread, throw it here instead.
+            elif output is None:
+                self.assertEqual(slot_index, len(expected), "Less output was received than expected.")
+                thread.join()
+                return
+            else:
+                self.assertLess(slot_index, len(expected), "More output was received than expected.")
+                exp_slot = expected[slot_index]
+                # print("slot:", slot_index, ", events: ", output)
+
+                self.assertEqual(len(exp_slot), len(output), "Slot %d length differs: Expected %s, but got %s instead." % (slot_index, exp_slot, output))
+
+                # sort both expected and actual lists of events before comparing,
+                # in theory the set of events at the end of a big step is unordered
+                key_f = lambda e: "%s.%s"%(e.port, e.name)
+                exp_slot.sort(key=key_f)
+                output.sort(key=key_f)
+
+                for (exp_event, event) in zip(exp_slot, output):
+                    matches = True
+                    if exp_event.name != event.name :
+                        matches = False
+                    if exp_event.port != event.port :
+                        matches = False
+                    if len(exp_event.parameters) != len(event.parameters) :
+                        matches = False
+                    for index in range(len(exp_event.parameters)) :
+                        if exp_event.parameters[index] !=  event.parameters[index]:
+                            matches = False
+
+                self.assertTrue(matches, "Slot %d entry differs: Expected %s, but got %s instead." % (slot_index, exp_slot, output))
+                slot_index += 1
+
+
+if __name__ == '__main__':
+    parser = argparse.ArgumentParser(
+        description="Run SCCD tests.",
+        epilog="Set environment variable SCCDDEBUG=1 to display debug information about the inner workings of the runtime.")
+    parser.add_argument('path', metavar='PATH', type=str, nargs='*', help="Tests to run. Can be a XML file or a directory. If a directory, it will be recursively scanned for XML files.")
+    parser.add_argument('--build-dir', metavar='BUILD_DIR', type=str, default='build', help="Directory for built tests. Defaults to 'build'")
+    args = parser.parse_args()
+
+    src_files = get_files(args.path, filter=filter_xml)
+
+    suite = unittest.TestSuite()
+    for src_file in src_files:
+        suite.addTest(PyTestCase(src_file))
+
+    if len(src_files) == 0:
+        print("No input files specified.")
+        print()
+        parser.print_usage()
+    else:
+        unittest.TextTestRunner(verbosity=2).run(suite)

test/test_files/compiler/stateref/flat_absolute+c.svg → test/legacy_test_files/compiler/stateref/flat_absolute+c.svg


test/test_files/compiler/stateref/flat_absolute.xml → test/legacy_test_files/compiler/stateref/flat_absolute.xml


test/test_files/compiler/stateref/flat_relative+c.svg → test/legacy_test_files/compiler/stateref/flat_relative+c.svg


test/test_files/compiler/stateref/flat_relative.xml → test/legacy_test_files/compiler/stateref/flat_relative.xml


test/test_files/compiler/stateref/nested_absolute+c.svg → test/legacy_test_files/compiler/stateref/nested_absolute+c.svg


test/test_files/compiler/stateref/nested_absolute.xml → test/legacy_test_files/compiler/stateref/nested_absolute.xml


test/test_files/compiler/stateref/nested_relative+c.svg → test/legacy_test_files/compiler/stateref/nested_relative+c.svg


test/test_files/compiler/stateref/nested_relative.xml → test/legacy_test_files/compiler/stateref/nested_relative.xml


test/test_files/pssm/PSSM_TestSuite.xmi → test/legacy_test_files/pssm/PSSM_TestSuite.xmi


test/test_files/scxml/schemas/scxml-attribs.xsd → test/legacy_test_files/scxml/schemas/scxml-attribs.xsd


test/test_files/scxml/schemas/scxml-contentmodels.xsd → test/legacy_test_files/scxml/schemas/scxml-contentmodels.xsd


test/test_files/scxml/schemas/scxml-copyright.xsd → test/legacy_test_files/scxml/schemas/scxml-copyright.xsd


test/test_files/scxml/schemas/scxml-core-strict.xsd → test/legacy_test_files/scxml/schemas/scxml-core-strict.xsd


test/test_files/scxml/schemas/scxml-data-strict.xsd → test/legacy_test_files/scxml/schemas/scxml-data-strict.xsd


test/test_files/scxml/schemas/scxml-datatypes.xsd → test/legacy_test_files/scxml/schemas/scxml-datatypes.xsd


test/test_files/scxml/schemas/scxml-external-strict.xsd → test/legacy_test_files/scxml/schemas/scxml-external-strict.xsd


test/test_files/scxml/schemas/scxml-strict.xsd → test/legacy_test_files/scxml/schemas/scxml-strict.xsd


test/test_files/scxml/tests/test144.txml → test/legacy_test_files/scxml/tests/test144.txml


test/test_files/scxml/tests/test147.txml → test/legacy_test_files/scxml/tests/test147.txml


test/test_files/scxml/tests/test148.txml → test/legacy_test_files/scxml/tests/test148.txml


test/test_files/scxml/tests/test149.txml → test/legacy_test_files/scxml/tests/test149.txml


test/test_files/scxml/tests/test150.txml → test/legacy_test_files/scxml/tests/test150.txml


test/test_files/scxml/tests/test151.txml → test/legacy_test_files/scxml/tests/test151.txml


test/test_files/scxml/tests/test152.txml → test/legacy_test_files/scxml/tests/test152.txml


test/test_files/scxml/tests/test153.txml → test/legacy_test_files/scxml/tests/test153.txml


test/test_files/scxml/tests/test155.txml → test/legacy_test_files/scxml/tests/test155.txml


test/test_files/scxml/tests/test156.txml → test/legacy_test_files/scxml/tests/test156.txml


test/test_files/scxml/tests/test158.txml → test/legacy_test_files/scxml/tests/test158.txml


test/test_files/scxml/tests/test159.txml → test/legacy_test_files/scxml/tests/test159.txml


test/test_files/scxml/tests/test172.txml → test/legacy_test_files/scxml/tests/test172.txml


test/test_files/scxml/tests/test173.txml → test/legacy_test_files/scxml/tests/test173.txml


test/test_files/scxml/tests/test174.txml → test/legacy_test_files/scxml/tests/test174.txml


test/test_files/scxml/tests/test175.txml → test/legacy_test_files/scxml/tests/test175.txml


test/test_files/scxml/tests/test176.txml → test/legacy_test_files/scxml/tests/test176.txml


test/test_files/scxml/tests/test178.txml → test/legacy_test_files/scxml/tests/test178.txml


test/test_files/scxml/tests/test179.txml → test/legacy_test_files/scxml/tests/test179.txml


test/test_files/scxml/tests/test183.txml → test/legacy_test_files/scxml/tests/test183.txml


test/test_files/scxml/tests/test185.txml → test/legacy_test_files/scxml/tests/test185.txml


test/test_files/scxml/tests/test186.txml → test/legacy_test_files/scxml/tests/test186.txml


test/test_files/scxml/tests/test187.txml → test/legacy_test_files/scxml/tests/test187.txml


test/test_files/scxml/tests/test189.txml → test/legacy_test_files/scxml/tests/test189.txml


test/test_files/scxml/tests/test190.txml → test/legacy_test_files/scxml/tests/test190.txml


test/test_files/scxml/tests/test191.txml → test/legacy_test_files/scxml/tests/test191.txml


test/test_files/scxml/tests/test192.txml → test/legacy_test_files/scxml/tests/test192.txml


test/test_files/scxml/tests/test193.txml → test/legacy_test_files/scxml/tests/test193.txml


test/test_files/scxml/tests/test194.txml → test/legacy_test_files/scxml/tests/test194.txml


test/test_files/scxml/tests/test198.txml → test/legacy_test_files/scxml/tests/test198.txml


+ 0 - 0
test/test_files/scxml/tests/test199.txml


이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.