compiled.py 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616
  1. import time
  2. def get_superclasses(a, b, **remainder):
  3. if 'value' not in b:
  4. b['value'], = yield [("RV", [b['id']])]
  5. model_dict, tm_dict = yield [("RD", [a['id'], "model"]),
  6. ("RD", [a['id'], "type_mapping"])]
  7. tm_dict, = yield [("RD", [tm_dict, "root"])]
  8. worklist = set([b['value']])
  9. found = set([])
  10. cache_value = {}
  11. while worklist:
  12. name = worklist.pop()
  13. if name in found:
  14. continue
  15. elem, = yield [("RD", [model_dict, name])]
  16. found.add(name)
  17. # Iterate over all outgoing links
  18. if elem is None:
  19. print("ERROR: " + str(locals()))
  20. outgoing, = yield [("RO", [elem])]
  21. outgoing = set(outgoing)
  22. while (outgoing):
  23. link = outgoing.pop()
  24. # If the link is typed by "Inheritance", we add its destination
  25. link_name_node, = yield [("CALL_ARGS", [reverseKeyLookup, [{'id': model_dict}, {'id': link}]])]
  26. if "value" not in link_name_node:
  27. link_name_node['value'], = yield [("RV", [link_name_node['id']])]
  28. t_edge, = yield [("RD", [tm_dict, link_name_node['value']])]
  29. t_edge, = yield [("RV", [t_edge])]
  30. if t_edge == "Inheritance":
  31. edge, = yield [("RE", [link])]
  32. src, dst = edge
  33. # Look up dst's name and add it
  34. if dst not in cache_value:
  35. dst_name, = yield [("CALL_ARGS", [reverseKeyLookup, [{'id': model_dict}, {'id': dst}]])]
  36. if 'value' not in dst_name:
  37. dst_name['value'], = yield [("RV", [dst_name['id']])]
  38. cache_value[dst] = dst_name['value']
  39. dst_name_value = cache_value[dst]
  40. worklist.add(dst_name_value)
  41. result, = yield [("CN", [])]
  42. yield [("CD", [result, i, result]) for i in found]
  43. yield [("RETURN", [{'id': result}])]
  44. def reverseKeyLookupMultiID(a, b, **remainder):
  45. edges, result = yield [("RO", [a['id']]), ("CN", [])]
  46. expanded_edges = yield [("RE", [i]) for i in edges]
  47. values = [i[1] for i in expanded_edges]
  48. # Keep results in a local Python set, as we want to bundle as many requests as possible
  49. todo = set()
  50. for i, edge in enumerate(values):
  51. if b['id'] == edge:
  52. todo.add(i)
  53. outgoings = yield [("RO", [edges[i]]) for i in todo]
  54. values = yield [("RE", [outgoing[0]]) for outgoing in outgoings]
  55. edges = yield [("CE", [result, result]) for value in values]
  56. yield [("CE", [edge, value[1]]) for edge, value in zip(edges, values)]
  57. yield [("RETURN", [{'id': result}])]
  58. def reverseKeyLookupMultiValue(a, b, **remainder):
  59. if "value" not in b:
  60. b['value'], = yield [("RV", [b['id']])]
  61. edges, result = yield [("RO", [a['id']]), ("CN", [])]
  62. expanded_edges = yield [("RE", [i]) for i in edges]
  63. values = yield [("RV", [i[1]]) for i in expanded_edges]
  64. # Keep results in a local Python set, as we want to bundle as many requests as possible
  65. todo = set()
  66. for i, edge in enumerate(values):
  67. if b['value'] == edge:
  68. todo.add(i)
  69. outgoings = yield [("RO", [edges[i]]) for i in todo]
  70. values = yield [("RE", [outgoing[0]]) for outgoing in outgoings]
  71. edges = yield [("CE", [result, result]) for value in values]
  72. yield [("CE", [edge, value[1]]) for edge, value in zip(edges, values)]
  73. yield [("RETURN", [{'id': result}])]
  74. def reverseKeyLookup(a, b, **remainder):
  75. edges_out, edges_in = yield [("RO", [a['id']]), ("RI", [b['id']])]
  76. if edges_out is None or edges_in is None:
  77. yield [("RETURN", [{'value': ""}])]
  78. if len(edges_in) > 2:
  79. edges_out = set(edges_out)
  80. for edge in edges_in:
  81. if edge in edges_out:
  82. out_edges, = yield [("RO", [edge])]
  83. # Select one option randomly
  84. if out_edges:
  85. out_edge = out_edges.pop()
  86. e, = yield [("RE", [out_edge])]
  87. yield [("RETURN", [{'id': e[1]}])]
  88. yield [("RETURN", [{'value': ""}])]
  89. def instantiated_name(a, b, **remainder):
  90. if "id" not in a:
  91. a['id'], = yield [("CNV", [a['value']])]
  92. if "value" not in b:
  93. b['value'], = yield [("RV", [b["id"]])]
  94. if b['value'] == "":
  95. yield [("RETURN", [{'value': "__" + str(a['id'])}])]
  96. else:
  97. yield [("RETURN", [b])]
  98. def set_merge(a, b, **remainder):
  99. keys, = yield [("RDK", [b['id']])]
  100. edges = yield [("CE", [a['id'], a['id']]) for key in keys]
  101. _ = yield [("CE", [edge, key]) for edge, key in zip(edges, keys)]
  102. yield [("RETURN", [a])]
  103. def has_value(a, **remainder):
  104. if "value" not in a:
  105. a['value'], = yield [("RV", [a['id']])]
  106. if a['value'] is None:
  107. yield [("RETURN", [{'value': False}])]
  108. else:
  109. yield [("RETURN", [{'value': True}])]
  110. def make_reverse_dictionary(a, **remainder):
  111. reverse, = yield [("CN", [])]
  112. if "id" not in a:
  113. yield [("RETURN", [{'id': reverse}])]
  114. key_nodes, = yield [("RDK", [a['id']])]
  115. values = yield [("RDN", [a['id'], i]) for i in key_nodes]
  116. yield [("CD", [reverse, str(v), k]) for k, v in zip(key_nodes, values)]
  117. yield [("RETURN", [{'id': reverse}])]
  118. def make_reverse_dictionary_multi(a, **remainder):
  119. reverse, keys = yield [("CN", []), ("RDK", [a['id']])]
  120. if "id" not in a:
  121. yield [("RETURN", [{'id': reverse}])]
  122. values = yield [("RDN", [a['id'], i]) for i in keys]
  123. keys = yield [("RV", [i]) for i in keys]
  124. values = yield [("RV", [i]) for i in values]
  125. ndict = {}
  126. for k, v in zip(keys, values):
  127. ndict.setdefault(v, set()).add(k)
  128. n = yield [("CN", []) for _ in ndict]
  129. for k in ndict:
  130. set_node = n.pop()
  131. yield [("CD", [reverse, k, set_node])]
  132. yield [("CD", [set_node, v, set_node]) for v in ndict[k]]
  133. yield [("RETURN", [{'id': reverse}])]
  134. def dict_eq(a, b, **remainder):
  135. key_nodes, = yield [("RDK", [a['id']])]
  136. key_values = yield [("RV", [i]) for i in key_nodes]
  137. values = yield [("RD", [a['id'], i]) for i in key_values]
  138. values = yield [("RV", [i]) for i in values]
  139. a_dict = dict(list(zip(key_values, values)))
  140. key_nodes, = yield [("RDK", [b['id']])]
  141. key_values = yield [("RV", [i]) for i in key_nodes]
  142. values = yield [("RD", [b['id'], i]) for i in key_values]
  143. values = yield [("RV", [i]) for i in values]
  144. b_dict = dict(list(zip(key_values, values)))
  145. yield [("RETURN", [{'value': a_dict == b_dict}])]
  146. def string_substr(a, b, c, **remainder):
  147. if "value" not in a:
  148. a['value'], = yield [("RV", [a['id']])]
  149. if "value" not in b:
  150. b['value'], = yield [("RV", [b['id']])]
  151. if "value" not in c:
  152. c['value'], = yield [("RV", [c['id']])]
  153. try:
  154. new_value = a['value'][b['value']:c['value']]
  155. except:
  156. new_value = ""
  157. yield [("RETURN", [{'value': new_value}])]
  158. def integer_gt(a, b, **remainder):
  159. if 'value' not in a:
  160. a['value'], = yield [("RV", [a['id']])]
  161. if 'value' not in b:
  162. b['value'], = yield [("RV", [b['id']])]
  163. yield [("RETURN", [{'value': a['value'] > b['value']}])]
  164. def integer_neg(a, **remainder):
  165. if 'value' not in a:
  166. a['value'], = yield [("RV", [a['id']])]
  167. yield [("RETURN", [{'value': -a['value']}])]
  168. def float_gt(a, b, **remainder):
  169. if 'value' not in a:
  170. a['value'], = yield [("RV", [a['id']])]
  171. if 'value' not in b:
  172. b['value'], = yield [("RV", [b['id']])]
  173. yield [("RETURN", [{'value': a['value'] > b['value']}])]
  174. def float_neg(a, **remainder):
  175. if 'value' not in a:
  176. a['value'], = yield [("RV", [a['id']])]
  177. yield [("RETURN", [{'value': -a['value']}])]
  178. def value_neq(a, b, **remainder):
  179. if 'value' not in a:
  180. a['value'], = yield [("RV", [a['id']])]
  181. if 'value' not in b:
  182. b['value'], = yield [("RV", [b['id']])]
  183. yield [("RETURN", [{'value': a['value'] != b['value']}])]
  184. def element_neq(a, b, **remainder):
  185. if 'id' not in a or 'id' not in b:
  186. yield [("RETURN", [{'value': False}])]
  187. else:
  188. yield [("RETURN", [{'value': a['id'] != b['id']}])]
  189. def list_append(a, b, **remainder):
  190. if "id" not in b:
  191. b['id'], = yield [("CNV", [b['value']])]
  192. a_outgoing, = yield [("RO", [a['id']])]
  193. _ = yield [("CD", [a['id'], len(a_outgoing), b['id']])]
  194. yield [("RETURN", [a])]
  195. def list_read(a, b, **remainder):
  196. if 'value' not in b:
  197. b['value'], = yield [("RV", [b['id']])]
  198. result, = yield [("RD", [a['id'], b['value']])]
  199. if result is None:
  200. raise Exception("List read out of bounds: %s" % b['value'])
  201. yield [("RETURN", [{'id': result}])]
  202. def list_len(a, **remainder):
  203. outgoings, = yield [("RO", [a['id']])]
  204. result, = yield [("CNV", [len(outgoings)])]
  205. yield [("RETURN", [{'id': result}])]
  206. def dict_add(a, b, c, **remainder):
  207. if 'id' not in b:
  208. b['id'], = yield [("CNV", [b['value']])]
  209. if 'id' not in c:
  210. c['id'], = yield [("CNV", [c['value']])]
  211. new_edge, = yield [("CE", [a['id'], c['id']])]
  212. yield [("CE", [new_edge, b['id']])]
  213. yield [("RETURN", [a])]
  214. def dict_len(a, **remainder):
  215. outgoings, = yield [("RO", [a['id']])]
  216. yield [("RETURN", [{'value': len(outgoings)}])]
  217. def set_add(a, b, **remainder):
  218. if 'value' not in b:
  219. b['value'], = yield [("RV", [b['id']])]
  220. is_in, = yield [("RD", [a['id'], b['value']])]
  221. if not is_in:
  222. _, = yield [("CD", [a['id'], b['value'], a['id']])]
  223. yield [("RETURN", [a])]
  224. def set_add_node(a, b, **remainder):
  225. if 'id' not in b:
  226. b['id'], = yield [("CNV", [b['value']])]
  227. is_in, = yield [("RDN", [a['id'], b['id']])]
  228. if not is_in:
  229. edge, = yield [("CE", [a['id'], a['id']])]
  230. _, = yield [("CE", [edge, b['id']])]
  231. yield [("RETURN", [a])]
  232. def set_pop(a, **remainder):
  233. outgoing, = yield [("RO", [a['id']])]
  234. if outgoing:
  235. outgoing = outgoing[0]
  236. new_outgoing, = yield [("RO", [outgoing])]
  237. new_outgoing = new_outgoing[0]
  238. edge, _ = yield [("RE", [new_outgoing]), ("DE", [outgoing])]
  239. yield [("RETURN", [{'id': edge[1]}])]
  240. else:
  241. raise Exception("POP from empty set")
  242. yield [("RETURN", [{'id': remainder["root"]}])]
  243. def set_create(**remainder):
  244. result, = yield [("CN", [])]
  245. yield [("RETURN", [{'id': result}])]
  246. def list_create(**remainder):
  247. result, = yield [("CN", [])]
  248. yield [("RETURN", [{'id': result}])]
  249. def dict_create(**remainder):
  250. result, = yield [("CN", [])]
  251. yield [("RETURN", [{'id': result}])]
  252. def create_tuple(a, b, **remainder):
  253. if "id" not in a:
  254. a['id'], = yield [("CNV", [a['value']])]
  255. if "id" not in b:
  256. b['id'], = yield [("CNV", [b['value']])]
  257. result, = yield [("CN", [])]
  258. _, _ = yield [("CD", [result, 0, a['id']]),
  259. ("CD", [result, 1, b['id']]),
  260. ]
  261. yield [("RETURN", [{'id': result}])]
  262. def set_overlap(a, b, **remainder):
  263. a_keys, b_keys, res = yield [("RDK", [a['id']]), ("RDK", [b['id']]), ("CN", [])]
  264. a_values = yield [("RV", [i]) for i in a_keys]
  265. b_values = yield [("RV", [i]) for i in b_keys]
  266. result = set(a_values) & set(b_values)
  267. yield [("CD", [res, value, res]) for value in result]
  268. yield [("RETURN", [{'id': res}])]
  269. def list_pop_final(a, **remainder):
  270. lst, = yield [("RO", [a['id']])]
  271. length = len(lst)
  272. result, result_edge = yield [("RD", [a['id'], length - 1]),
  273. ("RDE", [a['id'], length -1])]
  274. _, = yield [("DE", [result_edge])]
  275. yield [("RETURN", [{'id': result}])]
  276. def instantiate_node(a, b, c, **remainder):
  277. if "value" not in b:
  278. b['value'], = yield [("RV", [b['id']])]
  279. if "value" not in c:
  280. c['value'], = yield [("RV", [c['id']])]
  281. node, dict_entry, tm = \
  282. yield [("CN", []),
  283. ("RD", [a['id'], "model"]),
  284. ("RD", [a['id'], "type_mapping"]),
  285. ]
  286. if c['value'] == "":
  287. name = "__" + str(node)
  288. name_node = {'value': name}
  289. else:
  290. name = c['value']
  291. name_node = c
  292. _, root = yield [("CD", [dict_entry, name, node]),
  293. ("RD", [tm, "root"])]
  294. # Create new type links
  295. type_elem, instance_elem = yield [("CNV", [b['value']]), ("CNV", [name])]
  296. type_link, = yield [("CE", [root, type_elem])]
  297. instance_link, = yield [("CE", [type_link, instance_elem])]
  298. # Add them to the model
  299. yield [("CD", [tm, str(type_elem), type_elem]),
  300. ("CD", [tm, str(instance_elem), instance_elem]),
  301. ("CD", [tm, str(type_link), type_link]),
  302. ("CD", [tm, str(instance_link), instance_link])]
  303. yield [("RETURN", [name_node])]
  304. def instantiate_typed_link(a, b, c, d, e, **remainder):
  305. if "value" not in b:
  306. b['value'], = yield [("RV", [b['id']])]
  307. if "value" not in c:
  308. c['value'], = yield [("RV", [c['id']])]
  309. if "value" not in d:
  310. d['value'], = yield [("RV", [d['id']])]
  311. if "value" not in e:
  312. e['value'], = yield [("RV", [e['id']])]
  313. dict_entry, tm = yield [\
  314. ("RD", [a['id'], "model"]),
  315. ("RD", [a['id'], "type_mapping"]),
  316. ]
  317. src, dst = yield [\
  318. ("RD", [dict_entry, d['value']]),
  319. ("RD", [dict_entry, e['value']]),
  320. ]
  321. node, = yield [("CE", [src, dst])]
  322. if c['value'] == "":
  323. name = "__" + str(node)
  324. name_node = {'value': name}
  325. else:
  326. name = c['value']
  327. name_node = c
  328. _, root = yield [("CD", [dict_entry, name, node]),
  329. ("RD", [tm, "root"])]
  330. # Create new type links
  331. type_elem, instance_elem = yield [("CNV", [b['value']]), ("CNV", [name])]
  332. type_link, = yield [("CE", [root, type_elem])]
  333. instance_link, = yield [("CE", [type_link, instance_elem])]
  334. # Add them to the model
  335. yield [("CD", [tm, str(type_elem), type_elem]),
  336. ("CD", [tm, str(instance_elem), instance_elem]),
  337. ("CD", [tm, str(type_link), type_link]),
  338. ("CD", [tm, str(instance_link), instance_link])]
  339. yield [("RETURN", [name_node])]
  340. def list_insert(a, b, c, **remainder):
  341. if "id" not in b:
  342. b["id"], = yield [("CNV", [b['value']])]
  343. if "value" not in c:
  344. c['value'], = yield [("RV", [c['id']])]
  345. a_outgoing, = yield [("RO", [a['id']])]
  346. links = yield [("RD", [a['id'], i]) for i in range(c['value'], len(a_outgoing))] + \
  347. [("RDE", [a['id'], i]) for i in range(c['value'], len(a_outgoing))]
  348. values = links[:len(links) // 2]
  349. edges = links[len(links) // 2:]
  350. yield [("CD", [a['id'], c['value'], b['id']])] + \
  351. [("CD", [a['id'], c['value'] + 1 + index, value]) for index, value in enumerate(values)] + \
  352. [("DE", [i]) for i in edges]
  353. yield [("RETURN", [a])]
  354. def list_delete(a, b, **remainder):
  355. if "value" not in b:
  356. b['value'], = yield [("RV", [b['id']])]
  357. a_outgoing, = yield [("RO", [a['id']])]
  358. links = yield [("RD", [a['id'], i]) for i in range(b['value'], len(a_outgoing))] + \
  359. [("RDE", [a['id'], i]) for i in range(b['value'], len(a_outgoing))]
  360. values = links[:len(links) // 2]
  361. edges = links[len(links) // 2:]
  362. yield [("CD", [a['id'], b['value'] + index, value]) for index, value in enumerate(values[1:])] + \
  363. [("DE", [i]) for i in edges]
  364. yield [("RETURN", [a])]
  365. def set_len(a, **remainder):
  366. if "id" not in a:
  367. yield [("RETURN", [{'value': 0}])]
  368. else:
  369. outgoing, = yield [("RO", [a['id']])]
  370. yield [("RETURN", [{'value': len(outgoing)}])]
  371. def set_in(a, b, **remainder):
  372. if "value" not in b:
  373. b['value'], = yield [("RV", [b['id']])]
  374. value, = yield [("RD", [a['id'], b['value']])]
  375. yield [("RETURN", [{'value': value is not None}])]
  376. def set_in_node(a, b, **remainder):
  377. if "id" not in b:
  378. # Not even allocated the node, so it is certain not to be in the dictionary
  379. yield [("RETURN", [{'value': False}])]
  380. value, = yield [("RDN", [a['id'], b['id']])]
  381. yield [("RETURN", [{'value': value is not None}])]
  382. def read_type(a, b, **remainder):
  383. if "value" not in b:
  384. b['value'], = yield [("RV", [b['id']])]
  385. model, type_mapping, metamodel = yield [("RD", [a['id'], 'model']), ("RD", [a['id'], 'type_mapping']), ("RD", [a['id'], 'metamodel'])]
  386. type_mapping, = yield [("RD", [type_mapping, "root"])]
  387. metamodel, in_model, type_value = yield [("RD", [metamodel, 'model']), ("RD", [model, b['value']]), ("RD", [type_mapping, b['value']])]
  388. if in_model is None:
  389. yield [("RETURN", [{'value': ""}])]
  390. elif type_value is None:
  391. yield [("RETURN", [{'value': ""}])]
  392. else:
  393. type_value, = yield [("RV", [type_value])]
  394. in_metamodel, = yield [("RD", [metamodel, type_value])]
  395. if in_metamodel is None:
  396. yield [("RETURN", [{'value': ""}])]
  397. else:
  398. yield [("RETURN", [{'value': type_value}])]
  399. def retype(a, b, c, **remainder):
  400. if "value" not in b:
  401. b['value'], = yield [("RV", [b['id']])]
  402. if "value" not in c:
  403. c['value'], = yield [("RV", [c['id']])]
  404. tm, = yield [("RD", [a["id"], "type_mapping"])]
  405. root, = yield [("RD", [tm, "root"])]
  406. # remove_type
  407. val, = yield [("RD", [root, b["value"]])]
  408. if val is not None:
  409. # Key exists, so remove
  410. yield [("DN", [val])]
  411. # Create new type links
  412. type_elem, instance_elem = yield [("CNV", [c['value']]), ("CNV", [b['value']])]
  413. type_link, = yield [("CE", [root, type_elem])]
  414. instance_link, = yield [("CE", [type_link, instance_elem])]
  415. # Add them to the model
  416. yield [("CD", [tm, str(type_elem), type_elem]),
  417. ("CD", [tm, str(instance_elem), instance_elem]),
  418. ("CD", [tm, str(type_link), type_link]),
  419. ("CD", [tm, str(instance_link), instance_link])]
  420. yield [("RETURN", [None])]
  421. def set_equality(a, b, **remainder):
  422. if "id" not in a:
  423. yield [("RETURN", [{'value': False}])]
  424. if "id" not in b:
  425. yield [("RETURN", [{'value': False}])]
  426. keys_a, keys_b = yield [("RDK", [a["id"]]), ("RDK", [b["id"]])]
  427. if (len(keys_a) != len(keys_b)):
  428. yield [("RETURN", [{'value': False}])]
  429. keys_a = yield [("RV", [i]) for i in keys_a]
  430. keys_b = yield [("RV", [i]) for i in keys_b]
  431. yield [("RETURN", [{'value': keys_a == keys_b}])]
  432. def set_difference(a, b, **remainder):
  433. keys_a, keys_b = yield [("RDK", [a["id"]]), ("RDK", [b["id"]])]
  434. keys_a = yield [("RV", [i]) for i in keys_a]
  435. keys_b = yield [("RV", [i]) for i in keys_b]
  436. result = set(keys_a) - set(keys_b)
  437. res, = yield [("CN", [])]
  438. yield [("CD", [res, v, res]) for v in result]
  439. yield [("RETURN", [{'id': res}])]
  440. def string_startswith(a, b, **remainder):
  441. if "value" not in a:
  442. a['value'], = yield [("RV", [a['id']])]
  443. if "value" not in b:
  444. b['value'], = yield [("RV", [b['id']])]
  445. yield [("RETURN", [{"value": a['value'].startswith(b['value'])}])]
  446. def dict_copy(a, **remainder):
  447. keys, new = yield [("RDK", [a['id']]), ("CN", [])]
  448. values = yield [("RDN", [a['id'], i]) for i in keys]
  449. keys = yield [("RV", [i]) for i in keys]
  450. yield [("CD", [new, k, v]) for k, v in zip(keys, values)]
  451. yield [("RETURN", [{'id': new}])]
  452. def read_attribute(a, b, c, root, **remainder):
  453. if "value" not in b:
  454. b["value"], = yield [("RV", [b['id']])]
  455. if "value" not in c:
  456. c["value"], = yield [("RV", [c['id']])]
  457. m, metamodel = yield [("RD", [a['id'], "model"]), ("RD", [a['id'], "metamodel"])]
  458. mm, elem, tm = yield [("RD", [metamodel, "model"]), ("RD", [m, b['value']]), ("RD", [a['id'], "type_mapping"])]
  459. if elem is not None:
  460. # Read all outgoing links and their names
  461. outgoing_edges, tm = yield [("RO", [elem]), ("RD", [tm, "root"])]
  462. if outgoing_edges:
  463. outgoing_names = []
  464. backlinks = {}
  465. edges_out, = yield [("RO", [m])]
  466. for i in outgoing_edges:
  467. edges_in, = yield [("RI", [i])]
  468. if len(edges_in) > 2:
  469. edges_out = set(edges_out)
  470. for edge in edges_in:
  471. if edge in edges_out:
  472. out_edges, = yield [("RO", [edge])]
  473. # Select one option randomly
  474. out_edge = out_edges.pop()
  475. e, = yield [("RE", [out_edge])]
  476. val, = yield [("RV", [e[1]])]
  477. backlinks[val] = i
  478. outgoing_names.append(val)
  479. break
  480. if outgoing_names:
  481. # Read out the types and flatten
  482. types = yield [("RD", [tm, i]) for i in outgoing_names]
  483. types = yield [("RV", [i]) for i in types]
  484. edges = yield [("RD", [mm, i]) for i in types]
  485. sources = yield [("RE", [i]) for i in edges]
  486. sources = {i[0] for i in sources}
  487. backlinks = {e: backlinks[s] for e, s in zip(edges, outgoing_names)}
  488. # List the outgoing links with the attribute in it
  489. vals = yield [("RDE", [i, c['value']]) for i in sources]
  490. vals = [v for v in vals if v is not None]
  491. if vals:
  492. # Found the link and stored in vals[0]
  493. edge = vals[0]
  494. # Get the instance of this link
  495. if edge in backlinks:
  496. val, = yield [("RE", [backlinks[edge]])]
  497. yield [("RETURN", [{'id': val[1]}])]
  498. yield [("RETURN", [{'id': root}])]