to_python.alc 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  1. include "primitives.alh"
  2. include "modelling.alh"
  3. include "object_operations.alh"
  4. include "random.alh"
  5. include "utils.alh"
  6. Boolean function main(model : Element):
  7. String result
  8. Element nodes
  9. String node
  10. Element edges
  11. String edge
  12. String new_node
  13. String source
  14. String destination
  15. String name
  16. Element to_explore
  17. Element rules
  18. String rule
  19. String value
  20. Element explored
  21. Element remainder_to_explore
  22. String attr
  23. explored = set_create()
  24. result = ""
  25. // Add the preamble...
  26. result = result + "import modelverse_kernel.primitives as primitive_functions\n"
  27. result = result + "\n"
  28. result = result + "class ModelverseKernel(object):\n"
  29. result = result + " def __init__(self, root):\n"
  30. result = result + " self.root = root\n"
  31. result = result + " self.primitives = {}\n"
  32. result = result + " self.returnvalue = None\n"
  33. result = result + " self.success = True\n"
  34. result = result + " self.generators = {}\n"
  35. result = result + "\n"
  36. result = result + " def set_overlap(self, lst):\n"
  37. result = result + " s = set(lst.pop())\n"
  38. result = result + " while (lst):\n"
  39. result = result + " s &= set(lst.pop())\n"
  40. result = result + " return list(s)\n"
  41. result = result + "\n"
  42. result = result + " def execute_yields(self, taskname, operation, params, reply):\n"
  43. result = result + " try:\n"
  44. result = result + " self.success = True\n"
  45. result = result + " self.taskname = taskname\n"
  46. result = result + " if taskname not in self.generators:\n"
  47. result = result + " self.generators[taskname] = {}\n"
  48. result = result + " if operation not in self.generators[taskname]:\n"
  49. result = result + " # Create the generator for the function to execute\n"
  50. result = result + " self.generators[taskname][operation] = getattr(self, operation)(taskname, *params)\n"
  51. result = result + "\n"
  52. result = result + " if reply is not None:\n"
  53. result = result + " return self.generators[taskname][operation].send(reply)\n"
  54. result = result + " else:\n"
  55. result = result + " return self.generators[taskname][operation].next()\n"
  56. result = result + " except StopIteration:\n"
  57. result = result + " # Done, so remove the generator\n"
  58. result = result + " del self.generators[taskname][operation]\n"
  59. result = result + " return None\n"
  60. result = result + " except:\n"
  61. result = result + " raise\n"
  62. result = result + "\n"
  63. result = result + " ##########################\n"
  64. result = result + " ### Process primitives ###\n"
  65. result = result + " ##########################\n"
  66. result = result + " def load_primitives(self, taskname):\n"
  67. result = result + " hierarchy, = yield [('RD', [self.root, '__hierarchy'])]\n"
  68. result = result + " primitives, = yield [('RD', [hierarchy, 'primitives'])]\n"
  69. result = result + " keys, = yield [('RDK', [primitives])]\n"
  70. result = result + " function_names = yield [('RV', [f]) for f in keys]\n"
  71. result = result + " signatures = yield [('RDN', [primitives, f]) for f in keys]\n"
  72. result = result + " bodies = yield [('RD', [f, 'body']) for f in signatures]\n"
  73. result = result + " for i in range(len(keys)):\n"
  74. result = result + " self.primitives[bodies[i]] = getattr(primitive_functions, function_names[i])\n"
  75. result = result + "\n"
  76. result = result + " ########################################\n"
  77. result = result + " ### Execute input and output methods ###\n"
  78. result = result + " ########################################\n"
  79. result = result + " def get_output(self, taskname):\n"
  80. result = result + " task_root, = yield [('RD', [self.root, taskname])]\n"
  81. result = result + " first_output, = yield [('RD', [task_root, 'output'])]\n"
  82. result = result + " next_output, rv = yield [('RD', [first_output, 'next']),\n"
  83. result = result + " ('RD', [first_output, 'value']),\n"
  84. result = result + " ]\n"
  85. result = result + " if next_output is None:\n"
  86. result = result + " self.success = False\n"
  87. result = result + " self.returnvalue = None\n"
  88. result = result + " else:\n"
  89. result = result + " rv_value, = yield [('RV', [rv])]\n"
  90. result = result + " _, _ = yield [('CD', [task_root, 'output', next_output]),\n"
  91. result = result + " ('DN', [first_output]),\n"
  92. result = result + " ]\n"
  93. result = result + " self.returnvalue = rv_value\n"
  94. result = result + "\n"
  95. result = result + " def set_input(self, taskname, value):\n"
  96. result = result + " task_root, = yield [('RD', [self.root, taskname])]\n"
  97. result = result + " old_input, link = yield [('RD', [task_root, 'last_input']),\n"
  98. result = result + " ('RDE', [task_root, 'last_input']),\n"
  99. result = result + " ]\n"
  100. result = result + " new_input, = yield [('CN', [])]\n"
  101. result = result + " _, _ = yield [('CD', [task_root, 'last_input', new_input]),\n"
  102. result = result + " ('CD', [old_input, 'next', new_input]),\n"
  103. result = result + " ]\n"
  104. result = result + "\n"
  105. result = result + " new_value, = yield [('CNV', [value])]\n"
  106. result = result + " _, _ = yield [('CD', [old_input, 'value', new_value]),\n"
  107. result = result + " ('DE', [link])\n"
  108. result = result + " ]\n"
  109. result = result + " self.returnvalue = {'id': 100, 'value': 'success'}\n"
  110. result = result + "\n"
  111. result = result + " ### Generated rules\n"
  112. result = result + " def execute_rule(self, taskname):\n"
  113. // Done, now generate the variable code
  114. result = result + " root, = yield [('RR', [])]\n"
  115. nodes = allInstances(model, "Rules/Root")
  116. while (set_len(nodes) > 0):
  117. node = set_pop(nodes)
  118. source = string_replace(node, "/", "_")
  119. result = result + " " + source + " = root\n"
  120. // Keep following outgoing edges to find matching nodes
  121. to_explore = set_create()
  122. remainder_to_explore = set_create()
  123. set_add(to_explore, node)
  124. while (set_len(to_explore) > 0):
  125. // Still explore more!
  126. node = set_pop(to_explore)
  127. source = string_replace(node, "/", "_")
  128. edges = allOutgoingAssociationInstances(model, node, "Rules/MatchEdge")
  129. while (set_len(edges) > 0):
  130. edge = set_pop(edges)
  131. new_node = readAssociationDestination(model, edge)
  132. if (value_eq(read_attribute(model, new_node, "match"), True)):
  133. // Is a match node, so fetch the value on the edge
  134. name = read_attribute(model, edge, "value")
  135. destination = string_replace(new_node, "/", "_")
  136. if (element_eq(name, read_root())):
  137. String node_key
  138. node_key = string_replace(set_pop(allAssociationDestinations(model, edge, "")), "/", "_")
  139. if (set_in(explored, node_key)):
  140. result = result + " " + destination + ", = yield [('RDN', [" + source + ", " + node_key + "])]\n"
  141. else:
  142. set_add(remainder_to_explore, node)
  143. else:
  144. if (set_in(explored, destination)):
  145. // Already visited this one in another way, so try to merge!
  146. String rand
  147. rand = random_string(10)
  148. result = result + " " + rand + ", = yield [('RD', [" + source + ", " + name + "])]\n"
  149. result = result + " " + "if " + rand + " != " + destination + ":\n"
  150. // If the values don't agree, this is not a correct match, and we say that this element remains unmatched (i.e., assign None)
  151. result = result + " " + destination + " = None\n"
  152. else:
  153. // First visit to this element, so just assign
  154. result = result + " " + destination + ", = yield [('RD', [" + source + ", " + name + "])]\n"
  155. set_add(explored, destination)
  156. String value
  157. value = read_attribute(model, new_node, "value")
  158. if (element_neq(value, read_root())):
  159. // Match node has a value we should compare as well!
  160. // Read out the value from the Modelverse
  161. result = result + " " + destination + "_V, = yield [('RV', [" + destination + "])]\n"
  162. set_add(to_explore, new_node)
  163. if (bool_and(set_len(to_explore) == 0, set_len(remainder_to_explore) > 0)):
  164. to_explore = remainder_to_explore
  165. remainder_to_explore = set_create()
  166. rules = allInstances(model, "Rules/Rule")
  167. result = result + " " + "if (False):\n"
  168. result = result + " # here to make code generation nicer...\n"
  169. result = result + " pass\n"
  170. while (set_len(rules) > 0):
  171. // Check if this rule is applicable
  172. rule = set_pop(rules)
  173. // Fetch all elements with a "match" label and check that they are not None (and possibly, that they have a value)
  174. result = result + " elif (True "
  175. nodes = allAssociationDestinations(model, rule, "Rules/contains")
  176. while (set_len(nodes) > 0):
  177. node = set_pop(nodes)
  178. if (value_eq(read_attribute(model, node, "match"), True)):
  179. // We should match on this node:
  180. value = read_attribute(model, node, "value")
  181. if (bool_and(read_type(model, node) == "Rules/NAC", element_eq(value, read_root()))):
  182. result = result + " and " + string_replace(node, "/", "_") + " is None "
  183. else:
  184. result = result + " and " + string_replace(node, "/", "_") + " is not None "
  185. if (element_neq(value, read_root())):
  186. // Got a value, so match that as well
  187. // But check if it is an action element (first character == !)
  188. String sign
  189. if (read_type(model, node) == "Rules/NAC"):
  190. sign = "!="
  191. else:
  192. sign = "=="
  193. if (string_get(value, 0) == "!"):
  194. result = result + " and isinstance(" + string_replace(node, "/", "_") + "_V , dict) and " + string_replace(node, "/", "_") + "_V['value'] " + sign + " '" + string_replace(value, "!", "") + "'"
  195. elif (bool_or(bool_or(string_get(value, 0) == "'", string_get(value, 0) == "!"), bool_or(value == "True", value == "False"))):
  196. result = result + " and " + string_replace(node, "/", "_") + "_V " + sign + " " + value
  197. result = result + "):\n"
  198. result = result + " # Execute rule " + rule + "\n"
  199. // We know all the nodes that we already have (in variable "explored")
  200. // Still have to match all "match" and "delete" elements
  201. // For "match", it is exactly the same as before
  202. // For "delete" edges, we match using "RD" and "RDE"
  203. Element create_edges
  204. Element all_nodes
  205. Element assigned
  206. log("Matching rule " + rule)
  207. nodes = allAssociationDestinations(model, rule, "Rules/contains")
  208. all_nodes = set_overlap(nodes, allInstances(model, "Rules/Match"))
  209. create_edges = set_create()
  210. explored = set_create()
  211. assigned = set_create()
  212. // Username is always assigned in the beginning
  213. set_add(assigned, "username")
  214. set_add(assigned, "taskname")
  215. while (set_len(nodes) > 0):
  216. node = set_pop(nodes)
  217. if (read_type(model, node) == "Rules/Root"):
  218. // Found the root of this rule, so start exploring again
  219. // Keep following outgoing edges to find matching nodes
  220. to_explore = set_create()
  221. remainder_to_explore = set_create()
  222. set_add(to_explore, node)
  223. while (set_len(explored) < set_len(all_nodes)):
  224. while (set_len(to_explore) > 0):
  225. // Still explore more!
  226. node = set_pop(to_explore)
  227. log("Explore " + node)
  228. set_add(explored, node)
  229. source = string_replace(node, "/", "_")
  230. edges = allOutgoingAssociationInstances(model, node, "Rules/MatchEdge")
  231. while (set_len(edges) > 0):
  232. edge = set_pop(edges)
  233. new_node = readAssociationDestination(model, edge)
  234. name = read_attribute(model, edge, "value")
  235. destination = string_replace(new_node, "/", "_")
  236. if (element_eq(name, read_root())):
  237. String node_key
  238. node_key = set_pop(allAssociationDestinations(model, edge, ""))
  239. if (set_in(explored, node_key)):
  240. result = result + " " + destination + ", = yield [('RDN', [" + source + ", " + string_replace(node_key, "/", "_") + "])]\n"
  241. set_add(to_explore, new_node)
  242. else:
  243. set_add(remainder_to_explore, node)
  244. continue!
  245. if (read_type(model, edge) == "Rules/DeleteEdge"):
  246. // Delete edge
  247. result = result + " " + destination + "_DEL, = yield [('RDNE', [" + source + ", " + string_replace(node_key, "/", "_") + "])]\n"
  248. result = result + " yield [('DE', [" + destination + "_DEL])]\n"
  249. else:
  250. if (bool_or(string_get(name, 0) == "'", set_in(assigned, name))):
  251. if (set_in(explored, new_node)):
  252. // Already visited this one in another way, so try to merge!
  253. String rand
  254. rand = random_string(10)
  255. result = result + " " + rand + ", = yield [('RD', [" + source + ", " + name + "])]\n"
  256. result = result + " " + "if " + rand + " != " + destination + ":\n"
  257. // If the values don't agree, this is not a correct match, and we say that this element remains unmatched (i.e., assign None)
  258. result = result + " " + " " + destination + " = None\n"
  259. else:
  260. // First visit to this element, so just assign
  261. result = result + " " + destination + ", = yield [('RD', [" + source + ", " + name + "])]\n"
  262. String value
  263. value = read_attribute(model, new_node, "value")
  264. if (element_neq(value, read_root())):
  265. // Read out the value from the Modelverse, as this can be used later for reading edges
  266. if (bool_and(bool_and(string_get(value, 0) != "!", string_get(value, 0) != "'"), bool_and(value != "False", value != "True"))):
  267. result = result + " " + value + ", = yield [('RV', [" + destination + "])]\n"
  268. set_add(assigned, value)
  269. set_add(to_explore, new_node)
  270. if (read_type(model, edge) == "Rules/DeleteEdge"):
  271. // Delete edge
  272. result = result + " " + destination + "_DEL, = yield [('RDE', [" + source + ", " + name + "])]\n"
  273. result = result + " yield [('DE', [" + destination + "_DEL])]\n"
  274. else:
  275. set_add(remainder_to_explore, node)
  276. if (bool_and(set_len(to_explore) == 0, set_len(remainder_to_explore) > 0)):
  277. to_explore = remainder_to_explore
  278. remainder_to_explore = set_create()
  279. // Check for nodes that are unexplored, but seemingly not reachable from the root directly
  280. Element remaining
  281. String check_elem
  282. Boolean found
  283. if (set_len(explored) < set_len(all_nodes)):
  284. // Find all unexplored nodes
  285. remaining = set_difference(all_nodes, explored)
  286. log("Remain unexplored: " + set_to_string(remaining))
  287. while (set_len(remaining) > 0):
  288. check_elem = set_pop(remaining)
  289. edges = allOutgoingAssociationInstances(model, check_elem, "Rules/MatchEdge")
  290. found = False
  291. while (set_len(edges) > 0):
  292. edge = set_pop(edges)
  293. new_node = readAssociationDestination(model, edge)
  294. name = read_attribute(model, edge, "value")
  295. if (set_in(explored, new_node)):
  296. // We already explored this node, so we can do a RRD from this place!
  297. if (bool_not(found)):
  298. result = result + " matched = []\n"
  299. result = result + " _tmp, = yield [('RRD', [" + string_replace(new_node, "/", "_") + ", " + name + "])]\n"
  300. result = result + " matched.append(_tmp)\n"
  301. found = True
  302. // Iterated over all edges, so check how many we found!
  303. if (found):
  304. set_add(to_explore, check_elem)
  305. set_add(explored, check_elem)
  306. // Found at least one match, so we try to find an overlapping node
  307. result = result + " " + string_replace(check_elem, "/", "_") + " = self.set_overlap(matched)[0]\n"
  308. elif (read_type(model, node) == "Rules/Create"):
  309. // A node that we should create: do that already, as otherwise we might have to sort
  310. String attr
  311. attr = read_attribute(model, node, "value")
  312. if (element_eq(attr, read_root())):
  313. // Create empty node
  314. result = result + " " + string_replace(node, "/", "_") + ", = yield [('CN', [])]\n"
  315. else:
  316. // Create value node
  317. result = result + " " + string_replace(node, "/", "_") + ", = yield [('CNV', [" + cast_string(attr) + "])]\n"
  318. elif (read_type(model, node) == "Rules/CreateEdge"):
  319. // Encounter a create edge, so alreade record this for later
  320. set_add(create_edges, node)
  321. // Now create all the new edges, given that we assume everything to be matched
  322. while (set_len(create_edges) > 0):
  323. edge = set_pop(create_edges)
  324. attr = read_attribute(model, edge, "value")
  325. if (element_neq(attr, read_root())):
  326. result = result + " " + string_replace(edge, "/", "_") + ", = yield [('CD', [" + string_replace(readAssociationSource(model, edge), "/", "_") + ", " + attr + ", " + string_replace(readAssociationDestination(model, edge), "/", "_") + "])]\n"
  327. else:
  328. result = result + " " + string_replace(edge, "/", "_") + ", = yield [('CE', [" + string_replace(readAssociationSource(model, edge), "/", "_") + ", " + string_replace(readAssociationDestination(model, edge), "/", "_") + "])]\n"
  329. result = result + " else:\n"
  330. result = result + " task_root, = yield [('RD', [root, taskname])]\n"
  331. result = result + " task_frame, = yield [('RD', [task_root, 'frame'])]\n"
  332. result = result + " task_IP, = yield [('RD', [task_frame, 'IP'])]\n"
  333. result = result + " task_phase, = yield [('RD', [task_frame, 'phase'])]\n"
  334. result = result + " task_phase, = yield [('RV', [task_phase])]\n"
  335. result = result + " if (task_IP is not None and task_IP in self.primitives and task_phase == 'init'):\n"
  336. result = result + " # Execute a primitive!\n"
  337. result = result + " symbols, = yield [('RD', [task_frame, 'symbols'])]\n"
  338. result = result + " all_links, = yield [('RO', [symbols])]\n"
  339. result = result + " containers = yield [('RE', [v]) for v in all_links]\n"
  340. result = result + " outgoings = yield [('RO', [v]) for v in all_links]\n"
  341. result = result + " dict_values = yield [('RD', [v[1], 'value']) for v in containers]\n"
  342. result = result + " formals_1 = yield [('RE', [v[0]]) for v in outgoings]\n"
  343. result = result + " dict_keys_ref = yield [('RD', [v[1], 'name']) for v in formals_1]\n"
  344. result = result + " dict_keys = yield [('RV', [v]) for v in dict_keys_ref]\n"
  345. result = result + " parameters = dict(zip(dict_keys, dict_values))\n"
  346. result = result + " parameters['root'] = root\n"
  347. result = result + " parameters['task_root'] = task_root\n"
  348. result = result + " parameters['taskname'] = taskname\n"
  349. result = result + " parameters['mvk'] = self\n"
  350. result = result + " # prim is a generator itself!\n"
  351. result = result + " try:\n"
  352. result = result + " # Forward the message we get to this generator\n"
  353. 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"
  354. result = result + " prim = self.primitives[task_IP](**parameters)\n"
  355. result = result + " inp = None\n"
  356. result = result + " while 1:\n"
  357. result = result + " inp = yield prim.send(inp)\n"
  358. result = result + " except StopIteration:\n"
  359. result = result + " # Execution has ended without return value, so we have no idea what to do\n"
  360. result = result + " raise Exception('Primitive finished without returning a value!')\n"
  361. result = result + " except primitive_functions.PrimitiveFinished as e:\n"
  362. result = result + " # Execution has ended with a returnvalue, so read it out from the exception being thrown\n"
  363. result = result + " result = e.result\n"
  364. result = result + " #if result is None:\n"
  365. result = result + " # raise Exception('Primitive raised exception: value of None for operation %s with parameters %s' % (self.compiled[task_IP], str(parameters)))\n"
  366. result = result + " # Clean up the current stack, as if a return happened\n"
  367. result = result + " old_frame, = yield [('RD', [task_frame, 'prev'])]\n"
  368. result = result + " lnk, = yield [('RDE', [old_frame, 'returnvalue'])]\n"
  369. result = result + " _, _, _, _ = yield [('CD', [old_frame, 'returnvalue', result]),\n"
  370. result = result + " ('CD', [task_root, 'frame', old_frame]),\n"
  371. result = result + " ('DE', [lnk]),\n"
  372. result = result + " ('DN', [task_frame]),\n"
  373. result = result + " ]\n"
  374. result = result + "\n"
  375. result = result + " else:\n"
  376. result = result + " # no rules were applicable, so idle for some time\n"
  377. result = result + " pass #TODO\n"
  378. result = result + " raise primitive_functions.SleepKernel(1.0, True)\n"
  379. log("Got result:")
  380. log(result)
  381. String file
  382. file = instantiate_node(model, "Files/File", "")
  383. instantiate_attribute(model, file, "name", "generated_kernel.py")
  384. instantiate_attribute(model, file, "content", result)
  385. return True!