start writing tutorials
This commit is contained in:
parent
07edcc0a8e
commit
1dfeef767e
1 changed files with 152 additions and 0 deletions
152
tutorial/00_metamodeling.py
Normal file
152
tutorial/00_metamodeling.py
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
# 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)
|
||||
"""
|
||||
|
||||
# So far we've only created text strings. To parse the 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, and the parser cannot resolve circular dependencies. 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 'woods' 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 'woods' 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...
|
||||
Loading…
Add table
Add a link
Reference in a new issue