This is one of a sequence of pages that I have wriiten about Xtext which start here.
This page is intended to compliment the official documentation here. It is intended as reference information to give a better overall picture to help understand the concepts when they arise with tables and block diagrams of the main components.
Creating Xbase project from scratch
To see how I began creating an xbase project from scratch see this page.
I have put additional screen shots on this page.
Overview
The purpose of Xbase seems to be to allow the DSL designer to design the high level structure of the program but to allow standard java/xtend like components for capabilities such as expressions and statements. (I xtend the distinction between expressions and statements is blured). So typically the user defined grammar defines the structure down to a statement block at which point standard components are used.
This makes it much easier to build a DSL if it uses java-like expressions.
An Xbase jvm compiler project might have a directory structure something like this. I would like to investigate how these are implemented: |
Unlike non-xbase DSLs we don't generate the java code directly. As far as I can see we first convert to a model of the Java Virtual Machine (JVM) then, from there the java code can either be compiled or interpreted:
In the JvmModelInferrer we can call methods such as 'toClass', 'toField' and so on. These return the appropriate parts of the JVM model. There is more detail about this inferrer on this page. |
Grammar To Define Model
We first create a model using the grammar. Grammar file for a given project starts like this:
grammar org.myDomain.myProject.myLanguage.Domainmodel with org.eclipse.xtext.xbase.Xbase
generate domainmodel "http://www.eclipse.myDomain/myProject/myLanguage/Domainmodel"
We can then refer to Java Library (Jvm prefix) and XBase (X prefix) constructs in the grammar. I have listed some of these in the following tables:
from org.eclipse.xtext.?
see: https://github.com/eclipse/?
Grammar rule and Interfaces | Implementing Classes | Example |
AbstractElement | ||
JvmIdentifiableElement | ||
JvmFormalParameter | ||
JvmConstructor | ||
JvmType |
org.eclipse.xtext.xbase.Xtype (src)
Grammar rule and Interfaces | Implementing Classes | Example |
JvmTypeReference | ||
XFunctionTypeRef | ||
JvmParameterizedTypeReference | ||
JvmArgumentTypeReference | ||
JvmWildcardTypeReference | ||
JvmTypeParameter | ||
JvmUpperBound : | extends myclass | |
QualifiedName | myclass.myfunction |
org.eclipse.xtext.xbase.Xbase (src)
Grammar rule and Interfaces | Implementing Classes | Example |
XExpression | XExpressionImpl | any valid statement, expression or value |
XAssignment | XAssignmentImpl XAssignmentImplCustom | a=3 |
XBinaryOperation | XBinaryOperationImpl XBinaryOperationImplCustom | a && b |
XBlockExpression | XBlockExpressionImpl | true |
XBooleanLiteral | XBooleanLiteralImpl | true |
XCastedExpression | XCastedExpressionImpl | 2 as int |
XClosure | XClosureImpl | [a | b] |
XConstructorCall | XConstructorCallImpl XConstructorCallImplCustom | new mytype |
XDoWhileExpression | XDoWhileExpressionImpl | do x=x+1 while (x<10) |
XFeatureCall | XFeatureCallImpl XFeatureCallImplCustom | |
XForLoopExpression | XForLoopExpressionImpl | for(value:values) myblock |
XIfExpression | XIfExpressionImpl | if(x==2)myblock |
XMemberFeatureCall | XMemberFeatureCallImpl XMemberFeatureCallImplCustom | |
XNullLiteral | XNullLiteralImpl | null |
XReturnExpression | XReturnExpressionImpl | return 3 |
XStringLiteral | XStringLiteralImpl | "my text" |
XSwitchExpression | XSwitchExpressionImpl XSwitchExpressionImplCustom | switch(a) (case 2:x=3) |
XThrowExpression | XThrowExpressionImpl | throw 9 |
XTryCatchFinallyExpression | XTryCatchFinallyExpressionImpl | try {} catch () finally |
XTypeLiteral | XTypeLiteralImpl | typeof(int) |
XUnaryOperation | XUnaryOperationImpl XUnaryOperationImplCustom | !a |
XVariableDeclaration | XVariableDeclarationImpl XVariableDeclarationImplCustom | var int a=4 |
XWhileExpression | XWhileExpressionImpl | while (a<10){a=a+1} |
from org.eclipse.xtext.?
see: https://github.com/eclipse/?
Grammar rule and Interfaces | Implementing Classes | Example |
XIntLiteral | XIntLiteralImpl | |
XInstanceOfExpression | XInstanceOfExpressionImpl | |
SpecialBlockExpression | SpecialBlockExpressionImpl | |
XAbstractFeatureCall | XAbstractFeatureCallImpl XAbstractFeatureCallImplCustom | |
XAbstractWhileExpression | XAbstractWhileExpressionImpl |
from org.eclipse.xtext.xbase.annotations.XbaseWithAnnotations (src)
Grammar rule and Interfaces | Implementing Classes | Example |
XAnnotation | XAnnotationImpl | |
XAnnotationElementValueBinaryOperation | XAnnotationElementValueBinaryOperationImpl | |
XAnnotationValueArray | XAnnotationValueArrayImpl |
from org.eclipse.xtext.? (src)
Grammar rule and Interfaces | Implementing Classes | Example |
RichString | RichStringImpl | |
RichStringForLoop | RichStringForLoopImpl | |
RichStringIf | RichStringIfImpl | |
RichStringLiteral | RichStringLiteralImpl |
Generator to Map Model to Java Code
- What do IQualifiedNameProvider, TypeReferenceSerializer and so on do?
- How do I reference a type that is defined in the same file?
JvmModelInferrer
Now that we have used the grammar to create a model we now need to generate (compile) code from the model. The generator file starts like this:
class DomainmodelGenerator implements IGenerator { @Inject extension IQualifiedNameProvider @Inject extension TypeReferenceSerializer
class DomainmodelJvmModelInferrer extends AbstractModelInferrer { @Inject extension JvmTypesBuilder @Inject extension IQualifiedNameProvider def dispatch void infer(Entity element, IJvmDeclaredTypeAcceptor acceptor, boolean isPrelinkingPhase) { acceptor.accept(element.toClass(element.fullyQualifiedName)).initializeLater [ documentation = element.documentation for (feature : element.features) { members += feature.toField(feature.name, feature.type) members += feature.toSetter(feature.name, feature.type) members += feature.toGetter(feature.name, feature.type) } ] } } |