Introduction à Xtext

L'ingénierie des modèles est une nouvelle façon de définir des langages, des DSL. Dans l'environnement EMF, cela se fait via la définition d'un méta-modèle en Ecore. Ensuite, on peut éditer des modèles écrits dans ce DSL via l'éditeur générique de modèles XMI ou les manipuler de manière programmatique avec du code Java ou ATL comme cela a été fait dans les TP précédents.

L'éditeur par défaut d'EMF fonctionne bien mais n'est pas pratique pour définir des modèles complexes. Vous avez pu le constater par exemple avec les diagrammes de classes du TP précédent où le contenu des modèles XMI est difficile à étudier et à modifier. Dans ce TP, nous allons voir comment définir une syntaxe dédiée à un DSL créé via un méta-modèle Ecore afin de faciliter l'édition de modèles. Dans le monde EMF, il y a deux outils de référence pour cela :

Dans ce TP, nous allons voir comment créer un éditeur textuel avec Xtext. Pour cela, nous allons repartir du DSL de processus défini dans le TP 1. Pour reprendre l'exemple donné en début de ce TP, le but est d'avoir un éditeur textuel qui affiche ceci avec de la coloration syntaxique et de la complétion :

Processus {
   activites {
      Activite Intro_Generale {
         suivante Cours_Meta
      },
      Activite Cours_Meta {
         suivante TP_Meta
         precedente Intro_Generale
      },
      Activite TP_Meta {
         suivante TP_Kermeta
         precedente Cours_Meta
      },
      Activite TP_Kermeta {
         precedente TP_Kermeta
      }
   }
   // on définit le début et la fin en respectant les invariants de cohérence en OCL
   debut Intro_Generale
   fin TP_Kermeta
}

Modification du méta-modèle du TP 1

Xtext a pour objectif de définir une grammaire EBNF et de faire le lien avec un méta-modèle. Il y a deux façons de procéder : soit on génère la grammaire à partir du méta-modèle Ecore, soit on génère le méta-modèle à partir de la grammaire. Dans notre cas, le méta-modèle Ecore existe, on va donc générer la grammaire Xtext qui ensuite permettra d'éditer textuellement un modèle.

La grammaire Xtext va permettre de définir les éléments d'un processus : la liste des activités, le début et la fin. Ces éléments sont définis dans un ordre précis avec comme principe de référencer des éléments définis préalablement. Ainsi, le début et la fin qui référencent des activités sont définis après les activités. Dans notre exemple, il y a une exception à cet ordre : dans une activité, on référence la suivante qui sera définie plus bas dans le modèle (de manière plus générale, les références suivantes et précédentes sont indépendantes de l'ordre de définition de la liste des activités du processus). Au niveau de l'éditeur, cela peut poser des problèmes d'avoir ce type de référence croisée. Xtext propose une solution techhnique pour référencer de n'importe où un élément : qu'il soit identifié par un attribut intitulé "name" dans sa méta-classe.

Dans un premier temps, nous allons modifier notre méta-modèle pour que les activités aient un attribut "name". La modification est simple puisqu'il y a déjà un attribut "nom" qui joue le même rôle. En pratique, il y a plusieurs étapes à effectuer :

  1. Dans le méta-modèle Ecore, modifiez l'attribut "nom" de la classe "Activite" en "name".
  2. Modifiez au passage également le nsURI du package "LDP" pour y mettre un adressage absolu comme "http://LDP/1.0".
  3. Editez le méta-modèle en version textuelle pour mettre à jour les invariants OCL qui manipulaient l'attribut "nom" d'une activité.
  4. Il faut mettre à jour le fichier "genmodel" et regénérer le code Java pour le méta-modèle : sélectionnez le fichier "LDP.genmodel" dans l'arborescence puis clic droit -> Reload ... -> Next -> bouton Load -> Next -> Finish. Ouvrez le fichier "LDP.genmodel", sélectionnez le package "LDP" et via le menu contextuel, générez le code Java (Generate Model Code).
  5. Suite à ces modifications, les modèles XMI existants ne sont plus valides : il est possible de les éditer textuellement pour changer le nsURI et l'attribut "nom" des activités. Le code Java de la classe "LDPManipulation" doit aussi être modifié pour prendre en compte le changement du nom d'attribut de la classe "Activite".

Génération de l'éditeur textuel

Génération de la grammaire Xtext

