Browse Source

Greatest common divisor is calculated for all durations in a model, serving as the "model delta", the smallest amount of time that can be simulated. "After" transitions always have units.

Joeri Exelmans 5 years ago
parent
commit
8870590d16

+ 11 - 0
src/sccd/controller/controller.py

@@ -32,6 +32,8 @@ class Controller:
         self.simulated_time = 0 # integer
         self.initialized = False
 
+        self.model.context.assert_ready()
+
     # time_offset: the offset relative to the current simulated time
     # (the timestamp given in the last call to run_until)
     def add_input(self, input: InputEvent):
@@ -58,6 +60,10 @@ class Controller:
     def next_wakeup(self) -> Optional[Timestamp]:
         return self.queue.earliest_timestamp()
 
+    # Returns duration since start
+    def get_simulated_duration(self) -> Duration:
+        return self.model.context.delta * self.simulated_time
+
     # Run until the event queue has no more due events wrt given timestamp and until all instances are stable.
     # If no timestamp is given (now = None), run until event queue is empty.
     def run_until(self, now: Optional[Timestamp], pipe: queue.Queue, interrupt: queue.Queue = queue.SimpleQueue()):
@@ -101,6 +107,8 @@ class Controller:
 
         if not self.initialized:
             self.initialized = True
+
+            print_debug('time is now %s' % str(self.get_simulated_duration()))
             # first run...
             # initialize the object manager, in turn initializing our default class
             # and adding the generated events to the queue
@@ -110,6 +118,7 @@ class Controller:
                 if not stable:
                     unstable.append(i)
 
+
         # Actual "event loop"
         # TODO: What is are the right semantics for this loop?
         # Should we stabilize every object after it has made a big step?
@@ -126,9 +135,11 @@ class Controller:
                         return
                     # make time leap
                     self.simulated_time = timestamp
+                    print_debug('\ntime is now %s' % str(self.get_simulated_duration()))
                 # run all instances for whom there are events
                 for instance in entry.targets:
                     stable, output = instance.big_step(timestamp, [entry.event])
+                    # print_debug("completed big step (time = %s)" % str(self.model.context.delta * self.simulated_time))
                     process_big_step_output(output)
                     if not stable:
                         unstable.append(instance)

+ 1 - 1
src/sccd/execution/event.py

@@ -17,7 +17,7 @@ class Event:
         else:
             s = "Event("+self.name
         if self.parameters:
-            s += ", params="+str(self.parameters)
+            s += str(self.parameters)
         s += ")"
         return termcolor.colored(s, 'yellow')
 

+ 1 - 8
src/sccd/execution/statechart_instance.py

@@ -75,14 +75,12 @@ class StatechartInstance(Instance):
         self.state.initialize()
         stable, output = self.state.collect_output()
 
-        print_debug('completed initialization (time=%d)'%now+("(stable)" if stable else ""))
-
         return (stable, output)
 
     # perform a big step. generating a set of output events
     def big_step(self, now: Timestamp, input_events: List[Event]) -> Tuple[bool, List[OutputEvent]]:
 
-        # print_debug(termcolor.colored('attempting big step, input_events='+str(input_events), 'red'))
+        # print_debug('attempting big step, input_events='+str(input_events))
 
         self.set_input(input_events)
 
@@ -93,9 +91,4 @@ class StatechartInstance(Instance):
         # can the next big step still contain transitions, even if there are no input events?
         stable |= not input_events and not arenas_changed
 
-        if arenas_changed:
-            print_debug('completed big step (time=%d)'%now+(" (stable)" if stable else ""))
-        else:
-            print_debug("(stable)" if stable else "")
-
         return (stable, output)

+ 5 - 5
src/sccd/execution/statechart_state.py

@@ -130,7 +130,7 @@ class StatechartState:
 
   def _start_timers(self, triggers: List[AfterTrigger]):
       for after in triggers:
