1

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?

Michael_Scharf
  • 33,154
  • 22
  • 74
  • 95
  • I think I have found an example in https://eclipse.org/Xtext/documentation/207_template.html (Template Language) see the section *Extending the Compiler* – Michael_Scharf Jan 04 '17 at 19:51

2 Answers2

1

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
        }
    }
    
Michael_Scharf
  • 33,154
  • 22
  • 74
  • 95
0

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)

Christian Dietrich
  • 11,778
  • 4
  • 24
  • 32