Explorar el Código

Rust: clean things up

Joeri Exelmans hace 4 años
padre
commit
2c48732f80
Se han modificado 3 ficheros con 88 adiciones y 104 borrados
  1. 42 56
      src/sccd/cd/codegen/sccdlib.rs
  2. 36 39
      src/sccd/statechart/codegen/rust.py
  3. 10 9
      src/sccd/test/codegen/rust.py

+ 42 - 56
src/sccd/cd/codegen/sccdlib.rs

@@ -1,28 +1,28 @@
 use std::collections::BinaryHeap;
 use std::cmp::Ordering;
 
-type Timestamp = usize;
+type Timestamp = u32;
 
 type TimerId = u16;
 
-pub trait State<TimersType, Handle> {
+pub trait State<TimersType, ControllerType> {
   // Execute enter actions of only this state
-  fn enter_actions(timers: &mut TimersType, handle: &mut Handle);
+  fn enter_actions(timers: &mut TimersType, c: &mut ControllerType);
   // Execute exit actions of only this state
-  fn exit_actions(timers: &mut TimersType, handle: &mut Handle);
+  fn exit_actions(timers: &mut TimersType, c: &mut ControllerType);
 
   // Execute enter actions of this state and its 'default' child(ren), recursively
-  fn enter_default(timers: &mut TimersType, handle: &mut Handle);
+  fn enter_default(timers: &mut TimersType, c: &mut ControllerType);
 
   // Execute enter actions as if the configuration recorded in this state is being entered
-  fn enter_current(&self, timers: &mut TimersType, handle: &mut Handle);
+  fn enter_current(&self, timers: &mut TimersType, c: &mut ControllerType);
   // Execute exit actions as if the configuration recorded in this state is being exited
-  fn exit_current(&self, timers: &mut TimersType, handle: &mut Handle);
+  fn exit_current(&self, timers: &mut TimersType, c: &mut ControllerType);
 }
 
-pub trait SC<EventType, Handle> {
-  fn init(&mut self, handle: &mut Handle);
-  fn big_step(&mut self, event: Option<EventType>, handle: &mut Handle);
+pub trait SC<EventType, ControllerType> {
+  fn init(&mut self, c: &mut ControllerType);
+  fn big_step(&mut self, event: Option<EventType>, c: &mut ControllerType);
 }
 
 pub struct Entry<EventType> {
@@ -31,11 +31,6 @@ pub struct Entry<EventType> {
   id: TimerId,
 }
 
-// impl<EventType> Entry<EventType> {
-//   fn new(timestamp: Timestamp, event: EventType) -> Entry<EventType> {
-//     Self{ timestamp, event, removed: false }
-//   }
-// }
 
 // In order to implement Ord, also gotta implement PartialOrd, PartialEq and Eq:
 
@@ -56,7 +51,13 @@ impl<EventType> PartialEq for Entry<EventType> {
 }
 impl<EventType> Eq for Entry<EventType> {}
 
-pub struct Handle<EventType, OutputCallback> {
+#[derive(Debug)]
+pub struct OutEvent {
+  port: &'static str,
+  event: &'static str,
+}
+
+pub struct Controller<EventType, OutputCallback> {
   simtime: Timestamp,
   next_id: TimerId,
   queue: BinaryHeap<Entry<EventType>>,
@@ -64,55 +65,40 @@ pub struct Handle<EventType, OutputCallback> {
   output: OutputCallback,
 }
 
-impl<EventType, OutputCallback> Handle<EventType, OutputCallback> {
-  fn set_timeout(&mut self, delay: Timestamp, event: EventType) -> TimerId {
-    let id = self.next_id;
-    let entry = Entry::<EventType>{ timestamp: self.simtime + delay, event, id };
-    self.queue.push(entry);
-    self.next_id = self.next_id.wrapping_add(1); // increment with overflow
-    return id
-  }
-  fn unset_timeout(&mut self, id: TimerId) {
-    self.removed.push(id);
-  }
-}
-
-pub struct Controller<EventType, OutputCallback, StatechartType: SC<EventType, Handle<EventType, OutputCallback>>> {
-  handle: Handle<EventType, OutputCallback>,
-  statechart: StatechartType,
-}
-
 pub enum Until {
   Timestamp(Timestamp),
   Eternity,
 }
 
-impl<'a, EventType: Copy, OutputCallback: FnMut(&'a str, &'a str), StatechartType: SC<EventType, Handle<EventType, OutputCallback>> + Default>
-Controller<EventType, OutputCallback, StatechartType> {
+impl<EventType: Copy, OutputCallback: FnMut(OutEvent)>
+Controller<EventType, OutputCallback> {
   fn new(output: OutputCallback) -> Self {
     Self {
-      statechart: Default::default(),
-      handle: Handle {
-        simtime: 0,
-        next_id: 0,
-        queue: BinaryHeap::new(),
-        removed: BinaryHeap::new(),
-        output,
-      },
+      simtime: 0,
+      next_id: 0,
+      queue: BinaryHeap::new(),
+      removed: BinaryHeap::new(),
+      output,
     }
   }
-  fn add_input(&mut self, event: EventType) {
-    self.handle.set_timeout(0, event);
-    // self.handle.queue.push(entry);
+  fn set_timeout(&mut self, delay: Timestamp, event: EventType) -> TimerId {
+    let id = self.next_id;
+    let entry = Entry::<EventType>{ timestamp: self.simtime + delay, event, id };
+    self.queue.push(entry);
+    self.next_id = self.next_id.wrapping_add(1); // increment with overflow
+    return id
+  }
+  fn unset_timeout(&mut self, id: TimerId) {
+    self.removed.push(id);
   }
-  fn run_until(&mut self, until: Until) {
+  fn run_until<StatechartType: SC<EventType, Controller<EventType, OutputCallback>>>(&mut self, sc: &mut StatechartType, until: Until) {
     'running: loop {
-      if let Some(entry) = self.handle.queue.peek() {
+      if let Some(entry) = self.queue.peek() {
         // Check if event was removed
-        if let Some(removed) = self.handle.removed.peek() {
+        if let Some(removed) = self.removed.peek() {
           if entry.id == *removed {
-            self.handle.queue.pop();
-            self.handle.removed.pop();
+            self.queue.pop();
+            self.removed.pop();
             continue;
           }
         }
@@ -124,10 +110,10 @@ Controller<EventType, OutputCallback, StatechartType> {
           }
         }
         // OK, handle event
-        self.handle.simtime = entry.timestamp;
-        println!("time is now {}", self.handle.simtime);
-        self.statechart.big_step(Some(entry.event), &mut self.handle);
-        self.handle.queue.pop();
+        self.simtime = entry.timestamp;
+        println!("time is now {}", self.simtime);
+        sc.big_step(Some(entry.event), self);
+        self.queue.pop();
       }
       else {
         break 'running;

+ 36 - 39
src/sccd/statechart/codegen/rust.py

@@ -62,14 +62,11 @@ def ident_event(event_name: str) -> str:
     else:
         return "Event_" + event_name
 
-# Name of the output callback parameter, everywhere
-IDENT_HANDLE = "_handle" # underscore to keep Rust from warning us for unused variable
-
 def compile_actions(actions: List[Action], w: IndentingWriter):
     for a in actions:
         if isinstance(a, RaiseOutputEvent):
             # TODO: evaluate event parameters
-            w.writeln("(%s.output)(\"%s\", \"%s\");" % (IDENT_HANDLE, a.outport, a.name))
+            w.writeln("(ctrl.output)(OutEvent{port:\"%s\", event:\"%s\"});" % (a.outport, a.name))
         else:
             raise UnsupportedFeature(str(type(a)))
 
@@ -147,61 +144,61 @@ def compile_statechart(sc: Statechart, globals: Globals, w: IndentingWriter):
     # Write "enter/exit state" functions
 
     def write_enter_exit(state: State, children: List[State]):
-        w.writeln("impl<'a, OutputCallback: FnMut(&'a str, &'a str)> State<Timers, Handle<Event, OutputCallback>> for %s {" % ident_type(state))
-        # w.writeln("impl<'a, OutputCallback: FnMut(&'a str, &'a str)> State<Handle<Event, OutputCallback>> for %s {" % ident_type(state))
+        w.writeln("impl<'a, OutputCallback: FnMut(OutEvent)> State<Timers, Controller<Event, OutputCallback>> for %s {" % ident_type(state))
+        # w.writeln("impl<OutputCallback: FnMut(OutEvent)> State<Handle<Controller<Event, OutputCallback>>> for %s {" % ident_type(state))
 
-        w.writeln("  fn enter_actions(timers: &mut Timers, %s: &mut Handle<Event, OutputCallback>) {" % IDENT_HANDLE)
+        w.writeln("  fn enter_actions(timers: &mut Timers, ctrl: &mut Controller<Event, OutputCallback>) {")
         w.writeln("    println!(\"enter %s\");" % state.full_name);
         w.indent(); w.indent()
         compile_actions(state.enter, w)
         w.dedent(); w.dedent()
         for a in state.after_triggers:
-            w.writeln("    timers[%d] = %s.set_timeout(%d, Event::%s);" % (a.after_id, IDENT_HANDLE, a.delay.opt, ident_event(a.enabling[0].name)))
+            w.writeln("    timers[%d] = ctrl.set_timeout(%d, Event::%s);" % (a.after_id, a.delay.opt, ident_event(a.enabling[0].name)))
         w.writeln("  }")
 
-        w.writeln("  fn exit_actions(timers: &mut Timers, %s: &mut Handle<Event, OutputCallback>) {" % IDENT_HANDLE)
+        w.writeln("  fn exit_actions(timers: &mut Timers, ctrl: &mut Controller<Event, OutputCallback>) {")
         w.writeln("    println!(\"exit %s\");" % state.full_name);
         for a in state.after_triggers:
-            w.writeln("    %s.unset_timeout(timers[%d]);" % (IDENT_HANDLE, a.after_id))
+            w.writeln("    ctrl.unset_timeout(timers[%d]);" % (a.after_id))
         w.indent(); w.indent()
         compile_actions(state.exit, w)
         w.dedent(); w.dedent()
         w.writeln("  }")
 
-        w.writeln("  fn enter_default(timers: &mut Timers, %s: &mut Handle<Event, OutputCallback>) {" % IDENT_HANDLE)
-        w.writeln("    %s::enter_actions(timers, %s);" % (ident_type(state), IDENT_HANDLE))
+        w.writeln("  fn enter_default(timers: &mut Timers, ctrl: &mut Controller<Event, OutputCallback>) {")
+        w.writeln("    %s::enter_actions(timers, ctrl);" % (ident_type(state)))
         if isinstance(state.type, AndState):
             for child in children:
-                w.writeln("    %s::enter_default(timers, %s);" % (ident_type(child), IDENT_HANDLE))
+                w.writeln("    %s::enter_default(timers, ctrl);" % (ident_type(child)))
         elif isinstance(state.type, OrState):
-            w.writeln("    %s::enter_default(timers, %s);" % (ident_type(state.type.default_state), IDENT_HANDLE))
+            w.writeln("    %s::enter_default(timers, ctrl);" % (ident_type(state.type.default_state)))
         w.writeln("  }")
 
-        w.writeln("  fn exit_current(&self, timers: &mut Timers, %s: &mut Handle<Event, OutputCallback>) {" % IDENT_HANDLE)
+        w.writeln("  fn exit_current(&self, timers: &mut Timers, ctrl: &mut Controller<Event, OutputCallback>) {")
         # Children's exit actions
         if isinstance(state.type, AndState):
             for child in children:
-                w.writeln("    self.%s.exit_current(timers, %s);" % (ident_field(child), IDENT_HANDLE))
+                w.writeln("    self.%s.exit_current(timers, ctrl);" % (ident_field(child)))
         elif isinstance(state.type, OrState):
             w.writeln("    match self {")
             for child in children:
-                w.writeln("      Self::%s(s) => { s.exit_current(timers, %s); }," % (ident_enum_variant(child), IDENT_HANDLE))
+                w.writeln("      Self::%s(s) => { s.exit_current(timers, ctrl); }," % (ident_enum_variant(child)))
             w.writeln("    }")
         # Our own exit actions
-        w.writeln("    %s::exit_actions(timers, %s);" % (ident_type(state), IDENT_HANDLE))
+        w.writeln("    %s::exit_actions(timers, ctrl);" % (ident_type(state)))
         w.writeln("  }")
 
-        w.writeln("  fn enter_current(&self, timers: &mut Timers, %s: &mut Handle<Event, OutputCallback>) {" % IDENT_HANDLE)
+        w.writeln("  fn enter_current(&self, timers: &mut Timers, ctrl: &mut Controller<Event, OutputCallback>) {")
         # Children's enter actions
-        w.writeln("    %s::enter_actions(timers, %s);" % (ident_type(state), IDENT_HANDLE))
+        w.writeln("    %s::enter_actions(timers, ctrl);" % (ident_type(state)))
         # Our own enter actions
         if isinstance(state.type, AndState):
             for child in children:
-                w.writeln("    self.%s.enter_current(timers, %s);" % (ident_field(child), IDENT_HANDLE))
+                w.writeln("    self.%s.enter_current(timers, ctrl);" % (ident_field(child)))
         elif isinstance(state.type, OrState):
             w.writeln("    match self {")
             for child in children:
-                w.writeln("      Self::%s(s) => { s.enter_current(timers, %s); }," % (ident_enum_variant(child), IDENT_HANDLE))
+                w.writeln("      Self::%s(s) => { s.enter_current(timers, ctrl); }," % (ident_enum_variant(child)))
             w.writeln("    }")
         w.writeln("  }")
 
@@ -267,7 +264,7 @@ def compile_statechart(sc: Statechart, globals: Globals, w: IndentingWriter):
 
 
     # Function fair_step: a single "Take One" Maximality 'round' (= nonoverlapping arenas allowed to fire 1 transition)
-    w.writeln("fn fair_step<'a, OutputCallback: FnMut(&'a str, &'a str)>(sc: &mut Statechart, _event: Option<Event>, %s: &mut Handle<Event, OutputCallback>, dirty: Arenas) -> Arenas {" % IDENT_HANDLE)
+    w.writeln("fn fair_step<OutputCallback: FnMut(OutEvent)>(sc: &mut Statechart, _event: Option<Event>, ctrl: &mut Controller<Event, OutputCallback>, dirty: Arenas) -> Arenas {")
     w.writeln("  #![allow(non_snake_case)]")
     w.writeln("  #![allow(unused_labels)]")
     w.writeln("  #![allow(unused_variables)]")
@@ -306,7 +303,7 @@ def compile_statechart(sc: Statechart, globals: Globals, w: IndentingWriter):
 
                 if len(exit_path) == 1:
                     # Exit s:
-                    w.writeln("%s.exit_current(&mut sc.timers, %s);" % (ident_var(s), IDENT_HANDLE))
+                    w.writeln("%s.exit_current(&mut sc.timers, ctrl);" % (ident_var(s)))
                 else:
                     # Exit children:
                     if isinstance(s.type, AndState):
@@ -314,12 +311,12 @@ def compile_statechart(sc: Statechart, globals: Globals, w: IndentingWriter):
                             if exit_path[1] is c:
                                 write_exit(exit_path[1:]) # continue recursively
                             else:
-                                w.writeln("%s.exit_current(&mut sc.timers, %s);" % (ident_var(c), IDENT_HANDLE))
+                                w.writeln("%s.exit_current(&mut sc.timers, 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:
-                    w.writeln("%s::exit_actions(&mut sc.timers, %s);" % (ident_type(s), IDENT_HANDLE))
+                    w.writeln("%s::exit_actions(&mut sc.timers, ctrl);" % (ident_type(s)))
 
                 # Store history
                 if s.deep_history:
@@ -343,19 +340,19 @@ def compile_statechart(sc: Statechart, globals: Globals, w: IndentingWriter):
                 if len(enter_path) == 1:
                     # Target state.
                     if isinstance(s, HistoryState):
-                        w.writeln("sc.%s.enter_current(&mut sc.timers, %s); // Enter actions for history state" %(ident_history_field(s), IDENT_HANDLE))
+                        w.writeln("sc.%s.enter_current(&mut sc.timers, ctrl); // Enter actions for history state" %(ident_history_field(s)))
                     else:
-                        w.writeln("%s::enter_default(&mut sc.timers, %s);" % (ident_type(s), IDENT_HANDLE))
+                        w.writeln("%s::enter_default(&mut sc.timers, ctrl);" % (ident_type(s)))
                 else:
                     # Enter s:
-                    w.writeln("%s::enter_actions(&mut sc.timers, %s);" % (ident_type(s), IDENT_HANDLE))
+                    w.writeln("%s::enter_actions(&mut sc.timers, 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:
-                                w.writeln("%s::enter_default(&mut sc.timers, %s);" % (ident_type(c), IDENT_HANDLE))
+                                w.writeln("%s::enter_default(&mut sc.timers, 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
@@ -508,21 +505,21 @@ def compile_statechart(sc: Statechart, globals: Globals, w: IndentingWriter):
     w.writeln("}")
 
     def write_stepping_function(name: str, title: str, maximality: Maximality, substep: str, input_whole: bool):
-        w.write("fn %s<'a, OutputCallback: FnMut(&'a str, &'a str)>(sc: &mut Statechart, event: Option<Event>, %s: &mut Handle<Event, OutputCallback>, dirty: Arenas)" % (name, IDENT_HANDLE))
+        w.write("fn %s<OutputCallback: FnMut(OutEvent)>(sc: &mut Statechart, event: Option<Event>, ctrl: &mut Controller<Event, OutputCallback>, dirty: Arenas)" % (name))
         w.writeln(" -> Arenas {")
         if maximality == Maximality.TAKE_ONE:
             w.writeln("  // %s Maximality: Take One" % title)
-            w.writeln("  %s(sc, event, %s, dirty)" % (substep, IDENT_HANDLE))
+            w.writeln("  %s(sc, event, ctrl, dirty)" % (substep))
         else:
             w.writeln("  let mut fired: Arenas = dirty;")
             w.writeln("  let mut e = event;")
             w.writeln("  loop {")
             if maximality == Maximality.TAKE_MANY:
                 w.writeln("    // %s Maximality: Take Many" % title)
-                w.writeln("    let just_fired = %s(sc, e, %s, 0);" % (substep, IDENT_HANDLE))
+                w.writeln("    let just_fired = %s(sc, e, ctrl, 0);" % (substep))
             elif maximality == Maximality.SYNTACTIC:
                 w.writeln("    // %s Maximality: Syntactic" % title)
-                w.writeln("    let just_fired = %s(sc, e, %s, fired);" % (substep, IDENT_HANDLE))
+                w.writeln("    let just_fired = %s(sc, e, ctrl, fired);" % (substep))
             w.writeln("    if just_fired == 0 {")
             w.writeln("      break;")
             w.writeln("    }")
@@ -548,12 +545,12 @@ def compile_statechart(sc: Statechart, globals: Globals, w: IndentingWriter):
     w.writeln()
 
     # Implement 'SC' trait
-    w.writeln("impl<'a, OutputCallback: FnMut(&'a str, &'a str)> SC<Event, Handle<Event, OutputCallback>> for Statechart {")
-    w.writeln("  fn init(&mut self, %s: &mut Handle<Event, OutputCallback>) {" % IDENT_HANDLE)
-    w.writeln("    %s::enter_default(&mut self.timers, %s)" % (ident_type(tree.root), IDENT_HANDLE))
+    w.writeln("impl<OutputCallback: FnMut(OutEvent)> SC<Event, Controller<Event, OutputCallback>> for Statechart {")
+    w.writeln("  fn init(&mut self, ctrl: &mut Controller<Event, OutputCallback>) {")
+    w.writeln("    %s::enter_default(&mut self.timers, ctrl)" % (ident_type(tree.root)))
     w.writeln("  }")
-    w.writeln("  fn big_step(&mut self, event: Option<Event>, output: &mut Handle<Event, OutputCallback>) {")
-    w.writeln("    big_step(self, event, output, 0);")
+    w.writeln("  fn big_step(&mut self, event: Option<Event>, c: &mut Controller<Event, OutputCallback>) {")
+    w.writeln("    big_step(self, event, c, 0);")
     w.writeln("  }")
     w.writeln("}")
     w.writeln()

+ 10 - 9
src/sccd/test/codegen/rust.py

@@ -24,25 +24,26 @@ def compile_test(variants: List[TestVariant], w: IndentingWriter):
 
     for n, v in enumerate(variants):
         w.writeln("// Test variant %d" % n)
-        w.writeln("let mut raised = Vec::<&str>::new();")
-        w.writeln("let mut output = |port, event| {")
-        w.writeln("  println!(\"^{}:{}\", port, event);")
-        w.writeln("  raised.push(event);")
+        w.writeln("let mut raised = Vec::<OutEvent>::new();")
+        w.writeln("let mut output = |out: OutEvent| {")
+        w.writeln("  println!(\"^{}:{}\", out.port, out.event);")
+        w.writeln("  raised.push(out);")
         w.writeln("};")
-        w.writeln("let mut controller = Controller::<_,_,Statechart>::new(output);")
-        w.writeln("controller.statechart.init(&mut controller.handle);")
+        w.writeln("let mut controller = Controller::<Event,_>::new(&mut output);")
+        w.writeln("let mut sc: Statechart = Default::default();")
+        w.writeln("sc.init(&mut controller);")
         for i in v.input:
             if len(i.events) > 1:
                 raise Exception("Multiple simultaneous input events not supported")
             elif len(i.events) == 0:
                 raise Exception("Test declares empty bag of input events - not supported")
-            w.writeln("controller.handle.set_timeout(%d, Event::%s);" % (i.timestamp.opt, ident_event(i.events[0].name)))
+            w.writeln("controller.set_timeout(%d, Event::%s);" % (i.timestamp.opt, ident_event(i.events[0].name)))
 
-        w.writeln("controller.run_until(Until::Eternity);")
+        w.writeln("controller.run_until(&mut sc, Until::Eternity);")
         ctr = 0
         for o in v.output:
             for e in o:
-                w.writeln("  assert!(raised[%d] == \"%s\", format!(\"\nExpected: %s\nGot: {:#?}\", raised));" % (ctr, e.name, v.output))
+                w.writeln("  assert!(raised[%d].event == \"%s\", format!(\"\nExpected: %s\nGot: {:#?}\", raised));" % (ctr, e.name, v.output))
                 ctr += 1
         w.writeln("println!(\"Test variant %d passed\");" % n)