浏览代码

First explanation for language engineer and metamodelling

Yentl Van Tendeloo 8 年之前
父节点
当前提交
7ae8c7c753
共有 2 个文件被更改,包括 146 次插入8 次删除
  1. 5 0
      doc/language_engineer.rst
  2. 141 8
      doc/metamodelling.rst

+ 5 - 0
doc/language_engineer.rst

@@ -1,6 +1,11 @@
 Using the Modelverse as a Language Engineer
 ===========================================
 
+With all the modelling primitives given, the next step is to actually create the languages that were used before: how were the *PetriNets* and *FiniteStateAutomata* language defined?
+This is the job of the language engineer, who will create these languages through modelling as well.
+Indeed, everything in the Modelverse is explicitly modelled, including languages.
+When defining a language, the language engineer will mostly use the same operations as the modeller, though in a different context.
+
 .. toctree::
    :maxdepth: 2
 

+ 141 - 8
doc/metamodelling.rst

@@ -1,20 +1,153 @@
 Metamodelling
 =============
 
-Explain use of metamodelling
+Defining languages in the Modelverse is done through metamodelling.
+With metamodelling, a language is itself a model, which can be created through the usual operations.
+This explains why language engineers need to have the same knowledge of the Modelverse as modellers: language engineering is modelling in a domain-specific language for languages.
 
-Metamodels as Models
+Creating a metamodel
 --------------------
 
-Metamodels are models as well, and therefore quite similar in use
+To create a metamodel, you have to instantiate the *SimpleClassDiagrams* metamodel.
+While there is no restriction that this has to be *SimpleClassDiagrams*, for now we assume that this is the only possible meta-language.
+Therefore, to create the PetriNets language, we execute::
 
-Creating a metamodel
---------------------
+    >>> model_add("PetriNets", "SimpleClassDiagrams")
 
-Show how to create a new metamodel
-And adding some concepts
+From then on, we can simply use the PetriNets metamodel as if it were a model.
+Again, the *model_add* operation can take an optional third parameter, specifying the textual representation of the model.
+We will go deeper into this in one of the next sections.
 
 Instantiating a metamodel
 -------------------------
 
