to_python.alc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  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 = "root, = yield [('RR', [])]\n"
  25. nodes = allInstances(model, "Rules/Root")
  26. while (set_len(nodes) > 0):
  27. node = set_pop(nodes)
  28. source = string_replace(node, "/", "_")
  29. result = result + source + " = root\n"
  30. // Keep following outgoing edges to find matching nodes
  31. to_explore = set_create()
  32. remainder_to_explore = set_create()
  33. set_add(to_explore, node)
  34. while (set_len(to_explore) > 0):
  35. // Still explore more!
  36. node = set_pop(to_explore)
  37. source = string_replace(node, "/", "_")
  38. edges = allOutgoingAssociationInstances(model, node, "Rules/Edge")
  39. while (set_len(edges) > 0):
  40. edge = set_pop(edges)
  41. new_node = readAssociationDestination(model, edge)
  42. if (value_eq(read_attribute(model, new_node, "match"), True)):
  43. // Is a match node, so fetch the value on the edge
  44. name = read_attribute(model, edge, "value")
  45. destination = string_replace(new_node, "/", "_")
  46. if (element_eq(name, read_root())):
  47. String node_key
  48. node_key = string_replace(set_pop(allAssociationDestinations(model, edge, "")), "/", "_")
  49. if (set_in(explored, node_key)):
  50. result = result + destination + ", = yield [('RDN', [" + source + ", " + node_key + "])]\n"
  51. else:
  52. set_add(remainder_to_explore, node)
  53. else:
  54. if (set_in(explored, destination)):
  55. // Already visited this one in another way, so try to merge!
  56. String rand
  57. rand = random_string(10)
  58. result = result + rand + ", = yield [('RD', [" + source + ", " + name + "])]\n"
  59. result = result + "if " + rand + " != " + destination + ":\n"
  60. // If the values don't agree, this is not a correct match, and we say that this element remains unmatched (i.e., assign None)
  61. result = result + "\t" + destination + " = None\n"
  62. else:
  63. // First visit to this element, so just assign
  64. result = result + destination + ", = yield [('RD', [" + source + ", " + name + "])]\n"
  65. set_add(explored, destination)
  66. String value
  67. value = read_attribute(model, new_node, "value")
  68. if (element_neq(value, read_root())):
  69. // Match node has a value we should compare as well!
  70. // Read out the value from the Modelverse
  71. result = result + destination + "_V, = yield [('RV', [" + destination + "])]\n"
  72. set_add(to_explore, new_node)
  73. if (bool_and(set_len(to_explore) == 0, set_len(remainder_to_explore) > 0)):
  74. to_explore = remainder_to_explore
  75. remainder_to_explore = set_create()
  76. rules = allInstances(model, "Rules/Rule")
  77. result = result + "if (False):\n"
  78. result = result + "\t# here to make code generation nicer...\n"
  79. result = result + "\tpass\n"
  80. while (set_len(rules) > 0):
  81. // Check if this rule is applicable
  82. rule = set_pop(rules)
  83. // Fetch all elements with a "match" label and check that they are not None (and possibly, that they have a value)
  84. result = result + "elif (True "
  85. nodes = allAssociationDestinations(model, rule, "Rules/contains")
  86. while (set_len(nodes) > 0):
  87. node = set_pop(nodes)
  88. if (value_eq(read_attribute(model, node, "match"), True)):
  89. // We should match on this node:
  90. value = read_attribute(model, node, "value")
  91. if (bool_and(read_type(model, node) == "Rules/NAC", element_eq(value, read_root()))):
  92. result = result + " and " + string_replace(node, "/", "_") + " is None "
  93. else:
  94. result = result + " and " + string_replace(node, "/", "_") + " is not None "
  95. if (element_neq(value, read_root())):
  96. // Got a value, so match that as well
  97. // But check if it is an action element (first character == !)
  98. String sign
  99. if (read_type(model, node) == "Rules/NAC"):
  100. sign = "!="
  101. else:
  102. sign = "=="
  103. if (string_get(value, 0) == "!"):
  104. result = result + " and " + string_replace(node, "/", "_") + "_V['value'] " + sign + " '" + string_replace(value, "!", "") + "'"
  105. else:
  106. result = result + " and " + string_replace(node, "/", "_") + "_V " + sign + " " + value
  107. result = result + "):\n"
  108. result = result + "\t# Execute rule " + rule + "\n"
  109. // We know all the nodes that we already have (in variable "explored")
  110. // Still have to match all "match" and "delete" elements
  111. // For "match", it is exactly the same as before
  112. // For "delete" edges, we match using "RD" and "RDE"
  113. Element create_edges
  114. Element all_nodes
  115. Element assigned
  116. log("Matching rule " + rule)
  117. nodes = allAssociationDestinations(model, rule, "Rules/contains")
  118. all_nodes = set_overlap(nodes, allInstances(model, "Rules/Match"))
  119. create_edges = set_create()
  120. explored = set_create()
  121. assigned = set_create()
  122. // Username is always assigned in the beginning
  123. set_add(assigned, "username")
  124. set_add(assigned, "taskname")
  125. while (set_len(nodes) > 0):
  126. node = set_pop(nodes)
  127. if (read_type(model, node) == "Rules/Root"):
  128. // Found the root of this rule, so start exploring again
  129. // Keep following outgoing edges to find matching nodes
  130. to_explore = set_create()
  131. remainder_to_explore = set_create()
  132. set_add(to_explore, node)
  133. while (set_len(explored) < set_len(all_nodes)):
  134. while (set_len(to_explore) > 0):
  135. // Still explore more!
  136. node = set_pop(to_explore)
  137. log("Explore " + node)
  138. set_add(explored, node)
  139. source = string_replace(node, "/", "_")
  140. edges = allOutgoingAssociationInstances(model, node, "Rules/MatchEdge")
  141. while (set_len(edges) > 0):
  142. edge = set_pop(edges)
  143. new_node = readAssociationDestination(model, edge)
  144. name = read_attribute(model, edge, "value")
  145. destination = string_replace(new_node, "/", "_")
  146. if (element_eq(name, read_root())):
  147. String node_key
  148. node_key = set_pop(allAssociationDestinations(model, edge, ""))
  149. if (set_in(explored, node_key)):
  150. result = result + "\t" + destination + ", = yield [('RDN', [" + source + ", " + string_replace(node_key, "/", "_") + "])]\n"
  151. set_add(to_explore, new_node)
  152. else:
  153. set_add(remainder_to_explore, node)
  154. continue!
  155. if (read_type(model, edge) == "Rules/DeleteEdge"):
  156. // Delete edge
  157. result = result + "\t" + destination + "_DEL, = yield [('RDNE', [" + source + ", " + string_replace(node_key, "/", "_") + "])]\n"
  158. result = result + "\tyield [('DE', [" + destination + "_DEL])]\n"
  159. else:
  160. if (bool_or(string_get(name, 0) == "'", set_in(assigned, name))):
  161. if (set_in(explored, new_node)):
  162. // Already visited this one in another way, so try to merge!
  163. String rand
  164. rand = random_string(10)
  165. result = result + "\t" + rand + ", = yield [('RD', [" + source + ", " + name + "])]\n"
  166. result = result + "\t" + "if " + rand + " != " + destination + ":\n"
  167. // If the values don't agree, this is not a correct match, and we say that this element remains unmatched (i.e., assign None)
  168. result = result + "\t" + "\t" + destination + " = None\n"
  169. else:
  170. // First visit to this element, so just assign
  171. result = result + "\t" + destination + ", = yield [('RD', [" + source + ", " + name + "])]\n"
  172. String value
  173. value = read_attribute(model, new_node, "value")
  174. if (element_neq(value, read_root())):
  175. // Match node has a value we should compare as well!
  176. // Read out the value from the Modelverse
  177. if (bool_and(string_get(value, 0) != "!", string_get(value, 0) != "'")):
  178. result = result + "\t" + value + ", = yield [('RV', [" + destination + "])]\n"
  179. set_add(assigned, value)
  180. set_add(to_explore, new_node)
  181. if (read_type(model, edge) == "Rules/DeleteEdge"):
  182. // Delete edge
  183. result = result + "\t" + destination + "_DEL, = yield [('RDE', [" + source + ", " + name + "])]\n"
  184. result = result + "\tyield [('DE', [" + destination + "_DEL])]\n"
  185. else:
  186. set_add(remainder_to_explore, node)
  187. if (bool_and(set_len(to_explore) == 0, set_len(remainder_to_explore) > 0)):
  188. to_explore = remainder_to_explore
  189. remainder_to_explore = set_create()
  190. // Check for nodes that are unexplored, but seemingly not reachable from the root directly
  191. Element remaining
  192. String check_elem
  193. Boolean found
  194. if (set_len(explored) < set_len(all_nodes)):
  195. // Find all unexplored nodes
  196. remaining = set_difference(all_nodes, explored)
  197. log("Remain unexplored: " + set_to_string(remaining))
  198. while (set_len(remaining) > 0):
  199. check_elem = set_pop(remaining)
  200. edges = allOutgoingAssociationInstances(model, check_elem, "Rules/MatchEdge")
  201. found = False
  202. while (set_len(edges) > 0):
  203. edge = set_pop(edges)
  204. new_node = readAssociationDestination(model, edge)
  205. name = read_attribute(model, edge, "value")
  206. if (set_in(explored, new_node)):
  207. // We already explored this node, so we can do a RRD from this place!
  208. if (bool_not(found)):
  209. result = result + "\tmatched = []\n"
  210. result = result + "\t_tmp, = yield [('RRD', [" + string_replace(new_node, "/", "_") + ", " + name + "])]\n"
  211. result = result + "\tmatched.append(_tmp)\n"
  212. found = True
  213. // Iterated over all edges, so check how many we found!
  214. if (found):
  215. set_add(to_explore, check_elem)
  216. set_add(explored, check_elem)
  217. // Found at least one match, so we try to find an overlapping node
  218. result = result + "\t" + string_replace(check_elem, "/", "_") + " = self.set_overlap(matched)[0]\n"
  219. elif (read_type(model, node) == "Rules/Create"):
  220. // A node that we should create: do that already, as otherwise we might have to sort
  221. String attr
  222. attr = read_attribute(model, node, "value")
  223. if (element_eq(attr, read_root())):
  224. // Create empty node
  225. result = result + "\t" + string_replace(node, "/", "_") + ", = yield [('CN', [])]\n"
  226. else:
  227. // Create value node
  228. result = result + "\t" + string_replace(node, "/", "_") + ", = yield [('CNV', [" + cast_string(attr) + "])]\n"
  229. elif (read_type(model, node) == "Rules/CreateEdge"):
  230. // Encounter a create edge, so alreade record this for later
  231. set_add(create_edges, node)
  232. // Now create all the new edges, given that we assume everything to be matched
  233. while (set_len(create_edges) > 0):
  234. edge = set_pop(create_edges)
  235. attr = read_attribute(model, edge, "value")
  236. if (element_neq(attr, read_root())):
  237. result = result + "\t" + string_replace(edge, "/", "_") + ", = yield [('CD', [" + string_replace(readAssociationSource(model, edge), "/", "_") + ", " + attr + ", " + string_replace(readAssociationDestination(model, edge), "/", "_") + "])]\n"
  238. else:
  239. result = result + "\t" + string_replace(edge, "/", "_") + ", = yield [('CE', [" + string_replace(readAssociationSource(model, edge), "/", "_") + ", " + string_replace(readAssociationDestination(model, edge), "/", "_") + "])]\n"
  240. result = result + "else:\n"
  241. result = result + "\t# no rules were applicable, so idle for some time\n"
  242. result = result + "\tpass #TODO\n"
  243. log("Got result:")
  244. log(result)
  245. return True!