conformance_scd.alc 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. include "primitives.alh"
  2. include "library.alh"
  3. include "object_operations.alh"
  4. include "constructors.alh"
  5. Element function set_copy(elem_to_copy : Element):
  6. Element result
  7. Integer i
  8. Integer max
  9. result = create_node()
  10. // Expand the provided list by including all elements that need to be checked
  11. i = 0
  12. max = read_nr_out(elem_to_copy)
  13. while (i < max):
  14. set_add(result, read_edge_dst(read_out(elem_to_copy, i)))
  15. i = i + 1
  16. return result
  17. Boolean function is_direct_instance(model : Element, instance : Element, type : Element):
  18. // Just check whether or not the type mapping specifies the type as the type of the instance
  19. return dict_read_node(model["type_mapping"], instance) == type
  20. Boolean function is_nominal_instance(model : Element, instance : Element, type : Element):
  21. return is_nominal_subtype(type, dict_read_node(model["type_mapping"], instance), model["metamodel"]["type_mapping"], model["inheritance"])
  22. Boolean function is_nominal_subtype(superclass : Element, subclass : Element, types : Element, inheritance_link : Element):
  23. Integer counter
  24. Integer i
  25. Element edge
  26. Element destination
  27. // End of recursion
  28. if (element_eq(superclass, subclass)):
  29. return True
  30. // Iterate over all superclasses of the found class
  31. counter = read_nr_out(subclass)
  32. i = 0
  33. while (i < counter):
  34. edge = read_out(subclass, i)
  35. // Check if it even has a type (to prevent errors)
  36. if (dict_in_node(types, edge)):
  37. // Check whether it is an inheritance edge, as there is no other distinction between them
  38. if (element_eq(dict_read_node(types, edge), inheritance_link)):
  39. // It is an inheritance edge, so follow it to its destination
  40. destination = read_edge_dst(edge)
  41. // Found a new superclass to test
  42. if (is_nominal_subtype(superclass, destination, types, inheritance_link)):
  43. return True
  44. i = i + 1
  45. // No link seems to have been found, so it is False
  46. return False
  47. Boolean function is_structural_instance(model : Element, instance : Element, type : Element):
  48. return is_structural_subtype(dict_read_node(model["type_mapping"], instance), type)
  49. Boolean function is_structural_subtype(subtype : Element, supertype : Element):
  50. // Determine whether it is just the exact type or not
  51. if (subtype == supertype):
  52. return True
  53. // Find all links that are required (name and type) from the specified type
  54. Element required_keys
  55. required_keys = dict_keys(supertype)
  56. Integer required_keys_len
  57. required_keys_len = dict_len(required_keys)
  58. String key
  59. Element equivalent
  60. Integer i
  61. i = 0
  62. // Go over all keys that we require
  63. while (i < required_keys_len):
  64. key = set_pop(required_keys)
  65. // Check whether they exist in the instance
  66. if (dict_in(subtype, key)):
  67. // Normally, we should still check whether they don't violate the constraints imposed on the class (i.e., are actually present)
  68. // For now, we ignore this and simply require that it is always there in the metamodel (not necessarily in the instance)
  69. // TODO
  70. // Still check whether the types match
  71. if (bool_not(is_structural_subtype(subtype[key], supertype[key]))):
  72. return False
  73. // All clear, so pass on to the next attribute
  74. i = i + 1
  75. else:
  76. return False
  77. // No violations found, so OK
  78. return True
  79. String function conformance_scd(model : Element):
  80. // Initialization
  81. Element work_node
  82. Element model_src
  83. Element metamodel_src
  84. Element model_dst
  85. Element metamodel_dst
  86. Element models
  87. Element metamodels
  88. models = set_copy(model["model"])
  89. Element typing
  90. typing = model["type_mapping"]
  91. metamodels = set_copy(model["metamodel"]["model"])
  92. Element inheritance
  93. inheritance = model["metamodel"]["inheritance"]
  94. Element metamodel_typing
  95. metamodel_typing = model["metamodel"]["type_mapping"]
  96. // Iterate over all model elements and check if they are typed (in "typing") and their type is in the metamodel
  97. while (dict_len(models) > 0):
  98. work_node = set_pop(models)
  99. // Basic check: does the element have a type
  100. if (bool_not(dict_in_node(typing, work_node))):
  101. return "Model has no type specified: " + getName(model, work_node)
  102. // Basic check: is the type of the element part of the metamodel
  103. if (bool_not(set_in_node(metamodels, dict_read_node(typing, work_node)))):
  104. return "Type of element not in specified metamodel: " + getName(model, work_node)
  105. // For edges only: check whether the source is typed according to the metamodel
  106. if (is_edge(work_node)):
  107. model_src = read_edge_src(work_node)
  108. metamodel_src = read_edge_src(dict_read_node(typing, work_node))
  109. log((getName(model, model_src) + " : ") + getName(model["metamodel"], metamodel_src))
  110. if (bool_not(is_nominal_instance(model, model_src, metamodel_src))):
  111. return "Source of model edge not typed by source of type: " + getName(model, work_node)
  112. // For edges only: check whether the destination is typed according to the metamodel
  113. if (is_edge(work_node)):
  114. model_dst = read_edge_dst(work_node)
  115. metamodel_dst = read_edge_dst(dict_read_node(typing, work_node))
  116. if (bool_not(is_nominal_instance(model, model_dst, metamodel_dst))):
  117. return "Destination of model edge not typed by destination of type: " + getName(model, work_node)
  118. // Structure seems fine, now do static semantics
  119. if (dict_in(model["metamodel"], "constraints")):
  120. Element constraint_function
  121. constraint_function = model["metamodel"]["constraints"]
  122. return constraint_function(model)
  123. else:
  124. return "OK"
  125. Element function set_model_constraints(model : Element, func : Element):
  126. if (dict_in(model, "constraints")):
  127. dict_delete(model, "constraints")
  128. dict_add(model, "constraints", func)
  129. return model
  130. Element function generate_bottom_type_mapping(model : Element):
  131. Element mm
  132. mm = model["metamodel"]["model"]
  133. dict_delete(model, "type_mapping")
  134. Element tm
  135. tm = create_node()
  136. dict_add(model, "type_mapping", tm)
  137. // Iterate over every element
  138. Element elem_keys
  139. Element elem
  140. elem_keys = dict_keys(model["model"])
  141. while (0 < read_nr_out(elem_keys)):
  142. elem = model["model"][set_pop(elem_keys)]
  143. if (is_edge(elem)):
  144. dict_add(tm, elem, mm["Edge"])
  145. else:
  146. dict_add(tm, elem, mm["Node"])
  147. return model