compiled.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. from modelverse_kernel.primitives import PrimitiveFinished
  2. def reverseKeyLookup(a, b, **remainder):
  3. edges = yield [("RO", [a])]
  4. expanded_edges = yield [("RE", [i]) for i in edges]
  5. for i, edge in enumerate(expanded_edges):
  6. if b == edge[1]:
  7. # Found our edge: edges[i]
  8. outgoing = yield [("RO", [edges[i]])]
  9. result = yield [("RE", [outgoing[0]])]
  10. raise PrimitiveFinished(result[1])
  11. result = yield [("CNV", ["(unknown: %s)" % b])]
  12. raise PrimitiveFinished(result)
  13. def read_attribute(a, b, c, **remainder):
  14. def make_list(v, l):
  15. return [v] if l else v
  16. model_dict, b_val, c_val, type_mapping = \
  17. yield [("RD", [a, "model"]),
  18. ("RV", [b]),
  19. ("RV", [c]),
  20. ("RD", [a, "type_mapping"]),
  21. ]
  22. model_instance = \
  23. yield [("RD", [model_dict, b_val])]
  24. edges = yield [("RO", [model_instance])]
  25. edge_types = yield [("RDN", [type_mapping, i]) for i in edges]
  26. edge_types = make_list(edge_types, len(edges) == 1)
  27. type_edge_val = yield [("RE", [i]) for i in edge_types]
  28. type_edge_val = make_list(type_edge_val, len(edges) == 1)
  29. src_nodes = set([i[0] for i in type_edge_val])
  30. found_edges = yield [("RDE", [i, c_val]) for i in src_nodes]
  31. found_edges = make_list(found_edges, len(src_nodes) == 1)
  32. for e1 in found_edges:
  33. if e1 is not None:
  34. # Found an edge!
  35. for i, e2 in enumerate(edge_types):
  36. if e1 == e2:
  37. # The instance of this edge is the one we want!
  38. edge = edges[i]
  39. edge_val = yield [("RE", [edge])]
  40. result = edge_val[1]
  41. raise PrimitiveFinished(result)
  42. else:
  43. result = yield [("RR", [])]
  44. raise PrimitiveFinished(result)
  45. raise Exception("Error in reading edge!")
  46. def precompute_cardinalities(a, **remainder):
  47. result = yield [("CN", [])]
  48. # Read out all edges from the metamodel
  49. a = yield [("RD", [a, "metamodel"])]
  50. model_dict = yield [("RD", [a, "model"])]
  51. model_keys = yield [("RDK", [model_dict])]
  52. type_mapping = yield [("RD", [a, "type_mapping"])]
  53. elems = yield [("RDN", [model_dict, k]) for k in model_keys]
  54. model_keys_str= yield [("RV", [i]) for i in model_keys]
  55. elem_to_name = dict(zip(elems, model_keys_str))
  56. edges = yield [("RE", [i]) for i in elems]
  57. elems = [elems[i] for i, edge_val in enumerate(edges) if edge_val is not None]
  58. # Now we have all edges in the metamodel
  59. # Read out the type of the Association defining all cardinalities
  60. metamodel = yield [("RD", [a, "metamodel"])]
  61. metametamodel = yield [("RD", [metamodel, "metamodel"])]
  62. metametamodel_dict = \
  63. yield [("RD", [metametamodel, "model"])]
  64. assoc = yield [("RD", [metametamodel_dict, "Association"])]
  65. slc, suc, tlc, tuc = \
  66. yield [("RDE", [assoc, "source_lower_cardinality"]),
  67. ("RDE", [assoc, "source_upper_cardinality"]),
  68. ("RDE", [assoc, "target_lower_cardinality"]),
  69. ("RDE", [assoc, "target_upper_cardinality"]),
  70. ]
  71. # All that we now have to do is find, for each edge, whether or not it has an edge typed by any of these links!
  72. # Just find all links typed by these links!
  73. types = yield [("RDN", [type_mapping, i]) for i in elems]
  74. cardinalities = {}
  75. for i, edge_type in enumerate(types):
  76. if edge_type == slc:
  77. t = "slc"
  78. elif edge_type == suc:
  79. t = "suc"
  80. elif edge_type == tlc:
  81. t = "tlc"
  82. elif edge_type == tuc:
  83. t = "tuc"
  84. else:
  85. continue
  86. # Found a link, so add it
  87. source, destination = yield [("RE", [elems[i]])]
  88. # The edge gives the "source" the cardinality found in "destination"
  89. cardinalities.setdefault(elem_to_name[source], {})[t] = destination
  90. # Now we have to translate the "cardinalities" Python dictionary to a Modelverse dictionary
  91. nodes = yield [("CN", []) for i in cardinalities]
  92. yield [("CD", [result, i, node]) for i, node in zip(cardinalities.keys(), nodes)]
  93. l = cardinalities.keys()
  94. values = yield [("RD", [result, i]) for i in l]
  95. for i, value in enumerate(values):
  96. cards = cardinalities[l[i]]
  97. yield [("CD", [value, card_type, cards[card_type]]) for card_type in cards]
  98. raise PrimitiveFinished(result)
  99. def set_copy(a, **remainder):
  100. b = yield [("CN", [])]
  101. links = yield [("RO", [a])]
  102. exp_links = yield [("RE", [i]) for i in links]
  103. if len(links) == 1:
  104. exp_links = [exp_links]
  105. _ = yield [("CE", [b, i[1]]) for i in exp_links]
  106. raise PrimitiveFinished(b)
  107. def allInstances(a, b, **remainder):
  108. b_val = yield [("RV", [b])]
  109. model_dict= yield [("RD", [a, "model"])]
  110. metamodel = yield [("RD", [a, "metamodel"])]
  111. mm_dict = yield [("RD", [metamodel, "model"])]
  112. typing = yield [("RD", [a, "type_mapping"])]
  113. elem_keys = yield [("RDK", [model_dict])]
  114. elems = yield [("RDN", [model_dict, i]) for i in elem_keys]
  115. mms = yield [("RDN", [typing, i]) for i in elems]
  116. # Have the type for each name
  117. types_to_name_nodes = {}
  118. for key, mm in zip(elem_keys, mms):
  119. types_to_name_nodes.setdefault(mm, set()).add(key)
  120. # And now we have the inverse mapping: for each type, we have the node containing the name
  121. # Get the inheritance link type
  122. inheritance_type = yield [("RD", [metamodel, "inheritance"])]
  123. # Now we figure out which types are valid for the specified model
  124. desired_types = set()
  125. mm_element = yield [("RD", [mm_dict, b_val])]
  126. work_list = []
  127. work_list.append(mm_element)
  128. mm_typing = yield [("RD", [metamodel, "type_mapping"])]
  129. while work_list:
  130. mm_element = work_list.pop()
  131. if mm_element in desired_types:
  132. # Already been here, so stop
  133. continue
  134. # New element, so continue
  135. desired_types.add(mm_element)
  136. # Follow all inheritance links that COME IN this node, as all these are subtypes and should also match
  137. incoming = yield [("RI", [mm_element])]
  138. for i in incoming:
  139. t = yield [("RDN", [mm_typing, i])]
  140. if t == inheritance_type:
  141. e = yield [("RE", [i])]
  142. # Add the source of the inheritance link to the work list
  143. work_list.append(e[0])
  144. # Now desired_types holds all the direct types that we are interested in!
  145. # Construct the result out of all models that are direct instances of our specified type
  146. final = set()
  147. for t in desired_types:
  148. final |= types_to_name_nodes.get(t, set())
  149. # Result is a Python set with nodes, so just make this a Mv set
  150. result = yield [("CN", [])]
  151. v = yield [("RV", [i]) for i in final]
  152. _ = yield [("CE", [result, i]) for i in final]
  153. raise PrimitiveFinished(result)
  154. def add_AL(a, b, **remainder):
  155. worklist = [(b, "funcdef")]
  156. added = set()
  157. type_cache = {}
  158. model_dict = yield [("RD", [a, "model"])]
  159. metamodel = yield [("RD", [a, "metamodel"])]
  160. metamodel_dict = yield [("RD", [metamodel, "model"])]
  161. type_map = yield [("RD", [a, "type_mapping"])]
  162. outgoing = yield [("RO", [model_dict])]
  163. edges = yield [("RE", [i]) for i in outgoing]
  164. added |= set([i[1] for i in edges])
  165. result = yield [("CNV", ["__%s" % b])]
  166. # All the action language elements and their expected output links
  167. type_links = {
  168. "if": [("cond", ""), ("then", ""), ("else", ""), ("next", "")],
  169. "while": [("cond", ""), ("body", ""), ("next", "")],
  170. "assign": [("var", ""), ("value", ""), ("next", "")],
  171. "break": [("while", "while")],
  172. "continue": [("while", "while")],
  173. "return": [("value", "")],
  174. "resolve": [("var", "")],
  175. "access": [("var", "")],
  176. "constant": [("node", "")],
  177. "output": [("node", ""), ("next", "")],
  178. "global": [("var", "String"), ("next", "")],
  179. "param": [("name", "String"), ("value", ""), ("next_param", "param")],
  180. "funcdef": [("body", ""), ("next", "")],
  181. "call": [("func", ""), ("params", "param"), ("last_param", "param"), ("next", "")],
  182. }
  183. # Already add some often used types to the type cache, so we don't have to check for their presence
  184. to_str, string = yield [("RD", [metamodel_dict, "to_str"]),
  185. ("RD", [metamodel_dict, "String"])]
  186. type_cache = {"to_str": to_str,
  187. "String": string}
  188. while worklist:
  189. # Fetch the element and see if we need to add it
  190. worknode, expected_type = worklist.pop(0)
  191. if worknode in added:
  192. continue
  193. # Determine type of element
  194. if expected_type == "":
  195. value = yield [("RV", [worknode])]
  196. if (isinstance(value, dict)) and ("value" in value):
  197. v = value["value"]
  198. if v in ["if", "while", "assign", "call", "break", "continue", "return", "resolve", "access", "constant", "global", "declare"]:
  199. expected_type = v
  200. else:
  201. expected_type = "Any"
  202. else:
  203. expected_type = "Any"
  204. # Fill the cache
  205. if expected_type not in type_cache:
  206. type_cache[expected_type] = yield [("RD", [metamodel_dict, expected_type])]
  207. # Need to add it now
  208. yield [("CD", [model_dict, "__%s" % worknode, worknode])]
  209. added.add(worknode)
  210. # NOTE can't just use CD here, as the key is a node and not a value
  211. t1 = yield [("CE", [type_map, type_cache[expected_type]])]
  212. t2 = yield [("CE", [t1, worknode])]
  213. if t1 is None or t2 is None:
  214. raise Exception("ERROR")
  215. # Now add all its outgoing links, depending on the type we actually saw
  216. links = type_links.get(expected_type, [])
  217. for link in links:
  218. link_name, destination_type = link
  219. # Check if the link actually exists
  220. destination = yield [("RD", [worknode, link_name])]
  221. if destination is not None:
  222. # If so, we add it and continue
  223. edge = yield [("RDE", [worknode, link_name])]
  224. edge_outlinks = yield [("RO", [edge])]
  225. edge_outlink = edge_outlinks[0]
  226. edge_name = yield [("RE", [edge_outlink])]
  227. edge_name = edge_name[1]
  228. # Now add: edge, edge_outlink, edge_name
  229. # Add 'edge'
  230. yield [("CD", [model_dict, "__%s" % edge, edge])]
  231. added.add(edge)
  232. link_type = "%s_%s" % (expected_type, link_name)
  233. if link_type not in type_cache:
  234. type_cache[link_type] = yield [("RD", [metamodel_dict, link_type])]
  235. t = yield [("CE", [type_map, type_cache[link_type]])]
  236. yield [("CE", [t, edge])]
  237. # Add 'edge_outlink'
  238. yield [("CD", [model_dict, "__%s" % edge_outlink, edge_outlink])]
  239. added.add(edge_outlink)
  240. t = yield [("CE", [type_map, type_cache["to_str"]])]
  241. yield [("CE", [t, edge_outlink])]
  242. # Add 'edge_name' (if not present)
  243. if edge_name not in added:
  244. yield [("CD", [model_dict, "__%s" % edge_name, edge_name])]
  245. t = yield [("CE", [type_map, type_cache["String"]])]
  246. yield [("CE", [t, edge_name])]
  247. added.add(edge_name)
  248. # Add the destination to the worklist
  249. worklist.append((destination, destination_type))
  250. raise PrimitiveFinished(result)
  251. def get_superclasses(a, b, **remainder):
  252. inheritance = yield [("RD", [a, "inheritance"])]
  253. model_dict = yield [("RD", [a, "model"])]
  254. b_v = yield [("RV", [b])]
  255. subclass = yield [("RD", [model_dict, b_v])]
  256. type_mapping = yield [("RD", [a, "type_mapping"])]
  257. names = yield [("RDK", [model_dict])]
  258. elems = yield [("RDN", [model_dict, i]) for i in names]
  259. elem_to_name = dict(zip(elems, names))
  260. result = yield [("CN", [])]
  261. worklist = [subclass]
  262. while worklist:
  263. subclass = worklist.pop()
  264. res = elem_to_name[subclass]
  265. yield [("CE", [result, res])]
  266. outgoing = yield [("RO", [subclass])]
  267. types = yield [("RDN", [type_mapping, i]) for i in outgoing]
  268. types = [types] if len(outgoing) == 1 else types
  269. for i, t in enumerate(types):
  270. if t == inheritance:
  271. # Found an inheritance link!
  272. elem = outgoing[i]
  273. src, dst = \
  274. yield [("RE", [elem])]
  275. # Find elem in elems
  276. worklist.append(dst)
  277. raise PrimitiveFinished(result)
  278. def selectPossibleIncoming(a, b, c, **remainder):
  279. model_dict = yield [("RD", [a, "model"])]
  280. limit_set_links = \
  281. yield [("RO", [c])]
  282. limit_set = yield [("RE", [i]) for i in limit_set_links]
  283. limit_set_names = \
  284. [i[1] for i in limit_set]
  285. limit_set_names = [limit_set_names] if len(limit_set) == 1 else limit_set_names
  286. name_values = yield [("RV", [i]) for i in limit_set_names]
  287. limit_set = yield [("RD", [model_dict, i]) for i in name_values]
  288. limit_set = [limit_set] if len(limit_set_names) == 1 else limit_set
  289. try:
  290. gen = get_superclasses(a, b)
  291. inp = None
  292. while 1:
  293. inp = yield gen.send(inp)
  294. except PrimitiveFinished as e:
  295. superclasses = e.result
  296. vals = yield [("RO", [superclasses])]
  297. superclasses = yield [("RE", [i]) for i in vals]
  298. superclasses = [superclasses] if len(vals) == 1 else superclasses
  299. superclasses = [i[1] for i in superclasses]
  300. superclass_names = yield [("RV", [i]) for i in superclasses]
  301. superclass_names = [superclass_names] if len(superclasses) == 1 else superclass_names
  302. elems = yield [("RD", [model_dict, i]) for i in superclass_names]
  303. elems = [elems] if len(superclasses) == 1 else elems
  304. result = yield [("CN", [])]
  305. for i, edge in enumerate(limit_set):
  306. src, dst = yield [("RE", [edge])]
  307. if dst in elems:
  308. yield [("CE", [result, limit_set_names[i]])]
  309. raise PrimitiveFinished(result)
  310. def selectPossibleOutgoing(a, b, c, **remainder):
  311. model_dict = yield [("RD", [a, "model"])]
  312. limit_set_links = \
  313. yield [("RO", [c])]
  314. limit_set = yield [("RE", [i]) for i in limit_set_links]
  315. limit_set_names = \
  316. [i[1] for i in limit_set]
  317. limit_set_names = [limit_set_names] if len(limit_set) == 1 else limit_set_names
  318. name_values = yield [("RV", [i]) for i in limit_set_names]
  319. limit_set = yield [("RD", [model_dict, i]) for i in name_values]
  320. limit_set = [limit_set] if len(limit_set_names) == 1 else limit_set
  321. try:
  322. gen = get_superclasses(a, b)
  323. inp = None
  324. while 1:
  325. inp = yield gen.send(inp)
  326. except PrimitiveFinished as e:
  327. superclasses = e.result
  328. vals = yield [("RO", [superclasses])]
  329. superclasses = yield [("RE", [i]) for i in vals]
  330. superclasses = [superclasses] if len(vals) == 1 else superclasses
  331. superclasses = [i[1] for i in superclasses]
  332. superclass_names = yield [("RV", [i]) for i in superclasses]
  333. superclass_names = [superclass_names] if len(superclasses) == 1 else superclass_names
  334. elems = yield [("RD", [model_dict, i]) for i in superclass_names]
  335. elems = [elems] if len(superclasses) == 1 else elems
  336. result = yield [("CN", [])]
  337. for i, edge in enumerate(limit_set):
  338. src, dst = yield [("RE", [edge])]
  339. if src in elems:
  340. yield [("CE", [result, limit_set_names[i]])]
  341. raise PrimitiveFinished(result)
  342. def read_symbols(a, b, **remainder):
  343. b_v = yield [("RV", [b])]
  344. obj = yield [("RD", [a, b_v])]
  345. node = yield [("RD", [obj, "symbols"])]
  346. keys = yield [("RDK", [node])]
  347. keys_v = yield [("RV", [i]) for i in keys]
  348. is_in = yield [("RD", [node, i]) for i in keys_v]
  349. is_in_v = yield [("RV", [i]) for i in is_in]
  350. result_v = ["%s:%s\n" % (key, "1" if value else "0") for key, value in zip(keys_v, is_in_v)]
  351. result_v = "".join(result_v)
  352. result = yield [("CNV", [result_v])]
  353. raise PrimitiveFinished(result)