Explorar o código

Rust: Add support for timers

Joeri Exelmans %!s(int64=4) %!d(string=hai) anos
pai
achega
8d95f7753b

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 2 - 2
notes.txt


+ 76 - 39
src/sccd/cd/codegen/sccdlib.rs

@@ -1,33 +1,42 @@
 use std::collections::BinaryHeap;
-use std::collections::binary_heap::PeekMut;
 use std::cmp::Ordering;
 
-type Timestamp = usize; // unsigned integer, platform's word size
+type Timestamp = usize;
 
-pub trait State<OutputCallback> {
+type TimerId = usize;
+
+pub trait State<TimersType, Handle> {
   // Execute enter actions of only this state
-  fn enter_actions(output: &mut OutputCallback);
+  fn enter_actions(timers: &mut TimersType, handle: &mut Handle);
   // Execute exit actions of only this state
-  fn exit_actions(output: &mut OutputCallback);
+  fn exit_actions(timers: &mut TimersType, handle: &mut Handle);
+
   // Execute enter actions of this state and its 'default' child(ren), recursively
-  fn enter_default(output: &mut OutputCallback);
+  fn enter_default(timers: &mut TimersType, handle: &mut Handle);
 
   // Execute enter actions as if the configuration recorded in this state is being entered
-  fn enter_current(&self, output: &mut OutputCallback);
+  fn enter_current(&self, timers: &mut TimersType, handle: &mut Handle);
   // Execute exit actions as if the configuration recorded in this state is being exited
-  fn exit_current(&self, output: &mut OutputCallback);
+  fn exit_current(&self, timers: &mut TimersType, handle: &mut Handle);
 }
 
-pub trait SC<EventType, OutputCallback> {
-  fn init(output: &mut OutputCallback);
-  fn big_step(&mut self, event: Option<EventType>, output: &mut OutputCallback);
+pub trait SC<EventType, Handle> {
+  fn init(&mut self, handle: &mut Handle);
+  fn big_step(&mut self, event: Option<EventType>, handle: &mut Handle);
 }
 
 pub struct Entry<EventType> {
   timestamp: Timestamp,
   event: 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:
 
 impl<EventType> Ord for Entry<EventType> {
@@ -47,12 +56,30 @@ impl<EventType> PartialEq for Entry<EventType> {
 }
 impl<EventType> Eq for Entry<EventType> {}
 
+pub struct Handle<EventType, OutputCallback> {
+  simtime: Timestamp,
+  next_id: TimerId,
+  queue: BinaryHeap<Entry<EventType>>,
+  removed: BinaryHeap<TimerId>,
+  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, OutputCallback>> {
+pub struct Controller<EventType, OutputCallback, StatechartType: SC<EventType, Handle<EventType, OutputCallback>>> {
+  handle: Handle<EventType, OutputCallback>,
   statechart: StatechartType,
-  output: OutputCallback,
-  queue: BinaryHeap<Entry<EventType>>,
-  simtime: Timestamp,
 }
 
 pub enum Until {
@@ -60,40 +87,50 @@ pub enum Until {
   Eternity,
 }
 
-impl<'a, EventType: Copy, OutputCallback: FnMut(&'a str, &'a str), StatechartType: SC<EventType, OutputCallback> + Default>
+impl<'a, EventType: Copy, OutputCallback: FnMut(&'a str, &'a str), StatechartType: SC<EventType, Handle<EventType, OutputCallback>> + Default>
 Controller<EventType, OutputCallback, StatechartType> {
   fn new(output: OutputCallback) -> Self {
     Self {
       statechart: Default::default(),
-      output,
-      queue: BinaryHeap::new(),
-      simtime: 0,
+      handle: Handle {
+        simtime: 0,
+        next_id: 0,
+        queue: BinaryHeap::new(),
+        removed: BinaryHeap::new(),
+        output,
+      },
     }
   }
-  fn add_input(&mut self, entry: Entry<EventType>) {
-    self.queue.push(entry);
+  fn add_input(&mut self, event: EventType) {
+    self.handle.set_timeout(0, event);
+    // self.handle.queue.push(entry);
   }
   fn run_until(&mut self, until: Until) {
     'running: loop {
-      match self.queue.peek_mut() {
-        Some(entry) => {
-          if let Until::Timestamp(t) = until {
-            if entry.timestamp > t {
-              println!("break, timestamp {}, t {}", entry.timestamp, t);
-              break 'running;
-            }
+      if let Some(entry) = self.handle.queue.peek() {
+        // Check if event was removed
+        if let Some(removed) = self.handle.removed.peek() {
+          if entry.id == *removed {
+            self.handle.queue.pop();
+            self.handle.removed.pop();
+            continue;
           }
-
-          self.simtime = entry.timestamp;
-          println!("time is now {}", self.simtime);
-
-          let e = entry.event; // copy
-
-          self.statechart.big_step(Some(e), &mut self.output);
-
-          PeekMut::pop(entry);
-        },
-        None => { break 'running; },
+        }
+        // Check if event too far in the future
+        if let Until::Timestamp(t) = until {
+          if entry.timestamp > t {
+            println!("break, timestamp {}, t {}", entry.timestamp, t);
+            break 'running;
+          }
+        }
+        // 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();
+      }
+      else {
+        break 'running;
       }
     }
   }

+ 51 - 52
src/sccd/statechart/codegen/rust.py

@@ -55,14 +55,21 @@ def ident_arena_const(state: State) -> str:
 def ident_history_field(state: HistoryState) -> str:
     return "history" + snake_case(state.parent) # A history state records history value for its parent
 
+def ident_event(event_name: str) -> str:
+    if event_name[0] == '+':
+        # after event
+        return "After" + event_name.replace('+', '')
+    else:
+        return "Event_" + event_name
+
 # Name of the output callback parameter, everywhere
-IDENT_OC = "_output" # underscore to keep Rust from warning us for unused variable
+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(\"%s\", \"%s\");" % (IDENT_OC, a.outport, a.name))
+            w.writeln("(%s.output)(\"%s\", \"%s\");" % (IDENT_HANDLE, a.outport, a.name))
         else:
             raise UnsupportedFeature(str(type(a)))
 
@@ -83,6 +90,8 @@ def compile_statechart(sc: Statechart, globals: Globals, w: IndentingWriter):
     # (these naming collisions would be detected by the Rust compiler, so the error would not go unnoticed,
     # still, it's better to NOT break our model :)
 
+    w.writeln("type Timers = [TimerId; %d];" % tree.timer_count)
+    w.writeln()
 
     # Write 'current state' types
 
@@ -138,56 +147,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<OutputCallback> for %s {" % ident_type(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("  fn enter_actions(%s: &mut OutputCallback) {" % IDENT_OC)
+        w.writeln("  fn enter_actions(timers: &mut Timers, %s: &mut Handle<Event, OutputCallback>) {" % IDENT_HANDLE)
         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("  }")
 
-        w.writeln("  fn exit_actions(%s: &mut OutputCallback) {" % IDENT_OC)
+        w.writeln("  fn exit_actions(timers: &mut Timers, %s: &mut Handle<Event, OutputCallback>) {" % IDENT_HANDLE)
         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.indent(); w.indent()
         compile_actions(state.exit, w)
         w.dedent(); w.dedent()
         w.writeln("  }")
 
-        w.writeln("  fn enter_default(%s: &mut OutputCallback) {" % IDENT_OC)
-        w.writeln("    %s::enter_actions(%s);" % (ident_type(state), IDENT_OC))
+        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))
         if isinstance(state.type, AndState):
             for child in children:
-                w.writeln("    %s::enter_default(%s);" % (ident_type(child), IDENT_OC))
+                w.writeln("    %s::enter_default(timers, %s);" % (ident_type(child), IDENT_HANDLE))
         elif isinstance(state.type, OrState):
-            w.writeln("    %s::enter_default(%s);" % (ident_type(state.type.default_state), IDENT_OC))
+            w.writeln("    %s::enter_default(timers, %s);" % (ident_type(state.type.default_state), IDENT_HANDLE))
         w.writeln("  }")
 
-        w.writeln("  fn exit_current(&self, %s: &mut OutputCallback) {" % IDENT_OC)
+        w.writeln("  fn exit_current(&self, timers: &mut Timers, %s: &mut Handle<Event, OutputCallback>) {" % IDENT_HANDLE)
         # Children's exit actions
         if isinstance(state.type, AndState):
             for child in children:
-                w.writeln("    self.%s.exit_current(%s);" % (ident_field(child), IDENT_OC))
+                w.writeln("    self.%s.exit_current(timers, %s);" % (ident_field(child), IDENT_HANDLE))
         elif isinstance(state.type, OrState):
             w.writeln("    match self {")
             for child in children:
-                w.writeln("      Self::%s(s) => { s.exit_current(%s); }," % (ident_enum_variant(child), IDENT_OC))
+                w.writeln("      Self::%s(s) => { s.exit_current(timers, %s); }," % (ident_enum_variant(child), IDENT_HANDLE))
             w.writeln("    }")
         # Our own exit actions
-        w.writeln("    %s::exit_actions(%s);" % (ident_type(state), IDENT_OC))
+        w.writeln("    %s::exit_actions(timers, %s);" % (ident_type(state), IDENT_HANDLE))
         w.writeln("  }")
 
-        w.writeln("  fn enter_current(&self, %s: &mut OutputCallback) {" % IDENT_OC)
+        w.writeln("  fn enter_current(&self, timers: &mut Timers, %s: &mut Handle<Event, OutputCallback>) {" % IDENT_HANDLE)
         # Children's enter actions
-        w.writeln("    %s::enter_actions(%s);" % (ident_type(state), IDENT_OC))
+        w.writeln("    %s::enter_actions(timers, %s);" % (ident_type(state), IDENT_HANDLE))
         # Our own enter actions
         if isinstance(state.type, AndState):
             for child in children:
-                w.writeln("    self.%s.enter_current(%s);" % (ident_field(child), IDENT_OC))
+                w.writeln("    self.%s.enter_current(timers, %s);" % (ident_field(child), IDENT_HANDLE))
         elif isinstance(state.type, OrState):
             w.writeln("    match self {")
             for child in children:
-                w.writeln("      Self::%s(s) => { s.enter_current(%s); }," % (ident_enum_variant(child), IDENT_OC))
+                w.writeln("      Self::%s(s) => { s.enter_current(timers, %s); }," % (ident_enum_variant(child), IDENT_HANDLE))
             w.writeln("    }")
         w.writeln("  }")
 
@@ -208,7 +222,7 @@ def compile_statechart(sc: Statechart, globals: Globals, w: IndentingWriter):
     w.writeln("#[derive(Copy, Clone)]")
     w.writeln("enum Event {")
     for event_name in (globals.events.names[i] for i in bm_items(sc.internal_events)):
-        w.writeln("  %s," % event_name)
+        w.writeln("  %s," % ident_event(event_name))
     w.writeln("}")
     w.writeln()
 
@@ -235,7 +249,7 @@ def compile_statechart(sc: Statechart, globals: Globals, w: IndentingWriter):
     w.writeln("  current_state: %s," % ident_type(tree.root))
     for h in tree.history_states:
         w.writeln("  %s: %s," % (ident_history_field(h), ident_type(h.parent)))
-    w.writeln("  // TODO: timers")
+    w.writeln("  timers: Timers,")
     w.writeln("}")
     w.writeln()
 
@@ -245,7 +259,7 @@ def compile_statechart(sc: Statechart, globals: Globals, w: IndentingWriter):
     w.writeln("      current_state: Default::default(),")
     for h in tree.history_states:
         w.writeln("      %s: Default::default()," % (ident_history_field(h)))
-    # w.writeln("      timers: Default::default(),")
+    w.writeln("      timers: Default::default(),")
     w.writeln("    }")
     w.writeln("  }")
     w.writeln("}")
@@ -253,11 +267,10 @@ 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 OutputCallback, dirty: Arenas) -> Arenas {" % IDENT_OC)
+    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("  #![allow(non_snake_case)]")
     w.writeln("  #![allow(unused_labels)]")
     w.writeln("  #![allow(unused_variables)]")
-    w.writeln("  println!(\"fair step, dirty={}\", dirty);")
     w.writeln("  let mut fired: Arenas = 0;")
     w.writeln("  let %s = &mut sc.current_state;" % ident_var(tree.root))
     w.indent()
@@ -288,13 +301,12 @@ def compile_statechart(sc: Statechart, globals: Globals, w: IndentingWriter):
         # Writes statements that perform exit actions
         # in the correct order (children (last to first), then parent) for given 'exit path'.
         def write_exit(exit_path: List[State]):
-            # w.writeln("println!(\"exit path = %s\");" % str(exit_path).replace('"', "'"))
             if len(exit_path) > 0:
                 s = exit_path[0] # state to exit
 
                 if len(exit_path) == 1:
                     # Exit s:
-                    w.writeln("%s.exit_current(%s);" % (ident_var(s), IDENT_OC))
+                    w.writeln("%s.exit_current(&mut sc.timers, %s);" % (ident_var(s), IDENT_HANDLE))
                 else:
                     # Exit children:
                     if isinstance(s.type, AndState):
@@ -302,12 +314,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(%s);" % (ident_var(c), IDENT_OC))
+                                w.writeln("%s.exit_current(&mut sc.timers, %s);" % (ident_var(c), IDENT_HANDLE))
                     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(%s);" % (ident_type(s), IDENT_OC))
+                    w.writeln("%s::exit_actions(&mut sc.timers, %s);" % (ident_type(s), IDENT_HANDLE))
 
                 # Store history
                 if s.deep_history:
@@ -322,7 +334,6 @@ def compile_statechart(sc: Statechart, globals: Globals, w: IndentingWriter):
                     for c in s.real_children:
                         w.writeln("  %s::%s(_) => %s::%s(%s::default())," % (ident_type(s), ident_enum_variant(c), ident_type(s), ident_enum_variant(c), ident_type(c)))
                     w.writeln("};")
-                    # w.writeln("println!(\"recorded history\");")
 
         # Writes statements that perform enter actions
         # in the correct order (parent, children (first to last)) for given 'enter path'.
@@ -332,19 +343,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(%s); // Enter actions for history state" %(ident_history_field(s), IDENT_OC))
+                        w.writeln("sc.%s.enter_current(&mut sc.timers, %s); // Enter actions for history state" %(ident_history_field(s), IDENT_HANDLE))
                     else:
-                        w.writeln("%s::enter_default(%s);" % (ident_type(s), IDENT_OC))
+                        w.writeln("%s::enter_default(&mut sc.timers, %s);" % (ident_type(s), IDENT_HANDLE))
                 else:
                     # Enter s:
-                    w.writeln("%s::enter_actions(%s);" % (ident_type(s), IDENT_OC))
+                    w.writeln("%s::enter_actions(&mut sc.timers, %s);" % (ident_type(s), IDENT_HANDLE))
                     # 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(%s);" % (ident_type(c), IDENT_OC))
+                                w.writeln("%s::enter_default(&mut sc.timers, %s);" % (ident_type(c), IDENT_HANDLE))
                     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
@@ -394,7 +405,7 @@ def compile_statechart(sc: Statechart, globals: Globals, w: IndentingWriter):
                 if t.trigger is not EMPTY_TRIGGER:
                     if len(t.trigger.enabling) > 1:
                         raise UnsupportedFeature("Multi-event trigger")
-                    w.writeln("if let Some(Event::%s) = _event {" % t.trigger.enabling[0].name)
+                    w.writeln("if let Some(Event::%s) = _event {" % ident_event(t.trigger.enabling[0].name))
                     w.indent()
 
                 if t.guard is not None:
@@ -493,45 +504,33 @@ def compile_statechart(sc: Statechart, globals: Globals, w: IndentingWriter):
 
     w.dedent()
 
-    w.writeln("  println!(\"end fair step, fired={}\", fired);")
     w.writeln("  fired")
     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 OutputCallback, dirty: Arenas)" % (name, IDENT_OC))
-        # if return_arenas:
+        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.writeln(" -> Arenas {")
-        # else:
-            # w.writeln(" {")
-        w.writeln("  println!(\"%s, dirty={}\", dirty);" % name)
         if maximality == Maximality.TAKE_ONE:
             w.writeln("  // %s Maximality: Take One" % title)
-            # if return_arenas:
-            w.writeln("  %s(sc, event, %s, dirty)" % (substep, IDENT_OC))
-            # else:
-            #     w.writeln("  %s(sc, event, %s);" % (substep, IDENT_OC))
+            w.writeln("  %s(sc, event, %s, dirty)" % (substep, IDENT_HANDLE))
         else:
-            # if return_arenas:
             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_OC))
+                w.writeln("    let just_fired = %s(sc, e, %s, 0);" % (substep, IDENT_HANDLE))
             elif maximality == Maximality.SYNTACTIC:
                 w.writeln("    // %s Maximality: Syntactic" % title)
-                w.writeln("    let just_fired = %s(sc, e, %s, fired);" % (substep, IDENT_OC))
+                w.writeln("    let just_fired = %s(sc, e, %s, fired);" % (substep, IDENT_HANDLE))
             w.writeln("    if just_fired == 0 {")
             w.writeln("      break;")
             w.writeln("    }")
-            # if return_arenas:
             w.writeln("    fired |= just_fired & !ARENA_FIRED;")
             if not input_whole:
                 w.writeln("    // Input Event Lifeline: %s" % sc.semantics.input_event_lifeline)
                 w.writeln("    e = None;")
             w.writeln("  }")
-            # if return_arenas:
-            w.writeln("  println!(\"end %s, fired={}\", fired);" % name)
             w.writeln("  fired")
         w.writeln("}")
 
@@ -549,11 +548,11 @@ 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, OutputCallback> for Statechart {")
-    w.writeln("  fn init(%s: &mut OutputCallback) {" % IDENT_OC)
-    w.writeln("    %s::enter_default(%s)" % (ident_type(tree.root), IDENT_OC))
+    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("  }")
-    w.writeln("  fn big_step(&mut self, event: Option<Event>, output: &mut OutputCallback) {")
+    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("  }")
     w.writeln("}")

+ 1 - 0
src/sccd/statechart/parser/xml.py

@@ -251,6 +251,7 @@ def statechart_parser_rules(globals, path, load_external = True, parse_f = parse
             else:
               event_name = "+%d" % after_id
             transition.trigger = AfterTrigger(globals.events.assign_id(event_name), event_name, after_id, after_expr)
+            statechart.internal_events |= transition.trigger.enabling_bitmap
             after_id += 1
 
           def parse_attr_cond(cond):

+ 4 - 8
src/sccd/test/codegen/rust.py

@@ -1,5 +1,5 @@
 from sccd.test.static.syntax import *
-from sccd.statechart.codegen.rust import compile_statechart
+from sccd.statechart.codegen.rust import *
 from sccd.util.indenting_writer import *
 
 import os
@@ -27,20 +27,16 @@ def compile_test(variants: List[TestVariant], w: IndentingWriter):
         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); return;")
+        w.writeln("  raised.push(event);")
         w.writeln("};")
-        w.writeln("Statechart::init(&mut output);")
         w.writeln("let mut controller = Controller::<_,_,Statechart>::new(output);")
+        w.writeln("controller.statechart.init(&mut controller.handle);")
         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.add_input(Entry{")
-            w.writeln("  timestamp: %d," % i.timestamp.opt)
-            w.writeln("  event: Event::%s," % i.events[0].name)
-            w.writeln("});")
+            w.writeln("controller.handle.set_timeout(%d, Event::%s);" % (i.timestamp.opt, ident_event(i.events[0].name)))
 
         w.writeln("controller.run_until(Until::Eternity);")
         ctr = 0