-Show how we now create an instance of this newly created metamodel
+To actually define a metamodel, we need to add elements to it.
+These elements are tightly related to the metamodel of the model, being most likely *SimpleClassDiagrams*.
+In this language, there exist four major components: *Class*, *Association*, *Inheritance*, and attributes.
+
+Class
+^^^^^
+
+Creating a class is easy, and very similar to usual modelling.
+To define the *Place* concept, which can later on be used in models, we merely define this as a new class::
+
+    >>> instantiate("PetriNets", "Class", ID="Place")
+
+Note that here we must define an ID to get a sensible name to use.
+Of course, this ID does not need to be used, and the returned (randomized) ID can just as well be used.
+Nonetheless, if it is used, it becomes non-intuitive to use in future requests.
+In the instance of this newly created language, we can immediately use the new concept::
+
+    >>> instantiate("PetriNets", "Class", ID="Place")
+    >>> instantiate("my_pn", "Place")
+
+If the ID was not used, we must remember the ID that was provided to us::
+
+    >>> pn_place = instantiate("PetriNets", "Class")
+    >>> instantiate("my_pn", pn_place)
+
+While this is more reliable, it becomes difficult to refer to the concept in the future without any clue as to what it resembles.
+Later on, this can be solved with concrete syntax, in which case modellers can identify the concepts based on their visual representation.
+
+Association
+^^^^^^^^^^^
+
+Creating a link between two concepts is very similar.
+For example, to create the *P2T* association, merely create an instance of association, using the same remarks as before::
+
+    >>> instantiate("PetriNets", "Association", edge=("Place", "Transition"), ID="P2T")
+
+Inheritance
+^^^^^^^^^^^
+
+A useful concept is the use of inheritance, whereby the inheriting class can take on the responsibilities of the inherited class.
+To create this, simply instantiate the *Inheritance* association as usual.
+For example, it is possible to structure the *PetriNets* model (in an admittedly strange way) such that there is a generic concept of *NamedElement* and *Arc*::
+
+    >>> instantiate("PetriNets", "Class", ID="NamedElement")
+    >>> instantiate("PetriNets", "Class", ID="Place")
+    >>> instantiate("PetriNets", "Class", ID="Transition")
+    >>> instantiate("PetriNets", "Inheritance", edge=("Place", "NamedElement"))
+    >>> instantiate("PetriNets", "Inheritance", edge=("Transition", "NamedElement"))
+
+In the Modelverse, inheritance is possible between any two instances, including associations.
+To define the *Arc* relation, we act similar::
+
+    >>> instantiate("PetriNets", "Association", edge=("NamedElement", "NamedElement"), ID="Arc")
+    >>> instantiate("PetriNets", "Association", edge=("Place", "Transition"), ID="P2T")
+    >>> instantiate("PetriNets", "Association", edge=("Transition", "Place"), ID="T2P")
+    >>> instantiate("PetriNets", "Inheritance", edge=("P2T", "Arc"))
+    >>> instantiate("PetriNets", "Inheritance", edge=("T2P", "Arc"))
+
+Instantiating attributes
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+Instantiating attributes is similar as it was before::
+
+    >>> attr_assign("PetriNets", "NamedElement", "name", "NamedElement")
+    >>> attr_assign("PetriNets", "Transition", "name", "Transition")
+    >>> attr_assign("PetriNets", "Place", "name", "Place")
+
+Note that this *name* attribute is in no way related to the *name* attributes at the *my_pn* level.
+Indeed, the *name* in *PetriNets* specifies the name of the class.
+Other attributes that can be set on classes are:
+
+1. *lower_cardinality* specifies the number (integer) of instances that must at least exist of this element.
+2. *upper_cardinality* specifies the number (integer) of instances that must at most exist of this element.
+3. *constraint* specifies additional constraints on the instances of this class.
+
+For associations, we have the same three attributes, augmented with:
+
+4. *source_lower_cardinality* specifies the number (integer) of incoming edges that are at least required for the target.
+5. *source_upper_cardinality* specifies the number (integer) of incoming edges that are at most required for the target.
+6. *target_lower_cardinality* specifies the number (integer) of outgoing edges that are at least required for the source.
+7. *target_upper_cardinality* specifies the number (integer) of outgoing edges that are at most required for the source.
+
+Defining attributes
+^^^^^^^^^^^^^^^^^^^
+
+Defining attributes is an important consideration in a metamodel.
+Up to now, our *Place* and *Transition* were just nodes without any attributes.
+A meaningful (marked) petrinet has tokens in places, and names for the places and transitions.
+To define these attributes, we must take two steps:
+
+1. Define the type that will be used (e.g., String, Integer)
+2. Define the name and type of the attribute (e.g., *tokens* is an Integer, *name* is a String)
+
+To define the type that we want to use, we must manually define it.
+While many other tools provide a set of primitives, which cannot be altered in any way, the Modelverse leaves all this up to the language engineer.
+If the language engineer wants the concepts of a *Natural*, for example, it is not required that the attribute is specified as an Integer, with an additional constraint on each and every attribute that is defined this way.
+It is possible to define a new attribute type as follows::
+
+    >>> instantiate("PetriNets", "SimpleAttribute", ID="Natural")
+
+But now, the attribute is constrained in no way: it is merely called Natural, but can even contain a string.
+The attribute type must be constrained::
+
+    >>> attr_assign_code("PetriNets", "Natural", "constraint", \
+    ...     """
+    ...     String function constraint(value : Element):
+    ...         if (is_physical_integer(value)):
+    ...             if (integer_geq(value, 0)):
+    ...                 return "OK"!
+    ...             else:
+    ...                 return "Not a positive value"!
+    ...         else:
+    ...             return "Not a numeric value!"!
+
+Now, the *Natural* is correctly specified and can be used throughout the model.
+All uses of *Natural* will now make sure that the value is positive.
+This offers additional possibilities, such as defining complex attributes as if they were primitives, for example complex numbers.
+
+The next step is to define the attribute itself.
+This can be easily done as follows::
+
+    >>> define_attribute("PetriNets", "Place", "tokens", "Natural")
+
+For the name, *String* can be defined similarly (using *is_physical_string*).
+
+Constraints
+^^^^^^^^^^^
+
+A constraint specifies additional constraints on the instances of this model, which could not be expressed before.
+We distinguish between two types of constraints: