Xtext ist ein Open-Source-Framework für die Entwicklung von Programmiersprachen sowie domänenspezifischen Sprachen (englisch domain specific language, DSL) und ein Teil des Eclipse-Modeling-Framework-Projekts (EMF). Im Gegensatz zu normalen Parsergeneratoren wird bei Xtext nicht nur ein Parser generiert, sondern auch ein EMF Metamodell (ein Klassenmodell für den abstrakten Syntaxbaum) und ein in Eclipse integrierter Texteditor sowie die notwendige Infrastruktur für die Implementierung einer modernen Entwicklungsumgebung für die entwickelte Sprache bereitgestellt.

Xtext

Logo
Screenshot
Screenshot

Domänenspezifische Sprache zur Implementierung von Statemachines. Links Quelltexteditor, rechts Outline view
Basisdaten

Hauptentwickler Eclipse Foundation
Entwickler Eclipse Foundation, itemis AG, TypeFox
Erscheinungsjahr 2006
Aktuelle Version 2.21.0[1]
(3. März 2020)
Betriebssystem plattformübergreifend / Java Virtual Machine / Eclipse, IntelliJ IDEA
Programmier­sprache Java, Xtend
Kategorie Framework, Language workbench
Lizenz Eclipse Public License
eclipse.org/Xtext

Geschichte

Bearbeiten

Die erste Version von Xtext wurde im Jahr 2006 im Rahmen des Projektes openArchitectureWare (oAW) veröffentlicht. In der darauf folgenden Zeit wurden mit jeder Version neue Funktionen und Konzepte integriert. In der Version 4.3 von oAW ist die letzte oAW-Version von Xtext enthalten. Seit Anfang 2008 wird Xtext unterhalb des Eclipse Modeling Project im Textual Modeling Framework (TMF) weiterentwickelt. Mitarbeiter der Firmen itemis AG und TypeFox entwickeln hier eine neue Version des Frameworks. Das erste offizielle Release erfolgte am 16. Juni 2009, als Xtext in der Version 0.7.0 erschien.[2]

Im Juni 2010 hat das Framework die Version 1.0 erreicht. Version 2.0 erschien am 27. Juni 2011 zusammen mit Eclipse 3.7 (Indigo).[3]

Im Juni 2012 wurde mit Version 2.3 die Expression Language Xbase vorgestellt. Xbase ermöglicht einerseits eine nahtlose Integration einer DSL in das Java Typsystem und stellt andererseits typische Ausdrücke (Expressions) in einer Java-ähnlichen Syntax zur Integration in eine DSL zur Verfügung.[4][5] Eine weitere Neuerung von Version 2.3 ist die Programmiersprache Xtend, eine in Xtext selbst entwickelte, an Java angelehnte Programmier- und Templatesprache. Sie wird seitdem zur Implementierung vieler Sprach- und IDE-Konzepte propagiert.

Die nächste große Neuerung von Xtext wurde am 1. Dezember 2015 mit Version 2.9 vorgestellt. Xtext steht nun ebenfalls als Plug-In für die Entwicklungsumgebung IntelliJ IDEA zur Verfügung. Sowohl in der Version für Eclipse als auch in der Version für IntelliJ können Plug-ins für beide Plattformen entwickelt werden. Weiterhin besteht die Möglichkeit einen DSL Editor für eine Webanwendung zu generieren. Auch die Verwendung der Buildsysteme ist nun (teilweise) möglich.[6]

Funktionalität

Bearbeiten

Mit Xtext werden (domänenspezifische) Programmiersprachen entwickelt. Es ist weit mehr als ein einfacher Parsergenerator wie z. B. ANTLR, welcher dennoch Verwendung in Xtext findet, um Quelltexte einzulesen und einen abstrakten Syntaxbaum (AST) abzuleiten. Es bietet Möglichkeiten, den AST zu analysieren und zu validieren, den AST in eine beliebige andere (textuelle) Repräsentation zu überführen oder Javaklassen daraus abzuleiten. Zusätzlich zu diesen typischen Compilerfunktionen bietet Xtext Möglichkeiten viele IDE Konzepte für die Sprache zu implementieren. So kann am Ende des Entwicklungsprozesses ein Plug-In für Eclipse oder IntellJ stehen, welches mit Hilfe dieser Plattformen eine komplette IDE zur Verfügung stellt.

Im Folgenden werden die verschiedenen Funktionen und Konzepte, die mit Xtext implementiert werden können, kurz beschrieben.

Workflow

Bearbeiten

Xtext verwendet einen MWE2 Workflow um die Sprache zu konfigurieren. Wird der Workflow ausgeführt, so wird der Parser und das Metamodell generiert. Weiterhin werden Klassen- und Methodenrümpfe erzeugt, um verschiedene Compiler- und IDE-Konzepte zu implementieren. Werden die Konzepte nicht implementiert, werden die Standardimplementierungen von Xtext verwendet.

