Eclipse Xbase

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:

directory

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. xbase

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 XExpressionImplany valid statement, expression or value
XAssignmentXAssignmentImpl
XAssignmentImplCustom
a=3
XBinaryOperationXBinaryOperationImpl
XBinaryOperationImplCustom
a && b
XBlockExpressionXBlockExpressionImpltrue
XBooleanLiteralXBooleanLiteralImpltrue
XCastedExpressionXCastedExpressionImpl2 as int
XClosureXClosureImpl[a | b]
XConstructorCallXConstructorCallImpl
XConstructorCallImplCustom
new mytype
XDoWhileExpressionXDoWhileExpressionImpldo x=x+1 while (x<10)
XFeatureCallXFeatureCallImpl
XFeatureCallImplCustom
 
XForLoopExpressionXForLoopExpressionImplfor(value:values) myblock
XIfExpressionXIfExpressionImplif(x==2)myblock
XMemberFeatureCallXMemberFeatureCallImpl
XMemberFeatureCallImplCustom
 
XNullLiteralXNullLiteralImplnull
XReturnExpressionXReturnExpressionImplreturn 3
XStringLiteralXStringLiteralImpl"my text"
XSwitchExpressionXSwitchExpressionImpl
XSwitchExpressionImplCustom
switch(a) (case 2:x=3)
XThrowExpressionXThrowExpressionImplthrow 9
XTryCatchFinallyExpressionXTryCatchFinallyExpressionImpltry {} catch () finally
XTypeLiteralXTypeLiteralImpltypeof(int)
XUnaryOperationXUnaryOperationImpl
XUnaryOperationImplCustom
!a
XVariableDeclarationXVariableDeclarationImpl
XVariableDeclarationImplCustom
var int a=4
XWhileExpressionXWhileExpressionImplwhile (a<10){a=a+1}

from org.eclipse.xtext.?

see: https://github.com/eclipse/?

Grammar rule and Interfaces Implementing Classes Example
XIntLiteralXIntLiteralImpl 
XInstanceOfExpressionXInstanceOfExpressionImpl 
SpecialBlockExpressionSpecialBlockExpressionImpl 
XAbstractFeatureCallXAbstractFeatureCallImpl
XAbstractFeatureCallImplCustom
 
XAbstractWhileExpressionXAbstractWhileExpressionImpl 

from org.eclipse.xtext.xbase.annotations.XbaseWithAnnotations (src)

Grammar rule and Interfaces Implementing Classes Example
XAnnotationXAnnotationImpl 
XAnnotationElementValueBinaryOperationXAnnotationElementValueBinaryOperationImpl  
XAnnotationValueArrayXAnnotationValueArrayImpl 

from org.eclipse.xtext.? (src)

Grammar rule and Interfaces Implementing Classes Example
RichStringRichStringImpl 
RichStringForLoopRichStringForLoopImpl 
RichStringIfRichStringIfImpl 
RichStringLiteralRichStringLiteralImpl 

Generator to Map Model to Java Code

to java

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)
       }
    ]
  }
}

Extending XbaseCompiler

Extending XbaseCompiler allows us to customise expressions or statements

_toJavaExpression(XBlockExpression expr, ITreeAppendable b)
_toJavaExpression(XCastedExpression expr, ITreeAppendable b)
_toJavaExpression(XClosure call, ITreeAppendable b)
_toJavaExpression(XConstructorCall expr, ITreeAppendable b)
_toJavaExpression(XIfExpression expr, ITreeAppendable b)
_toJavaExpression(XInstanceOfExpression expr, ITreeAppendable b)
_toJavaExpression(XSwitchExpression expr, ITreeAppendable b)
_toJavaExpression(XTryCatchFinallyExpression expr, ITreeAppendable b)
_toJavaStatement(XBlockExpression expr, ITreeAppendable b, boolean isReferenced)
_toJavaStatement(XCastedExpression expr, ITreeAppendable b, boolean isReferenced)
_toJavaStatement(XClosure closure, ITreeAppendable b, boolean isReferenced)
_toJavaStatement(XConstructorCall expr, ITreeAppendable b, boolean isReferenced)
_toJavaStatement(XDoWhileExpression expr, ITreeAppendable b, boolean isReferenced)
_toJavaStatement(XForLoopExpression expr, ITreeAppendable b, boolean isReferenced)
_toJavaStatement(XIfExpression expr, ITreeAppendable b, boolean isReferenced)
_toJavaStatement(XInstanceOfExpression expr, ITreeAppendable b, boolean isReferenced)
_toJavaStatement(XReturnExpression expr, ITreeAppendable b, boolean isReferenced)
_toJavaStatement(XSwitchExpression expr, ITreeAppendable b, boolean isReferenced)
_toJavaStatement(XThrowExpression expr, ITreeAppendable b, boolean isReferenced)
_toJavaStatement(XTryCatchFinallyExpression expr, ITreeAppendable outerAppendable, boolean isReferenced)
_toJavaStatement(XVariableDeclaration varDeclaration, ITreeAppendable b, boolean isReferenced)
_toJavaStatement(XWhileExpression expr, ITreeAppendable b, boolean isReferenced) 

 

