woods.py 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. # Model transformation 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.cloner import clone_od
  11. from transformation import rewriter
  12. from services.bottom.V0 import Bottom
  13. from services.primitives.integer_type import Integer
  14. from concrete_syntax.plantuml import renderer as plantuml
  15. from concrete_syntax.textual_od import parser, renderer
  16. def main():
  17. state = DevState()
  18. root = state.read_root() # id: 0
  19. # Meta-meta-model: a class diagram that describes the language of class diagrams
  20. scd_mmm_id = bootstrap_scd(state)
  21. int_mm_id = UUID(state.read_value(state.read_dict(state.read_root(), "Integer")))
  22. string_mm_id = UUID(state.read_value(state.read_dict(state.read_root(), "String")))
  23. # conf = Conformance(state, scd_mmm_id, scd_mmm_id)
  24. # print("Conformance SCD_MM -> SCD_MM?", conf.check_nominal(log=True))
  25. # print("--------------------------------------")
  26. # print(renderer.render_od(state, scd_mmm_id, scd_mmm_id, hide_names=True))
  27. # print("--------------------------------------")
  28. # Create DSL MM with parser
  29. dsl_mm_cs = """
  30. # Integer:ModelRef
  31. Bear:Class
  32. Animal:Class {
  33. abstract = True;
  34. }
  35. Man:Class {
  36. lower_cardinality = 1;
  37. upper_cardinality = 2;
  38. constraint = ```
  39. get_value(get_slot(this, "weight")) > 20
  40. ```;
  41. }
  42. Man_weight:AttributeLink (Man -> Integer) {
  43. name = "weight";
  44. optional = False;
  45. constraint = ```
  46. # this is the same constraint as above, but this time, part of the attributelink itself (and thus shorter)
  47. tgt = get_target(this)
  48. tgt_type = get_type_name(tgt)
  49. get_value(tgt) > 20
  50. ```;
  51. }
  52. afraidOf:Association (Man -> Animal) {
  53. target_lower_cardinality = 1;
  54. }
  55. :Inheritance (Man -> Animal)
  56. :Inheritance (Bear -> Animal)
  57. not_too_fat:GlobalConstraint {
  58. constraint = ```
  59. # total weight of all men low enough
  60. total_weight = 0
  61. for man_name, man_id in get_all_instances("Man"):
  62. total_weight += get_value(get_slot(man_id, "weight"))
  63. total_weight < 85
  64. ```;
  65. }
  66. """
  67. dsl_mm_id = parser.parse_od(state, dsl_mm_cs, mm=scd_mmm_id)
  68. # Create DSL M with parser
  69. dsl_m_cs = """
  70. george:Man {
  71. weight = 80;
  72. }
  73. bear1:Bear
  74. bear2:Bear
  75. :afraidOf (george -> bear1)
  76. :afraidOf (george -> bear2)
  77. """
  78. dsl_m_id = parser.parse_od(state, dsl_m_cs, mm=dsl_mm_id)
  79. # print("DSL MM:")
  80. # print("--------------------------------------")
  81. # print(renderer.render_od(state, dsl_mm_id, scd_mmm_id, hide_names=True))
  82. # print("--------------------------------------")
  83. conf = Conformance(state, dsl_mm_id, scd_mmm_id)
  84. print("Conformance DSL_MM -> SCD_MM?", conf.check_nominal(log=True))
  85. # print("DSL M:")
  86. # print("--------------------------------------")
  87. # print(renderer.render_od(state, dsl_m_id, dsl_mm_id, hide_names=True))
  88. # print("--------------------------------------")
  89. conf = Conformance(state, dsl_m_id, dsl_mm_id)
  90. print("Conformance DSL_M -> DSL_MM?", conf.check_nominal(log=True))
  91. # RAMify MM
  92. prefix = "RAM_" # all ramified types can be prefixed to distinguish them a bit more
  93. ramified_mm_id = ramify(state, dsl_mm_id, prefix)
  94. ramified_int_mm_id = ramify(state, int_mm_id, prefix)
  95. # LHS - pattern to match
  96. # TODO: enable more powerful constraints
  97. lhs_cs = f"""
  98. # object to match
  99. man:{prefix}Man {{
  100. # match only men heavy enough
  101. {prefix}weight = `v > 60`;
  102. }}
  103. # object to delete
  104. scaryAnimal:{prefix}Animal
  105. # link to delete
  106. manAfraidOfAnimal:{prefix}afraidOf (man -> scaryAnimal)
  107. """
  108. lhs_id = parser.parse_od(state, lhs_cs, mm=ramified_mm_id)
  109. conf = Conformance(state, lhs_id, ramified_mm_id)
  110. print("Conformance LHS_M -> RAM_DSL_MM?", conf.check_nominal(log=True))
  111. # RHS of our rule
  112. # TODO: enable more powerful actions
  113. rhs_cs = f"""
  114. # matched object
  115. man:{prefix}Man {{
  116. # man gains weight
  117. {prefix}weight = `v + 5`;
  118. }}
  119. # object to create
  120. bill:{prefix}Man {{
  121. {prefix}weight = `100`;
  122. }}
  123. # link to create
  124. billAfraidOfMan:{prefix}afraidOf (bill -> man)
  125. """
  126. rhs_id = parser.parse_od(state, rhs_cs, mm=ramified_mm_id)
  127. conf = Conformance(state, rhs_id, ramified_mm_id)
  128. print("Conformance RHS_M -> RAM_DSL_MM?", conf.check_nominal(log=True))
  129. def render_ramification():
  130. uml = (""
  131. # Render original and RAMified meta-models
  132. + plantuml.render_package("DSL Meta-Model", plantuml.render_class_diagram(state, dsl_mm_id))
  133. + plantuml.render_package("Int Meta-Model", plantuml.render_class_diagram(state, int_mm_id))
  134. + plantuml.render_package("RAMified DSL Meta-Model", plantuml.render_class_diagram(state, ramified_mm_id))
  135. + plantuml.render_package("RAMified Int Meta-Model", plantuml.render_class_diagram(state, ramified_int_mm_id))
  136. # Render RAMification traceability links
  137. + plantuml.render_trace_ramifies(state, dsl_mm_id, ramified_mm_id)
  138. + plantuml.render_trace_ramifies(state, int_mm_id, ramified_int_mm_id)
  139. )
  140. # Render pattern
  141. uml += plantuml.render_package("LHS", plantuml.render_object_diagram(state, lhs_id, ramified_mm_id))
  142. uml += plantuml.render_trace_conformance(state, lhs_id, ramified_mm_id)
  143. # Render pattern
  144. uml += plantuml.render_package("RHS", plantuml.render_object_diagram(state, rhs_id, ramified_mm_id))
  145. uml += plantuml.render_trace_conformance(state, rhs_id, ramified_mm_id)
  146. return uml
  147. def render_all_matches():
  148. uml = render_ramification()
  149. # Render host graph (before rewriting)
  150. uml += plantuml.render_package("Model (before rewrite)", plantuml.render_object_diagram(state, dsl_m_id, dsl_mm_id))
  151. # Render conformance
  152. uml += plantuml.render_trace_conformance(state, dsl_m_id, dsl_mm_id)
  153. print("matching...")
  154. generator = mvs_adapter.match_od(state, dsl_m_id, dsl_mm_id, lhs_id, ramified_mm_id)
  155. for match, color in zip(generator, ["red", "orange"]):
  156. print("\nMATCH:\n", match)
  157. # Render every match
  158. uml += plantuml.render_trace_match(state, match, lhs_id, dsl_m_id, color)
  159. print("DONE")
  160. return uml
  161. def render_rewrite():
  162. uml = render_ramification()
  163. # Render host graph (before rewriting)
  164. uml += plantuml.render_package("Model (before rewrite)", plantuml.render_object_diagram(state, dsl_m_id, dsl_mm_id))
  165. # Render conformance
  166. uml += plantuml.render_trace_conformance(state, dsl_m_id, dsl_mm_id)
  167. generator = mvs_adapter.match_od(state, dsl_m_id, dsl_mm_id, lhs_id, ramified_mm_id)
  168. for i, (match, color) in enumerate(zip(generator, ["red", "orange"])):
  169. uml += plantuml.render_trace_match(state, match, lhs_id, dsl_m_id, color)
  170. # rewrite happens in-place (which sucks), so we will only modify a clone:
  171. snapshot_dsl_m_id = clone_od(state, dsl_m_id, dsl_mm_id)
  172. rewriter.rewrite(state, lhs_id, rhs_id, ramified_mm_id, match, snapshot_dsl_m_id, dsl_mm_id)
  173. conf = Conformance(state, snapshot_dsl_m_id, dsl_mm_id)
  174. print(f"Conformance DSL_M (after rewrite {i}) -> DSL_MM?", conf.check_nominal(log=True))
  175. # Render host graph (after rewriting)
  176. uml += plantuml.render_package(f"Model (after rewrite {i})", plantuml.render_object_diagram(state, snapshot_dsl_m_id, dsl_mm_id))
  177. # Render match
  178. uml += plantuml.render_trace_match(state, match, rhs_id, snapshot_dsl_m_id, color)
  179. # Render conformance
  180. uml += plantuml.render_trace_conformance(state, snapshot_dsl_m_id, dsl_mm_id)
  181. return uml
  182. # plantuml_str = render_all_matches()
  183. plantuml_str = render_rewrite()
  184. print()
  185. print("==============================================")
  186. print("BEGIN PLANTUML")
  187. print("==============================================")
  188. print(plantuml_str)
  189. print("==============================================")
  190. print("END PLANTUML")
  191. print("==============================================")
  192. if __name__ == "__main__":
  193. main()