Compilerfunktionen

Bearbeiten

Dieser Abschnitt fasst Konzepte zusammen, die typischerweise Teil des Compilers sind. Ein Compiler parst den Quelltext und erstellt einen abstrakten Syntaxbaum (AST, Abstract Syntax Tree). Bevor dies geschieht, wird eine Syntaxanalyse durchgeführt um ggf. Syntaxfehler zu finden. Nur wenn der Quelltext frei von Syntaxfehlern ist, wird der AST erzeugt. Auf dem AST werden oft statische Analysen durchgeführt (z. B. Typüberprüfung, Überlagerung/Schattierung, Sichtbarkeit etc.). Diese Analysen können Fehler aufdecken. Sollte der AST fehlerfrei sein, so wird er in die Ausgabesprache überführt. Dies kann eine beliebige (textuelle) Repräsentation sein oder Quelltext in einer beliebigen (Java) anderen Programmiersprache.

Parser / Grammatik der Sprache

Bearbeiten

Xtext generiert vollautomatisch einen ANTLR-Parser für die Sprache. Hierfür wird der ANTLR-Parsergenerator verwendet. Es muss für dieses Konzept lediglich die Grammatik der Sprache (syntaktische Regeln) definiert werden. Hierfür stellt Xtext eine eigene Sprache zur Verfügung. Das Besondere an der Grammatiksprache von Xtext ist, dass damit nicht nur die konkrete, sondern auch die abstrakte Syntax beschrieben wird. Üblicherweise wird aus der Grammatik nicht nur der ANTLR Parser generiert, sondern auch ein Ecore Metamodell und seine Implementierung in Java. Es wird als AST verwendet. Der generierte ANTLR TreeParser erzeugt eine Instanz dieses Modells und gibt es als AST zurück. Existiert bereits ein Metamodell und es soll nur noch die textuelle Syntax definiert werden, so kann das Metamodell in der Xtext-Grammatiksprache importiert werden. Dann wird auch kein eigenes Metamodell erzeugt.

Die Syntax der Grammatiksprache wird im Folgenden beschrieben. Jede Grammatik verfügt über einen Header, in dem der Name der Sprache und die Vatergrammatik definiert werden. Weiterhin können Metamodelle der Vatersprachen importiert werden, um ihre Regeln nutzen können. Sofern kein existierendes Metamodell verwendet wird, wird hier ebenfalls das Ecore Metamodell definiert:

grammar org.eclipse.mydsl.MyDsl with org.eclipse.xtext.xbase.Xbase

import "http://www.eclipse.org/emf/2002/Ecore" as ecore
import "http://www.eclipse.org/xtext/common/JavaVMTypes"
import "http://www.eclipse.org/xtext/xbase/Xtype"
generate MyDSL "http://www.eclipse.org/xtext/mydsl/MyDsl"

Auf den Header folgt die oberste (Root)-Regel der Sprache. Alle weiteren Regeln folgen in beliebiger, aber sinnvoller Reihenfolge auf die Rootregel. Eine Regel hat einen Namen, der mit einem Großbuchstaben beginnt, gefolgt von einem Doppelpunkt. Beendet wird eine Regel mit einem Semicolon. Zeichen, die in der definierten Sprache stehen, wie z. B. Kommas, Punkte, aber auch Schlüsselwörter, werden in einfache Anführungszeichen gesetzt. Enthält eine Regel weitere, (komplexe) Regeln oder hat bestimmte Attribute, so wird zunächst der Name des Attributes geschrieben (beginnend mit einem kleinen Buchstaben), gefolgt von einem Gleichheitszeichen und dann dem Namen der Kindregel. Eine typische Regel könnte z. B. so aussehen:

 AnyRule:
  'any' element=ID 'will' 'be' value=Value ';';

Es ist zwar nicht bekannt, wie die Regel Value aussieht, aber der hier beschriebene Quelltext könnte etwa so aussehen:

  any MyName will be 42;

Ein Attribut muss grundsätzlich genau einen Wert enthalten, es sei denn, es ist als optional gekennzeichnet oder es enthält eine Liste von Werten. Um ein Wert als optional zu kennzeichnen, wird ihm ein Fragezeichen angehängt, eine Liste von Werten, die auch leer sein darf, wird durch einen Stern gekennzeichnet und eine Liste, die mindestens ein Element enthalten muss, durch ein Plus. Der Zuweisungsoperator für Listenattribute ist das Plusgleich:

 SeveralAttributesRule:
  mustBeSet=AttributeMandatory
  canBeSet=AttributeOptional?
  possiblyEmptyList+=AttributeInList*
  listWithAtLeastOneElement+=AttributeInList+;

