This example features an executable language using GEMOC Sequential Engine.
It illustrates the GEMOC animation framework on a Finite State Machine language.
While similar to the K3FSM example (cf. K3FSM Example), this example focuses on the separation of the base language: FSM and the executable sequential language: XSFSM by using language polymorphism.
The tree editor and graphic editor are defined on top of the FSM language. They are considered as if they were pre-existing (Ie. legacy).
Then, Melange is used to built the XSFSM executable language by inheriting from FSM. The animation layer is also built as an extensions of the graphical editor.
This allows to use the model polymorphism. Ie. it is possible to edit FSM models and then run them as XSFSM with the appropriate animation extensions.
More information and the sources of these projects are available online on Github.
Install the projects of this language:
- File → new → Examples… → GEMOC MelangeK3FSM Language example (Sequential)
Create and start an eclipse runtime:
- Run → Run Configurations… → Eclipse application > new
Install sample models for the language:
- File → new → Examples… → GEMOC model example for MelangeK3FSM (Sequential)
The following figure presents :
- the base language fsm content;
- how the aspects extends the base classes;
- how the xsfsm language is built by inheriting from the fsm language and using the aspects.
Please note that for simplification of the diagram, the associations that doesn’t represent a containment, have been represented as attribute rather than links.
Main eclipse plugins:
- org.eclipse.gemoc.example.melangek3fsm.fsm contains the definition of the FSM language using the Melange language.
- org.eclipse.gemoc.example.melangek3fsm.fsm.design contains the graphical concrete syntax of FSM, using Sirius. It defines only the layer for edition.
- org.eclipse.gemoc.example.melangek3fsm.fsm.k3dsa contains the operational semantics of FSM (ie. the interpreter), using the Kermeta3 language.
- org.eclipse.gemoc.example.melangek3fsm.fsm.model contains the metamodel of FSM, using the Ecore language.
- org.eclipse.gemoc.example.melangek3fsm.fsm.model.edit contains EMF edition support. It is used to customize the various views in Sirius and in the simulator (for example by providing custom icons in the various views)
- org.eclipse.gemoc.example.melangek3fsm.fsm.model.editor contains EMF basic tree editor for FSM models.
- org.eclipse.gemoc.example.melangek3fsm.xsfsm contains the definition of the XSFSM language using the Melange language. Basically, it inherits from FSM language and add the aspects defined in the k3dsa project.
- org.eclipse.gemoc.example.melangek3fsm.xsfsm.design contains the graphical concrete syntax of XSFSM, using Sirius. It extends fsm.design editor by adding the layers used by the debug/animation.
- org.eclipse.gemoc.example.melangek3fsm.xsfsm.trace contains the trace metamodel automatically generated from the semantics. It is used by the omniscient debugger to support StepBack instruction and to display an interactive timeline of the execution.
- org.eclipse.gemoc.example.melangek3fsm.xsfsm.xsfsm contains the language runtime generated by Melange for XSFSM, ie. a new Ecore model that contains both static elements (from org.eclipse.gemoc.example.melangek3fsm.fsm.model) and dynamic features (from org.eclipse.gemoc.example.melangek3fsm.fsm.k3dsa).
The figure Figure 43, “Language relations, packages and classes view.” presents an overview of the main artefacts in the projects:
- the base language fsm is built by fsm.melange from the fsm.ecore. As it use the legacy modifier (ie. it doesn’t modifies the ecore definitions) the java classes from the ecore are directly reused as implementation for the fsm language;
- the aspects in fsm.k3dsa extends the base classes;
- the xsfsm.melange file defines the xsfsm language. It inherits from fsm and add the fsm.k3dsa aspects. This will generate the java implementation classes for the resulting xsfsm language.
By following these instructions, you’ll be able to reproduce this example from scratch.
Note
You may apply some of these steps in a different order. This is only an example of a valid scenario.
In the following step, we’ll create a language with usual EMF technologies: Ecore + Sirius
It will be considered as a "legacy" language (ie. as if it was developped by a third party).
Create an Ecore project:
-
Menu File → New → Ecore Modeling Project
- name it org.eclipse.gemoc.example.melangek3fsm.fsm.model
- Edit the ecore file and add the concepts corresponding to the syntaxic domain (ie. reproduce concepts of Figure 41, “FSM Syntaxic domain.”).
-
In the org.eclipse.gemoc.example.k3fsm project, open the genmodel file,
- change the Base Package for the model to
org.eclipse.gemoc.example.melangek3fsm
(on the package: Fsm → Fsm → section All) - Right click on the root element then Generate model code.
- change the Base Package for the model to
-
In the org.eclipse.gemoc.example.melangek3fsm.fsm.model project, open the genmodel file,
- Right click on the root element then Generate model code; Generate edit code; Generate editor code.
You’ll obtain the following projects: org.eclipse.gemoc.example.melangek3fsm.fsm.model.edit and org.eclipse.gemoc.example.melangek3fsm.fsm.model.editor
- Create a project for the graphical editor: File → New → Viewpoint Specification Project . name it: org.eclipse.gemoc.example.melangek3fsm.fsm.design
-
Create a representation for edition
- Change viewpoint name to "MelangeK3FSMViewPoint", label "K3FSM"
- New Diagram representation; set the ID to "FSM", add the k3fsm.ecore to the list of metamodels; set the domain class to the FSM class. In Advanced, set the title expression to "feature:name"
-
in the Default layer; New Diagram Element → Container; ID = "StateContainer"; Domain class = "State"; Semantic candidate expression =
[self.ownedStates/]
- on the StateContainer; New Style → Gradient
- on the StateContainer; New Contitional style; Predicate expression =
[self.eContainer().oclAsType(FSM).initialState = self/]
; create another gradient in it and set a border size to 4.
-
in the Default layer; New Diagram Element → Element Based Edge; ID = "TranditionEdge"; Domain class = "Transition"; Source mapping = "StateContainer"; source finder expression =
[self.source/]
; target Mapping = "StateContainer"; Target Finder Expression =[self.target/]
- On TranditionEdge/ Edge Style solid, verify the decorators, No decoration for source arrow, and InputArrow for Target Arrow
- On TranditionEdge/ Edge Style solid / Center Label Style 8; Label Expression =
aql:self.getLabel()
- Open the file org.eclipse.gemoc.example.melangek3fsm.design.Services; add a method: (use Eclipse quick fix to add the import to
import org.eclipse.gemoc.example.k3fsm.Transition;
)
public String getLabel(Transition transition) { final StringBuilder res = new StringBuilder(); res.append(transition.getName()); res.append("\n"); res.append(""); res.append(transition.getInput()); res.append(" / "); res.append(transition.getOutput()); return res.toString(); }
The following actions allow to declare a language for both GEMOC and Melange using the ecore defined previously.
- Menu File → New → Project… → Melange Project
- → Next ; Name it org.eclipse.gemoc.example.melangek3fsm.fsm ; → Next
- Check the Create a plug-in using one of the templates box and select Simple GEMOC Melange Sequential project
- → Next Fill the wizard with the following:
Label | Value |
---|---|
Package name |
org.eclipse.gemoc.example.melangek3fsm |
Language name |
FSM |
Melange file name |
FSM |
Ecore file location |
browse to find org.eclipse.gemoc.example.melangek3fsm.fsm.model/model/fsm.ecore |
- → Finish
- Edit the file /org.eclipse.gemoc.example.melangek3fsm.fsm/src/org/eclipse/gemoc/example/melangek3fsm/fsm/FSM.melange
- add external keywork to the language definition
external language FSM { syntax "platform:/resource/org.eclipse.gemoc.example.melangek3fsm.fsm.model/model/fsm.ecore" }
- Right click on the FSM.melange file → Melange → Generate All
- Right click on the org.eclipse.gemoc.example.melangek3fsm.fsm project → Configure → Add GEMOC Language Project Nature
- Create a new file /org.eclipse.gemoc.example.melangek3fsm.fsm/src/org/eclipse/gemoc/example/melangek3fsm/fsm/FSM.dsl * with the following content:
name = org.eclipse.gemoc.example.melangek3fsm.fsm.FSM ecore = platform:/resource/org.eclipse.gemoc.example.melangek3fsm.fsm.model/model/fsm.ecore metaprog = org.eclipse.gemoc.metaprog.ecore
- Menu File → New → Project… → K3 Project
- name it : org.eclipse.gemoc.example.melangek3fsm.fsm.k3dsa ; → Next
- Check the Create a plug-in using one of the templates box and select User Ecore Basic Aspects
- → Next
Fill the wizard with the following:
Label | Value |
---|---|
Aspect package prefix |
org.eclipse.gemoc.example.melangek3fsm |
Aspect package sufffix |
.aspects |
Aspect file name |
FSMAspects |
Aspect classes suffix |
Aspect |
Ecore base package name |
org.eclipse.gemoc.example.melangek3fsm |
Ecore file path |
browse to find org.eclipse.gemoc.example.melangek3fsm.fsm.model/model/fsm.ecore |
- → Finish
- Open the /org.eclipse.gemoc.example.melangek3fsm.fsm.k3dsa/src/org/eclipse/gemoc/example/melangek3fsm/fsm/aspects/fsmAspects.xtend file and add the following methods in the aspects:
package org.eclipse.gemoc.example.melangek3fsm.fsm.k3dsa import fr.inria.diverse.k3.al.annotationprocessor.Aspect import fr.inria.diverse.k3.al.annotationprocessor.InitializeModel import fr.inria.diverse.k3.al.annotationprocessor.Main import fr.inria.diverse.k3.al.annotationprocessor.Step import org.eclipse.gemoc.example.melangek3fsm.fsm.State import org.eclipse.gemoc.example.melangek3fsm.fsm.StateMachine import org.eclipse.gemoc.example.melangek3fsm.fsm.Transition import static extension org.eclipse.gemoc.example.melangek3fsm.fsm.k3dsa.StateAspect.* import static extension org.eclipse.gemoc.example.melangek3fsm.fsm.k3dsa.StateMachineAspect.* import static extension org.eclipse.gemoc.example.melangek3fsm.fsm.k3dsa.TransitionAspect.* import org.eclipse.emf.common.util.EList @Aspect(className=StateMachine) class StateMachineAspect { public State currentState public String unprocessedString public String consummedString public String producedString @Step @Main def void main() { try{ while (!_self.unprocessedString.isEmpty) { _self.currentState.step(_self.unprocessedString) } } /* catch (NoTransition nt){ println("Stopped due to NoTransition"+nt.message) } catch (NonDeterminism nt){ println("Stopped due to NonDeterminism"+nt.message) } */ catch (Exception nt){ println("Stopped due to "+nt.message) } println("unprocessed string: "+_self.unprocessedString) println("processed string: "+_self.consummedString) println("produced string: "+_self.producedString) } @Step @InitializeModel def void initializeModel(EList<String> args){ _self.currentState = _self.initialState; _self.unprocessedString = args.get(0) _self.consummedString = "" _self.producedString = "" } } @Aspect(className=State) class StateAspect { @Step def void step(String inputString) { // Get the valid transitions val validTransitions = _self.outgoingTransitions.filter[t | inputString.startsWith(t.input)] if(validTransitions.empty) { //throw new NoTransition() throw new Exception("No Transition") } if(validTransitions.size > 1) { //throw new NonDeterminism() throw new Exception("Non Determinism") } // Fire transition validTransitions.get(0).fire } } @Aspect(className=Transition) class TransitionAspect { @Step def void fire() { println("Firing " + _self.name + " and entering " + _self.target.name) val fsm = _self.source.owningFSM fsm.currentState = _self.target fsm.producedString = fsm.producedString + _self.output fsm.consummedString = fsm.consummedString + _self.input fsm.unprocessedString = fsm.unprocessedString.substring(_self.input.length) } } /* need to be enabled when feature request */ class NoTransition extends Exception{ } class NonDeterminism extends Exception{ }
runtime data added via aspect |
|
a method with @InitializeModel annotation in order to use the launch configuration parameters to set up the runtime data when the model execution starts. |
|
a method with @Main annotation that will be used to start the execution. |
|
a method with the @Step annotation that will be observable (ie. the debugger can do a pause when a object instance of this class call this method). |
|
another method with the @Step annotation that will be observable |
- Menu File → New → Project… → Melange Project
- → Next ; Name it org.eclipse.gemoc.example.melangek3fsm.xsfsm ; → Next
- Check the Create a plug-in using one of the templates box and select GEMOC Melange based sequential project (extended languages)
- → Next Fill the wizard with the following:
Label | Value |
---|---|
Package name |
org.eclipse.gemoc.example.melangek3fsm.xsfsm |
Language name |
XSFSM |
Melange file name |
XSFSM |
Base language name |
FSM |
Ecore file location |
browse to find org.eclipse.gemoc.example.melangek3fsm.fsm.model/model/fsm.ecore |
K3 DSA Project name |
browse to find org.eclipse.gemoc.example.melangek3fsm.fsm.k3dsa |
- → Finish
- open the /org.eclipse.gemoc.example.melangek3fsm.xsfsm/META-INF/MANIFEST.MF file, add a dependency to the org.eclipse.gemoc.example.melangek3fsm.fsm project.
check the XSFSM.melange file so that it correctly finds the inherited dsl.
package org.eclipse.gemoc.example.melangek3fsm.xsfsm import-dsl org.inria.gemoc.example.melangek3fsm.fsm.FSM language XSFSM inherits org.eclipse.gemoc.example.melangek3fsm.fsm.FSM { with org.eclipse.gemoc.example.melangek3fsm.fsm.k3dsa.StateAspect with org.eclipse.gemoc.example.melangek3fsm.fsm.k3dsa.StateMachineAspect with org.eclipse.gemoc.example.melangek3fsm.fsm.k3dsa.TransitionAspect }
- Right click on the XSFSM.melange file → Melange → Generate All
This generates a new GEMOC language project: org.eclipse.gemoc.example.melangek3fsm.xsfsm.xsfsm
Debug capabilities (breakpoint support, basic highlighting, …)
- Right click on the org.eclipse.gemoc.example.melangek3fsm.xsfsm.xsfsm project → GEMOC Language → Create animator project for language → Extends an existing diagram description → Next → select FSM (ie. the name of the representation in org.eclipse.gemoc.example.melangek3fsm.fsm.design) → Next
Fill the wizard with the following:
Label | Value |
---|---|
Project name |
org.eclipse.gemoc.example.melangek3fsm.xsfsm.design |
Viewpoint Specification Model name |
org.eclipse.gemoc.example.melangek3fsm.xsfsm.XSFSM.odesign |
Viewpoint name |
MelangeK3FSM_XSFSMViewpoint |
Diagram name |
org.eclipse.gemoc.example.melangek3fsm.xsfsm.XSFSM |
-> Finish
Domain specific animation
This is similar to <<K3FSM-example>> (see section Domain specific animation <<K3FSM-example-debug-animation>>).
It has some specificities: As the fsm.design is based on fsm.ecore but the executed model is actually based on xsfsm.ecore, the typing must use as much as possible the lazy typing of AQL (Sirius query language).
Ie. write `State` instead of `fsm.State`
Additionally, the java service classes should handle both case: edition and running
so the service methods defined in _/org.eclipse.gemoc.example.melangek3fsm.fsm.design/src/org/eclipse/gemoc/example/melangek3fsm/fsm/design/services/FSMServices.java_ that were dedicated to FSM must be duplicated and adapted to work with XSFSM in _/org.eclipse.gemoc.example.melangek3fsm.xsfsm.design/src/org/eclipse/gemoc/example/melangek3fsm/xsfsm/design/services/XFSMServices.java_
The following online resources are related to this examples.
- Tutorial "Language Engineering with The GEMOC Studio", ICSA'17: this tutorial uses the same FSM example as this official example. It provides some additional explanations and screenshots.
Note
as these resources have been written with a previous version of the GEMOC Studio, their content may need some adaptations to 100% work with the latest version.
[67] asciidoc source of this page: https://github.com/eclipse/gemoc-studio/tree/master/official_samples/MelangeK3FSM/docs/MelangeK3FSM_sequential.asciidoc.