Marcus Mathioudakis
Marcus Mathioudakis

Reputation: 837

How to generate code using values of declared variables with JvmModelInferrer in xtext?

So I have the following XText grammar:

grammar org.xtext.example.hyrule.HyRule with org.eclipse.xtext.xbase.Xbase

generate hyRule "http://www.xtext.org/example/hyrule/HyRule"


Start:
    rules+=Rule+;

Rule:
    constantDecs+= XVariableDeclaration*
    elementDecs+=elementDec+
    'PAYLOAD' payload=PAYLOAD 'CONSTRAINT' expression= XExpression
;

elementDec:
    variable=FullJvmFormalParameter '=' xpath=XPATH
;




PAYLOAD:
    "Stacons" |  "any" | "sse";



//we override the definition in Xtype.xtext, so that we can have // in Xpaths
terminal SL_COMMENT:
    '#' !('\n' | '\r')* ('\r'? '\n')?;

terminal XPATH: 
    (('//'|'/')('a'..'z'|'A'..'Z'|'_')('a'..'z'|'A'..'Z'|'_'|':'|'0'..'9')*)+

    ;

And I am using a JvmModelInferrer to infer a method for each Rule. The relevant part of the inferrer's code is:

def dispatch void infer(Start start, IJvmDeclaredTypeAcceptor acceptor, boolean isPreIndexingPhase) {

        for (rule: start.rules) {
            acceptor.accept(rule.toClass("Rule" + counter)).initializeLater[
                ...
                // method used to check the rule this class represents 
                members += rule.toMethod("checkRule",rule.newTypeRef('boolean'))[
                    for (e : rule.elementDecs) {
                        parameters += e.variable.toParameter(e.variable.name, e.variable.parameterType)
                    }
                    setStatic(true)
                    body = expression
                ]

What I can't figure out how to do is make the values of the variable decalarations in constantDecs visible to the expression, and more specifically how to generate code for that expression which contains those values. At the moment the variable declarations are in scope in the generated code, but their value is declared to be their name. For example input:

val j = Integer::parseInt('199')
int x = //val/v
PAYLOAD Stacons CONSTRAINT x>j

results in the generated method:

public static boolean checkRule(final int x) {
    int _j = j;
    boolean _greaterThan = (x > _j);
    return _greaterThan;
  }

whereas I would like it to generate the method:

public static boolean checkRule(final int x) {
        int _j = 199;
        boolean _greaterThan = (x > _j);
        return _greaterThan;
      }

My scope provider looks like this:

@Inject
    IJvmModelAssociations associations;

    @Override
    protected IScope createLocalVarScopeForJvmOperation(JvmOperation context, IScope parentScope) {
        parentScope = super.createLocalVarScopeForJvmOperation(context, parentScope);

        // retrieve the AST element associated to the method
        // created by our model inferrer
        EObject sourceElement = associations.getPrimarySourceElement(context);
        if (sourceElement instanceof Rule) {
            Rule rule = (Rule) sourceElement;
            return Scopes.scopeFor(rule.getConstantDecs(), parentScope);
        }

        return parentScope;

I have tried fiddling with the scopes and the inferrer but to no avail. Is what I'm trying to do possible?

Upvotes: 0

Views: 1085

Answers (1)

Sebastian Zarnekow
Sebastian Zarnekow

Reputation: 6729

There are basically two options:

  1. You could infer constants in the JvmType for each constantDecl in your model.
  2. You have to customize all sorts of things like scoping, code generation and validation in order to inline the constant values into your expression.

Since I find (2) way too bad, I suggest to go for (1).

acceptor.accept(rule.toClass("Rule" + counter)).initializeLater[
  ..
  for(varDecl : constantDecs) {
    switch(varDecl) {
     XVariableDeclaration: members += varDecl.toField(varDecl.name, varDecl.type) [
       initializer = varDecl.right
       setStatic(true)
       setFinal(true)
     ]
    }

  }
  // method used to check the rule this class represents 
  members += rule.toMethod("checkRule",rule.newTypeRef('boolean'))[
    for (e : rule.elementDecs) {
      parameters += e.variable.toParameter(e.variable.name, e.variable.parameterType) 
    }
    setStatic(true)
    body = expression
  ]
]

Upvotes: 2

Related Questions