|
@@ -0,0 +1,181 @@
|
|
|
+from modelverse_kernel.primitives import PrimitiveFinished
|
|
|
+
|
|
|
+def reverseKeyLookup(a, b, **remainder):
|
|
|
+ edges = yield [("RO", [a])]
|
|
|
+ expanded_edges = yield [("RE", [i]) for i in edges]
|
|
|
+ for i, edge in enumerate(expanded_edges):
|
|
|
+ if b == edge[1]:
|
|
|
+ # Found our edge: edges[i]
|
|
|
+ outgoing = yield [("RO", [edges[i]])]
|
|
|
+ result = yield [("RE", [outgoing[0]])]
|
|
|
+ raise PrimitiveFinished(result[1])
|
|
|
+
|
|
|
+ result = yield [("CNV", ["(unknown: %s)" % b])]
|
|
|
+ raise PrimitiveFinished(result)
|
|
|
+
|
|
|
+def read_attribute(a, b, c, **remainder):
|
|
|
+ def make_list(v, l):
|
|
|
+ return [v] if l else v
|
|
|
+
|
|
|
+ #TODO this can be optimized even further...
|
|
|
+ model_dict, b_val, c_val, type_mapping = \
|
|
|
+ yield [("RD", [a, "model"]),
|
|
|
+ ("RV", [b]),
|
|
|
+ ("RV", [c]),
|
|
|
+ ("RD", [a, "type_mapping"]),
|
|
|
+ ]
|
|
|
+ model_instance = \
|
|
|
+ yield [("RD", [model_dict, b_val])]
|
|
|
+ edges = yield [("RO", [model_instance])]
|
|
|
+ edge_types = yield [("RDN", [type_mapping, i]) for i in edges]
|
|
|
+ edge_types = make_list(edge_types, len(edges) == 1)
|
|
|
+ type_edge_val = yield [("RE", [i]) for i in edge_types]
|
|
|
+ type_edge_val = make_list(type_edge_val, len(edges) == 1)
|
|
|
+
|
|
|
+ src_nodes = set([i[0] for i in type_edge_val])
|
|
|
+
|
|
|
+ found_edges = yield [("RDE", [i, c_val]) for i in src_nodes]
|
|
|
+ found_edges = make_list(found_edges, len(src_nodes) == 1)
|
|
|
+
|
|
|
+ for e1 in found_edges:
|
|
|
+ if e1 is not None:
|
|
|
+ # Found an edge!
|
|
|
+ for i, e2 in enumerate(edge_types):
|
|
|
+ if e1 == e2:
|
|
|
+ # The instance of this edge is the one we want!
|
|
|
+ edge = edges[i]
|
|
|
+ edge_val = yield [("RE", [edge])]
|
|
|
+ result = edge_val[1]
|
|
|
+ raise PrimitiveFinished(result)
|
|
|
+ else:
|
|
|
+ result = yield [("RR", [])]
|
|
|
+ raise PrimitiveFinished(result)
|
|
|
+
|
|
|
+ raise Exception("Error in reading edge!")
|
|
|
+
|
|
|
+def precompute_cardinalities(a, **remainder):
|
|
|
+ result = yield [("CN", [])]
|
|
|
+
|
|
|
+ # Read out all edges from the metamodel
|
|
|
+ a = yield [("RD", [a, "metamodel"])]
|
|
|
+ model_dict = yield [("RD", [a, "model"])]
|
|
|
+ model_keys = yield [("RDK", [model_dict])]
|
|
|
+ type_mapping = yield [("RD", [a, "type_mapping"])]
|
|
|
+ elems = yield [("RDN", [model_dict, k]) for k in model_keys]
|
|
|
+ model_keys_str= yield [("RV", [i]) for i in model_keys]
|
|
|
+ elem_to_name = dict(zip(elems, model_keys_str))
|
|
|
+ edges = yield [("RE", [i]) for i in elems]
|
|
|
+ elems = [elems[i] for i, edge_val in enumerate(edges) if edge_val is not None]
|
|
|
+ # Now we have all edges in the metamodel
|
|
|
+
|
|
|
+ # Read out the type of the Association defining all cardinalities
|
|
|
+ metamodel = yield [("RD", [a, "metamodel"])]
|
|
|
+ metametamodel = yield [("RD", [metamodel, "metamodel"])]
|
|
|
+ metametamodel_dict = \
|
|
|
+ yield [("RD", [metametamodel, "model"])]
|
|
|
+ assoc = yield [("RD", [metametamodel_dict, "Association"])]
|
|
|
+ slc, suc, tlc, tuc = \
|
|
|
+ yield [("RDE", [assoc, "source_lower_cardinality"]),
|
|
|
+ ("RDE", [assoc, "source_upper_cardinality"]),
|
|
|
+ ("RDE", [assoc, "target_lower_cardinality"]),
|
|
|
+ ("RDE", [assoc, "target_upper_cardinality"]),
|
|
|
+ ]
|
|
|
+
|
|
|
+ # All that we now have to do is find, for each edge, whether or not it has an edge typed by any of these links!
|
|
|
+ # Just find all links typed by these links!
|
|
|
+ types = yield [("RDN", [type_mapping, i]) for i in elems]
|
|
|
+
|
|
|
+ cardinalities = {}
|
|
|
+ for i, edge_type in enumerate(types):
|
|
|
+ if edge_type == slc:
|
|
|
+ t = "slc"
|
|
|
+ elif edge_type == suc:
|
|
|
+ t = "suc"
|
|
|
+ elif edge_type == tlc:
|
|
|
+ t = "tlc"
|
|
|
+ elif edge_type == tuc:
|
|
|
+ t = "tuc"
|
|
|
+ else:
|
|
|
+ continue
|
|
|
+
|
|
|
+ # Found a link, so add it
|
|
|
+ source, destination = yield [("RE", [elems[i]])]
|
|
|
+ # The edge gives the "source" the cardinality found in "destination"
|
|
|
+ cardinalities.setdefault(elem_to_name[source], {})[t] = destination
|
|
|
+
|
|
|
+ # Now we have to translate the "cardinalities" Python dictionary to a Modelverse dictionary
|
|
|
+ nodes = yield [("CN", []) for i in cardinalities]
|
|
|
+ yield [("CD", [result, i, node]) for i, node in zip(cardinalities.keys(), nodes)]
|
|
|
+ l = cardinalities.keys()
|
|
|
+ values = yield [("RD", [result, i]) for i in l]
|
|
|
+
|
|
|
+ for i, value in enumerate(values):
|
|
|
+ cards = cardinalities[l[i]]
|
|
|
+ yield [("CD", [value, card_type, cards[card_type]]) for card_type in cards]
|
|
|
+
|
|
|
+ raise PrimitiveFinished(result)
|
|
|
+
|
|
|
+def set_copy(a, **remainder):
|
|
|
+ b = yield [("CN", [])]
|
|
|
+ links = yield [("RO", [a])]
|
|
|
+ exp_links = yield [("RE", [i]) for i in links]
|
|
|
+ if len(links) == 1:
|
|
|
+ exp_links = [exp_links]
|
|
|
+ _ = yield [("CE", [b, i[1]]) for i in exp_links]
|
|
|
+ raise PrimitiveFinished(b)
|
|
|
+
|
|
|
+def allInstances(a, b, **remainder):
|
|
|
+ b_val = yield [("RV", [b])]
|
|
|
+ model_dict= yield [("RD", [a, "model"])]
|
|
|
+ metamodel = yield [("RD", [a, "metamodel"])]
|
|
|
+ mm_dict = yield [("RD", [metamodel, "model"])]
|
|
|
+ typing = yield [("RD", [a, "type_mapping"])]
|
|
|
+ elem_keys = yield [("RDK", [model_dict])]
|
|
|
+ elems = yield [("RDN", [model_dict, i]) for i in elem_keys]
|
|
|
+ mms = yield [("RDN", [typing, i]) for i in elems]
|
|
|
+
|
|
|
+ # Have the type for each name
|
|
|
+ types_to_name_nodes = {}
|
|
|
+ for key, mm in zip(elem_keys, mms):
|
|
|
+ types_to_name_nodes.setdefault(mm, set()).add(key)
|
|
|
+ # And now we have the inverse mapping: for each type, we have the node containing the name
|
|
|
+
|
|
|
+ # Get the inheritance link type
|
|
|
+ inheritance_type = yield [("RD", [metamodel, "inheritance"])]
|
|
|
+
|
|
|
+ # Now we figure out which types are valid for the specified model
|
|
|
+ desired_types = set()
|
|
|
+ mm_element = yield [("RD", [mm_dict, b_val])]
|
|
|
+ work_list = []
|
|
|
+ work_list.append(mm_element)
|
|
|
+ mm_typing = yield [("RD", [metamodel, "type_mapping"])]
|
|
|
+
|
|
|
+ while work_list:
|
|
|
+ mm_element = work_list.pop()
|
|
|
+ if mm_element in desired_types:
|
|
|
+ # Already been here, so stop
|
|
|
+ continue
|
|
|
+
|
|
|
+ # New element, so continue
|
|
|
+ desired_types.add(mm_element)
|
|
|
+
|
|
|
+ # Follow all inheritance links that COME IN this node, as all these are subtypes and should also match
|
|
|
+ incoming = yield [("RI", [mm_element])]
|
|
|
+ for i in incoming:
|
|
|
+ t = yield [("RDN", [mm_typing, i])]
|
|
|
+ if t == inheritance_type:
|
|
|
+ e = yield [("RE", [i])]
|
|
|
+ # Add the source of the inheritance link to the work list
|
|
|
+ work_list.append(e[0])
|
|
|
+
|
|
|
+ # Now desired_types holds all the direct types that we are interested in!
|
|
|
+ # Construct the result out of all models that are direct instances of our specified type
|
|
|
+ final = set()
|
|
|
+ for t in desired_types:
|
|
|
+ final |= types_to_name_nodes.get(t, set())
|
|
|
+
|
|
|
+ # Result is a Python set with nodes, so just make this a Mv set
|
|
|
+ result = yield [("CN", [])]
|
|
|
+ v = yield [("RV", [i]) for i in final]
|
|
|
+ _ = yield [("CE", [result, i]) for i in final]
|
|
|
+ raise PrimitiveFinished(result)
|