exp_scd.py 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. # Simple Class Diagram experiment
  2. from state.devstate import DevState
  3. from bootstrap.scd import bootstrap_scd
  4. from uuid import UUID
  5. from services.scd import SCD
  6. from framework.conformance import Conformance
  7. from services.od import OD
  8. from transformation.ramify import ramify
  9. from transformation import rewriter
  10. from services.bottom.V0 import Bottom
  11. from services.primitives.integer_type import Integer
  12. from pattern_matching import mvs_adapter
  13. from pattern_matching.matcher import MatcherVF2
  14. from concrete_syntax import plantuml
  15. from concrete_syntax.textual_od import parser, renderer
  16. import sys
  17. def create_integer_node(state, i: int):
  18. node = state.create_node()
  19. integer_t = Integer(node, state)
  20. integer_t.create(i)
  21. return node
  22. def main():
  23. state = DevState()
  24. root = state.read_root() # id: 0
  25. scd_mm_id = bootstrap_scd(state)
  26. int_mm_id = UUID(state.read_value(state.read_dict(state.read_root(), "Integer")))
  27. string_mm_id = UUID(state.read_value(state.read_dict(state.read_root(), "String")))
  28. def create_dsl_mm_api():
  29. # Create DSL MM with SCD API
  30. dsl_mm_id = state.create_node()
  31. dsl_mm_scd = SCD(dsl_mm_id, state)
  32. dsl_mm_scd.create_class("Animal", abstract=True)
  33. dsl_mm_scd.create_class("Man", min_c=1, max_c=2)
  34. dsl_mm_scd.create_inheritance("Man", "Animal")
  35. dsl_mm_scd.create_model_ref("Integer", int_mm_id)
  36. dsl_mm_scd.create_attribute_link("Man", "Integer", "weight", optional=False)
  37. dsl_mm_scd.create_class("Bear")
  38. dsl_mm_scd.create_inheritance("Bear", "Animal")
  39. dsl_mm_scd.create_association("afraidOf", "Man", "Animal",
  40. # Every Man afraid of at least one Animal:
  41. src_min_c=0,
  42. src_max_c=None,
  43. tgt_min_c=1,
  44. tgt_max_c=None,
  45. )
  46. return dsl_mm_id
  47. def create_dsl_mm_parser():
  48. # Create DSL MM with parser
  49. dsl_mm_cs = """
  50. # Integer:ModelRef
  51. Bear:Class
  52. Animal:Class
  53. abstract = True
  54. Man:Class
  55. lower_cardinality = 1
  56. upper_cardinality = 2
  57. Man_weight:AttributeLink (Man -> Integer)
  58. name = "weight"
  59. optional = False
  60. afraidOf:Association (Man -> Animal)
  61. source_lower_cardinality = 0
  62. target_lower_cardinality = 1
  63. Man_inh_Animal:Inheritance (Man -> Animal)
  64. Bear_inh_Animal:Inheritance (Bear -> Animal)
  65. """
  66. dsl_mm_id = parser.parse_od(state, dsl_mm_cs, mm=scd_mm_id)
  67. return dsl_mm_id
  68. def create_dsl_m_api():
  69. # Create DSL M with OD API
  70. dsl_m_id = state.create_node()
  71. dsl_m_od = OD(dsl_mm_id, dsl_m_id, state)
  72. dsl_m_od.create_object("george", "Man")
  73. dsl_m_od.create_slot("weight", "george",
  74. dsl_m_od.create_integer_value("george.weight", 80))
  75. dsl_m_od.create_object("bear1", "Bear")
  76. dsl_m_od.create_object("bear2", "Bear")
  77. dsl_m_od.create_link("georgeAfraidOfBear1", "afraidOf", "george", "bear1")
  78. dsl_m_od.create_link("georgeAfraidOfBear2", "afraidOf", "george", "bear2")
  79. return dsl_m_id
  80. def create_dsl_m_parser():
  81. # Create DSL M with parser
  82. dsl_m_cs = """
  83. george :Man
  84. weight = 80
  85. bear1 :Bear
  86. bear2 :Bear
  87. :afraidOf (george -> bear1)
  88. :afraidOf (george -> bear2)
  89. """
  90. dsl_m_id = parser.parse_od(state, dsl_m_cs, mm=dsl_mm_id)
  91. return dsl_m_id
  92. # dsl_mm_id = create_dsl_mm_api()
  93. dsl_mm_id = create_dsl_mm_parser()
  94. print("DSL MM:")
  95. print("--------------------------------------")
  96. print(renderer.render_od(state, dsl_mm_id, scd_mm_id, hide_names=False))
  97. print("--------------------------------------")
  98. conf = Conformance(state, dsl_mm_id, scd_mm_id)
  99. print("Conformance DSL_MM -> SCD_MM?", conf.check_nominal(log=True))
  100. # dsl_m_id = create_dsl_m_api()
  101. dsl_m_id = create_dsl_m_parser()
  102. print("DSL M:")
  103. print("--------------------------------------")
  104. print(renderer.render_od(state, dsl_m_id, dsl_mm_id, hide_names=False))
  105. print("--------------------------------------")
  106. conf = Conformance(state, dsl_m_id, dsl_mm_id)
  107. print("Conformance DSL_M -> DSL_MM?", conf.check_nominal(log=True))
  108. # RAMify MM
  109. prefix = "RAM_" # all ramified types can be prefixed to distinguish them a bit more
  110. ramified_mm_id = ramify(state, dsl_mm_id, prefix)
  111. ramified_int_mm_id = ramify(state, int_mm_id, prefix)
  112. # LHS of our rule
  113. lhs_id = state.create_node()
  114. lhs_od = OD(ramified_mm_id, lhs_id, state)
  115. lhs_od.create_object("man", prefix+"Man")
  116. lhs_od.create_slot(prefix+"weight", "man", lhs_od.create_string_value(f"man.{prefix}weight", 'v < 99'))
  117. lhs_od.create_object("scaryAnimal", prefix+"Animal")
  118. lhs_od.create_link("manAfraidOfAnimal", prefix+"afraidOf", "man", "scaryAnimal")
  119. conf = Conformance(state, lhs_id, ramified_mm_id)
  120. print("Conformance LHS_M -> RAM_DSL_MM?", conf.check_nominal(log=True))
  121. # RHS of our rule
  122. rhs_id = state.create_node()
  123. rhs_od = OD(ramified_mm_id, rhs_id, state)
  124. rhs_od.create_object("man", prefix+"Man")
  125. rhs_od.create_slot(prefix+"weight", "man", rhs_od.create_string_value(f"man.{prefix}weight", 'v + 5'))
  126. rhs_od.create_object("bill", prefix+"Man")
  127. rhs_od.create_slot(prefix+"weight", "bill", rhs_od.create_string_value(f"bill.{prefix}weight", '100'))
  128. rhs_od.create_link("billAfraidOfMan", prefix+"afraidOf", "bill", "man")
  129. conf = Conformance(state, rhs_id, ramified_mm_id)
  130. print("Conformance RHS_M -> RAM_DSL_MM?", conf.check_nominal(log=True))
  131. def render_ramification():
  132. uml = (""
  133. # Render original and RAMified meta-models
  134. + plantuml.render_package("DSL Meta-Model", plantuml.render_class_diagram(state, dsl_mm_id))
  135. + plantuml.render_package("Int Meta-Model", plantuml.render_class_diagram(state, int_mm_id))
  136. + plantuml.render_package("RAMified DSL Meta-Model", plantuml.render_class_diagram(state, ramified_mm_id))
  137. + plantuml.render_package("RAMified Int Meta-Model", plantuml.render_class_diagram(state, ramified_int_mm_id))
  138. # Render RAMification traceability links
  139. + plantuml.render_trace_ramifies(state, dsl_mm_id, ramified_mm_id)
  140. + plantuml.render_trace_ramifies(state, int_mm_id, ramified_int_mm_id)
  141. )
  142. # Render pattern
  143. uml += plantuml.render_package("LHS", plantuml.render_object_diagram(state, lhs_id, ramified_mm_id))
  144. uml += plantuml.render_trace_conformance(state, lhs_id, ramified_mm_id)
  145. # Render pattern
  146. uml += plantuml.render_package("RHS", plantuml.render_object_diagram(state, rhs_id, ramified_mm_id))
  147. uml += plantuml.render_trace_conformance(state, rhs_id, ramified_mm_id)
  148. return uml
  149. def render_all_matches():
  150. uml = render_ramification()
  151. # Render host graph (before rewriting)
  152. uml += plantuml.render_package("Model (before rewrite)", plantuml.render_object_diagram(state, dsl_m_id, dsl_mm_id))
  153. # Render conformance
  154. uml += plantuml.render_trace_conformance(state, dsl_m_id, dsl_mm_id)
  155. print("matching...")
  156. generator = mvs_adapter.match_od(state, dsl_m_id, dsl_mm_id, lhs_id, ramified_mm_id)
  157. for name_mapping, color in zip(generator, ["red", "orange"]):
  158. print("\nMATCH:\n", name_mapping)
  159. # Render every match
  160. uml += plantuml.render_trace_match(state, name_mapping, lhs_id, dsl_m_id, color)
  161. print("DONE")
  162. return uml
  163. def render_rewrite():
  164. uml = render_ramification()
  165. generator = mvs_adapter.match_od(state, dsl_m_id, dsl_mm_id, lhs_id, ramified_mm_id)
  166. for name_mapping in generator:
  167. rewriter.rewrite(state, lhs_id, rhs_id, ramified_mm_id, name_mapping, dsl_m_id, dsl_mm_id)
  168. conf = Conformance(state, dsl_m_id, dsl_mm_id)
  169. print("Conformance DSL_M (after rewrite) -> DSL_MM?", conf.check_nominal(log=True))
  170. # Render match
  171. uml_match = plantuml.render_trace_match(state, name_mapping, rhs_id, dsl_m_id, 'orange')
  172. # Stop matching after rewrite
  173. break
  174. # Render host graph (after rewriting)
  175. uml += plantuml.render_package("Model (after rewrite)", plantuml.render_object_diagram(state, dsl_m_id, dsl_mm_id))
  176. # Render conformance
  177. uml += plantuml.render_trace_conformance(state, dsl_m_id, dsl_mm_id)
  178. uml += uml_match
  179. return uml
  180. # plantuml_str = render_all_matches()
  181. # plantuml_str = render_rewrite()
  182. # print()
  183. # print("==============================================")
  184. # print(plantuml_str)
  185. if __name__ == "__main__":
  186. main()