Browse Source

(WIP) add CBD language

Joeri Exelmans 9 months ago
parent
commit
641e4b9810

+ 55 - 0
examples/cbd/models.py

@@ -0,0 +1,55 @@
+import os
+from framework.conformance import Conformance, render_conformance_check_result
+from concrete_syntax.textual_od import parser
+
+
+# get file contents as string
+def read_file(filename):
+    dir = os.path.dirname(__file__)
+    with open(dir+'/'+filename) as file:
+        return file.read()
+
+# def parse_and_check(state, cs_file, mm):
+#     m_cs = read_file(cs_file)
+#     try:
+#         _parse_and_check(state, m_cs, mm)
+#     except Exception as e:
+#         e.add_note(f"While parsing '{cs_file}'")
+#         raise
+#     return m
+
+def parse_and_check(state, m_cs, mm, descr: str):
+    try:
+        m = parser.parse_od(
+            state,
+            m_text=m_cs,
+            mm=mm,
+        )
+        conf = Conformance(state, m, mm)
+        errors = conf.check_nominal()
+        if len(errors) > 0:
+            raise Exception(render_conformance_check_result(errors))
+    except Exception as e:
+        e.add_note("While parsing model " + descr)
+        raise
+    return m
+
+def get_metamodels(state, scd_mmm):
+    mm_cs    =         read_file('models/mm_design.od')
+    mm_rt_cs = mm_cs + read_file('models/mm_runtime.od')
+
+    mm    = parse_and_check(state, mm_cs,    scd_mmm, "Design meta-model")
+    mm_rt = parse_and_check(state, mm_rt_cs, scd_mmm, "Runtime meta-model")
+
+    return (mm, mm_rt)
+
+def get_fibonacci(state, scd_mmm):
+    mm, mm_rt = get_metamodels(state, scd_mmm)
+
+    m_cs            =        read_file('models/m_fibonacci.od')
+    m_rt_initial_cs = m_cs + read_file('models/m_fibonacci_initial.od')
+
+    m            = parse_and_check(state, m_cs,            mm,    "Fibonacci model")
+    m_rt_initial = parse_and_check(state, m_rt_initial_cs, mm_rt, "Fibonacci initial state")
+
+    return (mm, mm_rt, m, m_rt_initial)

+ 34 - 0
examples/cbd/models/m_fibonacci.od

@@ -0,0 +1,34 @@
+adder:Function {
+  func = ```
+    n2_out = in0 + in1
+  ```;
+}
+n0_in:IntInPort
+n1_in:IntInPort
+n2_out:IntOutPort
+:hasInPort (adder -> n0_in)
+:hasInPort (adder -> n1_in)
+:hasOutPort (adder -> n2_out)
+
+
+
+d0:Delay
+d0_in:IntInPort
+d0_out:IntOutPort
+:hasInPort (d0 -> d0_in)
+:hasOutPort (d0 -> d0_out)
+
+
+
+d1:Delay
+d1_in:IntInPort
+d1_out:IntOutPort
+:hasInPort (d1 -> d1_in)
+:hasOutPort (d1 -> d1_out)
+
+
+
+:intLink (n2_out -> d1_in)
+:intLink (d1_out -> n1_in)
+:intLink (d1_out -> d0_in)
+:intLink (d1_out -> n0_in)

+ 8 - 0
examples/cbd/models/m_fibonacci_initial.od

@@ -0,0 +1,8 @@
+d0s:IntState {
+  state = 0;
+}
+d1s:IntState {
+  state = 1;
+}
+:delay2State (d0 -> d0s)
+:delay2State (d1 -> d1s)

+ 129 - 0
examples/cbd/models/mm_design.od

