123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423 |
- 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 = ""
- // Add the preamble...
- result = result + "import modelverse_kernel.primitives as primitive_functions\n"
- result = result + "import modelverse_kernel.compiled as compiled_functions\n"
- result = result + "from collections import defaultdict\n"
- result = result + "import sys\n"
- result = result + "import time\n"
- result = result + "\n"
- result = result + "class ModelverseKernel(object):\n"
- result = result + " def __init__(self, root):\n"
- result = result + " self.root = root\n"
- result = result + " self.primitives = {}\n"
- result = result + " self.returnvalue = None\n"
- result = result + " self.success = True\n"
- result = result + " self.generators = {}\n"
- result = result + "\n"
- result = result + " def execute_yields(self, taskname, operation, params, reply):\n"
- result = result + " try:\n"
- result = result + " self.success = True\n"
- result = result + " self.taskname = taskname\n"
- result = result + " if taskname not in self.generators:\n"
- result = result + " self.generators[taskname] = {}\n"
- result = result + " if operation not in self.generators[taskname]:\n"
- result = result + " # Create the generator for the function to execute\n"
- result = result + " self.generators[taskname][operation] = getattr(self, operation)(taskname, *params)\n"
- result = result + "\n"
- result = result + " if reply is not None:\n"
- result = result + " return self.generators[taskname][operation].send(reply)\n"
- result = result + " else:\n"
- result = result + " return self.generators[taskname][operation].next()\n"
- result = result + " except StopIteration:\n"
- result = result + " # Done, so remove the generator\n"
- result = result + " del self.generators[taskname][operation]\n"
- result = result + " return None\n"
- result = result + " except:\n"
- result = result + " raise\n"
- result = result + "\n"
- result = result + " ##########################\n"
- result = result + " ### Process primitives ###\n"
- result = result + " ##########################\n"
- result = result + " def load_primitives(self, taskname):\n"
- result = result + " hierarchy, = yield [('RD', [self.root, '__hierarchy'])]\n"
- result = result + " primitives, = yield [('RD', [hierarchy, 'primitives'])]\n"
- result = result + " keys, = yield [('RDK', [primitives])]\n"
- result = result + " function_names = yield [('RV', [f]) for f in keys]\n"
- result = result + " signatures = yield [('RDN', [primitives, f]) for f in keys]\n"
- result = result + " bodies = yield [('RD', [f, 'body']) for f in signatures]\n"
- result = result + " for i in range(len(keys)):\n"
- result = result + " self.primitives[bodies[i]] = getattr(primitive_functions, function_names[i])\n"
- result = result + "\n"
- result = result + " def execute_primitive(self, task_root, inst, taskname):\n"
- result = result + " # execute_primitive\n"
- result = result + " task_frame, = yield [('RD', [task_root, 'frame'])]\n"
- result = result + " symbols, = yield [('RD', [task_frame, 'symbols'])]\n"
- result = result + " all_links, = yield [('RO', [symbols])]\n"
- result = result + " containers = yield [('RE', [v]) for v in all_links]\n"
- result = result + " outgoings = yield [('RO', [v]) for v in all_links]\n"
- result = result + " dict_values = yield [('RD', [v[1], 'value']) for v in containers]\n"
- result = result + " formals_1 = yield [('RE', [v[0]]) for v in outgoings]\n"
- result = result + " dict_keys_ref = yield [('RD', [v[1], 'name']) for v in formals_1]\n"
- result = result + " dict_keys = yield [('RV', [v]) for v in dict_keys_ref]\n"
- result = result + " parameters = dict(zip(dict_keys, dict_values))\n"
- result = result + "\n"
- result = result + " parameters['root'] = self.root\n"
- result = result + " parameters['task_root'] = task_root\n"
- result = result + " parameters['taskname'] = taskname\n"
- result = result + " parameters['mvk'] = self\n"
- result = result + "\n"
- result = result + " # prim is a generator itself!\n"
- result = result + " try:\n"
- result = result + " # Forward the message we get to this generator\n"
- result = result + " # Sometimes it might not even be a generator, in which case this should already be in the except block (i.e., for the Read Root operation)\n"
- result = result + " prim = self.primitives[inst](**parameters)\n"
- result = result + " inp = None\n"
- result = result + " while 1:\n"
- result = result + " inp = yield prim.send(inp)\n"
- result = result + " except StopIteration:\n"
- result = result + " # Execution has ended without return value, so we have no idea what to do\n"
- result = result + " raise Exception('Primitive finished without returning a value!')\n"
- result = result + " except primitive_functions.PrimitiveFinished as e:\n"
- result = result + " # Execution has ended with a returnvalue, so read it out from the exception being thrown\n"
- result = result + " result = e.result\n"
- result = result + "\n"
- result = result + " #if result is None:\n"
- result = result + " # raise Exception('Primitive raised exception: value of None for operation %s with parameters %s' % (self.compiled[inst], str(parameters)))\n"
- result = result + "\n"
- result = result + " # Clean up the current stack, as if a return happened\n"
- result = result + " old_frame, = yield [('RD', [task_frame, 'prev'])]\n"
- result = result + " lnk, = yield [('RDE', [old_frame, 'returnvalue'])]\n"
- result = result + " _, _, _, _ = yield [('CD', [old_frame, 'returnvalue', result]),\n"
- result = result + " ('CD', [task_root, 'frame', old_frame]),\n"
- result = result + " ('DE', [lnk]),\n"
- result = result + " ('DN', [task_frame]),\n"
- result = result + " ]\n"
- result = result + "\n"
- result = result + " ########################################\n"
- result = result + " ### Execute input and output methods ###\n"
- result = result + " ########################################\n"
- result = result + " def get_output(self, taskname):\n"
- result = result + " task_root, = yield [('RD', [self.root, taskname])]\n"
- result = result + " first_output, = yield [('RD', [task_root, 'output'])]\n"
- result = result + " next_output, rv = yield [('RD', [first_output, 'next']),\n"
- result = result + " ('RD', [first_output, 'value']),\n"
- result = result + " ]\n"
- result = result + " if next_output is None:\n"
- result = result + " self.success = False\n"
- result = result + " self.returnvalue = None\n"
- result = result + " else:\n"
- result = result + " rv_value, = yield [('RV', [rv])]\n"
- result = result + " _, _ = yield [('CD', [task_root, 'output', next_output]),\n"
- result = result + " ('DN', [first_output]),\n"
- result = result + " ]\n"
- result = result + " self.returnvalue = rv_value\n"
- result = result + "\n"
- result = result + " def set_input(self, taskname, value):\n"
- result = result + " task_root, = yield [('RD', [self.root, taskname])]\n"
- result = result + " old_input, link = yield [('RD', [task_root, 'last_input']),\n"
- result = result + " ('RDE', [task_root, 'last_input']),\n"
- result = result + " ]\n"
- result = result + " new_input, = yield [('CN', [])]\n"
- result = result + " _, _ = yield [('CD', [task_root, 'last_input', new_input]),\n"
- result = result + " ('CD', [old_input, 'next', new_input]),\n"
- result = result + " ]\n"
- result = result + "\n"
- result = result + " new_value, = yield [('CNV', [value])]\n"
- result = result + " _, _ = yield [('CD', [old_input, 'value', new_value]),\n"
- result = result + " ('DE', [link])\n"
- result = result + " ]\n"
- result = result + " self.returnvalue = {'id': 100, 'value': 'success'}\n"
- result = result + "\n"
- result = result + " ### Generated rules\n"
- result = result + " def execute_rule(self, taskname):\n"
- // Done, now generate the variable code
- result = 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/MatchEdge")
- 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 + " " + 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 + " # here to make code generation nicer...\n"
- result = result + " pass\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 + " # Execute rule " + rule + "\n"
- result = result + " print('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
- Element assigned
- 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()
- assigned = set_create()
- // Username is always assigned in the beginning
- set_add(assigned, "username")
- set_add(assigned, "taskname")
- 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 + " " + 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 + " " + destination + "_DEL, = yield [('RDNE', [" + source + ", " + string_replace(node_key, "/", "_") + "])]\n"
- result = result + " yield [('DE', [" + destination + "_DEL])]\n"
- else:
- if (bool_or(string_get(name, 0) == "'", set_in(assigned, name))):
- 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 + " " + 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 + " " + " " + destination + " = None\n"
- else:
- // First visit to this element, so just assign
- result = result + " " + destination + ", = yield [('RD', [" + source + ", " + name + "])]\n"
- String value
- value = read_attribute(model, new_node, "value")
- if (element_neq(value, read_root())):
- // Read out the value from the Modelverse, as this can be used later for reading edges
- if (bool_and(bool_and(string_get(value, 0) != "!", string_get(value, 0) != "'"), bool_and(value != "False", value != "True"))):
- result = result + " " + value + ", = yield [('RV', [" + destination + "])]\n"
- set_add(assigned, value)
- set_add(to_explore, new_node)
- if (read_type(model, edge) == "Rules/DeleteEdge"):
- // Delete edge
- result = result + " " + destination + "_DEL, = yield [('RDE', [" + source + ", " + name + "])]\n"
- result = result + " yield [('DE', [" + destination + "_DEL])]\n"
- else:
- set_add(remainder_to_explore, 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()
- // 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 + " matched = []\n"
- result = result + " _tmp, = yield [('RRD', [" + string_replace(new_node, "/", "_") + ", " + name + "])]\n"
- result = result + " matched.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 + " " + 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 + " " + string_replace(node, "/", "_") + ", = yield [('CN', [])]\n"
- else:
- // Create value node
- result = result + " " + 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 + " " + string_replace(edge, "/", "_") + ", = yield [('CD', [" + string_replace(readAssociationSource(model, edge), "/", "_") + ", " + attr + ", " + string_replace(readAssociationDestination(model, edge), "/", "_") + "])]\n"
- else:
- result = result + " " + string_replace(edge, "/", "_") + ", = yield [('CE', [" + string_replace(readAssociationSource(model, edge), "/", "_") + ", " + string_replace(readAssociationDestination(model, edge), "/", "_") + "])]\n"
- result = result + " else:\n"
- result = result + " # no rules were applicable, so idle for some time\n"
- result = result + " pass #TODO\n"
- result = result + " raise Exception(str(locals()))\n"
- log("Got result:")
- log(result)
- String file
- file = instantiate_node(model, "Files/File", "")
- instantiate_attribute(model, file, "name", "generated_kernel.py")
- instantiate_attribute(model, file, "content", result)
- return True!
|