Nachdem die Grammatik der Sprache implementiert oder geändert wurde, muss der MWE2-Workflow ausgeführt werden, damit Parser und Metamodell (neu) generiert werden.

Statische Analyse

Bearbeiten

Sobald der MWE2 Workflow das erste Mal ausgeführt wird, erzeugt Xtext die Klasse org.eclipse.xtext.mydsl.validation.MyDslValidator. Diese ist zunächst leer und es können beliebig viele Methoden implementiert werden, die einzelne Knoten des AST's prüfen oder analysieren können. Xtext findet diese Methoden und führt sie kontextabhängig automatisch aus. Um Xtext mitzuteilen, das eine bestimmte Methode eine Analyse enthält, muss diese einerseits mit der Annotation @Check gekennzeichnet werden und andererseits darf sie nur genau einen Parameter haben, dessen Typ ein Typ des Metamodells ist. Eine solche Analysemethode könnte in etwa so aussehen:

 @Check
 def checkRootElement(MyDslRoot root) {
   // …
 }

Diese Methoden haben keinen Rückgabewert (void). Wenn Fehler gefunden werden, sollte eine der error(…) Methoden aufgerufen werden. Diese empfängt einige Informationen und erstellt so einen Fehlermarker.

Analog zu Fehlern können (für den Editor, siehe IDE Konzepte) auch Warnungen (warning(…)) oder Informationen (info(…)) erzeugt werden. Diese Ergebnisse werden vom Editor im Quelltext angezeigt.

Code-Generierung

Bearbeiten

Xtext erzeugt für jede Sprache eine Klasse, mit der die Sprache in eine bestimmte Ausgabe übersetzt werden kann. Hierzu gibt es ab Version 2.3 zwei Möglichkeiten. Wird mit der Sprache z. B. eine Datenstruktur aufgebaut, so kann eine XML-Ausgabe oder ein JSON Object erzeugt werden, oder eine andere beliebige (textuelle) Repräsentation. Oft kommt es aber auch vor, dass eine Sprache einen kleinen Teilaspekt von einem großen Programm abdeckt. Dann ist es sinnvoll, Java-Klassen zu erzeugen. Hierzu wird der ModelInferrer verwendet. Er leitet eine Java-Klasse ab und integriert die Sprache somit nahtlos in das Javatypsystem (große Vorteile auf IDE-Ebene).

MyDslGenerator
Bearbeiten

Standardmäßig wird erst einmal eine Klasse org.eclipse.xtext.mydsl.generator.MyDslGenerator erzeugt. Diese enthält genau eine Methode doGenerate(Resource r, IFileSystemAccess fsa). Hier kann der Generationsprozess implementiert werden, der die Ausgabe des Compilers berechnet. Diese Methode wird beim Speichern der Datei im Eclipse Editor automatisch ausgeführt. Die erzeugten Dateien werden in der Regel im Verzeichnis src-gen abgelegt, es sei denn, etwas anderes wird eingestellt. Das Ausgabeformat ist hier beliebig.

MyDslModelInferrer
Bearbeiten

Bei der Verwendung von Xbase (z. B. um Cross-Referencing zu Java-types zu benutzen) wird anstatt der Generatorklasse ein ModelInferrer erzeugt, den es zu implementieren gilt. Dieser ermöglicht das Ableiten von Javatypen aus der Sprache. Hier muss auch nicht die Datei an sich erzeugt werden, sondern lediglich eine Transformation des Sprach-AST's hin zu einem Java-AST implementiert werden. Die eigentliche Serialisierung und Übersetzung in Bytecode übernimmt Xtext.

MyDslInterpreter
Bearbeiten

Xtext bietet auch die Möglichkeit, einen Interpreter anstelle eines Codegenerators zu implementieren, sodass der Code der Sprache direkt ausgeführt werden kann.

IDE Konzepte

Bearbeiten

(tbd) Neben den Compilerkomponenten, die teilweise auch IDE Konzepte implementieren, bzw. dem Editor zuarbeiten, können für Xtext-Sprache diverse IDE-Konzepte implementiert werden.

Der MWE2 Workflow erzeugt automatisch ein Editor-View mit einem Basis-Syntax-Highlighting.

Syntax-Highlighting
Bearbeiten

Dieses kann sowohl syntaktisch als auch semantisch angepasst/verfeinert werden. Es sind keine Grenzen bezüglich Farben, Schriftarten, Textdekorationen gesetzt. Mit einem entsprechenden Aufwand kann eine Seite für die Spracheinstellungen implementiert werden, in der der Endnutzer das Highlighting an die eigenen Bedürfnisse anpassen kann (z. B. Dark Theme oder Rot-Grün-Sehschwäche).

Autoformatierung
Bearbeiten

