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): 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] type_edge_val = yield [("RE", [i]) for i in edge_types] src_nodes = set([i[0] for i in type_edge_val]) found_edges = yield [("RDE", [i, c_val]) for i in src_nodes] 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 srcdst, = yield [("RE", [elems[i]])] source, destination = srcdst # 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] _ = 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"])] m3, = yield [("RD", [metamodel, "metamodel"])] m3_model, = yield [("RD", [m3, "model"])] 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", [m3_model, "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) def add_AL(a, b, **remainder): worklist = [(b, "funcdef")] added = set() type_cache = {} model_dict, = yield [("RD", [a, "model"])] metamodel, = yield [("RD", [a, "metamodel"])] metamodel_dict, = yield [("RD", [metamodel, "model"])] type_map, = yield [("RD", [a, "type_mapping"])] outgoing, = yield [("RO", [model_dict])] edges = yield [("RE", [i]) for i in outgoing] added |= set([i[1] for i in edges]) result, = yield [("CNV", ["__%s" % b])] # All the action language elements and their expected output links type_links = { "if": [("cond", ""), ("then", ""), ("else", ""), ("next", "")], "while": [("cond", ""), ("body", ""), ("next", "")], "assign": [("var", ""), ("value", ""), ("next", "")], "break": [("while", "while")], "continue": [("while", "while")], "return": [("value", "")], "resolve": [("var", "")], "access": [("var", "")], "constant": [("node", "")], "output": [("node", ""), ("next", "")], "global": [("var", "String"), ("next", "")], "param": [("name", "String"), ("value", ""), ("next_param", "param")], "funcdef": [("body", ""), ("next", "")], "call": [("func", ""), ("params", "param"), ("last_param", "param"), ("next", "")], } # Already add some often used types to the type cache, so we don't have to check for their presence to_str, string = yield [("RD", [metamodel_dict, "to_str"]), ("RD", [metamodel_dict, "String"])] type_cache = {"to_str": to_str, "String": string} while worklist: # Fetch the element and see if we need to add it worknode, expected_type = worklist.pop(0) if worknode in added: continue # Determine type of element if expected_type == "": value, = yield [("RV", [worknode])] if (isinstance(value, dict)) and ("value" in value): v = value["value"] if v in ["if", "while", "assign", "call", "break", "continue", "return", "resolve", "access", "constant", "global", "declare"]: expected_type = v else: expected_type = "Any" else: expected_type = "Any" # Fill the cache if expected_type not in type_cache: type_cache[expected_type], = yield [("RD", [metamodel_dict, expected_type])] # Need to add it now yield [("CD", [model_dict, "__%s" % worknode, worknode])] added.add(worknode) # NOTE can't just use CD here, as the key is a node and not a value t1, = yield [("CE", [type_map, type_cache[expected_type]])] t2, = yield [("CE", [t1, worknode])] if t1 is None or t2 is None: raise Exception("ERROR") # Now add all its outgoing links, depending on the type we actually saw links = type_links.get(expected_type, []) for link in links: link_name, destination_type = link # Check if the link actually exists destination, = yield [("RD", [worknode, link_name])] if destination is not None: # If so, we add it and continue edge, = yield [("RDE", [worknode, link_name])] edge_outlinks, = yield [("RO", [edge])] edge_outlink = edge_outlinks[0] edge_name, = yield [("RE", [edge_outlink])] edge_name = edge_name[1] # Now add: edge, edge_outlink, edge_name # Add 'edge' yield [("CD", [model_dict, "__%s" % edge, edge])] added.add(edge) link_type = "%s_%s" % (expected_type, link_name) if link_type not in type_cache: type_cache[link_type], = yield [("RD", [metamodel_dict, link_type])] t, = yield [("CE", [type_map, type_cache[link_type]])] yield [("CE", [t, edge])] # Add 'edge_outlink' yield [("CD", [model_dict, "__%s" % edge_outlink, edge_outlink])] added.add(edge_outlink) t, = yield [("CE", [type_map, type_cache["to_str"]])] yield [("CE", [t, edge_outlink])] # Add 'edge_name' (if not present) if edge_name not in added: yield [("CD", [model_dict, "__%s" % edge_name, edge_name])] t, = yield [("CE", [type_map, type_cache["String"]])] yield [("CE", [t, edge_name])] added.add(edge_name) # Add the destination to the worklist worklist.append((destination, destination_type)) raise PrimitiveFinished(result) def get_superclasses(a, b, **remainder): mm, = yield [("RD", [a, "metamodel"])] mm, = yield [("RD", [mm, "metamodel"])] m, = yield [("RD", [mm, "model"])] inheritance, = yield [("RD", [m, "Inheritance"])] model_dict, = yield [("RD", [a, "model"])] b_v, = yield [("RV", [b])] subclass, = yield [("RD", [model_dict, b_v])] type_mapping, = yield [("RD", [a, "type_mapping"])] names, = yield [("RDK", [model_dict])] elems = yield [("RDN", [model_dict, i]) for i in names] elem_to_name = dict(zip(elems, names)) result, = yield [("CN", [])] worklist = [subclass] touched = set() while worklist: subclass = worklist.pop() res = elem_to_name[subclass] if subclass not in touched: touched.add(subclass) yield [("CE", [result, res])] outgoing, = yield [("RO", [subclass])] types = yield [("RDN", [type_mapping, i]) for i in outgoing] for i, t in enumerate(types): if t == inheritance: # Found an inheritance link! elem = outgoing[i] srcdst, = yield [("RE", [elem])] src, dst = srcdst # Find elem in elems worklist.append(dst) raise PrimitiveFinished(result) def selectPossibleIncoming(a, b, c, **remainder): model_dict, = yield [("RD", [a, "model"])] limit_set_links, = \ yield [("RO", [c])] limit_set = yield [("RE", [i]) for i in limit_set_links] limit_set_names = [i[1] for i in limit_set] name_values = yield [("RV", [i]) for i in limit_set_names] limit_set = yield [("RD", [model_dict, i]) for i in name_values] try: gen = get_superclasses(a, b) inp = None while 1: inp = yield gen.send(inp) except PrimitiveFinished as e: superclasses = e.result vals, = yield [("RO", [superclasses])] superclasses = yield [("RE", [i]) for i in vals] superclasses = [i[1] for i in superclasses] superclass_names = yield [("RV", [i]) for i in superclasses] elems = yield [("RD", [model_dict, i]) for i in superclass_names] result, = yield [("CN", [])] for i, edge in enumerate(limit_set): srcdst, = yield [("RE", [edge])] src, dst = srcdst if dst in elems: yield [("CE", [result, limit_set_names[i]])] raise PrimitiveFinished(result) def selectPossibleOutgoing(a, b, c, **remainder): model_dict, = yield [("RD", [a, "model"])] limit_set_links, = \ yield [("RO", [c])] limit_set = yield [("RE", [i]) for i in limit_set_links] limit_set_names = \ [i[1] for i in limit_set] name_values = yield [("RV", [i]) for i in limit_set_names] limit_set = yield [("RD", [model_dict, i]) for i in name_values] try: gen = get_superclasses(a, b) inp = None while 1: inp = yield gen.send(inp) except PrimitiveFinished as e: superclasses = e.result vals, = yield [("RO", [superclasses])] superclasses = yield [("RE", [i]) for i in vals] superclasses = [i[1] for i in superclasses] superclass_names = yield [("RV", [i]) for i in superclasses] elems = yield [("RD", [model_dict, i]) for i in superclass_names] result, = yield [("CN", [])] for i, edge in enumerate(limit_set): srcdst, = yield [("RE", [edge])] src, dst = srcdst if src in elems: yield [("CE", [result, limit_set_names[i]])] raise PrimitiveFinished(result) def check_symbols(a, b, c, **remainder): symbols = {} function_name, = yield [("RV", [b])] symbols[function_name] = False object_links, = yield [("RO", [c])] set_elements = yield [("RE", [i]) for i in object_links] set_elements = [i[1] for i in set_elements] set_values = yield [("RV", [i]) for i in set_elements] set_elements = yield [("RD", [a, i]) for i in set_values] symbols_set = yield [("RD", [i, "symbols"]) for i in set_elements] all_keys = yield [("RDK", [i]) for i in symbols_set] for i, s in zip(all_keys, symbols_set): # For each object we have found keys = yield [("RV", [j]) for j in i] values = yield [("RD", [s, j]) for j in keys] values = yield [("RV", [j]) for j in values] for key, value in zip(keys, values): k = key v = value if v and symbols.get(k, False): result = yield [("CNV", ["ERROR: multiple definition of symbol " + str(key)])] raise PrimitiveFinished(result) elif v and not symbols.get(k, False): symbols[k] = True elif not v and k not in symbols: symbols[k] = False for i, j in symbols.items(): if i == "input" or i == "output": continue if not j: result, = yield [("CNV", ["ERROR: undefined symbol " + str(i)])] raise PrimitiveFinished(result) result, = yield [("CNV", ["OK"])] raise PrimitiveFinished(result) def construct_const(**remainder): v, = yield [("CNV", [{"value": "constant"}])] # Get input: keep trying until we get something try: gen = __get_input(remainder) inp = None while 1: inp = yield gen.send(inp) except PrimitiveFinished as e: inp = e.result yield [("CD", [v, "node", inp])] raise PrimitiveFinished(v) def instantiated_name(a, b, **remainder): name_value, = yield [("RV", [b])] if name_value == "": b, = yield [("CNV", ["__" + str(a)])] raise PrimitiveFinished(b) def retype(a, b, c, **remainder): tm, = yield [("RD", [a, "type_mapping"])] m, = yield [("RD", [a, "model"])] mm, = yield [("RD", [a, "metamodel"])] mm_dict, = yield [("RD", [mm, "model"])] c_val, = yield [("RV", [c])] mm_ref, = yield [("RD", [mm_dict, c_val])] b_val, = yield [("RV", [b])] m_ref, = yield [("RD", [m, b_val])] prev_edge, = yield [("RDNE", [tm, m_ref])] if prev_edge is not None: yield [("DE", [prev_edge])] t, = yield [("CE", [tm, mm_ref])] yield [("CE", [t, m_ref])] raise PrimitiveFinished(None) def __get_input(parameters): mvk = parameters["mvk"] user_root = parameters["user_root"] while 1: try: gen = mvk.input_init(user_root) inp = None while 1: inp = yield gen.send(inp) except StopIteration: # Finished if mvk.success: # Got some input, so we can access it raise PrimitiveFinished(mvk.input_value) else: # No input, so yield None but don't stop yield None