Plusieurs étapes sont nécessaires pour générer la grammaire Xtext à partir du méta-modèle Ecore :

  1. Sélectionnez le nom du projet "tp1" dans l'arborescence puis clic droit -> Configure -> Convert to Xtext Project.
  2. Via le menu principal d'Eclipse, créez un nouveau projet Xtext : File -> New -> Other -> Xtext -> Xtext Project From Existing Ecore Models. Cliquez sur Add... puis sélectionnez le fichier "LDP.genmodel" du projet "tp1". Modifiez le champ "Entry rule:" en bas pour qu'il contienne "Processus - LDP" : il faut préciser à Xtext quel est l'élément racine du métamodèle, ici c'est le processus. Cliquez sur Next et dans la fenêtre suivante, entrez : puis cliquez sur Finish. Ainsi, nous avons défini que l'extension de nos fichiers contenant les modèles sera "ldp" au lieu du "xmi" générique.
  3. A ce stade, Eclipse a créé plusieurs projets dont les noms commencent par "xtext.ldp". Ouvrez celui qui s'appelle "xtext.ldp" (tout court) et le fichier "Ldp.xtext" se trouvant dans le répertoire "src/xtext". Vous devez avoir ceci, c'est la grammaire Xtext générée automatiquement à partir du méta-modèle :



    La grammaire fait le lien avec les classes du méta-modèle tout en rajoutant des éléments de syntaxe pour définir textuellement les instances de ces classes. Les élements de syntaxe sont écrits entre quotes, par exemple 'Processus', 'activites' ou bien encore les accolades ou une virgule. Une règle définit comment un élément du méta-modèle est créé comme par exemple " ... returns Processus:" qui instancie la méta-classe Processus. Ensuite, dans la règle, il est précisé comment les attributs et les références de l'instance sont positionnés. Pour Processus, on retrouve par exemple "activites" ou "debut" qui font faire appel aux régles définies plus bas pour générer ces éléments.
  4. Pour finaliser l'éditeur, sélectionnez le fichier "GenerateLdp.mwe2" dans le même répertoire et clic droit -> Run as -> MWE2 Workflow.

Edition d'un modèle

Pour lancer l'édition de l'éditeur, il faut lancer une nouvelle instance d'Eclipse qui exécutera le projet Xtext :

  1. Sélectionnez le projet "xtext.ldp" dans l'arborescence puis clic droit -> Run As -> Eclipse Application
  2. Une fois le nouveau Eclipse lancé, fermez la fenêtre "Welcome" et créez un nouveau projet générique : File -> New -> Project -> General -> Project. Pour information, le nouveau Eclipse se lance en utilisant un workspace nommé "runtime-EclipseXtext".
  3. Dans le projet, créez un nouveau fichier que vous nommerez avec l'extension "ldp". Cliquez sur "Yes" à la question sur la conversion en un projet Xtext.
  4. Vous pouvez maintenant éditer votre modèle en respectant la syntaxe Xtext. Les mots-clés du langage sont mis en gras et Bordeaux, la complétion sur les noms d'activités fonctionne avec Ctrl+espace. Si vous voulez utiliser des espaces dans les noms des activités, il faut écrire les noms entre guillemets. Pendant l'édition, une croix rouge vous indique une erreur de syntaxe et un triangle jaune un invariant OCL qui n'est pas respecté. Pour l'exemple ci-dessus, le modèle doit être le suivant :

    .
  5. La syntaxe générée par défaut est un peu trop verbeuse notamment avec la définition des débuts et fins où il y a des redondances ou des mots-clés sans intérêt : fermez le nouveal Eclipse, revenez sur l'Eclipse initial, modifiez la grammaire Xtext pour avoir une syntaxe comme dans l'exemple donné en haut de la page, regénérez le workflow MWE2 et relancez un Eclipse sur le projet Xtext pour appliquer vos modifications.

Pour aller plus loin

Ce TP est une introduction à Xtext pour montrer la faisabilité de la définition d'une syntaxe textuelle pour un DSL défini par un méta-modèle Ecore. Les modèles textuels définis pourront être ensuite utilisés en entrée des transformations que vous aurez définies pour le méta-modèle. Il est également possible de customiser l'éditeur pour rajouter des règles d'édition ou générer des choses une fois le modèle édité. Cela se fait soit en Java, soit en Xtend.

Vous pourrez trouver des informations sur cela dans le cours/TP de Xtext de Olivier Le Goaer (avec des liens vers d'autres documentations) : support de cours et sujet de TP/tutoriel.


Eric Cariou, dernière modification : 04/02/24