Преглед изворни кода

Action language: Added ArrayIndexed construct as LValue and Expression

Joeri Exelmans пре 5 година
родитељ
комит
12f5b7ab72

+ 59 - 0
examples/stove/statechart_stove.xml

@@ -0,0 +1,59 @@
+<statechart>
+  <!-- this statechart is shown as an example in the thesis -->
+  <!-- is included here and can be "checked" for syntax correctness with the tool in sccd.statechart.cmd.check_model -->
+  <datamodel>
+    burners = [0, 0, 0, 0];
+    selected = 0;
+
+    min = func(a: int, b: int) {
+      if (a &lt; b) return a;
+      return b;
+    };
+
+    increase = func {
+      burners[selected] = min(burners[selected] + 1, 9);
+    };
+  </datamodel>
+
+  <inport name="in">
+    <event name="pressed_increase"/>
+    <event name="released_increase"/>
+    <event name="select_next"/>
+  </inport>
+
+  <root>
+    <parallel id="p">
+      <!-- upper orthogonal region -->
+      <state id="heat" initial="Released">
+        <state id="Released">
+          <transition event="pressed_increase" target="../Pushed"/>
+        </state>
+
+        <state id="Pushed" initial="Waiting">
+          <onentry>
+            <code> increase(); </code>
+          </onentry>
+          <transition event="released_increase" target="../Released"/>
+
+          <state id="Waiting">
+            <transition after="1 s" target="../Increasing"/>
+          </state>
+          <state id="Increasing">
+            <transition after="200 ms" target=".">
+              <code> increase(); </code>
+            </transition>
+          </state>
+        </state>
+      </state>
+
+      <!-- lower orthogonal region -->
+      <state id="burner_select">
+        <state id="BurnerSelect">
+          <transition event="select_next" target=".">
+            <code> selected = (selected + 1) % 4; </code>
+          </transition>
+        </state>
+      </state>
+    </parallel>
+  </root>
+</statechart>

+ 4 - 0
src/sccd/action_lang/parser/action_lang.g

@@ -39,6 +39,7 @@
      | "(" expr ")"             -> group
      | literal
      | func_call
+     | array_indexed
      | func_decl
      | array
 
@@ -47,6 +48,8 @@ IDENTIFIER: /[A-Za-z_][A-Za-z_0-9]*/
 func_call: atom "(" param_list ")"
 param_list: ( expr ("," expr)* )?  -> params
 
+array_indexed: atom "[" expr "]"
+
 func_decl: "func" params_decl stmt
 params_decl: ( "(" param_decl ("," param_decl)* ")" )?
 ?param_decl: IDENTIFIER ":" type_annot
@@ -132,6 +135,7 @@ assignment: lhs assign_operator expr
 increment: lhs "+=" expr
 
 ?lhs: IDENTIFIER -> identifier
+    | array_indexed
 
 ?assign_operator: ASSIGN | INCREMENT | DECREMENT | MULTIPLY | DIVIDE
 

+ 3 - 0
src/sccd/action_lang/parser/text.py

@@ -52,6 +52,9 @@ class ExpressionTransformer(Transformer):
   def func_call(self, node):
     return FunctionCall(node[0], node[1].children)
 
+  def array_indexed(self, node):
+    return ArrayIndexed(node[0], node[1])
+
   def identifier(self, node):
     name = node[0].value
     return Identifier(name)

+ 38 - 8
src/sccd/action_lang/static/expression.py

@@ -67,14 +67,9 @@ class LValue(Expression):
     #   offset ∈ [0, +∞[ : variable's memory address is within current scope
     #   offset ∈ ]-∞, 0[ : variable's memory address is in a parent scope (or better: 'context scope')
     @abstractmethod
-    def eval_lvalue(self) -> int:
+    def assign(self, memory: MemoryInterface, value: Any):
         pass
 
-    # Any type that is an LValue can also serve as an expression!
-    def eval(self, memory: MemoryInterface):
-        offset = self.eval_lvalue()
-        return memory.load(offset)
-
 @dataclass
 class Identifier(LValue):
     name: str
@@ -87,8 +82,11 @@ class Identifier(LValue):
     def init_lvalue(self, scope: Scope, type):
         self.offset = scope.put_lvalue(self.name, type)
 
-    def eval_lvalue(self) -> int:
-        return self.offset
+    def assign(self, memory: MemoryInterface, value: Any):
+        memory.store(self.offset, value)
+
+    def eval(self, memory: MemoryInterface):
+        return memory.load(self.offset)
 
     def render(self):
         return self.name
@@ -165,6 +163,38 @@ class FunctionDeclaration(Expression):
     def render(self) -> str:
         return "func(%s) [...]" % ", ".join(p.render() for p in self.params_decl) # todo
         
+@dataclass
+class ArrayIndexed(LValue):
+    array: Expression
+    index: Expression
+
+    def init_expr(self, scope: Scope) -> SCCDType:
+        array_type = self.array.init_expr(scope)
+        if not isinstance(array_type, SCCDArray):
+            raise StaticTypeError("Array indexation: Expression '%s' is not an array" % self.array.render())
+        index_type = self.index.init_expr(scope)
+        if index_type is not SCCDInt:
+            raise StaticTypeError("Array indexation: Expression '%s' is not an integer" % self.index_type.render())
+        return array_type.element_type
+
+    def init_lvalue(self, scope: Scope, type):
+        if not isinstance(self.array, LValue):
+            raise StaticTypeError("Array indexation as LValue: Expression '%s' must be an LValue" % self.array.render())
+
+        self.array.init_lvalue(scope, SCCDArray(element_type=type))
+
+    def assign(self, memory: MemoryInterface, value):
+        self.array.eval(memory)[self.index.eval(memory)] = value
+
+    def render(self):
+        return self.name
+
+    def eval(self, memory: MemoryInterface):
+        index = self.index.eval()
+        return array.eval(memory)[index]
+
+    def render(self):
+        return self.array.render() + '[' + self.index.render() + ']'
 
 @dataclass
 class StringLiteral(Expression):

+ 1 - 3
src/sccd/action_lang/static/statement.py

@@ -103,9 +103,7 @@ class Assignment(Statement):
 
     def exec(self, memory: MemoryInterface) -> Return:
         rhs_val = self.rhs.eval(memory)
-        offset = self.lhs.eval_lvalue()
-
-        memory.store(offset, rhs_val)
+        self.lhs.assign(memory, rhs_val)
 
         return DontReturn