123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158 |
- # Before we can create a model in muMLE, we have to create a meta-model.
- # Here's an example of a (silly) meta-model.
- # We use a textual concrete syntax:
- mm_cs = """
- # A class named 'A':
- A:Class
- # A class named 'B':
- B:Class
- # An association from 'A' to 'B':
- a2b:Association (A -> B) {
- # Every 'A' must be associated with at least one 'B'
- target_lower_cardinality = 1;
- }
- """
- # Now, we create a model that is an instance of our meta-model:
- m_cs = """
- myA:A
- myB:B
- myLnk:a2b (myA -> myB)
- """
- # Notice that the syntax for meta-model and model is the same: We always declare a named object/link, followed by a colon (:) and the name of the type. The type name refers to the name of an object/link in the meta-model of our model.
- # So far we've only created text strings in Python. To parse them as models, we first create our 'state', which is a mutable graph that will contain our models and meta-models:
- from state.devstate import DevState
- state = DevState()
- # Next, we must load the Simple Class Diagrams (SCD) meta-meta-model into our 'state'. The SCD meta-meta-model is a meta-model for our meta-model, and it is also a meta-model for itself.
- # The meta-meta-model is not specified in textual syntax because it is typed by itself. In textual syntax, it would contain things like:
- # Class:Class
- # which is an object typed by itself. The parser cannot handle this (or circular dependencies in general). Therefore, we load the meta-meta-model by mutating the 'state' directly at a very low level:
- from bootstrap.scd import bootstrap_scd
- print("Loading meta-meta-model...")
- mmm = bootstrap_scd(state)
- print("OK")
- # Now that the meta-meta-model has been loaded, we can parse our meta-model:
- from concrete_syntax.textual_od import parser
- print()
- print("Parsing meta-model...")
- mm = parser.parse_od(
- state,
- m_text=mm_cs, # the string of text to parse
- mm=mmm, # the meta-model of class diagrams (= our meta-meta-model)
- )
- print("OK")
- # And we can parse our model, the same way:
- print()
- print("Parsing model...")
- m = parser.parse_od(
- state,
- m_text=m_cs,
- mm=mm, # this time, the meta-model is the previous model we parsed
- )
- print("OK")
- # Now we can do a conformance check:
- from framework.conformance import Conformance, render_conformance_check_result
- print()
- print("Is our model a valid instance of our meta model?")
- conf = Conformance(state, m, mm)
- print(render_conformance_check_result(conf.check_nominal()))
- # Looks like it is OK!
- # We can also check if our meta-model is a valid class diagram:
- print()
- print("Is our meta-model a valid class diagram?")
- conf = Conformance(state, mm, mmm)
- print(render_conformance_check_result(conf.check_nominal()))
- # Also good.
- # Finally, we can even check if the meta-meta-model is a valid instance of itself (it should be):
- print()
- print("Is our meta-model a valid class diagram?")
- conf = Conformance(state, mmm, mmm)
- print(render_conformance_check_result(conf.check_nominal()))
- # All good!
- # Now let's make things a bit more interesting and introduce non-conformance:
- m2_cs = """
- myA:A
- myA2:A
- myB:B
- myLnk:a2b (myA -> myB)
- """
- # Parse it:
- m2 = parser.parse_od(
- state,
- m_text=m2_cs,
- mm=mm,
- )
- # The above model is non-conformant because 'myA2' should have at least one outgoing link of type 'a2b', but it doesn't.
- print()
- print("Is model 'm2' a valid instance of our meta-model? (it should not be)")
- conf = Conformance(state, m2, mm)
- print(render_conformance_check_result(conf.check_nominal()))
- # It should be non-conformant.
- # Finally, let's render everything as PlantUML:
- from concrete_syntax.plantuml import renderer as plantuml
- from concrete_syntax.plantuml.make_url import make_url
- uml = (""
- + plantuml.render_package("Meta-model", plantuml.render_class_diagram(state, mm))
- + plantuml.render_package("Model", plantuml.render_object_diagram(state, m, mm))
- + plantuml.render_trace_conformance(state, m, mm)
- # + plantuml.render_package("Meta-meta-model", plantuml.render_class_diagram(state, mmm))
- # + plantuml.render_trace_conformance(state, mm, mmm)
- )
- print()
- print("PlantUML output:", make_url(uml))
- # On to the next tutorial...
|