123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203 |
- from state.devstate import DevState
- from bootstrap.scd import bootstrap_scd
- from framework.conformance import Conformance, render_conformance_check_result
- from concrete_syntax.textual_od import parser, renderer
- from concrete_syntax.common import indent
- from concrete_syntax.plantuml import renderer as plantuml
- from util.prompt import yes_no, pause
- state = DevState()
- print("Loading meta-meta-model...")
- scd_mmm = bootstrap_scd(state)
- print("OK")
- print("Is our meta-meta-model a valid class diagram?")
- conf = Conformance(state, scd_mmm, scd_mmm)
- print(render_conformance_check_result(conf.check_nominal()))
- # If you are curious, you can serialize the meta-meta-model:
- # print("--------------")
- # print(indent(
- # renderer.render_od(state,
- # m_id=scd_mmm,
- # mm_id=scd_mmm),
- # 4))
- # print("--------------")
- # Change this:
- woods_mm_cs = """
- Animal:Class {
- # The class Animal is an abstract class:
- abstract = True;
- }
- # A class without attributes
- # The `abstract` attribute shown above is optional (default: False)
- Bear:Class
- # Inheritance between two Classes is expressed as follows:
- :Inheritance (Bear -> Animal) # meaning: Bear is an Animal
- Man:Class {
- # We can define lower and upper cardinalities on Classes
- # (if unspecified, the lower-card is 0, and upper-card is infinity)
- lower_cardinality = 1; # there must be at least one Man in every model
- upper_cardinality = 2; # there must be at most two Men in every model
- constraint = ```
- # Python code
- # the last statement must be a boolean expression
- # When conformance checking, this code will be run for every Man-object.
- # The variable 'this' refers to the current Man-object.
- # Every man weighs at least '20'
- # (the attribute 'weight' is added further down)
- get_value(get_slot(this, "weight")) > 20
- ```;
- }
- # Note that we can only declare the inheritance link after having declared both Man and Animal: We can only refer to earlier objects
- :Inheritance (Man -> Animal) # Man is also an Animal
- # BTW, we could also give the Inheritance-link a name, for instance:
- # man_is_animal:Inheritance (Man -> Animal)
- #
- # Likewise, Classes, Associations, ... can also be nameless, for instance:
- # :Class { ... }
- # :Association (Man -> Man) { ... }
- # However, we typically want to give names to classes and associations, because we want to refer to them later.
- # We now add an attribute to 'Man'
- # Attributes are not that different from Associations: both are represented by links
- Man_weight:AttributeLink (Man -> Integer) {
- name = "weight"; # mandatory!
- optional = False; # <- meaning: every Man *must* have a weight
- # We can also define constraints on attributes
- constraint = ```
- # Python code
- # Here, 'this' refers to the LINK that connects a Man-object to an Integer
- tgt = get_target(this) # <- we get the target of the LINK (an Integer-object)
- weight = get_value(tgt) # <- get the Integer-value (e.g., 80)
- weight > 20
- ```;
- }
- # Create an Association from Man to Animal
- afraidOf:Association (Man -> Animal) {
- # An association has the following (optional) attributes:
- # - source_lower_cardinality (default: 0)
- # - source_upper_cardinality (default: infinity)
- # - target_lower_cardinality (default: 0)
- # - target_upper_cardinality (default: infinity)
- # Every Man is afraid of at least one Animal:
- target_lower_cardinality = 1;
- # No more than 6 Men are afraid of the same Animal:
- source_upper_cardinality = 6;
- }
- # Create a GlobalConstraint
- total_weight_small_enough:GlobalConstraint {
- # Note: for GlobalConstraints, there is no 'this'-variable
- constraint = ```
- # Python code
- # compute sum of all weights
- total_weight = 0
- for man_name, man_id in get_all_instances("Man"):
- total_weight += get_value(get_slot(man_id, "weight"))
- # as usual, the last statement is a boolean expression that we think should be satisfied
- total_weight < 85
- ```;
- }
- """
- print()
- print("Parsing 'woods' meta-model...")
- woods_mm = parser.parse_od(
- state,
- m_text=woods_mm_cs, # the string of text to parse
- mm=scd_mmm, # the meta-model of class diagrams (= our meta-meta-model)
- )
- print("OK")
- # As a double-check, you can serialize the parsed model:
- # print("--------------")
- # print(indent(
- # renderer.render_od(state,
- # m_id=woods_mm,
- # mm_id=scd_mmm),
- # 4))
- # print("--------------")
- print("Is our 'woods' meta-model a valid class diagram?")
- conf = Conformance(state, woods_mm, scd_mmm)
- print(render_conformance_check_result(conf.check_nominal()))
- # Change this:
- woods_m_cs = """
- george:Man {
- weight = 15;
- }
- billy:Man {
- weight = 100;
- }
- bear1:Bear
- bear2:Bear
- :afraidOf (george -> bear1)
- :afraidOf (george -> bear2)
- """
- print()
- print("Parsing 'woods' model...")
- woods_m = parser.parse_od(
- state,
- m_text=woods_m_cs,
- mm=woods_mm, # this time, the meta-model is the previous model we parsed
- )
- print("OK")
- # As a double-check, you can serialize the parsed model:
- # print("--------------")
- # print(indent(
- # renderer.render_od(state,
- # m_id=woods_m,
- # mm_id=woods_mm),
- # 4))
- # print("--------------")
- print("Is our model a valid woods-diagram?")
- conf = Conformance(state, woods_m, woods_mm)
- print(render_conformance_check_result(conf.check_nominal()))
- print()
- print("==================================")
- if yes_no("Print PlantUML?"):
- print_mm = yes_no(" ▸ Print meta-model?")
- print_m = yes_no(" ▸ Print model?")
- print_conf = print_mm and print_m and yes_no(" ▸ Print conformance links?")
- uml = ""
- if print_mm:
- uml += plantuml.render_package("Meta-model", plantuml.render_class_diagram(state, woods_mm))
- if print_m:
- uml += plantuml.render_package("Model", plantuml.render_object_diagram(state, woods_m, woods_mm))
- if print_conf:
- uml += plantuml.render_trace_conformance(state, woods_m, woods_mm)
- print("==================================")
- print(uml)
- print("==================================")
- print("Go to either:")
- print(" ▸ https://www.plantuml.com/plantuml/uml")
- print(" ▸ https://mstro.duckdns.org/plantuml/uml")
- print("and paste the above string.")
|