include "primitives.alh" include "modelling.alh" include "object_operations.alh" include "random.alh" include "utils.alh" Boolean function main(model : Element): String result Element nodes String node Element edges String edge String new_node String source String destination String name Element to_explore Element rules String rule String value Element explored Element remainder_to_explore String attr explored = set_create() result = "root, = yield [('RR', [])]\n" nodes = allInstances(model, "Rules/Root") while (set_len(nodes) > 0): node = set_pop(nodes) source = string_replace(node, "/", "_") result = result + source + " = root\n" // Keep following outgoing edges to find matching nodes to_explore = set_create() remainder_to_explore = set_create() set_add(to_explore, node) while (set_len(to_explore) > 0): // Still explore more! node = set_pop(to_explore) source = string_replace(node, "/", "_") edges = allOutgoingAssociationInstances(model, node, "Rules/Edge") while (set_len(edges) > 0): edge = set_pop(edges) new_node = readAssociationDestination(model, edge) if (value_eq(read_attribute(model, new_node, "match"), True)): // Is a match node, so fetch the value on the edge name = read_attribute(model, edge, "value") destination = string_replace(new_node, "/", "_") if (element_eq(name, read_root())): String node_key node_key = string_replace(set_pop(allAssociationDestinations(model, edge, "")), "/", "_") if (set_in(explored, node_key)): result = result + destination + ", = yield [('RDN', [" + source + ", " + node_key + "])]\n" else: set_add(remainder_to_explore, node) else: if (set_in(explored, destination)): // Already visited this one in another way, so try to merge! String rand rand = random_string(10) result = result + rand + ", = yield [('RD', [" + source + ", " + name + "])]\n" result = result + "if " + rand + " != " + destination + ":\n" // If the values don't agree, this is not a correct match, and we say that this element remains unmatched (i.e., assign None) result = result + "\t" + destination + " = None\n" else: // First visit to this element, so just assign result = result + destination + ", = yield [('RD', [" + source + ", " + name + "])]\n" set_add(explored, destination) String value value = read_attribute(model, new_node, "value") if (element_neq(value, read_root())): // Match node has a value we should compare as well! // Read out the value from the Modelverse result = result + destination + "_V, = yield [('RV', [" + destination + "])]\n" set_add(to_explore, new_node) if (bool_and(set_len(to_explore) == 0, set_len(remainder_to_explore) > 0)): to_explore = remainder_to_explore remainder_to_explore = set_create() rules = allInstances(model, "Rules/Rule") result = result + "if (False):\n" result = result + "\t# here to make code generation nicer...\n" result = result + "\tpass\n" while (set_len(rules) > 0): // Check if this rule is applicable rule = set_pop(rules) // Fetch all elements with a "match" label and check that they are not None (and possibly, that they have a value) result = result + "elif (True " nodes = allAssociationDestinations(model, rule, "Rules/contains") while (set_len(nodes) > 0): node = set_pop(nodes) if (value_eq(read_attribute(model, node, "match"), True)): // We should match on this node: value = read_attribute(model, node, "value") if (bool_and(read_type(model, node) == "Rules/NAC", element_eq(value, read_root()))): result = result + " and " + string_replace(node, "/", "_") + " is None " else: result = result + " and " + string_replace(node, "/", "_") + " is not None " if (element_neq(value, read_root())): // Got a value, so match that as well // But check if it is an action element (first character == !) String sign if (read_type(model, node) == "Rules/NAC"): sign = "!=" else: sign = "==" if (string_get(value, 0) == "!"): result = result + " and " + string_replace(node, "/", "_") + "_V['value'] " + sign + " '" + string_replace(value, "!", "") + "'" else: result = result + " and " + string_replace(node, "/", "_") + "_V " + sign + " " + value result = result + "):\n" result = result + "\t# Execute rule " + rule + "\n" // We know all the nodes that we already have (in variable "explored") // Still have to match all "match" and "delete" elements // For "match", it is exactly the same as before // For "delete" edges, we match using "RD" and "RDE" Element create_edges Element all_nodes log("Matching rule " + rule) nodes = allAssociationDestinations(model, rule, "Rules/contains") all_nodes = set_overlap(nodes, allInstances(model, "Rules/Match")) create_edges = set_create() explored = set_create() while (set_len(nodes) > 0): node = set_pop(nodes) if (read_type(model, node) == "Rules/Root"): // Found the root of this rule, so start exploring again // Keep following outgoing edges to find matching nodes to_explore = set_create() remainder_to_explore = set_create() set_add(to_explore, node) while (set_len(explored) < set_len(all_nodes)): while (set_len(to_explore) > 0): // Still explore more! node = set_pop(to_explore) log("Explore " + node) set_add(explored, node) source = string_replace(node, "/", "_") edges = allOutgoingAssociationInstances(model, node, "Rules/MatchEdge") while (set_len(edges) > 0): edge = set_pop(edges) new_node = readAssociationDestination(model, edge) name = read_attribute(model, edge, "value") destination = string_replace(new_node, "/", "_") if (element_eq(name, read_root())): String node_key node_key = set_pop(allAssociationDestinations(model, edge, "")) if (set_in(explored, node_key)): result = result + "\t" + destination + ", = yield [('RDN', [" + source + ", " + string_replace(node_key, "/", "_") + "])]\n" set_add(to_explore, new_node) else: set_add(remainder_to_explore, node) continue! if (read_type(model, edge) == "Rules/DeleteEdge"): // Delete edge result = result + "\t" + destination + "_DEL, = yield [('RDNE', [" + source + ", " + string_replace(node_key, "/", "_") + "])]\n" result = result + "\tyield [('DE', [" + destination + "_DEL])]\n" else: if (set_in(explored, new_node)): // Already visited this one in another way, so try to merge! String rand rand = random_string(10) result = result + "\t" + rand + ", = yield [('RD', [" + source + ", " + name + "])]\n" result = result + "\t" + "if " + rand + " != " + destination + ":\n" // If the values don't agree, this is not a correct match, and we say that this element remains unmatched (i.e., assign None) result = result + "\t" + "\t" + destination + " = None\n" else: // First visit to this element, so just assign result = result + "\t" + destination + ", = yield [('RD', [" + source + ", " + name + "])]\n" String value value = read_attribute(model, new_node, "value") if (element_neq(value, read_root())): // Match node has a value we should compare as well! // Read out the value from the Modelverse result = result + "\t" + destination + "_V, = yield [('RV', [" + destination + "])]\n" set_add(to_explore, new_node) if (read_type(model, edge) == "Rules/DeleteEdge"): // Delete edge result = result + "\t" + destination + "_DEL, = yield [('RDE', [" + source + ", " + name + "])]\n" result = result + "\tyield [('DE', [" + destination + "_DEL])]\n" if (bool_and(set_len(to_explore) == 0, set_len(remainder_to_explore) > 0)): to_explore = remainder_to_explore remainder_to_explore = set_create() // Check for nodes that are unexplored, but seemingly not reachable from the root directly Element remaining String check_elem Boolean found if (set_len(explored) < set_len(all_nodes)): // Find all unexplored nodes remaining = set_difference(all_nodes, explored) log("Remain unexplored: " + set_to_string(remaining)) while (set_len(remaining) > 0): check_elem = set_pop(remaining) edges = allOutgoingAssociationInstances(model, check_elem, "Rules/MatchEdge") found = False while (set_len(edges) > 0): edge = set_pop(edges) new_node = readAssociationDestination(model, edge) name = read_attribute(model, edge, "value") if (set_in(explored, new_node)): // We already explored this node, so we can do a RRD from this place! if (bool_not(found)): result = result + "\tmatched = []\n" result = result + "\t_tmp, = yield [('RRD', [" + string_replace(new_node, "/", "_") + ", " + name + "])]\n" result = result + "\tmatched.append(_tmp)\n" found = True // Iterated over all edges, so check how many we found! if (found): set_add(to_explore, check_elem) set_add(explored, check_elem) // Found at least one match, so we try to find an overlapping node result = result + "\t" + string_replace(check_elem, "/", "_") + " = self.set_overlap(matched)[0]\n" elif (read_type(model, node) == "Rules/Create"): // A node that we should create: do that already, as otherwise we might have to sort String attr attr = read_attribute(model, node, "value") if (element_eq(attr, read_root())): // Create empty node result = result + "\t" + string_replace(node, "/", "_") + ", = yield [('CN', [])]\n" else: // Create value node result = result + "\t" + string_replace(node, "/", "_") + ", = yield [('CNV', [" + cast_string(attr) + "])]\n" elif (read_type(model, node) == "Rules/CreateEdge"): // Encounter a create edge, so alreade record this for later set_add(create_edges, node) // Now create all the new edges, given that we assume everything to be matched while (set_len(create_edges) > 0): edge = set_pop(create_edges) attr = read_attribute(model, edge, "value") if (element_neq(attr, read_root())): result = result + "\t" + string_replace(edge, "/", "_") + ", = yield [('CD', [" + string_replace(readAssociationSource(model, edge), "/", "_") + ", " + attr + ", " + string_replace(readAssociationDestination(model, edge), "/", "_") + "])]\n" else: result = result + "\t" + string_replace(edge, "/", "_") + ", = yield [('CE', [" + string_replace(readAssociationSource(model, edge), "/", "_") + ", " + string_replace(readAssociationDestination(model, edge), "/", "_") + "])]\n" result = result + "else:\n" result = result + "\t# no rules were applicable, so idle for some time\n" result = result + "\tpass #TODO\n" log("Got result:") log(result) return True!