Browse Source

Add expressions test.

Joeri Exelmans 5 years ago
parent
commit
b1d1ed4f9e

+ 49 - 5
src/sccd/runtime/expression.py

@@ -10,6 +10,7 @@ class DataModel:
     def __init__(self, names: Dict[str, Variable]):
         self.names = names
 
+
 class Expression(ABC):
     @abstractmethod
     def eval(self, events, datamodel):
@@ -24,6 +25,12 @@ class LHS(Expression):
     def eval(self, events, datamodel):
         return self.lhs(events, datamodel).value
 
+class Statement(ABC):
+    @abstractmethod
+    def exec(self, events, datamodel):
+        pass
+
+
 @dataclass
 class Identifier(LHS):
     identifier: str
@@ -57,6 +64,16 @@ class StringLiteral(Expression):
     def render(self):
         return '"'+self.string+'"'
 
+@dataclass
+class IntLiteral(Expression):
+    i: int 
+
+    def eval(self, events, datamodel):
+        return self.i
+
+    def render(self):
+        return str(self.i)
+
 @dataclass
 class Array(Expression):
     elements: List[Any]
@@ -70,11 +87,28 @@ class Array(Expression):
 @dataclass
 class BinaryExpression(Expression):
     lhs: Expression
-    operator: str # the operator token value from the grammar.
+    operator: str # token name from the grammar.
     rhs: Expression
 
     def eval(self, events, datamodel):
         return {
+            # "AND": lambda x,y: x and y,
+            # "OR": lambda x,y: x or y,
+            # "EQ": lambda x,y: x == y,
+            # "NEQ": lambda x,y: x != y,
+            # "GT": lambda x,y: x > y,
+            # "GEQ": lambda x,y: x >= y,
+            # "LT": lambda x,y: x < y,
+            # "LEQ": lambda x,y: x <= y,
+            # "PLUS": lambda x,y: x + y,
+            # "MINUS": lambda x,y: x - y,
+            # "MULT": lambda x,y: x * y,
+            # "DIV": lambda x,y: x / y,
+            # "FLOORDIV": lambda x,y: x // y,
+            # "MOD": lambda x,y: x % y,
+            # "EXP": lambda x,y: x ** y,
+
+
             "and": lambda x,y: x and y,
             "or": lambda x,y: x or y,
             "==": lambda x,y: x == y,
@@ -89,12 +123,22 @@ class BinaryExpression(Expression):
             "/": lambda x,y: x / y,
             "//": lambda x,y: x // y,
             "%": lambda x,y: x % y,
+            "**": lambda x,y: x ** y,
         }[self.operator](self.lhs.eval(events, datamodel), self.rhs.eval(events, datamodel))
 
-class Statement(ABC):
-    @abstractmethod
-    def exec(self, events, datamodel):
-        pass
+    def render(self):
+        return self.lhs.render() + ' ' + self.operator + ' ' + self.rhs.render()
+
+@dataclass
+class UnaryExpression(Expression):
+    operator: str # token name from the grammar.
+    expr: Expression
+
+    def eval(self, events, datamodel):
+        return {
+            "NOT": lambda x: not x,
+            "MINUS": lambda x: -x,
+        }[self.operator](self.expr.eval(events, datamodel))
 
 @dataclass
 class Assignment(Statement):

+ 16 - 2
src/sccd/runtime/xml_loader2.py

@@ -16,14 +16,21 @@ class ExpressionTransformer(Transformer):
   def string(self, node):
     return StringLiteral(node[0][1:-1])
 
+  def int(self, node):
+    return IntLiteral(int(node[0].value))
+
   def func_call(self, node):
     return FunctionCall(node[0], node[1].children)
 
   def identifier(self, node):
     return Identifier(node[0].value)
 
+  def binary_expr(self, node):
+    return BinaryExpression(node[0], node[1].value, node[2])
+
   array = Array
 
+
 expr_parser = Lark(grammar, parser="lalr", start=["expr"], transformer=ExpressionTransformer())
 
 state_ref_parser = Lark(grammar, parser="lalr", start=["state_ref"])
