Browse Source

transitions with only a guard are no longer given priority

Simon Van Mierlo 9 years ago
parent
commit
3f60a60dca

+ 115 - 0
examples/my-tests/python/exit_parallel.py

@@ -0,0 +1,115 @@
+"""
+Generated by Statechart compiler by Glenn De Jonghe, Joeri Exelmans, Simon Van Mierlo, and Yentl Van Tendeloo (for the inspiration)
+
+Date:   Wed Aug 10 11:42:10 2016
+
+Model name:   exit-parallel
+
+"""
+
+from sccd.runtime.statecharts_core import *
+
+# package "exit-parallel"
+
+class A(RuntimeClassBase):
+    def __init__(self, controller):
+        RuntimeClassBase.__init__(self, controller)
+        
+        self.semantics.big_step_maximality = StatechartSemantics.TakeMany
+        self.semantics.internal_event_lifeline = StatechartSemantics.Queue
+        self.semantics.input_event_lifeline = StatechartSemantics.FirstComboStep
+        self.semantics.priority = StatechartSemantics.SourceParent
+        self.semantics.concurrency = StatechartSemantics.Single
+        
+        # build Statechart structure
+        self.build_statechart_structure()
+        
+        # call user defined constructor
+        A.user_defined_constructor(self)
+    
+    def user_defined_constructor(self):
+        pass
+    
+    def user_defined_destructor(self):
+        pass
+    
+    
+    # builds Statechart structure
+    def build_statechart_structure(self):
+        
+        # state <root>
+        self.states[""] = State(0, self)
+        
+        # state /x
+        self.states["/x"] = ParallelState(1, self)
+        
+        # state /x/x1
+        self.states["/x/x1"] = State(2, self)
+        
+        # state /x/x1/x1
+        self.states["/x/x1/x1"] = State(3, self)
+        
+        # state /x/x2
+        self.states["/x/x2"] = State(4, self)
+        
+        # state /x/x2/x2
+        self.states["/x/x2/x2"] = State(5, self)
+        
+        # state /done
+        self.states["/done"] = State(6, self)
+        self.states["/done"].setEnter(self._done_enter)
+        
+        # add children
+        self.states[""].addChild(self.states["/x"])
+        self.states[""].addChild(self.states["/done"])
+        self.states["/x"].addChild(self.states["/x/x1"])
+        self.states["/x"].addChild(self.states["/x/x2"])
+        self.states["/x/x1"].addChild(self.states["/x/x1/x1"])
+        self.states["/x/x2"].addChild(self.states["/x/x2/x2"])
+        self.states[""].fixTree()
+        self.states[""].default_state = self.states["/x"]
+        self.states["/x/x1"].default_state = self.states["/x/x1/x1"]
+        self.states["/x/x2"].default_state = self.states["/x/x2/x2"]
+        
+        # transition /x/x1/x1
+        _x_x1_x1_0 = Transition(self, self.states["/x/x1/x1"], [self.states["/done"]])
+        _x_x1_x1_0.setAction(self._x_x1_x1_0_exec)
+        _x_x1_x1_0.setTrigger(None)
+        _x_x1_x1_0.setGuard(self._x_x1_x1_0_guard)
+        self.states["/x/x1/x1"].addTransition(_x_x1_x1_0)
+        _x_x1_x1_1 = Transition(self, self.states["/x/x1/x1"], [self.states["/done"]])
+        _x_x1_x1_1.setTrigger(Event("E", None))
+        self.states["/x/x1/x1"].addTransition(_x_x1_x1_1)
+    
+    def _done_enter(self):
+        print 'in done'
+    
+    def _x_x1_x1_0_exec(self, parameters):
+        print 'taking transition'
+    
+    def _x_x1_x1_0_guard(self, parameters):
+        return self.a == 5
+    
+    def initializeStatechart(self):
+        # enter default state
+        self.default_targets = self.states["/x"].getEffectiveTargetStates()
+        RuntimeClassBase.initializeStatechart(self)
+
+class ObjectManager(ObjectManagerBase):
+    def __init__(self, controller):
+        ObjectManagerBase.__init__(self, controller)
+    
+    def instantiate(self, class_name, construct_params):
+        if class_name == "A":
+            instance = A(self.controller)
+            instance.associations = {}
+        else:
+            raise Exception("Cannot instantiate class " + class_name)
+        return instance
+
+class Controller(ThreadsControllerBase):
+    def __init__(self, keep_running = None, behind_schedule_callback = None):
+        if keep_running == None: keep_running = True
+        if behind_schedule_callback == None: behind_schedule_callback = None
+        ThreadsControllerBase.__init__(self, ObjectManager(self), keep_running, behind_schedule_callback)
+        self.object_manager.createInstance("A", [])

