How to generate code for a XExpression subtype?

214 views Asked by At

I have a simple DSL that should generate async code for expressions (this is the simplest example I could come up with to illustrate my point). I just added to the scripting example an new async statement:

grammar org.xtext.scripting.Scripting with org.eclipse.xtext.xbase.Xbase

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

Script returns xbase::XBlockExpression:
    {Script}
    (expressions+=XExpressionOrVarDeclaration ';'?)*;

XExpression returns xbase::XExpression:
    super | Async
;

Async:
    'async' expression=XExpression
;

The idea would be that the async code is executed in another thread.

My question is, how can I generate code for the Async.expression using the ScriptingJvmModelInferrer?

In the simplest case I would just wrap the code from the Async.expression like this?

    AsyncRunner.exec(new Runnable() {
        @Override
        public void run() {
            // the Async.expression would end up here
        }
    })

Where is the hook to do that?

2

There are 2 answers

0
Christian Dietrich On

If you extend Xbase you ususally don't apapt the JvmModelInferrer for Compilation but you extend XbaseTypeComputer and XbaseCompiler.doInternalToJavaStatement/internalToConvertedExpression (depending on what you actually introduce)

0
Michael_Scharf On

You have to make 3 changes:

  1. Extend the compiler to deal with your language. The key point is to handle the Async expression.

    class ScriptingCompiler extends XbaseCompiler {
    
        override protected doInternalToJavaStatement(XExpression expr, ITreeAppendable it, boolean isReferenced) {
            switch expr {
                Async : {
                    newLine
                    append('''
                        AsyncRunner.exec(new Runnable() {
                          @Override
                          public void run() {''')
                    expr.expression.doInternalToJavaStatement(it, false)
                    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) 
        }
    }
    
  2. The type of the expression has to be specified

    class ScriptingTypeComputer extends XbaseWithAnnotationsTypeComputer {
    
        override computeTypes(XExpression expression, ITypeComputationState state) {
            if(expression instanceof Async) {
                super.computeTypes(expression.expression, state);
            } else {
                super.computeTypes(expression, state)
            }
        }
    }
    
  3. Both extensions have to be injected:

    class ScriptingRuntimeModule extends AbstractScriptingRuntimeModule {
        def Class<? extends XbaseCompiler> bindXbaseCompiler() {
            return ScriptingCompiler
        }
    
        def Class<? extends ITypeComputer> bindITypeComputer() {
            return ScriptingTypeComputer
        }
    }