|
@@ -4,6 +4,7 @@ from sccd.execution.event import *
|
|
|
from sccd.util.debug import print_debug
|
|
|
from sccd.util.bitmap import *
|
|
|
from sccd.syntax.scope import *
|
|
|
+from sccd.execution.exceptions import *
|
|
|
|
|
|
|
|
|
# Set of current states etc.
|
|
@@ -53,73 +54,78 @@ class StatechartState:
|
|
|
|
|
|
self.rhs_memory.flush_transition()
|
|
|
self.rhs_memory.flush_round()
|
|
|
+ self.gc_memory.flush_round()
|
|
|
|
|
|
# events: list SORTED by event id
|
|
|
def fire_transition(self, events: List[Event], t: Transition):
|
|
|
- def __exitSet():
|
|
|
- return [s for s in reversed(t.gen.lca.gen.descendants) if (s in self.configuration)]
|
|
|
-
|
|
|
- def __enterSet(targets):
|
|
|
- target = targets[0]
|
|
|
- for a in reversed(target.gen.ancestors):
|
|
|
- if a in t.source.gen.ancestors:
|
|
|
- continue
|
|
|
- else:
|
|
|
- yield a
|
|
|
- for target in targets:
|
|
|
- yield target
|
|
|
-
|
|
|
- def __getEffectiveTargetStates():
|
|
|
- targets = []
|
|
|
- for target in t.targets:
|
|
|
- for e_t in target.getEffectiveTargetStates(self):
|
|
|
- if not e_t in targets:
|
|
|
- targets.append(e_t)
|
|
|
- return targets
|
|
|
-
|
|
|
- # exit states...
|
|
|
- exit_set = __exitSet()
|
|
|
- for s in exit_set:
|
|
|
- # remember which state(s) we were in if a history state is present
|
|
|
- for h in s.gen.history:
|
|
|
- f = lambda s0: s0.gen.ancestors and s0.parent == s
|
|
|
- if isinstance(h, DeepHistoryState):
|
|
|
- f = lambda s0: not s0.gen.descendants and s0 in s.gen.descendants
|
|
|
- self.history_values[h.gen.state_id] = list(filter(f, self.configuration))
|
|
|
-
|
|
|
- ctx = EvalContext(current_state=self, events=events, memory=self.rhs_memory)
|
|
|
-
|
|
|
- print_debug("fire " + str(t))
|
|
|
- for s in exit_set:
|
|
|
- print_debug(termcolor.colored(' EXIT %s' % s.gen.full_name, 'green'))
|
|
|
- self.eventless_states -= s.gen.has_eventless_transitions
|
|
|
- # execute exit action(s)
|
|
|
- self._perform_actions(ctx, s.exit)
|
|
|
- # self.rhs_memory.pop_local_scope(s.scope)
|
|
|
- self.configuration_bitmap &= ~s.gen.state_id_bitmap
|
|
|
-
|
|
|
- # execute transition action(s)
|
|
|
- self.rhs_memory.push_frame(t.scope) # make room for event parameters on stack
|
|
|
- self._copy_event_params_to_stack(self.rhs_memory, t, events)
|
|
|
- self._perform_actions(ctx, t.actions)
|
|
|
- self.rhs_memory.pop_frame()
|
|
|
-
|
|
|
- # enter states...
|
|
|
- targets = __getEffectiveTargetStates()
|
|
|
- enter_set = __enterSet(targets)
|
|
|
- for s in enter_set:
|
|
|
- print_debug(termcolor.colored(' ENTER %s' % s.gen.full_name, 'green'))
|
|
|
- self.eventless_states += s.gen.has_eventless_transitions
|
|
|
- self.configuration_bitmap |= s.gen.state_id_bitmap
|
|
|
- # execute enter action(s)
|
|
|
- self._perform_actions(ctx, s.enter)
|
|
|
- self._start_timers(s.gen.after_triggers)
|
|
|
try:
|
|
|
- self.configuration = self.config_mem[self.configuration_bitmap]
|
|
|
- except KeyError:
|
|
|
- self.configuration = self.config_mem[self.configuration_bitmap] = [s for s in self.model.tree.state_list if self.configuration_bitmap & s.gen.state_id_bitmap]
|
|
|
+ def __exitSet():
|
|
|
+ return [s for s in reversed(t.gen.lca.gen.descendants) if (s in self.configuration)]
|
|
|
+
|
|
|
+ def __enterSet(targets):
|
|
|
+ target = targets[0]
|
|
|
+ for a in reversed(target.gen.ancestors):
|
|
|
+ if a in t.source.gen.ancestors:
|
|
|
+ continue
|
|
|
+ else:
|
|
|
+ yield a
|
|
|
+ for target in targets:
|
|
|
+ yield target
|
|
|
+
|
|
|
+ def __getEffectiveTargetStates():
|
|
|
+ targets = []
|
|
|
+ for target in t.targets:
|
|
|
+ for e_t in target.getEffectiveTargetStates(self):
|
|
|
+ if not e_t in targets:
|
|
|
+ targets.append(e_t)
|
|
|
+ return targets
|
|
|
+
|
|
|
+ # exit states...
|
|
|
+ exit_set = __exitSet()
|
|
|
+ for s in exit_set:
|
|
|
+ # remember which state(s) we were in if a history state is present
|
|
|
+ for h in s.gen.history:
|
|
|
+ f = lambda s0: s0.gen.ancestors and s0.parent == s
|
|
|
+ if isinstance(h, DeepHistoryState):
|
|
|
+ f = lambda s0: not s0.gen.descendants and s0 in s.gen.descendants
|
|
|
+ self.history_values[h.gen.state_id] = list(filter(f, self.configuration))
|
|
|
+
|
|
|
+ ctx = EvalContext(current_state=self, events=events, memory=self.rhs_memory)
|
|
|
+
|
|
|
+ print_debug("fire " + str(t))
|
|
|
+ for s in exit_set:
|
|
|
+ print_debug(termcolor.colored(' EXIT %s' % s.gen.full_name, 'green'))
|
|
|
+ self.eventless_states -= s.gen.has_eventless_transitions
|
|
|
+ # execute exit action(s)
|
|
|
+ self._perform_actions(ctx, s.exit)
|
|
|
+ # self.rhs_memory.pop_local_scope(s.scope)
|
|
|
+ self.configuration_bitmap &= ~s.gen.state_id_bitmap
|
|
|
+
|
|
|
+ # execute transition action(s)
|
|
|
+ self.rhs_memory.push_frame(t.scope) # make room for event parameters on stack
|
|
|
+ self._copy_event_params_to_stack(self.rhs_memory, t, events)
|
|
|
+ self._perform_actions(ctx, t.actions)
|
|
|
+ self.rhs_memory.pop_frame()
|
|
|
+
|
|
|
+ # enter states...
|
|
|
+ targets = __getEffectiveTargetStates()
|
|
|
+ enter_set = __enterSet(targets)
|
|
|
+ for s in enter_set:
|
|
|
+ print_debug(termcolor.colored(' ENTER %s' % s.gen.full_name, 'green'))
|
|
|
+ self.eventless_states += s.gen.has_eventless_transitions
|
|
|
+ self.configuration_bitmap |= s.gen.state_id_bitmap
|
|
|
+ # execute enter action(s)
|
|
|
+ self._perform_actions(ctx, s.enter)
|
|
|
+ self._start_timers(s.gen.after_triggers)
|
|
|
+ try:
|
|
|
+ self.configuration = self.config_mem[self.configuration_bitmap]
|
|
|
+ except KeyError:
|
|
|
+ self.configuration = self.config_mem[self.configuration_bitmap] = [s for s in self.model.tree.state_list if self.configuration_bitmap & s.gen.state_id_bitmap]
|
|
|
|
|
|
- self.rhs_memory.flush_transition()
|
|
|
+ self.rhs_memory.flush_transition()
|
|
|
+ except SCCDRuntimeException as e:
|
|
|
+ e.args = ("During execution of transition %s:\n" % str(t) +str(e),)
|
|
|
+ raise
|
|
|
|
|
|
@staticmethod
|
|
|
def _copy_event_params_to_stack(memory, t, events):
|
|
@@ -143,24 +149,25 @@ class StatechartState:
|
|
|
pass
|
|
|
|
|
|
def check_guard(self, t, events) -> bool:
|
|
|
- # Special case: after trigger
|
|
|
- if isinstance(t.trigger, AfterTrigger):
|
|
|
- e = [e for e in events if bit(e.id) & t.trigger.enabling_bitmap][0] # it's safe to assume the list will contain one element cause we only check a transition's guard after we know it may be enabled given the set of events
|
|
|
- if self.timer_ids[t.trigger.after_id] != e.params[0]:
|
|
|
- return False
|
|
|
-
|
|
|
- if t.guard is None:
|
|
|
- return True
|
|
|
- else:
|
|
|
- # print("evaluating guard for ", str(t))
|
|
|
- self.gc_memory.push_frame(t.scope)
|
|
|
- self._copy_event_params_to_stack(self.gc_memory, t, events)
|
|
|
- result = t.guard.eval(
|
|
|
- EvalContext(current_state=self, events=events, memory=self.gc_memory))
|
|
|
- self.gc_memory.pop_frame()
|
|
|
- self.gc_memory.flush_transition()
|
|
|
- # print("done with guard for ", str(t))
|
|
|
- return result
|
|
|
+ try:
|
|
|
+ # Special case: after trigger
|
|
|
+ if isinstance(t.trigger, AfterTrigger):
|
|
|
+ e = [e for e in events if bit(e.id) & t.trigger.enabling_bitmap][0] # it's safe to assume the list will contain one element cause we only check a transition's guard after we know it may be enabled given the set of events
|
|
|
+ if self.timer_ids[t.trigger.after_id] != e.params[0]:
|
|
|
+ return False
|
|
|
+
|
|
|
+ if t.guard is None:
|
|
|
+ return True
|
|
|
+ else:
|
|
|
+ self.gc_memory.push_frame(t.scope)
|
|
|
+ self._copy_event_params_to_stack(self.gc_memory, t, events)
|
|
|
+ result = t.guard.eval(
|
|
|
+ EvalContext(current_state=self, events=events, memory=self.gc_memory))
|
|
|
+ self.gc_memory.pop_frame()
|
|
|
+ return result
|
|
|
+ except SCCDRuntimeException as e:
|
|
|
+ e.args = ("While checking guard of transition %s:\n" % str(t) +str(e),)
|
|
|
+ raise
|
|
|
|
|
|
def check_source(self, t) -> bool:
|
|
|
return self.configuration_bitmap & t.source.gen.state_id_bitmap
|
|
@@ -174,7 +181,6 @@ class StatechartState:
|
|
|
for after in triggers:
|
|
|
delay: Duration = after.delay.eval(
|
|
|
EvalContext(current_state=self, events=[], memory=self.gc_memory))
|
|
|
- self.gc_memory.flush_transition()
|
|
|
timer_id = self._next_timer_id(after)
|
|
|
self.output.append(OutputEvent(
|
|
|
Event(id=after.id, name=after.name, params=[timer_id]),
|
|
@@ -195,7 +201,7 @@ class StatechartState:
|
|
|
# print_debug("not in state"+str(state_strings))
|
|
|
return in_state
|
|
|
|
|
|
- def collect_output(self) -> Tuple[bool, List[OutputEvent]]:
|
|
|
+ def collect_output(self) -> List[OutputEvent]:
|
|
|
output = self.output
|
|
|
self.output = []
|
|
|
- return (not self.eventless_states, output)
|
|
|
+ return output
|