to_python.alc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  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. log("Matching rule " + rule)
  116. nodes = allAssociationDestinations(model, rule, "Rules/contains")
  117. all_nodes = set_overlap(nodes, allInstances(model, "Rules/Match"))
  118. create_edges = set_create()
  119. explored = set_create()
  120. while (set_len(nodes) > 0):
  121. node = set_pop(nodes)
  122. if (read_type(model, node) == "Rules/Root"):
  123. // Found the root of this rule, so start exploring again
  124. // Keep following outgoing edges to find matching nodes
  125. to_explore = set_create()
  126. remainder_to_explore = set_create()
  127. set_add(to_explore, node)
  128. while (set_len(explored) < set_len(all_nodes)):
  129. while (set_len(to_explore) > 0):
  130. // Still explore more!
  131. node = set_pop(to_explore)
  132. log("Explore " + node)
  133. set_add(explored, node)
  134. source = string_replace(node, "/", "_")
  135. edges = allOutgoingAssociationInstances(model, node, "Rules/MatchEdge")
  136. while (set_len(edges) > 0):
  137. edge = set_pop(edges)
  138. new_node = readAssociationDestination(model, edge)
  139. name = read_attribute(model, edge, "value")
  140. destination = string_replace(new_node, "/", "_")
  141. if (element_eq(name, read_root())):
  142. String node_key
  143. node_key = set_pop(allAssociationDestinations(model, edge, ""))
  144. if (set_in(explored, node_key)):
  145. result = result + "\t" + destination + ", = yield [('RDN', [" + source + ", " + string_replace(node_key, "/", "_") + "])]\n"
  146. set_add(to_explore, new_node)
  147. else:
  148. set_add(remainder_to_explore, node)
  149. continue!
  150. if (read_type(model, edge) == "Rules/DeleteEdge"):
  151. // Delete edge
  152. result = result + "\t" + destination + "_DEL, = yield [('RDNE', [" + source + ", " + string_replace(node_key, "/", "_") + "])]\n"
  153. result = result + "\tyield [('DE', [" + destination + "_DEL])]\n"
  154. else:
  155. if (set_in(explored, new_node)):
  156. // Already visited this one in another way, so try to merge!
  157. String rand
  158. rand = random_string(10)
  159. result = result + "\t" + rand + ", = yield [('RD', [" + source + ", " + name + "])]\n"
  160. result = result + "\t" + "if " + rand + " != " + destination + ":\n"
  161. // If the values don't agree, this is not a correct match, and we say that this element remains unmatched (i.e., assign None)
  162. result = result + "\t" + "\t" + destination + " = None\n"
  163. else:
  164. // First visit to this element, so just assign
  165. result = result + "\t" + destination + ", = yield [('RD', [" + source + ", " + name + "])]\n"
  166. String value
  167. value = read_attribute(model, new_node, "value")
  168. if (element_neq(value, read_root())):
  169. // Match node has a value we should compare as well!
  170. // Read out the value from the Modelverse
  171. result = result + "\t" + destination + "_V, = yield [('RV', [" + destination + "])]\n"
  172. set_add(to_explore, new_node)
  173. if (read_type(model, edge) == "Rules/DeleteEdge"):
  174. // Delete edge
  175. result = result + "\t" + destination + "_DEL, = yield [('RDE', [" + source + ", " + name + "])]\n"
  176. result = result + "\tyield [('DE', [" + destination + "_DEL])]\n"
  177. if (bool_and(set_len(to_explore) == 0, set_len(remainder_to_explore) > 0)):
  178. to_explore = remainder_to_explore
  179. remainder_to_explore = set_create()
  180. // Check for nodes that are unexplored, but seemingly not reachable from the root directly
  181. Element remaining
  182. String check_elem
  183. Boolean found
  184. if (set_len(explored) < set_len(all_nodes)):
  185. // Find all unexplored nodes
  186. remaining = set_difference(all_nodes, explored)
  187. log("Remain unexplored: " + set_to_string(remaining))
  188. while (set_len(remaining) > 0):
  189. check_elem = set_pop(remaining)
  190. edges = allOutgoingAssociationInstances(model, check_elem, "Rules/MatchEdge")
  191. found = False
  192. while (set_len(edges) > 0):
  193. edge = set_pop(edges)
  194. new_node = readAssociationDestination(model, edge)
  195. name = read_attribute(model, edge, "value")
  196. if (set_in(explored, new_node)):
  197. // We already explored this node, so we can do a RRD from this place!
  198. if (bool_not(found)):
  199. result = result + "\tmatched = []\n"
  200. result = result + "\t_tmp, = yield [('RRD', [" + string_replace(new_node, "/", "_") + ", " + name + "])]\n"
  201. result = result + "\tmatched.append(_tmp)\n"
  202. found = True
  203. // Iterated over all edges, so check how many we found!
  204. if (found):
  205. set_add(to_explore, check_elem)
  206. set_add(explored, check_elem)
  207. // Found at least one match, so we try to find an overlapping node
  208. result = result + "\t" + string_replace(check_elem, "/", "_") + " = self.set_overlap(matched)[0]\n"
  209. elif (read_type(model, node) == "Rules/Create"):
  210. // A node that we should create: do that already, as otherwise we might have to sort
  211. String attr
  212. attr = read_attribute(model, node, "value")
  213. if (element_eq(attr, read_root())):
  214. // Create empty node
  215. result = result + "\t" + string_replace(node, "/", "_") + ", = yield [('CN', [])]\n"
  216. else:
  217. // Create value node
  218. result = result + "\t" + string_replace(node, "/", "_") + ", = yield [('CNV', [" + cast_string(attr) + "])]\n"
  219. elif (read_type(model, node) == "Rules/CreateEdge"):
  220. // Encounter a create edge, so alreade record this for later
  221. set_add(create_edges, node)
  222. // Now create all the new edges, given that we assume everything to be matched
  223. while (set_len(create_edges) > 0):
  224. edge = set_pop(create_edges)
  225. attr = read_attribute(model, edge, "value")
  226. if (element_neq(attr, read_root())):
  227. result = result + "\t" + string_replace(edge, "/", "_") + ", = yield [('CD', [" + string_replace(readAssociationSource(model, edge), "/", "_") + ", " + attr + ", " + string_replace(readAssociationDestination(model, edge), "/", "_") + "])]\n"
  228. else:
  229. result = result + "\t" + string_replace(edge, "/", "_") + ", = yield [('CE', [" + string_replace(readAssociationSource(model, edge), "/", "_") + ", " + string_replace(readAssociationDestination(model, edge), "/", "_") + "])]\n"
  230. result = result + "else:\n"
  231. result = result + "\t# no rules were applicable, so idle for some time\n"
  232. result = result + "\tpass #TODO\n"
  233. log("Got result:")
  234. log(result)
  235. return True!