class TemplateCompiler extends XbaseCompiler {

override protected doInternalToJavaStatement(XExpression expr, ITreeAppendable it, boolean isReferenced) {
switch expr {
RichString : {
val name = declareVariable(expr, '_appendable')
newLine
append('''
StringBuilder «name» = new StringBuilder();
''')
for (nestedExpression : expr.expressions) {
nestedExpression.internalToJavaStatement(it, true)
newLine
append('''«name».append(org.eclipse.xtext.xbase.lib.ObjectExtensions.operator_elvis(''')
nestedExpression.internalToJavaExpression(it)
append(',""));')
}
}

RichStringForLoop : {
expr.forExpression.internalToJavaStatement(it, true)
val paramType = typeProvider.getTypeForIdentifiable(expr.declaredParam)
val name = declareVariable(expr, '_forLoopResult')
newLine
append('''
StringBuilder «name» = new StringBuilder();
for (final ''')
serialize(paramType, expr, it);
append(''' «declareVariable(expr.declaredParam, makeJavaIdentifier(expr.declaredParam.name))» : ''')
internalToJavaExpression(expr.forExpression, it)
append(") {").increaseIndentation
expr.eachExpression.internalToJavaStatement(it, true)
newLine
append('''«name».append(''')
expr.eachExpression.internalToJavaExpression(it)
append(');')
decreaseIndentation.newLine.append("}")
}

default :
super.doInternalToJavaStatement(expr, it, isReferenced)
}
}

override protected internalToConvertedExpression(XExpression obj, ITreeAppendable it) {
if (hasName(obj))
append(getName(obj))
else
super.internalToConvertedExpression(obj, it)
}

}

Extending XbaseTypeProvider

Allows us to map types . For instance 3.2 to java.lang.Double

@Singleton
class TemplateTypeProvider extends XbaseTypeProvider {

@Inject TypeReferences typeReferences

def dispatch type(RichString string, JvmTypeReference typeRef, boolean isRawTypes) {
typeReferences.getTypeForName(typeof(StringBuilder), string)
}

def dispatch type(RichStringForLoop string, JvmTypeReference typeRef, boolean isRawTypes) {
typeReferences.getTypeForName(typeof(StringBuilder), string)
}

def dispatch expectedType(RichStringForLoop container, EReference reference, int index, boolean rawType) {
if (reference == XFOR_LOOP_EXPRESSION__EACH_EXPRESSION)
typeReferences.getTypeForName(typeof(Object), container)
else
super._expectedType(container,reference,index, rawType)
}
}
eclipse.buildId=M20120914-1800
java.version=1.7.0_07
java.vendor=Oracle Corporation
BootLoader constants: OS=linux, ARCH=x86_64, WS=gtk, NL=en_GB
Framework arguments: -product org.eclipse.platform.ide
Command-line arguments: -product org.eclipse.platform.ide -data /home/martin/workspace/../runtime-EclipseXtext -dev
file:/home/martin/workspace/.metadata/.plugins/org.eclipse.pde.core/Launch Runtime Eclipse/dev.properties -os linux -ws gtk -arch x86_64
Error
Tue Oct 09 16:39:48 BST 2012
Conflicting handlers for org.eclipse.ui.edit.text.contentAssist.proposals: {org.eclipse.xtext.ui.editor.handler.ContentAssistHandler} vs {ActionHandler(org.eclipse.ui.texteditor.ContentAssistAction@663328d8)}

Helper Files

import org.eclipse.xtext.service.SingletonBinding;
import org.eclipse.xtext.xbase.scoping.featurecalls.StaticImplicitMethodsFeatureForTypeProvider;
import org.eclipse.xtext.xbase.scoping.featurecalls.StaticImplicitMethodsFeatureForTypeProvider.ExtensionClassNameProvider;
import org.xtext.builddsl.scoping.AllImportsAreStaticFeatureProvider;
import org.xtext.builddsl.scoping.BuildDSLExtensionClassNameProvider;
import org.xtext.builddsl.validation.BuildDSLValidator;

/**
* Use this class to register components to be used at runtime / without the Equinox extension registry.
*/
public class BuildDSLRuntimeModule extends org.xtext.builddsl.AbstractBuildDSLRuntimeModule {

@SingletonBinding(eager = true)
public Class<? extends BuildDSLValidator> bindValidator() {
return BuildDSLValidator.class;
}

public Class<? extends ExtensionClassNameProvider> bindExtensionClassNameProvider() {
return BuildDSLExtensionClassNameProvider.class;
}

public Class<? extends StaticImplicitMethodsFeatureForTypeProvider> bindStaticImplicitMethodsFeatureForTypeProvider() {
return AllImportsAreStaticFeatureProvider.class;
}

}

 

/**
* Initialization support for running Xtext languages
* without equinox extension registry
*/
public class BuildDSLStandaloneSetup extends BuildDSLStandaloneSetupGenerated{

public static void doSetup() {
new BuildDSLStandaloneSetup().createInjectorAndDoEMFRegistration();
}
}


metadata block
see also:
Correspondence about this page

This site may have errors. Don't use for critical systems.

Copyright (c) 1998-2023 Martin John Baker - All rights reserved - privacy policy.