@@ -0,0 +1,129 @@
+Block:Class {
+  abstract = True;
+}
+
+InPort:Class {
+  abstract = True;
+}
+OutPort:Class {
+  abstract = True;
+}
+
+hasInPort:Association (Block -> InPort) {
+  # Every Port contained by exactly one Block:
+  source_lower_cardinality = 1;
+  source_upper_cardinality = 1;
+}
+hasOutPort:Association (Block -> OutPort) {
+  # Every Port contained by exactly one Block:
+  source_lower_cardinality = 1;
+  source_upper_cardinality = 1;
+}
+
+link:Association (OutPort -> InPort) {
+  #abstract = True;
+
+  # Every InPort connected to exactly one OutPort
+  source_lower_cardinality = 1;
+  source_upper_cardinality = 1;
+}
+
+
+# In- and Out-Ports are labeled:
+
+# hasInPort_label:AttributeLink (hasInPort -> String) {
+#   name = "label";
+#   optional = False;
+# }
+# hasOutPort_label:AttributeLink (hasOutPort -> String) {
+#   name = "label";
+#   optional = False;
+# }
+
+
+
+# Function Block: pure function that computes outputs based on inputs
+
+Function:Class
+:Inheritance (Function -> Block)
+
+Function_func:AttributeLink (Function -> ActionCode) {
+  name = "func";
+  optional = False;
+}
+
+DetailedFunction:Class
+:Inheritance (DetailedFunction -> Function)
+
+VeryDetailedFunction:Class
+:Inheritance (VeryDetailedFunction -> DetailedFunction)
+
+
+
+# Delay Block
+
+Delay:Class {
+  constraint = ```
+    errors = []
+    num_inports = len(get_outgoing(this, "hasInPort"))
+    num_outports = len(get_outgoing(this, "hasOutPort"))
+    if num_inports != 1:
+      errors.append(f"Delay block must have one inport, instead got {num_inports}")
+      in_type = None
+    else:
+      in_type = get_type_name(get_target(get_outgoing(this, "hasInPort")[0]))
+    if num_outports != 1:
+      errors.append(f"Delay block must have one inport, instead got {num_outports}")
+      out_type = None
+    else:
+      out_type = get_type_name(get_target(get_outgoing(this, "hasOutPort")[0]))
+    if in_type != None and out_type != None and in_type[0:3] != out_type[0:3]:
+      errors.append(f"Inport type ({in_type}) differs from outport type ({out_type})")
+    errors
+  ```;
+}
+:Inheritance (Delay -> Block)
+
+
+
+
+# Object Diagrams are statically typed, so we must create in/out-ports, and MemorySlots for all primitive types:
+
+
+# Port types
+
+BoolInPort:Class
+IntInPort:Class
+StrInPort:Class
+
+BoolOutPort:Class
+IntOutPort:Class
+StrOutPort:Class
+
+:Inheritance (BoolInPort -> InPort)
+:Inheritance (IntInPort -> InPort)
+:Inheritance (StrInPort -> InPort)
+
+:Inheritance (BoolOutPort -> OutPort)
+:Inheritance (IntOutPort -> OutPort)
+:Inheritance (StrOutPort -> OutPort)
+
+# Link types
+
+boolLink:Association (BoolOutPort -> BoolInPort)
+intLink:Association (IntOutPort -> IntInPort)
+strLink:Association (StrOutPort -> StrInPort)
+
+:Inheritance (boolLink -> link)
+:Inheritance (intLink -> link)
+:Inheritance (strLink -> link)
+
+# Delay block types
+
+BoolDelay:Class
+IntDelay:Class
+StrDelay:Class
+
+:Inheritance (BoolDelay -> Delay)
+:Inheritance (IntDelay -> Delay)
+:Inheritance (StrDelay -> Delay)

+ 55 - 0
examples/cbd/models/mm_runtime.od

@@ -0,0 +1,55 @@
+# Link state ("signal")
+# is optional: absent for yet-to-compute signals
+
+intLink_signal:AttributeLink (intLink -> Integer) {
+  name = "signal";
+  optional = True;
+}
+boolLink_signal:AttributeLink (boolLink -> Boolean) {
+  name = "signal";
+  optional = True;
+}
+strLink_signal:AttributeLink (strLink -> String) {
+  name = "signal";
+  optional = True;
+}
+
+
+
+# Delay block state
+# mandatory - otherwise we cannot determine the output signal of a delay block
+
+State:Class {
+  abstract = True;
+}
+
+delay2State:Association (Delay -> State) {
+  source_lower_cardinality = 1;
+  source_upper_cardinality = 1;
+  target_lower_cardinality = 1;
+  target_upper_cardinality = 1;
+}
+
+BoolState:Class
+IntState:Class
+StrState:Class
+
+:Inheritance (BoolState -> State)
+:Inheritance (IntState -> State)
+:Inheritance (StrState -> State)
+
+
+BoolState_state:AttributeLink (BoolState -> Boolean) {
+  name = "state";
+  optional = False;
+}
+
+IntState_state:AttributeLink (IntState -> Integer) {
+  name = "state";
+  optional = False;
+}
+
+StrState_state:AttributeLink (StrState -> String) {
+  name = "state";
+  optional = False;
+}

+ 8 - 0
examples/cbd/runner.py

@@ -0,0 +1,8 @@
+from state.devstate import DevState
+from bootstrap.scd import bootstrap_scd
+import models
+
+state = DevState()
+scd_mmm = bootstrap_scd(state)
+
+mm, mm_rt, m, m_rt_initial = models.get_fibonacci(state, scd_mmm)