transform.alc 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. include "primitives.alh"
  2. include "object_operations.alh"
  3. include "modelling.alh"
  4. Element function make_matching_schedule(LHS_model : Element):
  5. Element schedule
  6. Element workset
  7. Element all_elements
  8. Element full_all_elements
  9. Integer required_size
  10. String new_element
  11. Integer counter
  12. String next
  13. // Initialize
  14. schedule = create_node()
  15. workset = create_node()
  16. all_elements = allInstances(LHS_model, "Pre_Element")
  17. full_all_elements = set_copy(all_elements)
  18. required_size = read_nr_out(all_elements)
  19. // Need to keep adding to the schedule
  20. while (read_nr_out(schedule) < required_size):
  21. // workset is empty, but we still need to add to the list
  22. // Therefore, we pick a random, unbound node, and add it to the workset
  23. new_element = set_pop(all_elements)
  24. while (bool_or(set_in(schedule, new_element), is_edge(LHS_model["model"][new_element]))):
  25. // Element is not usable, so pick another one
  26. new_element = set_pop(all_elements)
  27. set_add(workset, new_element)
  28. // Handle the workset
  29. while (read_nr_out(workset) > 0):
  30. // Still elements in the workset, so pop from these first
  31. next = set_pop(workset)
  32. // Check if element might not be already used somewhere
  33. if (bool_not(set_in(schedule, next))):
  34. if (set_in(full_all_elements, next)):
  35. list_append(schedule, next)
  36. // If it is an edge, we should also add the target and source
  37. if (is_edge(LHS_model["model"][next])):
  38. // Add the target/source to the schedule
  39. set_add(workset, reverseKeyLookup(LHS_model["model"], read_edge_src(LHS_model["model"][next])))
  40. set_add(workset, reverseKeyLookup(LHS_model["model"], read_edge_dst(LHS_model["model"][next])))
  41. // Also add all outgoing links
  42. counter = read_nr_out(LHS_model["model"][next])
  43. while (counter > 0):
  44. counter = counter - 1
  45. if (set_in_node(LHS_model["model"], read_out(LHS_model["model"][next], counter))):
  46. set_add(workset, reverseKeyLookup(LHS_model["model"], read_out(LHS_model["model"][next], counter)))
  47. return schedule!
  48. Element function get_possible_bindings(host_model : Element, LHS_model : Element, current_element : String, map : Element):
  49. Element options
  50. String src_label
  51. String dst_label
  52. String typename
  53. String original_typename
  54. options = create_node()
  55. typename = reverseKeyLookup(LHS_model["metamodel"]["model"], dict_read_node(LHS_model["type_mapping"], LHS_model["model"][current_element]))
  56. original_typename = string_substr(typename, 4, string_len(typename))
  57. if (is_edge(LHS_model["model"][current_element])):
  58. // Is an edge, so check for already bound source/target
  59. src_label = read_attribute(LHS_model, reverseKeyLookup(LHS_model["model"], read_edge_src(LHS_model["model"][current_element])), "label")
  60. dst_label = read_attribute(LHS_model, reverseKeyLookup(LHS_model["model"], read_edge_dst(LHS_model["model"][current_element])), "label")
  61. if (bool_and(set_in(dict_keys(map), src_label), set_in(dict_keys(map), dst_label))):
  62. // Source and destination are bound
  63. options = allOutgoingAssociationInstances(host_model, map[src_label], original_typename)
  64. options = set_overlap(options, allIncomingAssociationInstances(host_model, map[dst_label], original_typename))
  65. elif (set_in(dict_keys(map), src_label)):
  66. // Source is bound
  67. options = allOutgoingAssociationInstances(host_model, map[src_label], original_typename)
  68. elif (set_in(dict_keys(map), dst_label)):
  69. // Destination is bound
  70. options = allIncomingAssociationInstances(host_model, map[dst_label], original_typename)
  71. else:
  72. // Neither is bound, so just get all of them
  73. log("ERROR: unbound source/target for association!")
  74. return create_node()!
  75. else:
  76. // Is a node, so check for already bound incoming/outgoing
  77. options = allInstances(host_model, original_typename)
  78. // Filter options further
  79. Element filtered_options
  80. String option
  81. filtered_options = create_node()
  82. while (read_nr_out(options) > 0):
  83. option = set_pop(options)
  84. // Check for detecting same element twice
  85. if (bool_not(set_in(map, option))):
  86. // Option is already present with another label, so skip this!
  87. // Check for local constraints of element
  88. if (element_eq(read_attribute(LHS_model, current_element, "constraint"), read_root())):
  89. // No local constraints, so all is well
  90. set_add(filtered_options, option)
  91. else:
  92. // Check local constraints and add only if positive
  93. Element constraint_function
  94. constraint_function = read_attribute(LHS_model, current_element, "constraint")
  95. Boolean result
  96. result = constraint_function(host_model, option)
  97. if (result):
  98. set_add(filtered_options, option)
  99. return filtered_options!
  100. Element function match(host_model : Element, LHS_model : Element):
  101. // Match the LHS_model to the host_model, returning all possible mappings from LHS_model elements to host_model elements
  102. // Make the schedule first
  103. Element schedule
  104. schedule = make_matching_schedule(LHS_model)
  105. // Now follow the schedule, incrementally building all mappings
  106. Element mappings
  107. Element new_mappings
  108. Element new_map
  109. String current_element
  110. Element map
  111. String option
  112. Element options
  113. mappings = create_node()
  114. set_add(mappings, create_node())
  115. while (bool_and(read_nr_out(schedule) > 0, read_nr_out(mappings) > 0)):
  116. current_element = list_pop(schedule, 0)
  117. new_mappings = create_node()
  118. while (read_nr_out(mappings) > 0):
  119. map = set_pop(mappings)
  120. options = get_possible_bindings(host_model, LHS_model, current_element, map)
  121. while (read_nr_out(options) > 0):
  122. option = set_pop(options)
  123. new_map = dict_copy(map)
  124. dict_add(new_map, read_attribute(LHS_model, current_element, "label"), option)
  125. set_add(new_mappings, new_map)
  126. mappings = new_mappings
  127. return mappings!
  128. Void function rewrite(host_model : Element, RHS_model : Element, mapping : Element):
  129. // Rewrite the host model based on the mapping combined with the RHS
  130. Element LHS_labels
  131. Element RHS_labels
  132. Element RHS_elements
  133. Element remaining
  134. String elem
  135. String label
  136. Element labels_to_remove
  137. Element labels_to_add
  138. String typename
  139. String original_typename
  140. String src
  141. String dst
  142. Element new_mapping
  143. String new_name
  144. Element RHS_map
  145. String tmp
  146. Element value
  147. Element value_function
  148. LHS_labels = dict_keys(mapping)
  149. RHS_labels = create_node()
  150. RHS_map = create_node()
  151. RHS_elements = allInstances(RHS_model, "Post_Element")
  152. while (read_nr_out(RHS_elements) > 0):
  153. tmp = set_pop(RHS_elements)
  154. label = read_attribute(RHS_model, tmp, "label")
  155. log("Read label of " + cast_v2s(tmp))
  156. set_add(RHS_labels, label)
  157. dict_add(RHS_map, label, tmp)
  158. remaining = set_overlap(LHS_labels, RHS_labels)
  159. while (read_nr_out(remaining) > 0):
  160. elem = set_pop(remaining)
  161. set_remove(LHS_labels, elem)
  162. set_remove(RHS_labels, elem)
  163. labels_to_remove = LHS_labels
  164. labels_to_add = set_to_list(RHS_labels)
  165. new_mapping = dict_copy(mapping)
  166. while (read_nr_out(labels_to_remove) > 0):
  167. // Remove the elements linked to these labels
  168. label = set_pop(labels_to_remove)
  169. model_delete_element(host_model, mapping[label])
  170. dict_delete(new_mapping, label)
  171. log("Removed " + cast_v2s(label))
  172. while (read_nr_out(labels_to_add) > 0):
  173. // Add the elements linked to these labels
  174. label = list_pop(labels_to_add, 0)
  175. log("Add element linked to label " + label)
  176. log("Label: " + cast_v2s(label))
  177. log("Element with label: " + cast_v2s(RHS_map[label]))
  178. log("Element: " + cast_e2s(RHS_model["model"][RHS_map[label]]))
  179. log("Value: " + cast_v2s(read_attribute(RHS_model, RHS_map[label], "label")))
  180. if (element_neq(read_attribute(RHS_model, RHS_map[label], "value"), read_root())):
  181. // There is an action associated with this node
  182. log("Fetching action")
  183. value_function = read_attribute(RHS_model, RHS_map[label], "value")
  184. log("Executing action!")
  185. log("Got function: " + cast_e2s(value_function))
  186. value = value_function(host_model, RHS_model)
  187. log("Got value to assign: " + cast_v2s(value))
  188. typename = reverseKeyLookup(RHS_model["metamodel"]["model"], dict_read_node(RHS_model["type_mapping"], RHS_model["model"][RHS_map[label]]))
  189. original_typename = string_substr(typename, 5, string_len(typename))
  190. log("Instantiate type " + original_typename)
  191. new_name = instantiate_value(host_model, original_typename, "", value)
  192. dict_add(new_mapping, label, new_name)
  193. elif (is_edge(RHS_model["model"][mapping[label]])):
  194. // Edge
  195. src = read_attribute(RHS_model, reverseKeyLookup(RHS_model["model"], read_edge_src(RHS_model["model"][RHS_map[label]])), "label")
  196. dst = read_attribute(RHS_model, reverseKeyLookup(RHS_model["model"], read_edge_dst(RHS_model["model"][RHS_map[label]])), "label")
  197. // First check whether both source and destination are already created
  198. if (bool_and(dict_in(new_mapping, src), dict_in(new_mapping, dst))):
  199. // Both are present, so we can make the link
  200. typename = reverseKeyLookup(RHS_model["metamodel"]["model"], dict_read_node(RHS_model["type_mapping"], RHS_model["model"][mapping[label]]))
  201. original_typename = string_substr(typename, 5, string_len(typename))
  202. new_name = instantiate_link(host_model, original_typename, "", new_mapping[src], new_mapping[dst])
  203. dict_add(new_mapping, label, new_name)
  204. else:
  205. // Delay this a bit, until all are bound
  206. list_append(labels_to_add, label)
  207. else:
  208. // Node
  209. // Create the node and add it
  210. typename = reverseKeyLookup(RHS_model["metamodel"]["model"], dict_read_node(RHS_model["type_mapping"], RHS_model["model"][RHS_map[label]]))
  211. original_typename = string_substr(typename, 5, string_len(typename))
  212. log("Instantiate type " + original_typename)
  213. new_name = instantiate_node(host_model, original_typename, "")
  214. dict_add(new_mapping, label, new_name)
  215. return!
  216. Void function transform(host_model : Element, LHS_model : Element, RHS_model : Element):
  217. Element mapping
  218. Element mappings
  219. // Get all possible mappings
  220. mappings = match(host_model, LHS_model)
  221. log("Found total mappings: " + cast_v2s(read_nr_out(mappings)))
  222. // Select one such mapping and rewrite it
  223. if (read_nr_out(mappings) > 0):
  224. // Mapping found, so can rewrite it
  225. mapping = set_pop(mappings)
  226. log("Found example mapping " + dict_to_string(mapping))
  227. rewrite(host_model, RHS_model, mapping)
  228. else:
  229. output("No mapping found!")
  230. return!