|
@@ -9,7 +9,7 @@ from sccd.statechart.static import priority
|
|
|
from sccd.util.indenting_writer import *
|
|
|
|
|
|
# Hardcoded limit on number of sub-rounds of combo and big step to detect never-ending superrounds.
|
|
|
-# TODO: make this a model parameter
|
|
|
+# TODO: make this a model parameter, also allowing for +infinity
|
|
|
LIMIT = 1000
|
|
|
|
|
|
# Conversion functions from abstract syntax elements to identifiers in Rust
|
|
@@ -90,7 +90,7 @@ class StatechartRustGenerator(ActionLangRustGenerator):
|
|
|
# Write 'current state' types
|
|
|
if isinstance(state.type, AndState):
|
|
|
self.w.writeln("// And-state")
|
|
|
- # TODO: Only annotate Copy for states that will be recorded by deep history.
|
|
|
+ # We need Copy for states that will be recorded as history.
|
|
|
self.w.writeln("#[derive(Default, Copy, Clone)]")
|
|
|
self.w.writeln("struct %s {" % ident_type(state))
|
|
|
for child in state.real_children:
|
|
@@ -115,76 +115,69 @@ class StatechartRustGenerator(ActionLangRustGenerator):
|
|
|
self.w.writeln("}")
|
|
|
|
|
|
# Implement trait 'State': enter/exit
|
|
|
- # self.w.writeln("impl<'a, OutputCallback: FnMut(OutEvent)> State<Timers, Controller<InEvent, OutputCallback>> for %s {" % ident_type(state))
|
|
|
- # self.w.writeln("impl<'a, OutputCallback: FnMut(OutEvent)> %s {" % ident_type(state))
|
|
|
self.w.writeln("impl %s {" % ident_type(state))
|
|
|
|
|
|
# Enter actions: Executes enter actions of only this state
|
|
|
- # self.w.writeln(" fn enter_actions(timers: &mut Timers, internal: &mut InternalLifeline, ctrl: &mut Controller<InEvent, OutputCallback>) {")
|
|
|
- self.w.writeln(" fn enter_actions<OutputCallback: FnMut(OutEvent)>(timers: &mut Timers, internal: &mut InternalLifeline, ctrl: &mut Controller<InEvent, OutputCallback>) {")
|
|
|
+ self.w.writeln(" fn enter_actions<OutputCallback: FnMut(OutEvent)>(timers: &mut Timers, data: &mut DataModel, internal: &mut InternalLifeline, ctrl: &mut Controller<InEvent, OutputCallback>) {")
|
|
|
self.w.writeln(" eprintln!(\"enter %s\");" % state.full_name);
|
|
|
+ self.w.writeln(" let scope = data;")
|
|
|
self.w.indent(); self.w.indent()
|
|
|
for a in state.enter:
|
|
|
a.accept(self)
|
|
|
- # compile_actions(state.enter, w)
|
|
|
self.w.dedent(); self.w.dedent()
|
|
|
for a in state.after_triggers:
|
|
|
self.w.writeln(" timers[%d] = ctrl.set_timeout(%d, InEvent::%s);" % (a.after_id, a.delay.opt, ident_event_type(a.enabling[0].name)))
|
|
|
self.w.writeln(" }")
|
|
|
|
|
|
# Enter actions: Executes exit actions of only this state
|
|
|
- # self.w.writeln(" fn exit_actions(timers: &mut Timers, internal: &mut InternalLifeline, ctrl: &mut Controller<InEvent, OutputCallback>) {")
|
|
|
- self.w.writeln(" fn exit_actions<OutputCallback: FnMut(OutEvent)>(timers: &mut Timers, internal: &mut InternalLifeline, ctrl: &mut Controller<InEvent, OutputCallback>) {")
|
|
|
- self.w.writeln(" eprintln!(\"exit %s\");" % state.full_name);
|
|
|
+ self.w.writeln(" fn exit_actions<OutputCallback: FnMut(OutEvent)>(timers: &mut Timers, data: &mut DataModel, internal: &mut InternalLifeline, ctrl: &mut Controller<InEvent, OutputCallback>) {")
|
|
|
+ self.w.writeln(" let scope = data;")
|
|
|
for a in state.after_triggers:
|
|
|
self.w.writeln(" ctrl.unset_timeout(timers[%d]);" % (a.after_id))
|
|
|
self.w.indent(); self.w.indent()
|
|
|
for a in state.exit:
|
|
|
a.accept(self)
|
|
|
- # compile_actions(state.exit, w)
|
|
|
+ self.w.writeln(" eprintln!(\"exit %s\");" % state.full_name);
|
|
|
self.w.dedent(); self.w.dedent()
|
|
|
self.w.writeln(" }")
|
|
|
|
|
|
# Enter default: Executes enter actions of entering this state and its default substates, recursively
|
|
|
- # self.w.writeln(" fn enter_default(timers: &mut Timers, internal: &mut InternalLifeline, ctrl: &mut Controller<InEvent, OutputCallback>) {")
|
|
|
- self.w.writeln(" fn enter_default<OutputCallback: FnMut(OutEvent)>(timers: &mut Timers, internal: &mut InternalLifeline, ctrl: &mut Controller<InEvent, OutputCallback>) {")
|
|
|
- self.w.writeln(" %s::enter_actions(timers, internal, ctrl);" % (ident_type(state)))
|
|
|
+ self.w.writeln(" fn enter_default<OutputCallback: FnMut(OutEvent)>(timers: &mut Timers, data: &mut DataModel, internal: &mut InternalLifeline, ctrl: &mut Controller<InEvent, OutputCallback>) {")
|
|
|
+ self.w.writeln(" %s::enter_actions(timers, data, internal, ctrl);" % (ident_type(state)))
|
|
|
if isinstance(state.type, AndState):
|
|
|
for child in state.real_children:
|
|
|
- self.w.writeln(" %s::enter_default(timers, internal, ctrl);" % (ident_type(child)))
|
|
|
+ self.w.writeln(" %s::enter_default(timers, data, internal, ctrl);" % (ident_type(child)))
|
|
|
elif isinstance(state.type, OrState):
|
|
|
- self.w.writeln(" %s::enter_default(timers, internal, ctrl);" % (ident_type(state.type.default_state)))
|
|
|
+ self.w.writeln(" %s::enter_default(timers, data, internal, ctrl);" % (ident_type(state.type.default_state)))
|
|
|
self.w.writeln(" }")
|
|
|
|
|
|
# Exit current: Executes exit actions of this state and current children, recursively
|
|
|
- # self.w.writeln(" fn exit_current(&self, timers: &mut Timers, internal: &mut InternalLifeline, ctrl: &mut Controller<InEvent, OutputCallback>) {")
|
|
|
- self.w.writeln(" fn exit_current<OutputCallback: FnMut(OutEvent)>(&self, timers: &mut Timers, internal: &mut InternalLifeline, ctrl: &mut Controller<InEvent, OutputCallback>) {")
|
|
|
+ self.w.writeln(" fn exit_current<OutputCallback: FnMut(OutEvent)>(&self, timers: &mut Timers, data: &mut DataModel, internal: &mut InternalLifeline, ctrl: &mut Controller<InEvent, OutputCallback>) {")
|
|
|
# first, children (recursion):
|
|
|
if isinstance(state.type, AndState):
|
|
|
for child in state.real_children:
|
|
|
- self.w.writeln(" self.%s.exit_current(timers, internal, ctrl);" % (ident_field(child)))
|
|
|
+ self.w.writeln(" self.%s.exit_current(timers, data, internal, ctrl);" % (ident_field(child)))
|
|
|
elif isinstance(state.type, OrState):
|
|
|
self.w.writeln(" match self {")
|
|
|
for child in state.real_children:
|
|
|
- self.w.writeln(" Self::%s(s) => { s.exit_current(timers, internal, ctrl); }," % (ident_enum_variant(child)))
|
|
|
+ self.w.writeln(" Self::%s(s) => { s.exit_current(timers, data, internal, ctrl); }," % (ident_enum_variant(child)))
|
|
|
self.w.writeln(" }")
|
|
|
# then, parent:
|
|
|
- self.w.writeln(" %s::exit_actions(timers, internal, ctrl);" % (ident_type(state)))
|
|
|
+ self.w.writeln(" %s::exit_actions(timers, data, internal, ctrl);" % (ident_type(state)))
|
|
|
self.w.writeln(" }")
|
|
|
|
|
|
# Exit current: Executes enter actions of this state and current children, recursively
|
|
|
- # self.w.writeln(" fn enter_current(&self, timers: &mut Timers, internal: &mut InternalLifeline, ctrl: &mut Controller<InEvent, OutputCallback>) {")
|
|
|
- self.w.writeln(" fn enter_current<OutputCallback: FnMut(OutEvent)>(&self, timers: &mut Timers, internal: &mut InternalLifeline, ctrl: &mut Controller<InEvent, OutputCallback>) {")
|
|
|
+ self.w.writeln(" fn enter_current<OutputCallback: FnMut(OutEvent)>(&self, timers: &mut Timers, data: &mut DataModel, internal: &mut InternalLifeline, ctrl: &mut Controller<InEvent, OutputCallback>) {")
|
|
|
# first, parent:
|
|
|
- self.w.writeln(" %s::enter_actions(timers, internal, ctrl);" % (ident_type(state)))
|
|
|
+ self.w.writeln(" %s::enter_actions(timers, data, internal, ctrl);" % (ident_type(state)))
|
|
|
# then, children (recursion):
|
|
|
if isinstance(state.type, AndState):
|
|
|
for child in state.real_children:
|
|
|
- self.w.writeln(" self.%s.enter_current(timers, internal, ctrl);" % (ident_field(child)))
|
|
|
+ self.w.writeln(" self.%s.enter_current(timers, data, internal, ctrl);" % (ident_field(child)))
|
|
|
elif isinstance(state.type, OrState):
|
|
|
self.w.writeln(" match self {")
|
|
|
for child in state.real_children:
|
|
|
- self.w.writeln(" Self::%s(s) => { s.enter_current(timers, internal, ctrl); }," % (ident_enum_variant(child)))
|
|
|
+ self.w.writeln(" Self::%s(s) => { s.enter_current(timers, data, internal, ctrl); }," % (ident_enum_variant(child)))
|
|
|
self.w.writeln(" }")
|
|
|
self.w.writeln(" }")
|
|
|
|
|
@@ -192,6 +185,8 @@ class StatechartRustGenerator(ActionLangRustGenerator):
|
|
|
self.w.writeln()
|
|
|
|
|
|
def visit_Statechart(self, sc):
|
|
|
+ self.scope.push(sc.scope)
|
|
|
+
|
|
|
if sc.semantics.concurrency == Concurrency.MANY:
|
|
|
raise UnsupportedFeature("concurrency")
|
|
|
|
|
@@ -251,9 +246,6 @@ class StatechartRustGenerator(ActionLangRustGenerator):
|
|
|
# self.w.writeln("}")
|
|
|
self.w.writeln()
|
|
|
|
|
|
- # Write state types
|
|
|
- tree.root.accept(self)
|
|
|
-
|
|
|
syntactic_maximality = (
|
|
|
sc.semantics.big_step_maximality == Maximality.SYNTACTIC
|
|
|
or sc.semantics.combo_step_maximality == Maximality.SYNTACTIC)
|
|
@@ -286,38 +278,39 @@ class StatechartRustGenerator(ActionLangRustGenerator):
|
|
|
# self.w.writeln("const ARENA_UNSTABLE: Arenas = false; // inapplicable to chosen semantics - all transition targets considered stable")
|
|
|
self.w.writeln()
|
|
|
|
|
|
- # Write datamodel type
|
|
|
- # sc.scope.accept(self)
|
|
|
- # RustGenerator(w).visit_Scope(sc.scope)
|
|
|
- # self.w.writeln("struct DataModel {")
|
|
|
-
|
|
|
- # self.w.writeln(" ")
|
|
|
- # self.w.writeln(")")
|
|
|
-
|
|
|
# Write statechart type
|
|
|
- self.w.writeln("pub struct Statechart {")
|
|
|
- self.w.writeln(" current_state: %s," % ident_type(tree.root))
|
|
|
- # We always store a history value as 'deep' (also for shallow history).
|
|
|
- # TODO: We may save a tiny bit of space in some rare cases by storing shallow history as only the exited child of the Or-state.
|
|
|
- for h in tree.history_states:
|
|
|
- self.w.writeln(" %s: %s," % (ident_history_field(h), ident_type(h.parent)))
|
|
|
- self.w.writeln(" timers: Timers,")
|
|
|
- self.w.writeln(" data: %s," % self.ident_scope(sc.scope))
|
|
|
- self.w.writeln("}")
|
|
|
-
|
|
|
self.w.writeln("impl Default for Statechart {")
|
|
|
self.w.writeln(" fn default() -> Self {")
|
|
|
+ self.w.writeln(" // Initialize data model")
|
|
|
+ self.w.indent(); self.w.indent();
|
|
|
+ self.w.writeln(" let scope = Empty{};")
|
|
|
+ if sc.datamodel is not None:
|
|
|
+ sc.datamodel.accept(self)
|
|
|
+ datamodel_type = self.scope.commit(sc.scope.size(), self.w)
|
|
|
+ self.w.dedent(); self.w.dedent();
|
|
|
self.w.writeln(" Self {")
|
|
|
self.w.writeln(" current_state: Default::default(),")
|
|
|
for h in tree.history_states:
|
|
|
self.w.writeln(" %s: Default::default()," % (ident_history_field(h)))
|
|
|
self.w.writeln(" timers: Default::default(),")
|
|
|
- self.w.writeln(" data: %s()," % self.ident_new_scope(sc.scope))
|
|
|
+ self.w.writeln(" data: scope,")
|
|
|
self.w.writeln(" }")
|
|
|
self.w.writeln(" }")
|
|
|
self.w.writeln("}")
|
|
|
+ self.w.writeln("type DataModel = %s;" % datamodel_type)
|
|
|
+ self.w.writeln("pub struct Statechart {")
|
|
|
+ self.w.writeln(" current_state: %s," % ident_type(tree.root))
|
|
|
+ # We always store a history value as 'deep' (also for shallow history).
|
|
|
+ # TODO: We may save a tiny bit of space in some rare cases by storing shallow history as only the exited child of the Or-state.
|
|
|
+ for h in tree.history_states:
|
|
|
+ self.w.writeln(" %s: %s," % (ident_history_field(h), ident_type(h.parent)))
|
|
|
+ self.w.writeln(" timers: Timers,")
|
|
|
+ self.w.writeln(" data: DataModel,")
|
|
|
+ self.w.writeln("}")
|
|
|
self.w.writeln()
|
|
|
|
|
|
+ self.write_decls()
|
|
|
+
|
|
|
# Function fair_step: a single "Take One" Maximality 'round' (= nonoverlapping arenas allowed to fire 1 transition)
|
|
|
self.w.writeln("fn fair_step<OutputCallback: FnMut(OutEvent)>(sc: &mut Statechart, input: Option<InEvent>, internal: &mut InternalLifeline, ctrl: &mut Controller<InEvent, OutputCallback>, dirty: Arenas) -> Arenas {")
|
|
|
self.w.writeln(" let mut fired: Arenas = ARENA_NONE;")
|
|
@@ -352,7 +345,7 @@ class StatechartRustGenerator(ActionLangRustGenerator):
|
|
|
|
|
|
if len(exit_path) == 1:
|
|
|
# Exit s:
|
|
|
- self.w.writeln("%s.exit_current(&mut sc.timers, internal, ctrl);" % (ident_var(s)))
|
|
|
+ self.w.writeln("%s.exit_current(&mut sc.timers, &mut sc.data, internal, ctrl);" % (ident_var(s)))
|
|
|
else:
|
|
|
# Exit children:
|
|
|
if isinstance(s.type, AndState):
|
|
@@ -360,12 +353,12 @@ class StatechartRustGenerator(ActionLangRustGenerator):
|
|
|
if exit_path[1] is c:
|
|
|
write_exit(exit_path[1:]) # continue recursively
|
|
|
else:
|
|
|
- self.w.writeln("%s.exit_current(&mut sc.timers, internal, ctrl);" % (ident_var(c)))
|
|
|
+ self.w.writeln("%s.exit_current(&mut sc.timers, &mut sc.data, internal, ctrl);" % (ident_var(c)))
|
|
|
elif isinstance(s.type, OrState):
|
|
|
write_exit(exit_path[1:]) # continue recursively with the next child on the exit path
|
|
|
|
|
|
# Exit s:
|
|
|
- self.w.writeln("%s::exit_actions(&mut sc.timers, internal, ctrl);" % (ident_type(s)))
|
|
|
+ self.w.writeln("%s::exit_actions(&mut sc.timers, &mut sc.data, internal, ctrl);" % (ident_type(s)))
|
|
|
|
|
|
# Store history
|
|
|
if s.deep_history:
|
|
@@ -389,19 +382,19 @@ class StatechartRustGenerator(ActionLangRustGenerator):
|
|
|
if len(enter_path) == 1:
|
|
|
# Target state.
|
|
|
if isinstance(s, HistoryState):
|
|
|
- self.w.writeln("sc.%s.enter_current(&mut sc.timers, internal, ctrl); // Enter actions for history state" %(ident_history_field(s)))
|
|
|
+ self.w.writeln("sc.%s.enter_current(&mut sc.timers, &mut sc.data, internal, ctrl); // Enter actions for history state" %(ident_history_field(s)))
|
|
|
else:
|
|
|
- self.w.writeln("%s::enter_default(&mut sc.timers, internal, ctrl);" % (ident_type(s)))
|
|
|
+ self.w.writeln("%s::enter_default(&mut sc.timers, &mut sc.data, internal, ctrl);" % (ident_type(s)))
|
|
|
else:
|
|
|
# Enter s:
|
|
|
- self.w.writeln("%s::enter_actions(&mut sc.timers, internal, ctrl);" % (ident_type(s)))
|
|
|
+ self.w.writeln("%s::enter_actions(&mut sc.timers, &mut sc.data, internal, ctrl);" % (ident_type(s)))
|
|
|
# Enter children:
|
|
|
if isinstance(s.type, AndState):
|
|
|
for c in s.children:
|
|
|
if enter_path[1] is c:
|
|
|
write_enter(enter_path[1:]) # continue recursively
|
|
|
else:
|
|
|
- self.w.writeln("%s::enter_default(&mut sc.timers, internal, ctrl);" % (ident_type(c)))
|
|
|
+ self.w.writeln("%s::enter_default(&mut sc.timers, &mut sc.data, internal, ctrl);" % (ident_type(c)))
|
|
|
elif isinstance(s.type, OrState):
|
|
|
if len(s.children) > 0:
|
|
|
write_enter(enter_path[1:]) # continue recursively with the next child on the enter path
|
|
@@ -474,6 +467,8 @@ class StatechartRustGenerator(ActionLangRustGenerator):
|
|
|
self.w.writeln("if %s {" % " && ".join(condition))
|
|
|
self.w.indent()
|
|
|
|
|
|
+ self.w.writeln("let parent1 = scope;")
|
|
|
+
|
|
|
if t.guard is not None:
|
|
|
self.w.write("if ")
|
|
|
t.guard.accept(self)
|
|
@@ -641,12 +636,7 @@ class StatechartRustGenerator(ActionLangRustGenerator):
|
|
|
# Implement 'SC' trait
|
|
|
self.w.writeln("impl<OutputCallback: FnMut(OutEvent)> SC<InEvent, Controller<InEvent, OutputCallback>> for Statechart {")
|
|
|
self.w.writeln(" fn init(&mut self, ctrl: &mut Controller<InEvent, OutputCallback>) {")
|
|
|
- if sc.datamodel is not None:
|
|
|
- self.w.indent(); self.w.indent();
|
|
|
- self.w.writeln("let scope = &mut self.data;")
|
|
|
- sc.datamodel.accept(self)
|
|
|
- self.w.dedent(); self.w.dedent();
|
|
|
- self.w.writeln(" %s::enter_default(&mut self.timers, &mut Default::default(), ctrl)" % (ident_type(tree.root)))
|
|
|
+ self.w.writeln(" %s::enter_default(&mut self.timers, &mut self.data, &mut Default::default(), ctrl)" % (ident_type(tree.root)))
|
|
|
self.w.writeln(" }")
|
|
|
self.w.writeln(" fn big_step(&mut self, input: Option<InEvent>, c: &mut Controller<InEvent, OutputCallback>) {")
|
|
|
self.w.writeln(" let mut internal: InternalLifeline = Default::default();")
|
|
@@ -655,10 +645,8 @@ class StatechartRustGenerator(ActionLangRustGenerator):
|
|
|
self.w.writeln("}")
|
|
|
self.w.writeln()
|
|
|
|
|
|
-
|
|
|
- # Write 'instance' scope (and all other scopes, recursively)
|
|
|
- self.write_scopes()
|
|
|
- self.w.writeln()
|
|
|
+ # Write state types
|
|
|
+ tree.root.accept(self)
|
|
|
|
|
|
if DEBUG:
|
|
|
self.w.writeln("use std::mem::size_of;")
|