Top

Using Xbase Expressions

Xbase is an expression language that can be embedded into Xtext languages. Its syntax is close to Java, but it additionally offers type inferrence, closures, a powerful switch expression and a lot more. For details on this expression langugae, please consult the reference documentation and the Xbase tutorial. Xbase ships with an interpreter and a compiler that produces Java code. Thus, it is easy to add executable behavior to your DSLs. As Xbase integrates tightly with Java, there is usually no additional code needed to run your DSL as part of a Java application.

Making Your Grammar Refer To Xbase

If you want to refer to EClassifiers from the Xbase model, you need to import it first. The same holds for the common types model:

import "http://www.eclipse.org/xtext/xbase/Xbase" as xbase

Now identify the location in your grammar, where you want references to Java types and Xbase expression to appear and call the appropriate rules of the super grammar. Have a look at the domainmodel example: An Operation's parameters are JvmFormalParamters, its return type refers to a Java type and its body is an XBlockExpression, so its parser rule reads as

Operation:
    'op' name=ValidID '(' 
    (params+=JvmFormalParameter (',' params+=JvmFormalParameter)*)? ')' 
    ':' type=JvmTypeReference 
        body=XBlockExpression;

If you're unsure which entry point to choose for your expressions, consider the XBlockExpression.

To integrate Operations in our models, we have to call this rule. We copy the previous Feature to a new rule Property and let Feature become the supertype of Property and Operation:

Feature:
    Property | Operation
;
 
Property:
  name = ID ':' type = JvmTypeReference
;

Note: You will have to adapt the IJvmModelInferrer (src) to these changes, i.e. rename Feature to Property and create a JvmOperation (src) for each Operation. We leave that as an exercise :-)

If you're done with that, everything should work out of the box. Since each expression is now logically contained in an operation (src), all the scoping rules and visibility constrains can be deduced from that. The framework will take care of the fact, that the operation's parameters are reachable in the operation body or that the declared return types are validated against the actual expression types.

There is yet another aspect of the JVM model that can be explored. Since all the coarse grained concepts such as types (src) and operations (src) were already derived from the model, a generator can be used to serialize that information to Java code. There is no need to write a code generator on top of that. The JvmModelGenerator (src) knows how to generate operation bodies properly.

Using the Xbase Interpreter

Sometimes it is more convenient to interpret a model that uses Xbase than to generate code from it. Xbase ships with the XbaseInterpreter (src) which makes this rather easy.

An interpreter is essentially an external visitor, that recursively processes a model based on the model element's types. By now you should be aware that polymorphic dispatch is exactly the technology needed here. In the XbaseInterpreter (src), the dispatch method is called _evaluate<SomeDescription> and takes three parameters, e.g.

protected Object _evaluateBlockExpression(XBlockExpression literal, 
                                          IEvaluationContext context, 
                                          CancelIndicator indicator)

The IEvaluationContext keeps the state of the running application, i.e. the local variables and their values. Additionally, it can be forked, thus allowing to shadow the elements of the original context. Here is an example code snippet how to call the XbaseInterpreter (src):

@Inject private XbaseInterpreter xbaseInterpreter;

@Inject private Provider<IEvaluationContext> contextProvider;

...
public Object evaluate(XExpression expression, Object thisElement) {
    IEvaluationContext evaluationContext = contextProvider.get();
    evaluationContext.newValue(XbaseScopeProvider.THIS, thisElement);
    IEvaluationResult result = xbaseInterpreter.evaluate(expression,     
        evaluationContext, CancelIndicator.NullImpl);
    if (result.getException() != null) {
        // handle exception
    } 
    return result.getResult();
}