Das aus Eclipse bekannte Feature der Autoformatierung von Quelltext kann ebenfalls für eine Xtextsprache implementiert werden. Xtext stellt hierfür eine API bereit. Die hier definierten Patterns werden auf den Quelltext angewendet, wenn der entsprechende Befehl gegeben wird bzw. wenn eine Quelltextdatei erzeugt wird, indem der AST Stück für Stück aufgebaut und dann serialisiert wird.

Das aus Eclipse bekannte Feature der Hyperlinks zu Feld-, Methoden- oder Klassendefinitionen zu springen, kann ebenfalls für Xtextsprachen implementiert werden. Xtext stellt hierfür eine API bereit. In Verbindung mit der Expression language Xbase und dem JvmModelInferrer kann so auf IDE-Ebene eine nahtlose Integration der Sprache in das Java Typsystem geschaffen werden. Einerseits lässt sich so ein Hyperlink zu einer Methode einer Java-Klasse implementieren, andererseits ist es auch möglich in Javaklassen die abgeleiteten Javatypen zu verwenden. Wird der Hyperlink im Javaeditor angeklickt, öffnet dann sogar der Xtext-Spracheditor die entsprechende Datei und markiert den Referenzierten Teil.

Anzeige von Analyseergebnisse
Bearbeiten

Wie im Abschnitt über die Compiler-Konzepte beschrieben, können Fehler, Warnungen und Informationen im Quelltext gefunden werden. Diese werden automatisch im Editor von Eclipse angezeigt.

Codefolding
Bearbeiten

Xtexteditoren unterstützten automatisch das Zusammenklappen von Quelltextblöcken.

Autovervollständigung und Quickfixes
Bearbeiten

Xtext stellt eine Klasse bereit, um das Autovervollständigungs-Feature von Eclipse zu unterstützen. So lässt sich implementieren, welche Inhalte vorgeschlagen werden. In Kombination mit den angezeigten Fehlern und Warnungen können in gewissem Maße sogar Verbesserungsvorschläge generiert werden. Diese können dann den als fehlerhaft markierten Bereich eines Dokumentes durch den Vorschlag ersetzen, um Fehler zu entfernen.

Outline View

Bearbeiten

Aus Eclipse ist der s.g. Outline View bekannt. Dieser zeigt z. B. alle Felder und Methoden einer Java-Klasse an. Ein solcher Outline View kann auch für eine Xtextsprache implementiert werden. Dieser ist dann auch mit der geöffneten Datei verknüpft, sodass der Courser mit einem Klick auf ein Element im Outline zu der entsprechenden Stelle im Text springt.

Rename Refactoring

Bearbeiten

Rename Refactoring wird von Xtexteditoren unterstützt.

Weiterverarbeitung von DSL-Modellen

Bearbeiten

DSLs sind formale Sprachen und müssen daher ausführbar gemacht werden. Dies geschieht auf zwei unterschiedlichen Wegen:

  • Zur Codegenerierung bietet sich Xtend an, welches vom gleichen Team entwickelt wird und ebenfalls bei Eclipse Modeling gehostet ist. Bei der Codegenerierung können beliebige Zielplattformen verwendet werden.
  • Die Interpretation von EMF-Modellen muss mit einer zur Java Virtual Machine kompatiblen Sprache geschehen, da EMF und Xtext bisher nur in Java implementiert sind. Die Zielplattform ist daher auf diese Sprachen eingeschränkt.
  • Seit Version 2.11 wird das Language Server Protocol (LSP) unterstützt. Für die eigenen domänenspezifischen Sprachen können so eigene Programmiersprachen-Server generiert werden.[7]

Auszeichnung

Bearbeiten
  • Eclipse Community Awards 2010: “Most Innovative New Feature or Eclipse Project”[8]

Literatur

Bearbeiten
  • Lorenzo Bettini: Implementing Domain-Specific Languages with Xtext and Xtend. 1. Auflage. Packt Publishing Ltd., 2013, ISBN 978-1-78216-030-4, S. 342 (englisch, packtpub.com).
Bearbeiten

Einzelnachweise

Bearbeiten
  1. www.eclipse.org.
  2. Eclipse Modeling News. eclipse.org, abgerufen am 4. März 2010.
  3. Eclipse Indigo mit vielen Neuerungen für Java-Entwickler. heise.de, abgerufen am 28. Juni 2011.
  4. The Future of Xtext. blog.efftinge.de, abgerufen am 12. Januar 2016.
  5. The Future of Xtext. speakerdeck.com, abgerufen am 12. Januar 2016.
  6. Xtext 2.9.0 Release Review. projects.eclipse.org, abgerufen am 12. Januar 2016.
  7. Alexander Neumann: Xtext 2.11 unterstützt Language Server Protocol. In: heise Developer. 1. Februar 2017, abgerufen am 22. Oktober 2021.
  8. eclipse.org