-          delay = after.delay.eval([], self.data_model)
+          delay: int = after.delay.eval([], self.data_model)
           self.output.append(OutputEvent(
               Event(id=after.id, name=after.name, parameters=[after.nextTimerId()]),
               target=InstancesTarget([self.instance]),
@@ -140,10 +140,10 @@ class StatechartState:
   def in_state(self, state_strings: List[str]) -> bool:
       state_ids_bitmap = Bitmap.from_list((self.model.tree.state_dict[state_string].gen.state_id for state_string in state_strings))
       in_state = self.configuration_bitmap.has_all(state_ids_bitmap)
-      if in_state:
-          print_debug("in state"+str(state_strings))
-      else:
-          print_debug("not in state"+str(state_strings))
+      # if in_state:
+      #     print_debug("in state"+str(state_strings))
+      # else:
+      #     print_debug("not in state"+str(state_strings))
       return in_state
 
   def collect_output(self) -> Tuple[bool, List[OutputEvent]]:

+ 23 - 1
src/sccd/model/context.py

@@ -2,6 +2,7 @@
 from typing import *
 from sccd.syntax.expression import *
 from sccd.util.namespace import *
+from sccd.util.duration import *
 
 # @dataclass
 class Context:
@@ -9,4 +10,25 @@ class Context:
     self.events = Namespace()
     self.inports = Namespace()
     self.outports = Namespace()
-    self.durations: List[DurationLiteral] = []
+    self.durations: List[DurationLiteral] = []
+
+    # The smallest unit for all durations in the model
+    self.delta: Optional[Duration] = None
+
+  def _conv(self):
+    for d in self.durations:
+      if d.original % self.delta != Duration(0):
+        print("Warning: Duration %s cannot be represented by delta %s" % (str(d.original), str(self.delta)))
+      d.converted = d.original // self.delta
+
+  def convert_durations_fixed_delta(self, delta: Duration):
+    self.delta = delta
+    self._conv()
+    
+  def convert_durations_auto_delta(self):
+    self.delta = gcd(*(d.original for d in self.durations))
+    self._conv()
+
+  def assert_ready(self):
+    if self.delta is None:
+      raise Exception("Context not ready: durations not yet converted.")

+ 0 - 1
src/sccd/model/xml_parser.py

@@ -240,7 +240,6 @@ def parse(event_generator, handler: ElementHandler):
   for event, el in event_generator:
 
     try:
-
       if event == "start":
         start_method = getattr(handler, "start_"+el.tag, None)
         if start_method:

+ 4 - 3
src/sccd/syntax/expression.py

@@ -115,16 +115,17 @@ class DurationLiteral(Expression):
     original: Duration
 
     # All duration expressions in a model evaluate to a duration with the same unit.
-    normalized: Optional[Duration] = None
+    # What remains is a just an integer in  that unit.
+    converted: Optional[int] = None
 
     def eval(self, events, datamodel):
-        return self.normalized
+        return self.converted
 
     def render(self):
         return self.original.__str__()
 
     def get_static_type(self) -> type:
-        return Duration
+        return int
 
 @dataclass
 class Array(Expression):

+ 7 - 5
src/sccd/test/xml_loader.py

@@ -36,7 +36,7 @@ class PseudoFailedTest(unittest.TestCase):
 def load_test(src_file) -> List[Test]:
   should_fail = os.path.basename(src_file).startswith("fail_")
 
-  namespace = Context()
+  context = Context()
 
   test_node = etree.parse(src_file).getroot()
 
@@ -44,12 +44,12 @@ def load_test(src_file) -> List[Test]:
     sc_node = test_node.find("statechart")
     src = sc_node.get("src")
     if src is None:
-      statechart = load_statechart(namespace, sc_node)
+      statechart = load_statechart(context, sc_node)
     else:
       external_file = os.path.join(os.path.dirname(src_file), src)
       # print("loading", external_file, "...")
       external_node = etree.parse(external_file).getroot()
-      statechart = load_statechart(namespace, external_node)
+      statechart = load_statechart(context, external_node)
       semantics_node = sc_node.find("override_semantics")
       load_semantics(statechart.semantics, semantics_node)
 
@@ -58,10 +58,12 @@ def load_test(src_file) -> List[Test]:
     input = load_input(input_node)
     output = load_output(output_node)
 
+    context.convert_durations_auto_delta()
+
     def variant_description(i, variant) -> str:
       if not variant:
         return ""
-      return " (variant %d: %s)" % (i, ",".join(str(val) for val in variant.values()))
+      return " (variant %d: %s)" % (i, ", ".join(str(val) for val in variant.values()))
 
     if should_fail:
       return [PseudoFailedTest(name=src_file, e=Exception("Unexpectedly succeeded at loading."))]
@@ -70,7 +72,7 @@ def load_test(src_file) -> List[Test]:
         Test(
           name=src_file + variant_description(i, variant),
           model=SingleInstanceModel(
-            namespace,
+            context,
             Statechart(tree=statechart.tree, datamodel=deepcopy(statechart.datamodel), semantics=dataclasses.replace(statechart.semantics, **variant))),
           input=input,
           output=output)

+ 52 - 22
src/sccd/util/duration.py

@@ -5,7 +5,7 @@ import math
 import functools
 
 @dataclass
-class _Unit:
+class Unit:
   notation: str
   relative_size: int
   larger: Optional[Tuple[Any, int]] = None
@@ -14,15 +14,15 @@ class _Unit:
   def __eq__(self, other):
     return self is other
 
-FemtoSecond = _Unit("fs", 1)
-PicoSecond = _Unit("ps", 1000)
-Nanosecond = _Unit("ns", 1000000)
-Microsecond = _Unit("µs", 1000000000)
-Millisecond = _Unit("ms", 1000000000000)
-Second = _Unit("s", 1000000000000000)
-Minute = _Unit("m", 60000000000000000)
-Hour = _Unit("h", 3600000000000000000)
-Day = _Unit("D", 86400000000000000000)
+FemtoSecond = Unit("fs", 1)
+PicoSecond = Unit("ps", 1000)
+Nanosecond = Unit("ns", 1000000)
+Microsecond = Unit("µs", 1000000000)
+Millisecond = Unit("ms", 1000000000000)
+Second = Unit("s", 1000000000000000)
+Minute = Unit("m", 60000000000000000)
+Hour = Unit("h", 3600000000000000000)
+Day = Unit("D", 86400000000000000000)
 
 FemtoSecond.larger = (PicoSecond, 1000)
 PicoSecond.larger = (Nanosecond, 1000)
@@ -45,9 +45,10 @@ Hour.larger = (Day, 24)
 
 # @dataclass
 class Duration:
-  def __init__(self, val: int, unit: _Unit = None):
+  def __init__(self, val: int, unit: Unit = None):
     self.val = val
     self.unit = unit
+
     if self.val != 0 and self.unit is None:
       raise Exception("Duration: Non-zero value should have unit")
     # Zero-durations are treated a bit special
@@ -56,7 +57,7 @@ class Duration:
 
   # Can only convert to smaller units.
   # Returns new Duration.
-  def convert(self, unit: _Unit):
+  def convert(self, unit: Unit):
     if self.unit is None:
       return self
 
@@ -92,7 +93,42 @@ class Duration:
     return self.val == other.val and self.unit is other.unit
 
   def __mul__(self, other):
-    return Duration(self.val*other, self.unit)
+    new_val = self.val * other
+    if new_val == 0:
+      return Duration(0)
+    else:
+      return Duration(new_val, self.unit)
+
+  # Commutativity
+  __rmul__ = __mul__
+
+  def __floordiv__(self, other):
+    # if isinstance(other, Duration):
+      self_conv, other_conv = same_unit(self, other)
+      return self_conv.val // other_conv.val
+    # else:
+      # return Duration(self.val//other, self.unit)
+
+
+  def __mod__(self, other):
+    # if isinstance(other, Duration):
+      self_conv, other_conv = same_unit(self, other)
+      new_val = self_conv.val % other_conv.val
+      if new_val == 0:
+        return Duration(0)
+      else:
+        return Duration(new_val, self_conv.unit)
+    # else:
+      # return Duration(self.val%other, self.unit)
+
+def same_unit(x: Duration, y: Duration) -> Tuple[Duration, Duration]:
+  if x.unit.relative_size >= y.unit.relative_size:
+    x_conv = x.convert(y.unit)
+    y_conv = y
+  else:
+    x_conv = x
+    y_conv = y.convert(x.unit)
+  return (x_conv, y_conv)
 
 def gcd_pair(x: Duration, y: Duration) -> Duration:
   if x.unit is None:
@@ -100,15 +136,9 @@ def gcd_pair(x: Duration, y: Duration) -> Duration:
   if y.unit is None:
     return x
 
-  if x.unit.relative_size >= y.unit.relative_size:
-    x_converted = x.convert(y.unit)
-    y_converted = y
-  else:
-    x_converted = x
-    y_converted = y.convert(x.unit)
-  # x_conv and y_conv are now the same unit
-  gcd = math.gcd(x_converted.val, y_converted.val)
-  return Duration(gcd, x_converted.unit).normalize()
+  x_conv, y_conv = same_unit(x, y)
+  gcd = math.gcd(x_conv.val, y_conv.val)
+  return Duration(gcd, x_conv.unit).normalize()
 
 def gcd(*iterable) -> Duration:
   return functools.reduce(gcd_pair, iterable, Duration(0))

+ 26 - 1
src/sccd/util/test_duration.py

@@ -1,7 +1,6 @@
 import unittest
 from duration import *
 
-
 class TestDuration(unittest.TestCase):
 
   def test_equal(self):
@@ -79,3 +78,29 @@ class TestDuration(unittest.TestCase):
     u = gcd(*l)
 
     self.assertEqual(u, Duration(0))
+
+  def test_mult(self):
+    x = Duration(10, Millisecond)
+    
+    self.assertEqual(x * 10, Duration(100, Millisecond))
+    self.assertEqual(10 * x, Duration(100, Millisecond))
+
+  def test_floordiv(self):
+    x = Duration(100, Millisecond)
+    y = Duration(10, Millisecond)
+    z = Duration(3, Millisecond)
+
+    # Duration divided by duration is factor
+    self.assertEqual(x // y, 10)
+    self.assertEqual(y // x, 0)
+    self.assertEqual(x // z, 33)
+
+  def test_mod(self):
+    x = Duration(100, Millisecond)
+    y = Duration(10, Microsecond)
+    z = Duration(1, Second)
+    i = Duration(3, Millisecond)
+
+    self.assertEqual(x % y, Duration(0))
+    self.assertEqual(x % z, Duration(100, Millisecond))
+    self.assertEqual(x % i, Duration(1, Millisecond))

+ 0 - 80
test/test_files/features/after/test_after.svg

@@ -1,80 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
- "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<!-- Generated by graphviz version 2.40.1 (20161225.0304)
- -->
-<!-- Title: state transitions Pages: 1 -->
-<svg width="242pt" height="231pt"
- viewBox="0.00 0.00 242.00 231.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
-<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 227)">
-<title>state transitions</title>
-<polygon fill="#ffffff" stroke="transparent" points="-4,4 -4,-227 238,-227 238,4 -4,4"/>
-<!-- __initial -->
-<g id="node1" class="node">
-<title>__initial</title>
-<ellipse fill="#000000" stroke="#000000" stroke-width="2" cx="117" cy="-217.5" rx="5.5" ry="5.5"/>
-</g>
-<!-- _s1 -->
-<g id="node2" class="node">
-<title>_s1</title>
-<polygon fill="transparent" stroke="transparent" stroke-width="2" points="145,-184 89,-184 89,-148 145,-148 145,-184"/>
-<text text-anchor="start" x="110.6646" y="-162.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">s1</text>
-<path fill="none" stroke="#000000" stroke-width="2" d="M101.3333,-149C101.3333,-149 132.6667,-149 132.6667,-149 138.3333,-149 144,-154.6667 144,-160.3333 144,-160.3333 144,-171.6667 144,-171.6667 144,-177.3333 138.3333,-183 132.6667,-183 132.6667,-183 101.3333,-183 101.3333,-183 95.6667,-183 90,-177.3333 90,-171.6667 90,-171.6667 90,-160.3333 90,-160.3333 90,-154.6667 95.6667,-149 101.3333,-149"/>
-</g>
-<!-- __initial&#45;&gt;_s1 -->
-<g id="edge1" class="edge">
-<title>__initial&#45;&gt;_s1</title>
-<path fill="none" stroke="#000000" d="M117,-211.9886C117,-207.6293 117,-201.1793 117,-194.4801"/>
-<polygon fill="#000000" stroke="#000000" points="120.5001,-194.0122 117,-184.0122 113.5001,-194.0122 120.5001,-194.0122"/>
-<text text-anchor="middle" x="118.3895" y="-195" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"> </text>
-</g>
-<!-- _s2 -->
-<g id="node3" class="node">
-<title>_s2</title>
-<polygon fill="transparent" stroke="transparent" stroke-width="2" points="106,-120 0,-120 0,-74 106,-74 106,-120"/>
-<text text-anchor="start" x="46.6646" y="-103.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">s2</text>
-<text text-anchor="start" x="5.5022" y="-83.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">onentry/ ^out.in_2</text>
-<polygon fill="#000000" stroke="#000000" points="0,-97 0,-97 106,-97 106,-97 0,-97"/>
-<path fill="none" stroke="#000000" stroke-width="2" d="M13,-75C13,-75 93,-75 93,-75 99,-75 105,-81 105,-87 105,-87 105,-107 105,-107 105,-113 99,-119 93,-119 93,-119 13,-119 13,-119 7,-119 1,-113 1,-107 1,-107 1,-87 1,-87 1,-81 7,-75 13,-75"/>
-</g>
-<!-- _s1&#45;&gt;_s2 -->
-<g id="edge2" class="edge">
-<title>_s1&#45;&gt;_s2</title>
-<path fill="none" stroke="#000000" d="M100.1848,-147.8711C94.4188,-141.6547 87.7966,-134.5151 81.372,-127.5886"/>
-<polygon fill="#000000" stroke="#000000" points="83.8947,-125.1616 74.5281,-120.21 78.7625,-129.9219 83.8947,-125.1616"/>
-<text text-anchor="start" x="93" y="-131" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">after(100) &#160;&#160;</text>
-</g>
-<!-- _s3 -->
-<g id="node4" class="node">
-<title>_s3</title>
-<polygon fill="transparent" stroke="transparent" stroke-width="2" points="234,-120 128,-120 128,-74 234,-74 234,-120"/>
-<text text-anchor="start" x="174.6646" y="-103.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">s3</text>
-<text text-anchor="start" x="133.5022" y="-83.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">onentry/ ^out.in_3</text>
-<polygon fill="#000000" stroke="#000000" points="128,-97 128,-97 234,-97 234,-97 128,-97"/>
-<path fill="none" stroke="#000000" stroke-width="2" d="M141,-75C141,-75 221,-75 221,-75 227,-75 233,-81 233,-87 233,-87 233,-107 233,-107 233,-113 227,-119 221,-119 221,-119 141,-119 141,-119 135,-119 129,-113 129,-107 129,-107 129,-87 129,-87 129,-81 135,-75 141,-75"/>
-</g>
-<!-- _s1&#45;&gt;_s3 -->
-<g id="edge3" class="edge">
-<title>_s1&#45;&gt;_s3</title>
-<path fill="none" stroke="#000000" d="M141.4695,-147.9993C144.4564,-145.4372 147.376,-142.7385 150,-140 153.4025,-136.4491 156.7352,-132.5071 159.8791,-128.4919"/>
-<polygon fill="#000000" stroke="#000000" points="162.8542,-130.3572 166.029,-120.2492 157.2437,-126.1712 162.8542,-130.3572"/>
-<text text-anchor="start" x="159" y="-131" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">after(200) &#160;&#160;</text>
-</g>
-<!-- _s4 -->
-<g id="node5" class="node">
-<title>_s4</title>
-<polygon fill="transparent" stroke="transparent" stroke-width="2" points="106,-46 0,-46 0,0 106,0 106,-46"/>
-<text text-anchor="start" x="46.6646" y="-29.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">s4</text>
-<text text-anchor="start" x="5.5022" y="-9.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">onentry/ ^out.in_4</text>
-<polygon fill="#000000" stroke="#000000" points="0,-23 0,-23 106,-23 106,-23 0,-23"/>
-<path fill="none" stroke="#000000" stroke-width="2" d="M13,-1C13,-1 93,-1 93,-1 99,-1 105,-7 105,-13 105,-13 105,-33 105,-33 105,-39 99,-45 93,-45 93,-45 13,-45 13,-45 7,-45 1,-39 1,-33 1,-33 1,-13 1,-13 1,-7 7,-1 13,-1"/>
-</g>
-<!-- _s2&#45;&gt;_s4 -->
-<g id="edge4" class="edge">
-<title>_s2&#45;&gt;_s4</title>
-<path fill="none" stroke="#000000" d="M53,-73.9916C53,-68.476 53,-62.474 53,-56.5881"/>
-<polygon fill="#000000" stroke="#000000" points="56.5001,-56.249 53,-46.2491 49.5001,-56.2491 56.5001,-56.249"/>
-<text text-anchor="start" x="53" y="-57" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">after(150) &#160;&#160;</text>
-</g>
-</g>
-</svg>

+ 3 - 3
test/test_files/features/after/test_after.xml

@@ -8,14 +8,14 @@
     <tree>
       <state initial="s1">
         <state id="s1">
-          <transition after="100" target="/s2"/>
-          <transition after="200" target="/s3"/>
+          <transition after="100 ms" target="/s2"/>
+          <transition after="200 ms" target="/s3"/>
         </state>
         <state id="s2">
           <onentry>
             <raise event="in_2" port="out" />
           </onentry>
-          <transition after="150" target="/s4"/>
+          <transition after="150 ms" target="/s4"/>
         </state>
         <state id="s3">
           <onentry>

+ 0 - 43
test/test_files/features/after/test_after_fixed_delta.xml

@@ -1,43 +0,0 @@
-<?xml version="1.0" ?>
-<test should_fail_load="true">
-  <statechart>
-    <!-- after events are always received as input events in a later big step -->
-    <semantics
-        big_step_maximality="*"
-        combo_step_maximality="*"/>
-    <tree>
-      <state initial="s1">
-        <state id="s1">
-          <transition after="100 us" target="/s2"/>
-          <transition after="200 ms" target="/s3"/>
-        </state>
-        <state id="s2">
-          <onentry>
-            <raise event="in_2" port="out" />
-          </onentry>
-          <transition after="150 h" target="/s4"/>
-        </state>
-        <state id="s3">
-          <onentry>
-            <raise event="in_3" port="out"/>
-          </onentry>
-        </state>
-        <state id="s4">
-          <onentry>
-            <raise event="in_4" port="out"/>
-          </onentry>
-        </state>
-      </state>
-    </tree>
-  </statechart>
-  <delta
-    fixed="10 ms"/>
-  <output>
-    <big_step>
-      <event name="in_2" port="out"/>
-    </big_step>
-    <big_step>
-      <event name="in_4" port="out"/>
-    </big_step>
-  </output>
-</test>

+ 0 - 134
test/test_files/features/after/test_after_reentry.svg

@@ -1,134 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
- "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<!-- Generated by graphviz version 2.40.1 (20161225.0304)
- -->
-<!-- Title: state transitions Pages: 1 -->
-<svg width="479pt" height="404pt"
- viewBox="0.00 0.00 479.00 404.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
-<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 400)">
-<title>state transitions</title>
-<polygon fill="#ffffff" stroke="transparent" points="-4,4 -4,-400 475,-400 475,4 -4,4"/>
-<g id="clust1" class="cluster">
-<title>cluster__p</title>
-<path fill="none" stroke="#000000" stroke-width="2" d="M20,-8C20,-8 451,-8 451,-8 457,-8 463,-14 463,-20 463,-20 463,-345 463,-345 463,-351 457,-357 451,-357 451,-357 20,-357 20,-357 14,-357 8,-351 8,-345 8,-345 8,-20 8,-20 8,-14 14,-8 20,-8"/>
-<text text-anchor="start" x="232.1646" y="-338.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">p</text>
-</g>
-<g id="clust2" class="cluster">
-<title>cluster__p_o0</title>
-<polygon fill="none" stroke="#000000" stroke-dasharray="5,2" points="122,-16 122,-319 455,-319 455,-16 122,-16"/>
-<text text-anchor="start" x="282.3292" y="-300.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">o0</text>
-</g>
-<g id="clust3" class="cluster">
-<title>cluster__p_o1</title>
-<polygon fill="none" stroke="#000000" stroke-dasharray="5,2" points="24,-21 24,-319 114,-319 114,-21 24,-21"/>
-<text text-anchor="start" x="62.8292" y="-300.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">o1</text>
-</g>
-<!-- __initial -->
-<g id="node1" class="node">
-<title>__initial</title>
-<ellipse fill="#000000" stroke="#000000" stroke-width="2" cx="16" cy="-390.5" rx="5.5" ry="5.5"/>
-</g>
-<!-- _p -->
-<!-- __initial&#45;&gt;_p -->
-<g id="edge1" class="edge">
-<title>__initial&#45;&gt;_p</title>
-<path fill="none" stroke="#000000" d="M16,-384.9533C16,-380.7779 16,-374.5043 16,-367.0332"/>
-<polygon fill="#000000" stroke="#000000" points="19.5001,-366.9971 16,-356.9971 12.5001,-366.9972 19.5001,-366.9971"/>
-<text text-anchor="middle" x="17.3895" y="-368" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"> </text>
-</g>
-<!-- _p_o0 -->
-<!-- _p_o0_initial -->
-<g id="node4" class="node">
-<title>_p_o0_initial</title>
-<ellipse fill="#000000" stroke="#000000" stroke-width="2" cx="348" cy="-275.5" rx="5.5" ry="5.5"/>
-</g>
-<!-- _p_o0_a -->
-<g id="node5" class="node">
-<title>_p_o0_a</title>
-<polygon fill="transparent" stroke="transparent" stroke-width="2" points="376,-188 320,-188 320,-152 376,-152 376,-188"/>
-<text text-anchor="start" x="344.6646" y="-166.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">a</text>
-<path fill="none" stroke="#000000" stroke-width="2" d="M332.3333,-153C332.3333,-153 363.6667,-153 363.6667,-153 369.3333,-153 375,-158.6667 375,-164.3333 375,-164.3333 375,-175.6667 375,-175.6667 375,-181.3333 369.3333,-187 363.6667,-187 363.6667,-187 332.3333,-187 332.3333,-187 326.6667,-187 321,-181.3333 321,-175.6667 321,-175.6667 321,-164.3333 321,-164.3333 321,-158.6667 326.6667,-153 332.3333,-153"/>
-</g>
-<!-- _p_o0_initial&#45;&gt;_p_o0_a -->
-<g id="edge2" class="edge">
-<title>_p_o0_initial&#45;&gt;_p_o0_a</title>
-<path fill="none" stroke="#000000" d="M348,-269.8288C348,-265.1736 348,-258.4097 348,-252.5 348,-252.5 348,-252.5 348,-205.5 348,-203.1079 348,-200.6252 348,-198.1342"/>
-<polygon fill="#000000" stroke="#000000" points="351.5001,-198.0597 348,-188.0598 344.5001,-198.0598 351.5001,-198.0597"/>
-<text text-anchor="middle" x="349.3895" y="-226" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"> </text>
-</g>
-<!-- _p_o0_b -->
-<g id="node6" class="node">
-<title>_p_o0_b</title>
-<polygon fill="transparent" stroke="transparent" stroke-width="2" points="278,-70 172,-70 172,-24 278,-24 278,-70"/>
-<text text-anchor="start" x="221.6646" y="-53.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">b</text>
-<text text-anchor="start" x="177.5022" y="-33.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">onentry/ ^out.in_b</text>
-<polygon fill="#000000" stroke="#000000" points="172,-47 172,-47 278,-47 278,-47 172,-47"/>
-<path fill="none" stroke="#000000" stroke-width="2" d="M185,-25C185,-25 265,-25 265,-25 271,-25 277,-31 277,-37 277,-37 277,-57 277,-57 277,-63 271,-69 265,-69 265,-69 185,-69 185,-69 179,-69 173,-63 173,-57 173,-57 173,-37 173,-37 173,-31 179,-25 185,-25"/>
-</g>
-<!-- _p_o0_a&#45;&gt;_p_o0_b -->
-<g id="edge3" class="edge">
-<title>_p_o0_a&#45;&gt;_p_o0_b</title>
-<path fill="none" stroke="#000000" d="M319.918,-167.7853C265.7222,-163.1318 152,-151.3584 152,-134.5 152,-134.5 152,-134.5 152,-87.5 152,-78.3329 156.4562,-71.2234 163.1666,-65.7143"/>
-<polygon fill="#000000" stroke="#000000" points="165.5053,-68.3661 171.9476,-59.9549 161.6661,-62.5128 165.5053,-68.3661"/>
-<text text-anchor="start" x="152" y="-108" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">after(100) [INSTATE([&quot;/p/o1/x&quot;])] &#160;&#160;</text>
-</g>
-<!-- _p_o0_c -->
-<g id="node7" class="node">
-<title>_p_o0_c</title>
-<polygon fill="transparent" stroke="transparent" stroke-width="2" points="447,-70 341,-70 341,-24 447,-24 447,-70"/>
-<text text-anchor="start" x="391" y="-53.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">c</text>
-<text text-anchor="start" x="346.8376" y="-33.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">onentry/ ^out.in_c</text>
-<polygon fill="#000000" stroke="#000000" points="341,-47 341,-47 447,-47 447,-47 341,-47"/>
-<path fill="none" stroke="#000000" stroke-width="2" d="M354,-25C354,-25 434,-25 434,-25 440,-25 446,-31 446,-37 446,-37 446,-57 446,-57 446,-63 440,-69 434,-69 434,-69 354,-69 354,-69 348,-69 342,-63 342,-57 342,-57 342,-37 342,-37 342,-31 348,-25 354,-25"/>
-</g>
-<!-- _p_o0_a&#45;&gt;_p_o0_c -->
-<g id="edge4" class="edge">
-<title>_p_o0_a&#45;&gt;_p_o0_c</title>
-<path fill="none" stroke="#000000" d="M376.1541,-159.659C386.1638,-154.0322 395,-145.8506 395,-134.5 395,-134.5 395,-134.5 395,-87.5 395,-85.1262 394.9826,-82.6744 394.9524,-80.2065"/>
-<polygon fill="#000000" stroke="#000000" points="398.4505,-80.0625 394.7681,-70.1282 391.4517,-80.1906 398.4505,-80.0625"/>
-<text text-anchor="start" x="395" y="-108" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">after(150) &#160;&#160;</text>
-</g>
-<!-- _p_o0_b&#45;&gt;_p_o0_a -->
-<g id="edge5" class="edge">
-<title>_p_o0_b&#45;&gt;_p_o0_a</title>
-<path fill="none" stroke="#000000" d="M278.2342,-59.6571C311.4764,-68.3378 348,-79.6594 348,-87.5 348,-134.5 348,-134.5 348,-134.5 348,-136.8921 348,-139.3748 348,-141.8658"/>
-<polygon fill="#000000" stroke="#000000" points="344.5001,-141.9402 348,-151.9402 351.5001,-141.9403 344.5001,-141.9402"/>
-<text text-anchor="middle" x="349.3895" y="-108" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"> </text>
-</g>
-<!-- _p_o1 -->
-<!-- _p_o1_initial -->
-<g id="node9" class="node">
-<title>_p_o1_initial</title>
-<ellipse fill="#000000" stroke="#000000" stroke-width="2" cx="60" cy="-275.5" rx="5.5" ry="5.5"/>
-</g>
-<!-- _p_o1_x -->
-<g id="node10" class="node">
-<title>_p_o1_x</title>
-<polygon fill="transparent" stroke="transparent" stroke-width="2" points="88,-188 32,-188 32,-152 88,-152 88,-188"/>
-<text text-anchor="start" x="57" y="-166.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">x</text>
-<path fill="none" stroke="#000000" stroke-width="2" d="M44.3333,-153C44.3333,-153 75.6667,-153 75.6667,-153 81.3333,-153 87,-158.6667 87,-164.3333 87,-164.3333 87,-175.6667 87,-175.6667 87,-181.3333 81.3333,-187 75.6667,-187 75.6667,-187 44.3333,-187 44.3333,-187 38.6667,-187 33,-181.3333 33,-175.6667 33,-175.6667 33,-164.3333 33,-164.3333 33,-158.6667 38.6667,-153 44.3333,-153"/>
-</g>
-<!-- _p_o1_initial&#45;&gt;_p_o1_x -->
-<g id="edge6" class="edge">
-<title>_p_o1_initial&#45;&gt;_p_o1_x</title>
-<path fill="none" stroke="#000000" d="M60,-269.8288C60,-265.1736 60,-258.4097 60,-252.5 60,-252.5 60,-252.5 60,-205.5 60,-203.1079 60,-200.6252 60,-198.1342"/>
-<polygon fill="#000000" stroke="#000000" points="63.5001,-198.0597 60,-188.0598 56.5001,-198.0598 63.5001,-198.0597"/>
-<text text-anchor="middle" x="61.3895" y="-226" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"> </text>
-</g>
-<!-- _p_o1_y -->
-<g id="node11" class="node">
-<title>_p_o1_y</title>
-<polygon fill="transparent" stroke="transparent" stroke-width="2" points="88,-65 32,-65 32,-29 88,-29 88,-65"/>
-<text text-anchor="start" x="57" y="-43.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">y</text>
-<path fill="none" stroke="#000000" stroke-width="2" d="M44.3333,-30C44.3333,-30 75.6667,-30 75.6667,-30 81.3333,-30 87,-35.6667 87,-41.3333 87,-41.3333 87,-52.6667 87,-52.6667 87,-58.3333 81.3333,-64 75.6667,-64 75.6667,-64 44.3333,-64 44.3333,-64 38.6667,-64 33,-58.3333 33,-52.6667 33,-52.6667 33,-41.3333 33,-41.3333 33,-35.6667 38.6667,-30 44.3333,-30"/>
-</g>
-<!-- _p_o1_x&#45;&gt;_p_o1_y -->
-<g id="edge7" class="edge">
-<title>_p_o1_x&#45;&gt;_p_o1_y</title>
-<path fill="none" stroke="#000000" d="M55.7033,-151.6741C54.7416,-146.1833 54,-140.1255 54,-134.5 54,-134.5 54,-134.5 54,-87.5 54,-83.4573 54.2962,-79.2119 54.7569,-75.0534"/>
-<polygon fill="#000000" stroke="#000000" points="58.2353,-75.4511 56.1661,-65.0603 51.3039,-74.4736 58.2353,-75.4511"/>
-<text text-anchor="start" x="54" y="-108" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">after(250) &#160;&#160;</text>
-</g>
-</g>
-</svg>

+ 3 - 3
test/test_files/features/after/test_after_reentry.xml

@@ -9,8 +9,8 @@
         <parallel id="p">
           <state id="o0" initial="a">
             <state id="a">
-              <transition after="100" cond='INSTATE(["/p/o1/x"])' target="../b"/>
-              <transition after="150" target="../c"/>
+              <transition after="100 ms" cond='INSTATE(["/p/o1/x"])' target="../b"/>
+              <transition after="150 ms" target="../c"/>
             </state>
             <state id="b">
               <onentry>
@@ -26,7 +26,7 @@
           </state>
           <state id="o1" initial="x">
             <state id="x">
-              <transition after="250" target="../y"/>
+              <transition after="250 ms" target="../y"/>
             </state>
             <state id="y"/>
           </state>

+ 0 - 80
test/test_files/features/after/test_after_units.svg

@@ -1,80 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
- "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<!-- Generated by graphviz version 2.40.1 (20161225.0304)
- -->
-<!-- Title: state transitions Pages: 1 -->
-<svg width="242pt" height="231pt"
- viewBox="0.00 0.00 242.00 231.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
-<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 227)">
-<title>state transitions</title>
-<polygon fill="#ffffff" stroke="transparent" points="-4,4 -4,-227 238,-227 238,4 -4,4"/>
-<!-- __initial -->
-<g id="node1" class="node">
-<title>__initial</title>
-<ellipse fill="#000000" stroke="#000000" stroke-width="2" cx="117" cy="-217.5" rx="5.5" ry="5.5"/>
-</g>
-<!-- _s1 -->
-<g id="node2" class="node">
-<title>_s1</title>
-<polygon fill="transparent" stroke="transparent" stroke-width="2" points="145,-184 89,-184 89,-148 145,-148 145,-184"/>
-<text text-anchor="start" x="110.6646" y="-162.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">s1</text>
-<path fill="none" stroke="#000000" stroke-width="2" d="M101.3333,-149C101.3333,-149 132.6667,-149 132.6667,-149 138.3333,-149 144,-154.6667 144,-160.3333 144,-160.3333 144,-171.6667 144,-171.6667 144,-177.3333 138.3333,-183 132.6667,-183 132.6667,-183 101.3333,-183 101.3333,-183 95.6667,-183 90,-177.3333 90,-171.6667 90,-171.6667 90,-160.3333 90,-160.3333 90,-154.6667 95.6667,-149 101.3333,-149"/>
-</g>
-<!-- __initial&#45;&gt;_s1 -->
-<g id="edge1" class="edge">
-<title>__initial&#45;&gt;_s1</title>
-<path fill="none" stroke="#000000" d="M117,-211.9886C117,-207.6293 117,-201.1793 117,-194.4801"/>
-<polygon fill="#000000" stroke="#000000" points="120.5001,-194.0122 117,-184.0122 113.5001,-194.0122 120.5001,-194.0122"/>
-<text text-anchor="middle" x="118.3895" y="-195" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"> </text>
-</g>
-<!-- _s2 -->
-<g id="node3" class="node">
-<title>_s2</title>
-<polygon fill="transparent" stroke="transparent" stroke-width="2" points="106,-120 0,-120 0,-74 106,-74 106,-120"/>
-<text text-anchor="start" x="46.6646" y="-103.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">s2</text>
-<text text-anchor="start" x="5.5022" y="-83.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">onentry/ ^out.in_2</text>
-<polygon fill="#000000" stroke="#000000" points="0,-97 0,-97 106,-97 106,-97 0,-97"/>
-<path fill="none" stroke="#000000" stroke-width="2" d="M13,-75C13,-75 93,-75 93,-75 99,-75 105,-81 105,-87 105,-87 105,-107 105,-107 105,-113 99,-119 93,-119 93,-119 13,-119 13,-119 7,-119 1,-113 1,-107 1,-107 1,-87 1,-87 1,-81 7,-75 13,-75"/>
-</g>
-<!-- _s1&#45;&gt;_s2 -->
-<g id="edge2" class="edge">
-<title>_s1&#45;&gt;_s2</title>
-<path fill="none" stroke="#000000" d="M96.3763,-147.8814C93.6472,-145.2958 90.9328,-142.6227 88.436,-140 84.8592,-136.2428 81.226,-132.1729 77.717,-128.0861"/>
-<polygon fill="#000000" stroke="#000000" points="80.2789,-125.6942 71.1695,-120.2841 74.9168,-130.1941 80.2789,-125.6942"/>
-<text text-anchor="start" x="88" y="-131" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">after(100 µs) &#160;&#160;</text>
-</g>
-<!-- _s3 -->
-<g id="node4" class="node">
-<title>_s3</title>
-<polygon fill="transparent" stroke="transparent" stroke-width="2" points="234,-120 128,-120 128,-74 234,-74 234,-120"/>
-<text text-anchor="start" x="174.6646" y="-103.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">s3</text>
-<text text-anchor="start" x="133.5022" y="-83.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">onentry/ ^out.in_3</text>
-<polygon fill="#000000" stroke="#000000" points="128,-97 128,-97 234,-97 234,-97 128,-97"/>
-<path fill="none" stroke="#000000" stroke-width="2" d="M141,-75C141,-75 221,-75 221,-75 227,-75 233,-81 233,-87 233,-87 233,-107 233,-107 233,-113 227,-119 221,-119 221,-119 141,-119 141,-119 135,-119 129,-113 129,-107 129,-107 129,-87 129,-87 129,-81 135,-75 141,-75"/>
-</g>
-<!-- _s1&#45;&gt;_s3 -->
-<g id="edge3" class="edge">
-<title>_s1&#45;&gt;_s3</title>
-<path fill="none" stroke="#000000" d="M145.1022,-148.8417C148.6296,-146.1072 152.0347,-143.1369 155,-140 158.1875,-136.6281 161.1728,-132.8012 163.9023,-128.8539"/>
-<polygon fill="#000000" stroke="#000000" points="167.0262,-130.4645 169.4484,-120.1502 161.1228,-126.7027 167.0262,-130.4645"/>
-<text text-anchor="start" x="164" y="-131" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">after(200 ms) &#160;&#160;</text>
-</g>
-<!-- _s4 -->
-<g id="node5" class="node">
-<title>_s4</title>
-<polygon fill="transparent" stroke="transparent" stroke-width="2" points="106,-46 0,-46 0,0 106,0 106,-46"/>
-<text text-anchor="start" x="46.6646" y="-29.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">s4</text>
-<text text-anchor="start" x="5.5022" y="-9.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">onentry/ ^out.in_4</text>
-<polygon fill="#000000" stroke="#000000" points="0,-23 0,-23 106,-23 106,-23 0,-23"/>
-<path fill="none" stroke="#000000" stroke-width="2" d="M13,-1C13,-1 93,-1 93,-1 99,-1 105,-7 105,-13 105,-13 105,-33 105,-33 105,-39 99,-45 93,-45 93,-45 13,-45 13,-45 7,-45 1,-39 1,-33 1,-33 1,-13 1,-13 1,-7 7,-1 13,-1"/>
-</g>
-<!-- _s2&#45;&gt;_s4 -->
-<g id="edge4" class="edge">
-<title>_s2&#45;&gt;_s4</title>
-<path fill="none" stroke="#000000" d="M53,-73.9916C53,-68.476 53,-62.474 53,-56.5881"/>
-<polygon fill="#000000" stroke="#000000" points="56.5001,-56.249 53,-46.2491 49.5001,-56.2491 56.5001,-56.249"/>
-<text text-anchor="start" x="53" y="-57" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">after(150 h) &#160;&#160;</text>
-</g>
-</g>
-</svg>

+ 0 - 41
test/test_files/features/after/test_after_units.xml

@@ -1,41 +0,0 @@
-<?xml version="1.0" ?>
-<test>
-  <statechart>
-    <!-- after events are always received as input events in a later big step -->
-    <semantics
-        big_step_maximality="*"
-        combo_step_maximality="*"/>
-    <tree>
-      <state initial="s1">
-        <state id="s1">
-          <transition after="100 us" target="/s2"/>
-          <transition after="200 ms" target="/s3"/>
-        </state>
-        <state id="s2">
-          <onentry>
-            <raise event="in_2" port="out" />
-          </onentry>
-          <transition after="150 h" target="/s4"/>
-        </state>
-        <state id="s3">
-          <onentry>
-            <raise event="in_3" port="out"/>
-          </onentry>
-        </state>
-        <state id="s4">
-          <onentry>
-            <raise event="in_4" port="out"/>
-          </onentry>
-        </state>
-      </state>
-    </tree>
-  </statechart>
-  <output>
-    <big_step>
-      <event name="in_2" port="out"/>
-    </big_step>
-    <big_step>
-      <event name="in_4" port="out"/>
-    </big_step>
-  </output>
-</test>

test/test_files/features/datamodel/test_datamodel_expr.xml → test/test_files/features/datamodel/test_cond.xml