@@ -148,8 +155,15 @@ def load_state_tree(namespace: ModelNamespace, tree_node) -> StateTree:
     # Guard
     cond = t_node.get("cond")
     if cond is not None:
-      expr = expr_parser.parse(cond, start="expr")
-      transition.setGuard(expr)
+      try:
+        # expr_parser2 = Lark(grammar, parser="lalr", start=["expr"])
+        # tree2 = expr_parser2.parse(cond, start="expr")
+        # print(tree2.pretty())
+
+        expr = expr_parser.parse(cond, start="expr")
+        transition.setGuard(expr)
+      except:
+        raise Exception("Line %d: <transition> with cond=\"%s\": Parse error." % (t_node.sourceline, cond))
     source.addTransition(transition)
 
   # Calculate stuff like list of ancestors, descendants, etc.

+ 36 - 13
src/sccd/schema/grammar.g

@@ -24,34 +24,55 @@ _path_sequence: (CURRENT_NODE | PARENT_NODE | IDENTIFIER) (_PATH_SEP _path_seque
 
 // We use the same operators and operator precedence rules as Python
 
-COMPARE_OPERATOR: "==" | "!=" | ">" | ">=" | "<" | "<="
-ADD_OPERATOR: "+" | "-"
-MULT_OPERATOR: "*" | "/" | "//" | "%"
+?compare_operator: EQ | NEQ | GT | GEQ | LT | LEQ
+?add_operator: PLUS | MINUS
+?mult_operator: MULT | DIV | FLOORDIV | MOD
+
+AND: "and"
+OR: "or"
+EQ: "=="
+NEQ: "!="
+GT: ">"
+GEQ: ">="
+LT: "<"
+LEQ: "<="
+PLUS: "+"
+MINUS: "-"
+MULT: "*"
+DIV: "/"
+FLOORDIV: "//"
+MOD: "%"
+EXP: "**"
+
+NOT: "not"
 
 ?expr: or_expr
 
 ?or_expr: and_expr
-        | or_expr "or" and_expr    -> or
+        | or_expr OR and_expr    -> binary_expr
 
-?and_expr: atom
-         | and_expr "and" not_expr  -> and
+?and_expr: not_expr
+         | and_expr AND not_expr  -> binary_expr
 
 ?not_expr: comp_expr
-         | "not" comp_expr           -> not
+         | NOT comp_expr           -> unary_expr
 
 ?comp_expr: add_expr
-          | comp_expr COMPARE_OPERATOR add_expr -> compare
+          | comp_expr compare_operator add_expr -> binary_expr
 
 
 ?add_expr: mult_expr
-         | add_expr ADD_OPERATOR mult_expr -> add
+         | add_expr add_operator mult_expr -> binary_expr
 
 
 ?mult_expr: unary
-          | mult_expr MULT_OPERATOR unary -> mult
+          | mult_expr mult_operator unary -> binary_expr
 
-?unary: atom
-      | "-" atom  -> neg
+?unary: exponent
+      | MINUS exponent  -> unary_expr
+
+?exponent: atom
+         | atom EXP exponent -> binary_expr
 
 ?atom: IDENTIFIER               -> identifier
      | "(" expr ")"             -> group
@@ -62,9 +83,11 @@ MULT_OPERATOR: "*" | "/" | "//" | "%"
 array: "[" (expr ("," expr)*)? "]"
 
 ?literal: ESCAPED_STRING -> string
-        | SIGNED_NUMBER -> number
+        | INT -> int
         | bool_literal -> bool
 
+INT: /[0-9]+/
+
 ?bool_literal: TRUE | FALSE
 
 func_call: atom "(" param_list ")"

+ 150 - 0
test/new_test_files/features/expressions/test_expressions.svg

@@ -0,0 +1,150 @@
+<?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="174pt" height="752pt"
+ viewBox="0.00 0.00 173.50 752.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 748)">
+<title>state transitions</title>
+<polygon fill="#ffffff" stroke="transparent" points="-4,4 -4,-748 169.5,-748 169.5,4 -4,4"/>
+<g id="clust1" class="cluster">
+<title>cluster__arithmetic</title>
+<path fill="none" stroke="#000000" stroke-width="2" d="M40.5,-74C40.5,-74 145.5,-74 145.5,-74 151.5,-74 157.5,-80 157.5,-86 157.5,-86 157.5,-693 157.5,-693 157.5,-699 151.5,-705 145.5,-705 145.5,-705 40.5,-705 40.5,-705 34.5,-705 28.5,-699 28.5,-693 28.5,-693 28.5,-86 28.5,-86 28.5,-80 34.5,-74 40.5,-74"/>
+<text text-anchor="start" x="67.5014" y="-686.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">arithmetic</text>
+</g>
+<!-- __initial -->
+<g id="node1" class="node">
+<title>__initial</title>
+<ellipse fill="#000000" stroke="#000000" stroke-width="2" cx="120.5" cy="-738.5" rx="5.5" ry="5.5"/>
+</g>
+<!-- _arithmetic -->
+<!-- __initial&#45;&gt;_arithmetic -->
+<g id="edge1" class="edge">
+<title>__initial&#45;&gt;_arithmetic</title>
+<path fill="none" stroke="#000000" d="M120.5,-732.9623C120.5,-728.7143 120.5,-722.3733 120.5,-715.1925"/>
+<polygon fill="#000000" stroke="#000000" points="124.0001,-714.9976 120.5,-704.9976 117.0001,-714.9976 124.0001,-714.9976"/>
+<text text-anchor="middle" x="121.8895" y="-716" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"> </text>
+</g>
+<!-- _final -->
+<g id="node2" class="node">
+<title>_final</title>
+<polygon fill="transparent" stroke="transparent" stroke-width="2" points="129,-46 0,-46 0,0 129,0 129,-46"/>
+<text text-anchor="start" x="53.999" y="-29.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">final</text>
+<text text-anchor="start" x="6.1646" y="-9.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">onentry/ ^out.all_good</text>
+<polygon fill="#000000" stroke="#000000" points=".5,-23 .5,-23 129.5,-23 129.5,-23 .5,-23"/>
+<path fill="none" stroke="#000000" stroke-width="2" d="M13,-1C13,-1 116,-1 116,-1 122,-1 128,-7 128,-13 128,-13 128,-33 128,-33 128,-39 122,-45 116,-45 116,-45 13,-45 13,-45 7,-45 1,-39 1,-33 1,-33 1,-13 1,-13 1,-7 7,-1 13,-1"/>
+</g>
+<!-- _arithmetic_initial -->
+<g id="node4" class="node">
+<title>_arithmetic_initial</title>
+<ellipse fill="#000000" stroke="#000000" stroke-width="2" cx="64.5" cy="-661.5" rx="5.5" ry="5.5"/>
+</g>
+<!-- _arithmetic_s1 -->
+<g id="node5" class="node">
+<title>_arithmetic_s1</title>
+<polygon fill="transparent" stroke="transparent" stroke-width="2" points="92.5,-610 36.5,-610 36.5,-574 92.5,-574 92.5,-610"/>
+<text text-anchor="start" x="58.1646" y="-588.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">s1</text>
+<path fill="none" stroke="#000000" stroke-width="2" d="M48.8333,-575C48.8333,-575 80.1667,-575 80.1667,-575 85.8333,-575 91.5,-580.6667 91.5,-586.3333 91.5,-586.3333 91.5,-597.6667 91.5,-597.6667 91.5,-603.3333 85.8333,-609 80.1667,-609 80.1667,-609 48.8333,-609 48.8333,-609 43.1667,-609 37.5,-603.3333 37.5,-597.6667 37.5,-597.6667 37.5,-586.3333 37.5,-586.3333 37.5,-580.6667 43.1667,-575 48.8333,-575"/>
+</g>
+<!-- _arithmetic_initial&#45;&gt;_arithmetic_s1 -->
+<g id="edge2" class="edge">
+<title>_arithmetic_initial&#45;&gt;_arithmetic_s1</title>
+<path fill="none" stroke="#000000" d="M64.5,-655.5745C64.5,-647.7003 64.5,-633.2498 64.5,-620.1135"/>
+<polygon fill="#000000" stroke="#000000" points="68.0001,-620.0109 64.5,-610.011 61.0001,-620.011 68.0001,-620.0109"/>
+<text text-anchor="middle" x="65.8895" y="-630" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"> </text>
+</g>
+<!-- _arithmetic_s2 -->
+<g id="node6" class="node">
+<title>_arithmetic_s2</title>
+<polygon fill="transparent" stroke="transparent" stroke-width="2" points="92.5,-528 36.5,-528 36.5,-492 92.5,-492 92.5,-528"/>
+<text text-anchor="start" x="58.1646" y="-506.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">s2</text>
+<path fill="none" stroke="#000000" stroke-width="2" d="M48.8333,-493C48.8333,-493 80.1667,-493 80.1667,-493 85.8333,-493 91.5,-498.6667 91.5,-504.3333 91.5,-504.3333 91.5,-515.6667 91.5,-515.6667 91.5,-521.3333 85.8333,-527 80.1667,-527 80.1667,-527 48.8333,-527 48.8333,-527 43.1667,-527 37.5,-521.3333 37.5,-515.6667 37.5,-515.6667 37.5,-504.3333 37.5,-504.3333 37.5,-498.6667 43.1667,-493 48.8333,-493"/>
+</g>
+<!-- _arithmetic_s1&#45;&gt;_arithmetic_s2 -->
+<g id="edge3" class="edge">
+<title>_arithmetic_s1&#45;&gt;_arithmetic_s2</title>
+<path fill="none" stroke="#000000" d="M64.5,-573.8015C64.5,-563.3976 64.5,-550.1215 64.5,-538.3768"/>
+<polygon fill="#000000" stroke="#000000" points="68.0001,-538.1476 64.5,-528.1476 61.0001,-538.1476 68.0001,-538.1476"/>
+<text text-anchor="start" x="64.5" y="-548" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">[1 + 1 == 2] &#160;&#160;</text>
+</g>
+<!-- _arithmetic_s3 -->
+<g id="node7" class="node">
+<title>_arithmetic_s3</title>
+<polygon fill="transparent" stroke="transparent" stroke-width="2" points="92.5,-446 36.5,-446 36.5,-410 92.5,-410 92.5,-446"/>
+<text text-anchor="start" x="58.1646" y="-424.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">s3</text>
+<path fill="none" stroke="#000000" stroke-width="2" d="M48.8333,-411C48.8333,-411 80.1667,-411 80.1667,-411 85.8333,-411 91.5,-416.6667 91.5,-422.3333 91.5,-422.3333 91.5,-433.6667 91.5,-433.6667 91.5,-439.3333 85.8333,-445 80.1667,-445 80.1667,-445 48.8333,-445 48.8333,-445 43.1667,-445 37.5,-439.3333 37.5,-433.6667 37.5,-433.6667 37.5,-422.3333 37.5,-422.3333 37.5,-416.6667 43.1667,-411 48.8333,-411"/>
+</g>
+<!-- _arithmetic_s2&#45;&gt;_arithmetic_s3 -->
+<g id="edge4" class="edge">
+<title>_arithmetic_s2&#45;&gt;_arithmetic_s3</title>
+<path fill="none" stroke="#000000" d="M64.5,-491.8015C64.5,-481.3976 64.5,-468.1215 64.5,-456.3768"/>
+<polygon fill="#000000" stroke="#000000" points="68.0001,-456.1476 64.5,-446.1476 61.0001,-456.1476 68.0001,-456.1476"/>
+<text text-anchor="start" x="64.5" y="-466" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">[42 == 52 &#45; 11 + 1] &#160;&#160;</text>
+</g>
+<!-- _arithmetic_s4 -->
+<g id="node8" class="node">
+<title>_arithmetic_s4</title>
+<polygon fill="transparent" stroke="transparent" stroke-width="2" points="92.5,-364 36.5,-364 36.5,-328 92.5,-328 92.5,-364"/>
+<text text-anchor="start" x="58.1646" y="-342.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">s4</text>
+<path fill="none" stroke="#000000" stroke-width="2" d="M48.8333,-329C48.8333,-329 80.1667,-329 80.1667,-329 85.8333,-329 91.5,-334.6667 91.5,-340.3333 91.5,-340.3333 91.5,-351.6667 91.5,-351.6667 91.5,-357.3333 85.8333,-363 80.1667,-363 80.1667,-363 48.8333,-363 48.8333,-363 43.1667,-363 37.5,-357.3333 37.5,-351.6667 37.5,-351.6667 37.5,-340.3333 37.5,-340.3333 37.5,-334.6667 43.1667,-329 48.8333,-329"/>
+</g>
+<!-- _arithmetic_s3&#45;&gt;_arithmetic_s4 -->
+<g id="edge5" class="edge">
+<title>_arithmetic_s3&#45;&gt;_arithmetic_s4</title>
+<path fill="none" stroke="#000000" d="M64.5,-409.8015C64.5,-399.3976 64.5,-386.1215 64.5,-374.3768"/>
+<polygon fill="#000000" stroke="#000000" points="68.0001,-374.1476 64.5,-364.1476 61.0001,-374.1476 68.0001,-374.1476"/>
+<text text-anchor="start" x="64.5" y="-384" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">[2 * 3 == 6] &#160;&#160;</text>
+</g>
+<!-- _arithmetic_s5 -->
+<g id="node9" class="node">
+<title>_arithmetic_s5</title>
+<polygon fill="transparent" stroke="transparent" stroke-width="2" points="92.5,-282 36.5,-282 36.5,-246 92.5,-246 92.5,-282"/>
+<text text-anchor="start" x="58.1646" y="-260.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">s5</text>
+<path fill="none" stroke="#000000" stroke-width="2" d="M48.8333,-247C48.8333,-247 80.1667,-247 80.1667,-247 85.8333,-247 91.5,-252.6667 91.5,-258.3333 91.5,-258.3333 91.5,-269.6667 91.5,-269.6667 91.5,-275.3333 85.8333,-281 80.1667,-281 80.1667,-281 48.8333,-281 48.8333,-281 43.1667,-281 37.5,-275.3333 37.5,-269.6667 37.5,-269.6667 37.5,-258.3333 37.5,-258.3333 37.5,-252.6667 43.1667,-247 48.8333,-247"/>
+</g>
+<!-- _arithmetic_s4&#45;&gt;_arithmetic_s5 -->
+<g id="edge6" class="edge">
+<title>_arithmetic_s4&#45;&gt;_arithmetic_s5</title>
+<path fill="none" stroke="#000000" d="M64.5,-327.8015C64.5,-317.3976 64.5,-304.1215 64.5,-292.3768"/>
+<polygon fill="#000000" stroke="#000000" points="68.0001,-292.1476 64.5,-282.1476 61.0001,-292.1476 68.0001,-292.1476"/>
+<text text-anchor="start" x="64.5" y="-302" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">[21 / 3 == 7] &#160;&#160;</text>
+</g>
+<!-- _arithmetic_s6 -->
+<g id="node10" class="node">
+<title>_arithmetic_s6</title>
+<polygon fill="transparent" stroke="transparent" stroke-width="2" points="92.5,-200 36.5,-200 36.5,-164 92.5,-164 92.5,-200"/>
+<text text-anchor="start" x="58.1646" y="-178.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">s6</text>
+<path fill="none" stroke="#000000" stroke-width="2" d="M48.8333,-165C48.8333,-165 80.1667,-165 80.1667,-165 85.8333,-165 91.5,-170.6667 91.5,-176.3333 91.5,-176.3333 91.5,-187.6667 91.5,-187.6667 91.5,-193.3333 85.8333,-199 80.1667,-199 80.1667,-199 48.8333,-199 48.8333,-199 43.1667,-199 37.5,-193.3333 37.5,-187.6667 37.5,-187.6667 37.5,-176.3333 37.5,-176.3333 37.5,-170.6667 43.1667,-165 48.8333,-165"/>
+</g>
+<!-- _arithmetic_s5&#45;&gt;_arithmetic_s6 -->
+<g id="edge7" class="edge">
+<title>_arithmetic_s5&#45;&gt;_arithmetic_s6</title>
+<path fill="none" stroke="#000000" d="M64.5,-245.8015C64.5,-235.3976 64.5,-222.1215 64.5,-210.3768"/>
+<polygon fill="#000000" stroke="#000000" points="68.0001,-210.1476 64.5,-200.1476 61.0001,-210.1476 68.0001,-210.1476"/>
+<text text-anchor="start" x="64.5" y="-220" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">[256 == 2 ** 2 ** 3] &#160;&#160;</text>
+</g>
+<!-- _arithmetic_s7 -->
+<g id="node11" class="node">
+<title>_arithmetic_s7</title>
+<polygon fill="transparent" stroke="transparent" stroke-width="2" points="92.5,-118 36.5,-118 36.5,-82 92.5,-82 92.5,-118"/>
+<text text-anchor="start" x="58.1646" y="-96.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">s7</text>
+<path fill="none" stroke="#000000" stroke-width="2" d="M48.8333,-83C48.8333,-83 80.1667,-83 80.1667,-83 85.8333,-83 91.5,-88.6667 91.5,-94.3333 91.5,-94.3333 91.5,-105.6667 91.5,-105.6667 91.5,-111.3333 85.8333,-117 80.1667,-117 80.1667,-117 48.8333,-117 48.8333,-117 43.1667,-117 37.5,-111.3333 37.5,-105.6667 37.5,-105.6667 37.5,-94.3333 37.5,-94.3333 37.5,-88.6667 43.1667,-83 48.8333,-83"/>
+</g>
+<!-- _arithmetic_s6&#45;&gt;_arithmetic_s7 -->
+<g id="edge8" class="edge">
+<title>_arithmetic_s6&#45;&gt;_arithmetic_s7</title>
+<path fill="none" stroke="#000000" d="M64.5,-163.8015C64.5,-153.3976 64.5,-140.1215 64.5,-128.3768"/>
+<polygon fill="#000000" stroke="#000000" points="68.0001,-128.1476 64.5,-118.1476 61.0001,-128.1476 68.0001,-128.1476"/>
+<text text-anchor="start" x="64.5" y="-138" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">[5 % 2 == 1] &#160;&#160;</text>
+</g>
+<!-- _arithmetic_s7&#45;&gt;_final -->
+<g id="edge9" class="edge">
+<title>_arithmetic_s7&#45;&gt;_final</title>
+<path fill="none" stroke="#000000" d="M64.5,-81.7521C64.5,-74.0806 64.5,-64.9093 64.5,-56.1197"/>
+<polygon fill="#000000" stroke="#000000" points="68.0001,-56.0895 64.5,-46.0895 61.0001,-56.0895 68.0001,-56.0895"/>
+<text text-anchor="middle" x="65.8895" y="-57" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"> </text>
+</g>
+</g>
+</svg>

+ 50 - 0
test/new_test_files/features/expressions/test_expressions.xml

@@ -0,0 +1,50 @@
+<?xml version="1.0" ?>
+<test>
+  <statechart>
+    <!-- after events are always received as input events in a later big step -->
+    <semantics
+        big_step_maximality="take_many"
+        combo_step_maximality="*"/>
+    <tree>
+      <state initial="arithmetic">
+
+        <state id="arithmetic" initial="s1">
+          <state id="s1">
+            <transition cond="1 + 1 == 2" target="../s2"/>
+          </state>
+          <state id="s2">
+            <transition cond="42 == 52 - 11 + 1" target="../s3"/>
+          </state>
+          <state id="s3">
+            <transition cond="2 * 3 == 6" target="../s4"/>
+          </state>
+          <state id="s4">
+            <transition cond="21 / 3 == 7" target="../s5"/>
+          </state>
+          <state id="s5">
+            <transition cond="256 == 2 ** 2 ** 3" target="../s6"/>
+          </state>
+          <state id="s6">
+            <transition cond="5 % 2 == 1" target="../s7"/>
+          </state>
+          <state id="s7">
+            <transition target="/final"/>
+          </state>
+
+        </state>
+
+        <state id="final">
+          <onentry>
+            <raise event="all_good" port="out"/>
+          </onentry>
+        </state>
+
+      </state>
+    </tree>
+  </statechart>
+  <output>
+    <big_step>
+      <event name="all_good" port="out"/>
+    </big_step>
+  </output>
+</test>