exp_scd.py 8.7 KB

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