Folgendes Problem:
Ich hab irgendwo Xtext gelernt. In der Uni, in einem Internet-Tutorial oder beim Surfen auf dem Pott. "Warum nicht einfach mal ne Sprache entwickeln, die statt der bekannten Keywords, Scrubs-Zitate benutzt? Da ist Xtext schließlich da!" - Das ist korrekt. Allerdings muss man dann ja das komplette Scoping, Typenberechnung, Validierung und Codegeneration selbst übernehmen. Möchte ich das? Nein. Eine mögliche Lösung hierfür ist Xbase.
Unser Ziel ist es nun, eine Grammatik zu schreiben, die Klassen erzeugt und in den Klassen Felder definieren lässt. So soll folgender Code möglich sein:
Beim Testen der Sprache stellt sich heraus, entweder durch einen Unit-Test oder zunächst einer Eclipse-Instanz(wichtig: Es muss ein Java-Projekt erstellt werden und die DSL-File im src Verzeichnis liegen!), stellt sich heraus, dass das oben gezeigte Beispiel erfolgreich geparsed wird. Nur wird kein Code generiert. Warum?
Wer sich für das Thema interessiert, sei das Buch "Implementing Domain Specific Languages with Xtext and Xtend" von Lorenzo Bettini sehr empfohlen.
Ich hab irgendwo Xtext gelernt. In der Uni, in einem Internet-Tutorial oder beim Surfen auf dem Pott. "Warum nicht einfach mal ne Sprache entwickeln, die statt der bekannten Keywords, Scrubs-Zitate benutzt? Da ist Xtext schließlich da!" - Das ist korrekt. Allerdings muss man dann ja das komplette Scoping, Typenberechnung, Validierung und Codegeneration selbst übernehmen. Möchte ich das? Nein. Eine mögliche Lösung hierfür ist Xbase.
Was ist Xbase?
Xbase ist eine Erweiterung von Xtext. Hierbei wird das Javatypsystem benutzt, um die Vorteile dessen zu nutzen. Die Typisierung, das Scoping und auch die Validierung ("Kann ich dieser Variable diesen Wert zuordnen?") wird hierbei bereits von Haus aus vorgegeben. Weiterhin werden auch IDE-Features wie der Debugger out-of-the-box mitgeliefert. Weitere Details hierzu sind in der Dokumentation hier zu finden.Erste Schritte in Xbase
1. Voraussetzungen
Zunächst wird eine laufende Version von Eclipse mit den DSL-Developer-Tools benötigt. Weiterhin werden Kenntnisse des Compilerbaus, Grammatiken, Parsing und Xtext im Allgemeinen vorausgesetzt.2. Erste eigene Sprache
Zunächst muss ein neues Xtext Projekt angelegt werden. Die Standardmäßig generierte Xtext-Datei wird um folgendes ergänzt:
grammar org.xtext.xbase.Scrubs with org.eclipse.xtext.xbase.Xbase
Dadurch wird Xbase importiert.Unser Ziel ist es nun, eine Grammatik zu schreiben, die Klassen erzeugt und in den Klassen Felder definieren lässt. So soll folgender Code möglich sein:
jambalaja MeineKlasse {
bananarama jd int
bananarama turk double
bananarama carla boolean
}
3. Javatypen in der Grammatik
Die Grammatik hierfür sieht folgendermaßen aus:
Scrubs:
classes+=Class*;
Class:
'jambalaja' name=ID '{'
variables+=Variable*
'}';
Variable:
'bananarama' name=ID type=JvmTypeReference;
Der besondere, neue Teil ist der type der Variablen, nämlich einer JvmTypeReference. Dies entspricht, vereinfacht gesagt, einem Java-Datentypen. Das kann zum Beispiel int, double, float oder boolean sein. Nach dem Erfolgreichen Ausführen des mw2-Workflows, werden eine Menge zusätzlicher Klassen erzeugt.Beim Testen der Sprache stellt sich heraus, entweder durch einen Unit-Test oder zunächst einer Eclipse-Instanz(wichtig: Es muss ein Java-Projekt erstellt werden und die DSL-File im src Verzeichnis liegen!), stellt sich heraus, dass das oben gezeigte Beispiel erfolgreich geparsed wird. Nur wird kein Code generiert. Warum?
Der JvmModelInferrer
Zur Codegeneration liegt im Package jvmmodel der JvmModelInferrer. Dieser ist dafür zuständig, den gewünschten Javacode zur DSL zu erzeugen. Er beschreibt das Mapping der DSL auf Java-Elemente. Der Code für unser Beispiel ist folgender:
def dispatch void infer(Scrubs element, IJvmDeclaredTypeAcceptor acceptor, boolean isPreIndexingPhase) {
for(classes : element.classes){
acceptor.accept(classes.toClass(classes.name))[
for(member : classes.variables){
val field = member.toField(member.name, member.type)
members += field
}]}}
Zur Erklärung: Der Code iteriert über alle Klassen des Programmes und erzeugt für jede eine Javaklasse, damit auch eine .java File im src-gen Ordner. Für jede Klasse werden darin die Variablen als Felder erzeugt. Die Klasse zum erzeugten Code sieht folgendermaßen aus:
public class MeineKlasse {
private int jd;
private double turk;
private boolean carla;
}
Fazit und Ausblick
Grundsätzlich ist zu sehen, dass die Codegenerierung und das Einbinden von Xbase sehr einfach ist. Das Verwenden von Javatypen und damit der richtigen Typberechnung ist trivial. Allerdings ist der Code noch nicht ausführbar. Hierfür fehlen Operationen, die über XExpressions realisiert werden können. Außerdem lässt sich Xbase erweitern und fast alles lässt sich auf die eigenen Bedürfnisse anpassen. Mehr dazu im nächsten Beitrag.Wer sich für das Thema interessiert, sei das Buch "Implementing Domain Specific Languages with Xtext and Xtend" von Lorenzo Bettini sehr empfohlen.
Kommentare
Kommentar veröffentlichen