Add conformance checking example
This commit is contained in:
parent
b69efc9af0
commit
17bff66e8e
8 changed files with 227 additions and 16 deletions
27
examples/conformance/metacircularity.py
Normal file
27
examples/conformance/metacircularity.py
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
from state.devstate import DevState
|
||||
from bootstrap.scd import bootstrap_scd
|
||||
from services.scd import SCD
|
||||
from concrete_syntax.plantuml import renderer as plantuml
|
||||
|
||||
def main():
|
||||
state = DevState()
|
||||
root = state.read_root() # id: 0
|
||||
|
||||
scd_mm_id = bootstrap_scd(state)
|
||||
|
||||
uml = ""
|
||||
|
||||
# Render SCD Meta-Model as Object Diagram
|
||||
uml += plantuml.render_package("Object Diagram", plantuml.render_object_diagram(state, scd_mm_id, scd_mm_id, prefix_ids="od_"))
|
||||
|
||||
# Render SCD Meta-Model as Class Diagram
|
||||
uml += plantuml.render_package("Class Diagram", plantuml.render_class_diagram(state, scd_mm_id, prefix_ids="cd_"))
|
||||
|
||||
# Render conformance
|
||||
uml += plantuml.render_trace_conformance(state, scd_mm_id, scd_mm_id, prefix_inst_ids="od_", prefix_type_ids="cd_")
|
||||
|
||||
print(uml)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
199
examples/conformance/woods.py
Normal file
199
examples/conformance/woods.py
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
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 http://www.plantuml.com/plantuml/uml/")
|
||||
print("and paste the above string.")
|
||||
139
examples/model_transformation/woods.plantuml
Normal file
139
examples/model_transformation/woods.plantuml
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
package "DSL Meta-Model" {
|
||||
class "Bear" as 00000000_0000_0000_0000_00000000046d {
|
||||
}
|
||||
abstract class "Animal" as 00000000_0000_0000_0000_000000000474 {
|
||||
}
|
||||
class "Man" as 00000000_0000_0000_0000_000000000491 {
|
||||
weight : Integer
|
||||
}
|
||||
|
||||
00000000_0000_0000_0000_000000000474 <|-- 00000000_0000_0000_0000_000000000491
|
||||
00000000_0000_0000_0000_000000000474 <|-- 00000000_0000_0000_0000_00000000046d
|
||||
|
||||
00000000_0000_0000_0000_000000000491 " " --> "1 .. *" 00000000_0000_0000_0000_000000000474 : afraidOf
|
||||
}
|
||||
package "Int Meta-Model" {
|
||||
class "Integer" as 00000000_0000_0000_0000_000000000094 {
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
package "RAMified DSL Meta-Model" {
|
||||
class "RAM_Bear" as 00000000_0000_0000_0000_0000000005bb {
|
||||
}
|
||||
class "RAM_Animal" as 00000000_0000_0000_0000_0000000005c5 {
|
||||
}
|
||||
class "RAM_Man" as 00000000_0000_0000_0000_0000000005cf {
|
||||
RAM_weight : ActionCode
|
||||
}
|
||||
|
||||
00000000_0000_0000_0000_0000000005c5 <|-- 00000000_0000_0000_0000_0000000005cf
|
||||
00000000_0000_0000_0000_0000000005c5 <|-- 00000000_0000_0000_0000_0000000005bb
|
||||
|
||||
00000000_0000_0000_0000_0000000005cf " " --> "0 .. *" 00000000_0000_0000_0000_0000000005c5 : RAM_afraidOf
|
||||
}
|
||||
package "RAMified Int Meta-Model" {
|
||||
class "RAM_Integer" as 00000000_0000_0000_0000_00000000064c {
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
00000000_0000_0000_0000_0000000005bb ..> 00000000_0000_0000_0000_00000000046d #line:green;text:green : RAMifies
|
||||
00000000_0000_0000_0000_0000000005c5 ..> 00000000_0000_0000_0000_000000000474 #line:green;text:green : RAMifies
|
||||
00000000_0000_0000_0000_0000000005cf ..> 00000000_0000_0000_0000_000000000491 #line:green;text:green : RAMifies
|
||||
00000000_0000_0000_0000_0000000005cf::RAM_weight ..> 00000000_0000_0000_0000_000000000491::weight #line:green;text:green : RAMifies
|
||||
00000000_0000_0000_0000_00000000064c ..> 00000000_0000_0000_0000_000000000094 #line:green;text:green : RAMifies
|
||||
package "LHS" {
|
||||
map "scaryAnimal : RAM_Animal" as 00000000_0000_0000_0000_00000000068a {
|
||||
}
|
||||
map "man : RAM_Man" as 00000000_0000_0000_0000_00000000066d {
|
||||
RAM_weight => `v > 60`
|
||||
}
|
||||
|
||||
00000000_0000_0000_0000_00000000066d -> 00000000_0000_0000_0000_00000000068a : :RAM_afraidOf
|
||||
}
|
||||
00000000_0000_0000_0000_00000000068a ..> 00000000_0000_0000_0000_0000000005c5 #line:blue;text:blue : instanceOf
|
||||
00000000_0000_0000_0000_00000000066d ..> 00000000_0000_0000_0000_0000000005cf #line:blue;text:blue : instanceOf
|
||||
00000000_0000_0000_0000_00000000066d::RAM_weight ..> 00000000_0000_0000_0000_0000000005cf::RAM_weight #line:blue;text:blue : instanceOf
|
||||
|
||||
package "RHS" {
|
||||
map "man : RAM_Man" as 00000000_0000_0000_0000_000000000699 {
|
||||
RAM_weight => `v + 5`
|
||||
}
|
||||
map "bill : RAM_Man" as 00000000_0000_0000_0000_0000000006b6 {
|
||||
RAM_weight => `100`
|
||||
}
|
||||
|
||||
00000000_0000_0000_0000_0000000006b6 -> 00000000_0000_0000_0000_000000000699 : :RAM_afraidOf
|
||||
}
|
||||
00000000_0000_0000_0000_000000000699 ..> 00000000_0000_0000_0000_0000000005cf #line:blue;text:blue : instanceOf
|
||||
00000000_0000_0000_0000_000000000699::RAM_weight ..> 00000000_0000_0000_0000_0000000005cf::RAM_weight #line:blue;text:blue : instanceOf
|
||||
00000000_0000_0000_0000_0000000006b6 ..> 00000000_0000_0000_0000_0000000005cf #line:blue;text:blue : instanceOf
|
||||
00000000_0000_0000_0000_0000000006b6::RAM_weight ..> 00000000_0000_0000_0000_0000000005cf::RAM_weight #line:blue;text:blue : instanceOf
|
||||
|
||||
package "Model (before rewrite)" {
|
||||
map "bear2 : Bear" as 00000000_0000_0000_0000_000000000597 {
|
||||
}
|
||||
map "bear1 : Bear" as 00000000_0000_0000_0000_000000000590 {
|
||||
}
|
||||
map "george : Man" as 00000000_0000_0000_0000_000000000573 {
|
||||
weight => 80
|
||||
}
|
||||
|
||||
00000000_0000_0000_0000_000000000573 -> 00000000_0000_0000_0000_000000000590 : :afraidOf
|
||||
00000000_0000_0000_0000_000000000573 -> 00000000_0000_0000_0000_000000000597 : :afraidOf
|
||||
}
|
||||
00000000_0000_0000_0000_000000000597 ..> 00000000_0000_0000_0000_00000000046d #line:blue;text:blue : instanceOf
|
||||
00000000_0000_0000_0000_000000000590 ..> 00000000_0000_0000_0000_00000000046d #line:blue;text:blue : instanceOf
|
||||
00000000_0000_0000_0000_000000000573 ..> 00000000_0000_0000_0000_000000000491 #line:blue;text:blue : instanceOf
|
||||
00000000_0000_0000_0000_000000000573::weight ..> 00000000_0000_0000_0000_000000000491::weight #line:blue;text:blue : instanceOf
|
||||
|
||||
00000000_0000_0000_0000_00000000068a ..> 00000000_0000_0000_0000_000000000590 #line:red;line.dotted;text:red : matchedWith
|
||||
00000000_0000_0000_0000_00000000066d ..> 00000000_0000_0000_0000_000000000573 #line:red;line.dotted;text:red : matchedWith
|
||||
00000000_0000_0000_0000_00000000066d::RAM_weight ..> 00000000_0000_0000_0000_000000000573::weight #line:red;line.dotted;text:red : matchedWith
|
||||
package "Model (after rewrite 0)" {
|
||||
map "bear2 : Bear" as 00000000_0000_0000_0000_0000000006db {
|
||||
}
|
||||
map "george : Man" as 00000000_0000_0000_0000_0000000006e9 {
|
||||
weight => 85
|
||||
}
|
||||
map "bill0 : Man" as 00000000_0000_0000_0000_000000000723 {
|
||||
weight => 100
|
||||
}
|
||||
|
||||
00000000_0000_0000_0000_000000000723 -> 00000000_0000_0000_0000_0000000006e9 : :afraidOf
|
||||
00000000_0000_0000_0000_0000000006e9 -> 00000000_0000_0000_0000_0000000006db : :afraidOf
|
||||
}
|
||||
00000000_0000_0000_0000_000000000699 ..> 00000000_0000_0000_0000_0000000006e9 #line:red;line.dotted;text:red : matchedWith
|
||||
00000000_0000_0000_0000_000000000699::RAM_weight ..> 00000000_0000_0000_0000_0000000006e9::weight #line:red;line.dotted;text:red : matchedWith
|
||||
00000000_0000_0000_0000_0000000006b6 ..> 00000000_0000_0000_0000_000000000723 #line:red;line.dotted;text:red : matchedWith
|
||||
00000000_0000_0000_0000_0000000006db ..> 00000000_0000_0000_0000_00000000046d #line:blue;text:blue : instanceOf
|
||||
00000000_0000_0000_0000_0000000006e9 ..> 00000000_0000_0000_0000_000000000491 #line:blue;text:blue : instanceOf
|
||||
00000000_0000_0000_0000_0000000006e9::weight ..> 00000000_0000_0000_0000_000000000491::weight #line:blue;text:blue : instanceOf
|
||||
00000000_0000_0000_0000_000000000723 ..> 00000000_0000_0000_0000_000000000491 #line:blue;text:blue : instanceOf
|
||||
00000000_0000_0000_0000_000000000723::weight ..> 00000000_0000_0000_0000_000000000491::weight #line:blue;text:blue : instanceOf
|
||||
|
||||
00000000_0000_0000_0000_00000000068a ..> 00000000_0000_0000_0000_000000000597 #line:orange;line.dotted;text:orange : matchedWith
|
||||
00000000_0000_0000_0000_00000000066d ..> 00000000_0000_0000_0000_000000000573 #line:orange;line.dotted;text:orange : matchedWith
|
||||
00000000_0000_0000_0000_00000000066d::RAM_weight ..> 00000000_0000_0000_0000_000000000573::weight #line:orange;line.dotted;text:orange : matchedWith
|
||||
package "Model (after rewrite 1)" {
|
||||
map "bear1 : Bear" as 00000000_0000_0000_0000_000000000747 {
|
||||
}
|
||||
map "george : Man" as 00000000_0000_0000_0000_00000000074e {
|
||||
weight => 85
|
||||
}
|
||||
map "bill0 : Man" as 00000000_0000_0000_0000_000000000788 {
|
||||
weight => 100
|
||||
}
|
||||
|
||||
00000000_0000_0000_0000_000000000788 -> 00000000_0000_0000_0000_00000000074e : :afraidOf
|
||||
00000000_0000_0000_0000_00000000074e -> 00000000_0000_0000_0000_000000000747 : :afraidOf
|
||||
}
|
||||
00000000_0000_0000_0000_000000000699 ..> 00000000_0000_0000_0000_00000000074e #line:orange;line.dotted;text:orange : matchedWith
|
||||
00000000_0000_0000_0000_000000000699::RAM_weight ..> 00000000_0000_0000_0000_00000000074e::weight #line:orange;line.dotted;text:orange : matchedWith
|
||||
00000000_0000_0000_0000_0000000006b6 ..> 00000000_0000_0000_0000_000000000788 #line:orange;line.dotted;text:orange : matchedWith
|
||||
00000000_0000_0000_0000_000000000747 ..> 00000000_0000_0000_0000_00000000046d #line:blue;text:blue : instanceOf
|
||||
00000000_0000_0000_0000_00000000074e ..> 00000000_0000_0000_0000_000000000491 #line:blue;text:blue : instanceOf
|
||||
00000000_0000_0000_0000_00000000074e::weight ..> 00000000_0000_0000_0000_000000000491::weight #line:blue;text:blue : instanceOf
|
||||
00000000_0000_0000_0000_000000000788 ..> 00000000_0000_0000_0000_000000000491 #line:blue;text:blue : instanceOf
|
||||
00000000_0000_0000_0000_000000000788::weight ..> 00000000_0000_0000_0000_000000000491::weight #line:blue;text:blue : instanceOf
|
||||
236
examples/model_transformation/woods.py
Normal file
236
examples/model_transformation/woods.py
Normal file
|
|
@ -0,0 +1,236 @@
|
|||
# Model transformation experiment
|
||||
|
||||
from state.devstate import DevState
|
||||
from bootstrap.scd import bootstrap_scd
|
||||
from uuid import UUID
|
||||
from services.scd import SCD
|
||||
from framework.conformance import Conformance
|
||||
from services.od import OD
|
||||
from transformation.matcher import mvs_adapter
|
||||
from transformation.ramify import ramify
|
||||
from transformation.cloner import clone_od
|
||||
from transformation import rewriter
|
||||
from services.bottom.V0 import Bottom
|
||||
from services.primitives.integer_type import Integer
|
||||
from concrete_syntax.plantuml import renderer as plantuml
|
||||
from concrete_syntax.textual_od import parser, renderer
|
||||
|
||||
def main():
|
||||
state = DevState()
|
||||
root = state.read_root() # id: 0
|
||||
|
||||
# Meta-meta-model: a class diagram that describes the language of class diagrams
|
||||
scd_mmm_id = bootstrap_scd(state)
|
||||
int_mm_id = UUID(state.read_value(state.read_dict(state.read_root(), "Integer")))
|
||||
string_mm_id = UUID(state.read_value(state.read_dict(state.read_root(), "String")))
|
||||
|
||||
# conf = Conformance(state, scd_mmm_id, scd_mmm_id)
|
||||
# print("Conformance SCD_MM -> SCD_MM?", conf.check_nominal(log=True))
|
||||
# print("--------------------------------------")
|
||||
# print(renderer.render_od(state, scd_mmm_id, scd_mmm_id, hide_names=True))
|
||||
# print("--------------------------------------")
|
||||
|
||||
# Create DSL MM with parser
|
||||
dsl_mm_cs = """
|
||||
# Integer:ModelRef
|
||||
Bear:Class
|
||||
Animal:Class {
|
||||
abstract = True;
|
||||
}
|
||||
Man:Class {
|
||||
lower_cardinality = 1;
|
||||
upper_cardinality = 2;
|
||||
constraint = ```
|
||||
get_value(get_slot(this, "weight")) > 20
|
||||
```;
|
||||
}
|
||||
Man_weight:AttributeLink (Man -> Integer) {
|
||||
name = "weight";
|
||||
optional = False;
|
||||
constraint = ```
|
||||
# this is the same constraint as above, but this time, part of the attributelink itself (and thus shorter)
|
||||
tgt = get_target(this)
|
||||
tgt_type = get_type_name(tgt)
|
||||
get_value(tgt) > 20
|
||||
```;
|
||||
}
|
||||
afraidOf:Association (Man -> Animal) {
|
||||
target_lower_cardinality = 1;
|
||||
}
|
||||
:Inheritance (Man -> Animal)
|
||||
:Inheritance (Bear -> Animal)
|
||||
|
||||
not_too_fat:GlobalConstraint {
|
||||
constraint = ```
|
||||
# total weight of all men low enough
|
||||
total_weight = 0
|
||||
for man_name, man_id in get_all_instances("Man"):
|
||||
total_weight += get_value(get_slot(man_id, "weight"))
|
||||
total_weight < 85
|
||||
```;
|
||||
}
|
||||
"""
|
||||
dsl_mm_id = parser.parse_od(state, dsl_mm_cs, mm=scd_mmm_id)
|
||||
|
||||
# Create DSL M with parser
|
||||
dsl_m_cs = """
|
||||
george:Man {
|
||||
weight = 80;
|
||||
}
|
||||
bear1:Bear
|
||||
bear2:Bear
|
||||
:afraidOf (george -> bear1)
|
||||
:afraidOf (george -> bear2)
|
||||
"""
|
||||
dsl_m_id = parser.parse_od(state, dsl_m_cs, mm=dsl_mm_id)
|
||||
|
||||
# print("DSL MM:")
|
||||
# print("--------------------------------------")
|
||||
# print(renderer.render_od(state, dsl_mm_id, scd_mmm_id, hide_names=True))
|
||||
# print("--------------------------------------")
|
||||
|
||||
conf = Conformance(state, dsl_mm_id, scd_mmm_id)
|
||||
print("Conformance DSL_MM -> SCD_MM?", conf.check_nominal(log=True))
|
||||
|
||||
# print("DSL M:")
|
||||
# print("--------------------------------------")
|
||||
# print(renderer.render_od(state, dsl_m_id, dsl_mm_id, hide_names=True))
|
||||
# print("--------------------------------------")
|
||||
|
||||
conf = Conformance(state, dsl_m_id, dsl_mm_id)
|
||||
print("Conformance DSL_M -> DSL_MM?", conf.check_nominal(log=True))
|
||||
|
||||
# RAMify MM
|
||||
prefix = "RAM_" # all ramified types can be prefixed to distinguish them a bit more
|
||||
ramified_mm_id = ramify(state, dsl_mm_id, prefix)
|
||||
ramified_int_mm_id = ramify(state, int_mm_id, prefix)
|
||||
|
||||
# LHS - pattern to match
|
||||
|
||||
# TODO: enable more powerful constraints
|
||||
lhs_cs = f"""
|
||||
# object to match
|
||||
man:{prefix}Man {{
|
||||
# match only men heavy enough
|
||||
{prefix}weight = `v > 60`;
|
||||
}}
|
||||
|
||||
# object to delete
|
||||
scaryAnimal:{prefix}Animal
|
||||
|
||||
# link to delete
|
||||
manAfraidOfAnimal:{prefix}afraidOf (man -> scaryAnimal)
|
||||
"""
|
||||
lhs_id = parser.parse_od(state, lhs_cs, mm=ramified_mm_id)
|
||||
|
||||
|
||||
conf = Conformance(state, lhs_id, ramified_mm_id)
|
||||
print("Conformance LHS_M -> RAM_DSL_MM?", conf.check_nominal(log=True))
|
||||
|
||||
# RHS of our rule
|
||||
|
||||
# TODO: enable more powerful actions
|
||||
rhs_cs = f"""
|
||||
# matched object
|
||||
man:{prefix}Man {{
|
||||
# man gains weight
|
||||
{prefix}weight = `v + 5`;
|
||||
}}
|
||||
|
||||
# object to create
|
||||
bill:{prefix}Man {{
|
||||
{prefix}weight = `100`;
|
||||
}}
|
||||
|
||||
# link to create
|
||||
billAfraidOfMan:{prefix}afraidOf (bill -> man)
|
||||
"""
|
||||
rhs_id = parser.parse_od(state, rhs_cs, mm=ramified_mm_id)
|
||||
|
||||
conf = Conformance(state, rhs_id, ramified_mm_id)
|
||||
print("Conformance RHS_M -> RAM_DSL_MM?", conf.check_nominal(log=True))
|
||||
|
||||
def render_ramification():
|
||||
uml = (""
|
||||
# Render original and RAMified meta-models
|
||||
+ plantuml.render_package("DSL Meta-Model", plantuml.render_class_diagram(state, dsl_mm_id))
|
||||
+ plantuml.render_package("Int Meta-Model", plantuml.render_class_diagram(state, int_mm_id))
|
||||
+ plantuml.render_package("RAMified DSL Meta-Model", plantuml.render_class_diagram(state, ramified_mm_id))
|
||||
+ plantuml.render_package("RAMified Int Meta-Model", plantuml.render_class_diagram(state, ramified_int_mm_id))
|
||||
|
||||
# Render RAMification traceability links
|
||||
+ plantuml.render_trace_ramifies(state, dsl_mm_id, ramified_mm_id)
|
||||
+ plantuml.render_trace_ramifies(state, int_mm_id, ramified_int_mm_id)
|
||||
)
|
||||
|
||||
# Render pattern
|
||||
uml += plantuml.render_package("LHS", plantuml.render_object_diagram(state, lhs_id, ramified_mm_id))
|
||||
uml += plantuml.render_trace_conformance(state, lhs_id, ramified_mm_id)
|
||||
|
||||
# Render pattern
|
||||
uml += plantuml.render_package("RHS", plantuml.render_object_diagram(state, rhs_id, ramified_mm_id))
|
||||
uml += plantuml.render_trace_conformance(state, rhs_id, ramified_mm_id)
|
||||
return uml
|
||||
|
||||
def render_all_matches():
|
||||
uml = render_ramification()
|
||||
# Render host graph (before rewriting)
|
||||
uml += plantuml.render_package("Model (before rewrite)", plantuml.render_object_diagram(state, dsl_m_id, dsl_mm_id))
|
||||
# Render conformance
|
||||
uml += plantuml.render_trace_conformance(state, dsl_m_id, dsl_mm_id)
|
||||
|
||||
print("matching...")
|
||||
generator = mvs_adapter.match_od(state, dsl_m_id, dsl_mm_id, lhs_id, ramified_mm_id)
|
||||
for match, color in zip(generator, ["red", "orange"]):
|
||||
print("\nMATCH:\n", match)
|
||||
|
||||
# Render every match
|
||||
uml += plantuml.render_trace_match(state, match, lhs_id, dsl_m_id, color)
|
||||
|
||||
print("DONE")
|
||||
return uml
|
||||
|
||||
def render_rewrite():
|
||||
uml = render_ramification()
|
||||
|
||||
# Render host graph (before rewriting)
|
||||
uml += plantuml.render_package("Model (before rewrite)", plantuml.render_object_diagram(state, dsl_m_id, dsl_mm_id))
|
||||
# Render conformance
|
||||
uml += plantuml.render_trace_conformance(state, dsl_m_id, dsl_mm_id)
|
||||
|
||||
generator = mvs_adapter.match_od(state, dsl_m_id, dsl_mm_id, lhs_id, ramified_mm_id)
|
||||
for i, (match, color) in enumerate(zip(generator, ["red", "orange"])):
|
||||
uml += plantuml.render_trace_match(state, match, lhs_id, dsl_m_id, color)
|
||||
|
||||
# rewrite happens in-place (which sucks), so we will only modify a clone:
|
||||
snapshot_dsl_m_id = clone_od(state, dsl_m_id, dsl_mm_id)
|
||||
rewriter.rewrite(state, lhs_id, rhs_id, ramified_mm_id, match, snapshot_dsl_m_id, dsl_mm_id)
|
||||
|
||||
conf = Conformance(state, snapshot_dsl_m_id, dsl_mm_id)
|
||||
print(f"Conformance DSL_M (after rewrite {i}) -> DSL_MM?", conf.check_nominal(log=True))
|
||||
|
||||
# Render host graph (after rewriting)
|
||||
uml += plantuml.render_package(f"Model (after rewrite {i})", plantuml.render_object_diagram(state, snapshot_dsl_m_id, dsl_mm_id))
|
||||
# Render match
|
||||
uml += plantuml.render_trace_match(state, match, rhs_id, snapshot_dsl_m_id, color)
|
||||
# Render conformance
|
||||
uml += plantuml.render_trace_conformance(state, snapshot_dsl_m_id, dsl_mm_id)
|
||||
|
||||
return uml
|
||||
|
||||
# plantuml_str = render_all_matches()
|
||||
plantuml_str = render_rewrite()
|
||||
|
||||
print()
|
||||
print("==============================================")
|
||||
print("BEGIN PLANTUML")
|
||||
print("==============================================")
|
||||
|
||||
print(plantuml_str)
|
||||
|
||||
print("==============================================")
|
||||
print("END PLANTUML")
|
||||
print("==============================================")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Loading…
Add table
Add a link
Reference in a new issue