+ 32 - 0
examples/my-tests/python/exit_parallel.xml

@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<diagram name="exit-parallel">
+    <class name="A" default="true">
+        <constructor>
+            self.a = 4
+        </constructor>
+        <scxml initial="x">
+            <parallel id="x">
+                <state id="x1">
+                    <state id="x1">
+                        <transition target="../../../done" cond="self.a == 5">
+                            <script>
+                                print 'taking transition'
+                            </script>
+                        </transition>
+                        <transition event="E" target="../../../done" />
+                    </state>
+                </state>
+                <state id="x2">
+                    <state id="x2" />
+                </state>
+            </parallel>
+            <state id="done">
+                <onentry>
+                    <script>
+                        print 'in done'
+                    </script>
+                </onentry>
+            </state>
+        </scxml>
+    </class>
+</diagram>

examples/after-0/python/runner.py → examples/my-tests/python/runner.py


+ 3 - 0
examples/my-tests/python/runner_exit_parallel.py

@@ -0,0 +1,3 @@
+import exit_parallel
+controller = exit_parallel.Controller(False)
+controller.start()

examples/after-0/python/server.py → examples/my-tests/python/server.py


examples/after-0/python/server.xml → examples/my-tests/python/server.xml


+ 9 - 21
src/python_sccd/python_sccd_compiler/sccd_constructs.py

@@ -482,7 +482,10 @@ class StateChartNode(Visitable):
         #transitions
         self.transitions = []
         for transition_xml in xml_element.findall("transition"):
-            self.transitions.append(StateChartTransition(transition_xml, self))
+            transition = StateChartTransition(transition_xml, self)
+            self.transitions.append(transition)
+            if transition.trigger.isAfter():
+                self.has_timers = True
             
         self.optimizeTransitions()
         self.generateChildren(xml_element)    
@@ -538,26 +541,11 @@ class StateChartNode(Visitable):
             self.exit_action = ExitAction(self)
             
     def optimizeTransitions(self):
-        """If a transition with no trigger and no guard is found then it is considered as the only transition.
-        Otherwise the list is ordered by placing transitions having guards only first."""
-        onlyguards = []
-        withtriggers = []
-        optimized = []
-        for transition in self.transitions:
-            if transition.isUCTransition():
-                if not transition.hasGuard():
-                    if optimized :
-                        raise TransitionException("More than one transition found at a single node, that has no trigger and no guard.")
-                    optimized.append(transition)
-                else:
-                    onlyguards.append(transition)
-            else:
-                withtriggers.append(transition)
-                if transition.trigger.isAfter():
-                    self.has_timers = True
-        if not optimized :        
-            optimized = onlyguards + withtriggers
-        self.transitions = optimized
+        """If a transition with no trigger and no guard is found then it is considered as the only transition."""
+        try:
+            self.transitions = [next(t for t in self.transitions if (t.isUCTransition() and not t.hasGuard()))]
+        except StopIteration:
+            pass
     
     def generateChildren(self, xml):
         children_names = []