javagrammarxtextebnf

Xtext grammar variable definition/reference


A [any type]Realisation grammar rule initialization should be a value or a reference to a predefined variable. For Integer it looks similar like what you know from java:

public int i = 3;

Why does the following grammar throw an exception?

Integer returns ecore::ELong:
  (Plus|Minus)? INT;

IntegerRealisation:
  {Integer} Integer | 
  ref=[Integer];

Exception:

Caused by: java.io.IOException: Generated EMF Model incomplete: The context 'IntegerRealisation' is not valid for type 'Integer'
Recommended contexts for type 'Integer': 
Other valid contexts for type 'Integer': .... The context 'IntegerRealisation' is valid for types: Integer, IntegerRealisation

Why does the first and the last line of the same error disagree each other?

What's going wrong here?


Solution

  • You try to reference an Integer literal instead of any other Integer typed variable. To implement s.th. like

    public int i = 5; // 5 is a value
    public int j = i; // i reference to a predefined variable
    

    your grammar definition should look like

    VariableDeclaration:
        modifiers+=Modifier* type=Type name=ID ('=' value=VariableValue)? ';';
    
    VariableValue:
        TypedLiteral | VariableReference;
    
    TypedLiteral:
        IntegerLiteral | ...;
    
    IntegerLiteral:
        value=INTVAL;
    
    terminal INTVAL returns ecore::ELong:
        (Plus|Minus)? INT;
    
    VariableReference:
        ref=[VariableDeclaration|QualifiedName];
    

    As you can see, it starts with the a rule to define a variable. This variable has a name attribute which is really important for the reference implementation later. The actual value allocation is optional (because I would do it like this!) Important at this point is the abstract rule VariableValue which will model either a literal (aka. constant value) or a reference to any other variable.

    If you want to reference to any predefined variable you will use the other variables name, but not its value. Because of this reason we will also need the VariableReference which defines that we reference any other variable (in front of the pipe operator) by a (qualified) name (beind the pipe operator |).

    To ensure type safety you have to implement the yourdsl.validation.YourDslValidator class to check whether the literal is compatible with the type and whether the type of a referenced variable is compatible to the type.

    Edit: I optimized the grammar a little bit. The first version was a little bit unclear.

    Answering your additional questions:

    What is the return type of VariableValue?

    VariableValue itself is the common (but abstract) return type of all possible values. It is like java.lang.Number which is the super type of java.lang.Integer, java.lang.Double, ...

    The problem here is that the word type itself is ambiguous here. The type of the value will be int (IntegerLiteral extends TypedLiteral extends VariableValue) but the type of the AST node is either IntegerLiteral or VariableReference.

    To determine the value type of a VariableReference you have to look into the value attribute of the referenced VariableDeclaration (((VariableReference)vd1.getValue()).getRef().getValue()). There will never be an EString value type!

    To set a value to the VariableDeclaration.value attribute you need either an IntegerLiteral (most explicit TypedLiteral) or a VariableReference.