Przeglądaj źródła

fixed after(0) bug

Simon Van Mierlo 9 lat temu
rodzic
commit
c811fddf1a

+ 3 - 0
examples/after-0/python/runner.py

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

+ 183 - 0
examples/after-0/python/server.py

@@ -0,0 +1,183 @@
+"""
+Generated by Statechart compiler by Glenn De Jonghe, Joeri Exelmans, Simon Van Mierlo, and Yentl Van Tendeloo (for the inspiration)
+
+Date:   Fri Aug  5 15:59:05 2016
+
+Model author: Yentl Van Tendeloo
+Model name:   broken
+Model description:
+Broken!
+"""
+
+from sccd.runtime.statecharts_core import *
+
+# package "broken"
+
+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"] = State(1, self)
+        self.states["/x"].setEnter(self._x_enter)
+        
+        # state /ready
+        self.states["/ready"] = State(2, self)
+        self.states["/ready"].setEnter(self._ready_enter)
+        
+        # state /done
+        self.states["/done"] = State(3, self)
+        
+        # add children
+        self.states[""].addChild(self.states["/x"])
+        self.states[""].addChild(self.states["/ready"])
+        self.states[""].addChild(self.states["/done"])
+        self.states[""].fixTree()
+        self.states[""].default_state = self.states["/x"]
+        
+        # transition /x
+        _x_0 = Transition(self, self.states["/x"], [self.states["/ready"]])
+        _x_0.setAction(self._x_0_exec)
+        _x_0.trigger = Event("instance_created", None)
+        self.states["/x"].addTransition(_x_0)
+        
+        # transition /ready
+        _ready_0 = Transition(self, self.states["/ready"], [self.states["/done"]])
+        _ready_0.setAction(self._ready_0_exec)
+        _ready_0.trigger = Event("close", None)
+        self.states["/ready"].addTransition(_ready_0)
+    
+    def _x_enter(self):
+        self.big_step.outputEventOM(Event("create_instance", None, [self, 'child', 'B']))
+    
+    def _ready_enter(self):
+        self.big_step.outputEventOM(Event("start_instance", None, [self, self.instancename]))
+    
+    def _x_0_exec(self, parameters):
+        instancename = parameters[0]
+        self.instancename = instancename
+        print(self.instancename)
+    
+    def _ready_0_exec(self, parameters):
+        print("CLOSED")
+        self.big_step.outputEventOM(Event("delete_instance", None, [self, self.instancename]))
+    
+    def initializeStatechart(self):
+        # enter default state
+        states = self.states["/x"].getEffectiveTargetStates()
+        self.updateConfiguration(states)
+        for state in states:
+            if state.enter:
+                state.enter()
+
+class B(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
+        B.user_defined_constructor(self)
+    
+    def user_defined_constructor(self):
+        print("READY")
+    
+    def user_defined_destructor(self):
+        pass
+    
+    
+    # builds Statechart structure
+    def build_statechart_structure(self):
+        
+        # state <root>
+        self.states[""] = State(0, self)
+        
+        # state /z
+        self.states["/z"] = State(1, self)
+        self.states["/z"].setEnter(self._z_enter)
+        self.states["/z"].setExit(self._z_exit)
+        
+        # add children
+        self.states[""].addChild(self.states["/z"])
+        self.states[""].fixTree()
+        self.states[""].default_state = self.states["/z"]
+        
+        # transition /z
+        _z_0 = Transition(self, self.states["/z"], [self.states["/z"]])
+        _z_0.setAction(self._z_0_exec)
+        _z_0.trigger = Event("_0after")
+        self.states["/z"].addTransition(_z_0)
+    
+    def _z_enter(self):
+        self.addTimer(0, 0)
+        print("RUN")
+    
+    def _z_exit(self):
+        self.removeTimer(0)
+    
+    def _z_0_exec(self, parameters):
+        print("RAISE")
+        self.big_step.outputEventOM(Event("broad_cast", None, [Event("close", None, [])]))
+    
+    def initializeStatechart(self):
+        # enter default state
+        states = self.states["/z"].getEffectiveTargetStates()
+        self.updateConfiguration(states)
+        for state in states:
+            if state.enter:
+                state.enter()
+
+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 = {}
+            instance.associations["child"] = Association("B", 0, 1)
+        elif class_name == "B":
+            instance = B(self.controller)
+            instance.associations = {}
+            instance.associations["parent"] = Association("A", 1, 1)
+        else:
+            raise Exception("Cannot instantiate class " + class_name)
+        return instance
+
+class Controller(ThreadsControllerBase):
+    def __init__(self, keep_running = None):
+        if keep_running == None: keep_running = True
+        ThreadsControllerBase.__init__(self, ObjectManager(self), keep_running)
+        self.object_manager.createInstance("A", [])

+ 79 - 0
examples/after-0/python/server.xml

@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<diagram author="Yentl Van Tendeloo" name="broken">
+    <description>
+        Broken!
+    </description>
+
+    <class name="A" default="true">
+        <relationships>
+            <association name="child" class="B" min="0" max="1"/>
+        </relationships>
+
+        <scxml initial="x">
+            <state id="x">
+                <onentry>
+                    <raise scope="cd" event="create_instance">
+                        <parameter expr="'child'"/>
+                        <parameter expr="'B'"/>
+                    </raise>
+                </onentry>
+
+                <transition event="instance_created" target="../ready">
+                    <parameter name="instancename"/>
+                    <script>
+                        self.instancename = instancename
+                        print(self.instancename)
+                    </script>
+                </transition>
+
+            </state>
+            <state id="ready">
+                <onentry>
+                    <raise scope="cd" event="start_instance">
+                        <parameter expr="self.instancename"/>
+                    </raise>
+                </onentry>
+
+                <transition event="close" target="../done">
+                    <script>
+                        print("CLOSED")
+                    </script>
+                    <raise scope="cd" event="delete_instance">
+                        <parameter expr="self.instancename"/>
+                    </raise>
+                </transition>
+
+            </state>
+            <state id="done"/>
+        </scxml>
+    </class>
+
+    <class name="B">
+        <constructor>
+            <body>
+                print("READY")
+            </body>
+        </constructor>
+
+        <relationships>
+            <association name="parent" class="A" min="1" max="1"/>
+        </relationships>
+
+        <scxml initial="z">
+            <state id="z">
+                <onentry>
+                    <script>
+                        print("RUN")
+                    </script>
+                </onentry>
+                <transition after="0" target=".">
+                    <script>
+                        print("RAISE")
+                    </script>
+                    <raise scope="broad" event="close"/>
+                </transition>
+            </state>
+        </scxml>
+    </class>
+
+</diagram>

+ 14 - 6
src/javascript_sccd_runtime/statecharts_core.js

@@ -459,7 +459,7 @@ function ControllerBase(object_manager) {
 	this.output_ports = new Array();
 	this.output_listeners = new Array();
 
-    this.simulated_time = 0
+    this.simulated_time = null;
 }
 
 ControllerBase.prototype.getSimulatedTime = function() {
@@ -490,6 +490,7 @@ ControllerBase.prototype.broadcast = function(new_event, time_offset) {
 
 ControllerBase.prototype.start = function() {
     start_time = (new Date()).getTime();
+    this.simulated_time = 0;
 	this.object_manager.start();
 };
 
@@ -510,7 +511,7 @@ ControllerBase.prototype.addInput = function(input_event_list, time_offset) {
 		if (input_port === undefined) {
 			throw new InputException("Input port mismatch, no such port: " + input_event_list[e].port + ".");
 		}
-        this.input_queue.add(new EventQueueEntry((this.simulated_time ? time() : 0) + time_offset, input_event_list[e]));
+        this.input_queue.add(new EventQueueEntry((this.simulated_time === null ? 0 : time()) + time_offset, input_event_list[e]));
 	}
 };
 
@@ -605,7 +606,7 @@ function EventLoopControllerBase(object_manager, event_loop, finished_callback)
 	ControllerBase.call(this, object_manager);
 	this.event_loop = event_loop;
 	this.finished_callback = finished_callback;
-	this.last_print_time = 0.0;
+	this.last_print_time = 0;
 }
 
 EventLoopControllerBase.prototype = new ControllerBase();
@@ -642,9 +643,9 @@ EventLoopControllerBase.prototype.run = function() {
             return;
 		}
         var now = time();
-        if (now - start_time > 10 || earliest_event_time - now > 0.0) {
+        if (now - start_time > 10 || earliest_event_time - now > 0) {
             this.event_loop.schedule(this.run.bind(this), earliest_event_time - now, now - start_time > 10);
-            if (now - earliest_event_time > 10 && now - this.last_print_time >= 1) {
+            if (now - earliest_event_time > 10 && now - this.last_print_time >= 1000) {
                 console.log('running ' + (now - earliest_event_time) + ' ms behind schedule');
                 this.last_print_time = now;
             }
@@ -982,6 +983,7 @@ RuntimeClassBase.prototype.start = function() {
 	this.current_state = new Object();
 	this.history_values = new Object();
 	this.timers = new Object();
+    this.timers_to_add = new Object();
 
 	this.big_step = new BigStepState();
 	this.combo_step = new ComboStepState();
@@ -1008,10 +1010,11 @@ RuntimeClassBase.prototype.stop = function() {
 };
 
 RuntimeClassBase.prototype.addTimer = function(index, timeout) {
-	this.timers[index] = this.events.add(new EventQueueEntry(this.controller.simulated_time + Math.trunc(timeout * 1000), new Event("_" + index + "after")));
+    this.timers_to_add[index] = new EventQueueEntry(this.controller.simulated_time + Math.trunc(timeout * 1000), new Event("_" + index + "after"));
 };
 
 RuntimeClassBase.prototype.removeTimer = function(index) {
+    if (index in this.timers_to_add) delete this.timers_to_add[index];
 	this.events.remove(this.timers[index]);
     delete this.timers[index];
 };
@@ -1070,6 +1073,11 @@ RuntimeClassBase.prototype.step = function(delta) {
         is_stable = !this.bigStep(due);
         this.processBigStepOutput();
     }
+    for (key in this.timers_to_add) {
+        if (!this.timers_to_add.hasOwnProperty(key)) continue;
+        this.timers[key] = this.events.add(this.timers_to_add[key]);
+    }
+	this.timers_to_add = new Object();
     this.__set_stable(true);
 };
 

+ 2 - 1
src/python_sccd/python_sccd_runtime/accurate_time.py

@@ -4,7 +4,8 @@ import os
 global start_time
 def set_start_time():
     global start_time
-    start_time = t.time()
+    if os.name == 'posix':
+        start_time = t.time()
 
 if os.name == 'posix':
     def time():

+ 16 - 8
src/python_sccd/python_sccd_runtime/statecharts_core.py

@@ -340,7 +340,7 @@ class ControllerBase(object):
         self.output_ports = []
         self.output_listeners = []
         
-        self.simulated_time = 0
+        self.simulated_time = None
         
     def getSimulatedTime(self):
         return self.simulated_time
@@ -362,6 +362,7 @@ class ControllerBase(object):
         
     def start(self):
         set_start_time()
+        self.simulated_time = 0
         self.object_manager.start()
     
     def stop(self):
@@ -378,7 +379,7 @@ class ControllerBase(object):
             if e.getPort() not in self.input_ports :
                 raise InputException("Input port mismatch, no such port: " + e.getPort() + ".")
             
-            self.input_queue.add(((time() if self.simulated_time else 0) + time_offset, e))
+            self.input_queue.add(((0 if self.simulated_time is None else time()) + time_offset, e))
 
     def getEarliestEventTime(self):
         return min(self.object_manager.getEarliestEventTime(), self.input_queue.getEarliestTime())
@@ -459,7 +460,7 @@ class EventLoopControllerBase(ControllerBase):
         self.event_loop = event_loop
         self.finished_callback = finished_callback
         self.behind_schedule_callback = behind_schedule_callback
-        self.last_print_time = 0.0
+        self.last_print_time = 0
         self.behind = False
 
     def addInput(self, input_event, time_offset = 0):
@@ -492,7 +493,7 @@ class EventLoopControllerBase(ControllerBase):
             now = time()
             if now - start_time > 10 or earliest_event_time - now > 0:
                 self.event_loop.schedule(self.run, earliest_event_time - now, now - start_time > 10)
-                if now - earliest_event_time > 10 and now - self.last_print_time >= 1:
+                if now - earliest_event_time > 10 and now - self.last_print_time >= 1000:
                     if self.behind_schedule_callback:
                         self.behind_schedule_callback(self, now - earliest_event_time)
                     print '\rrunning %ims behind schedule' % (now - earliest_event_time),
@@ -815,6 +816,7 @@ class RuntimeClassBase(object):
         self.current_state = {}
         self.history_values = {}
         self.timers = {}
+        self.timers_to_add = {}
 
         self.big_step = BigStepState()
         self.combo_step = ComboStepState()
@@ -840,11 +842,14 @@ class RuntimeClassBase(object):
         self.__set_stable(True)
     
     def addTimer(self, index, timeout):
-        self.timers[index] = self.events.add((self.controller.simulated_time + int(timeout * 1000), Event("_%iafter" % index)))
+        self.timers_to_add[index] = (self.controller.simulated_time + int(timeout * 1000), Event("_%iafter" % index))
     
     def removeTimer(self, index):
-        self.events.remove(self.timers[index])
-        del self.timers[index]
+        if index in self.timers_to_add:
+            del self.timers_to_add[index]
+        if index in self.timers:
+            self.events.remove(self.timers[index])
+            del self.timers[index]
         
     def addEvent(self, event_list, time_offset = 0):
         event_time = self.controller.simulated_time + time_offset
@@ -868,7 +873,7 @@ class RuntimeClassBase(object):
         self.is_stable = is_stable
         # self.earliest_event_time keeps track of the earliest time this instance will execute a transition
         if not is_stable:
-            self.earliest_event_time = 0.0
+            self.earliest_event_time = 0
         elif not self.active:
             self.earliest_event_time = INFINITY
         else:
@@ -882,6 +887,9 @@ class RuntimeClassBase(object):
                 due = [self.events.pop()]
             is_stable = not self.bigStep(due)
             self.processBigStepOutput()
+        for index, entry in self.timers_to_add.iteritems():
+            self.timers[index] = self.events.add(entry)
+        self.timers_to_add = {}
         self.__set_stable(True)
 
     def inState(self, state_strings):