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)