Parcourir la source

Rust codegen: Add event triggers

Joeri Exelmans il y a 5 ans
Parent
commit
7e2ef246da
2 fichiers modifiés avec 30 ajouts et 13 suppressions
  1. 28 11
      src/sccd/statechart/codegen/rust.py
  2. 2 2
      src/sccd/statechart/static/tree.py

+ 28 - 11
src/sccd/statechart/codegen/rust.py

@@ -207,8 +207,8 @@ def compile_to_rust(sc: Statechart, globals: Globals):
             print(' '*self.spaces + str)
 
     print("impl Statechart {")
-    print("  fn big_step(&mut self) {")
-    print("    println!(\"big step\");")
+    print("  fn fair_step(&mut self, event: Option<Event>) {")
+    print("    println!(\"fair step\");")
     print("    let %s = &mut self.current_state;" % ident_var(tree.root))
 
     w = IndentingWriter(4)
@@ -274,6 +274,7 @@ def compile_to_rust(sc: Statechart, globals: Globals):
                             # The parser should have rejected the model before we even get here
                             raise Exception("Basic state in the middle of enter path")
 
+        # Comment of 'write_exit' applies here as well
         def write_enter(enter_path: List[State]):
             if len(enter_path) > 0:
                 s = enter_path[0]
@@ -301,7 +302,14 @@ def compile_to_rust(sc: Statechart, globals: Globals):
         def parent():
             for t in state.transitions:
                 w.print("// Outgoing transition")
-                # TODO: optimize: static calculation for Or-state ancestors of transition's source
+
+                if t.trigger is not EMPTY_TRIGGER:
+                    if len(t.trigger.enabling) > 1:
+                        raise Exception("Multi-event triggers currently unsupported")
+                    w.print("if let Some(Event::%s) = event {" % t.trigger.enabling[0].name)
+                    w.indent()
+
+                # 1. Execute transition's actions
 
                 # Path from arena to source, including source but not including arena
                 exit_path_bm = t.opt.arena.opt.descendants & (t.source.opt.state_id_bitmap | t.source.opt.ancestors) # bitmap
@@ -311,22 +319,31 @@ def compile_to_rust(sc: Statechart, globals: Globals):
                 enter_path_bm = t.opt.arena.opt.descendants & (t.target.opt.state_id_bitmap | t.target.opt.ancestors) # bitmap
                 enter_path = list(tree.bitmap_to_states(enter_path_bm)) # list of states
 
-                w.print("// Exit states")
+                w.print("// Exit actions")
                 write_exit(exit_path)
 
-                w.print("// TODO: execute transition's actions here")
+                w.print("// Transition's actions")
                 w.print("println!(\"%s\");" % str(t))
 
-                w.print("// Construct new states")
-                write_new_configuration([t.opt.arena] + enter_path)
-
-                w.print("// Enter states")
+                w.print("// Enter actions")
                 write_enter(enter_path)
 
+                # 2. Update state
+
+                # A state configuration is just a value
+                w.print("// Build new state configuration")
+                write_new_configuration([t.opt.arena] + enter_path)
+
                 w.print("// Update arena configuration")
                 w.print("*%s = new_%s;" % (ident_var(t.opt.arena), ident_var(t.opt.arena)))
+
+                # This arena is done:
                 w.print("break '%s;" % (ident_arena_label(t.opt.arena)))
 
+                if t.trigger is not EMPTY_TRIGGER:
+                    w.dedent()
+                    w.print("}")
+
         def child():
             if isinstance(state, ParallelState):
                 for child in state.children:
@@ -368,8 +385,8 @@ def compile_to_rust(sc: Statechart, globals: Globals):
     print("fn main() {")
     print("  let mut sc = Statechart{current_state: Default::default()};")
     print("  Root::enter_default();")
-    print("  sc.big_step();")
-    print("  sc.big_step();")
+    print("  sc.fair_step(None);")
+    print("  sc.fair_step(None);")
     # print("  sc.current_state.exit();")
     print("}")
     print()

+ 2 - 2
src/sccd/statechart/static/tree.py

@@ -169,7 +169,7 @@ class AfterTrigger(Trigger):
     def copy_params_to_stack(self, events: List[InternalEvent], memory: MemoryInterface):
         pass
 
-_empty_trigger = Trigger(enabling=[])
+EMPTY_TRIGGER = Trigger(enabling=[])
 
 class Transition(Freezable):
     __slots__ = ["source", "target", "scope", "target_string", "guard", "actions", "trigger", "opt"]
@@ -185,7 +185,7 @@ class Transition(Freezable):
 
         self.guard: Optional[Expression] = None
         self.actions: List[Action] = []
-        self.trigger: Trigger = _empty_trigger
+        self.trigger: Trigger = EMPTY_TRIGGER
 
         # Statically computed stuff from tree structure:
         self.opt: Optional['TransitionStatic'] = None