Hello,
I have a grammar for mathematical expressions (formula) generated from my Ecore model.
When serializing a certain expression from EObject it uses the wrong ParserRule which results in a wrong formula string.
I cutted it down to what is relevant.
Here is the grammar:
grammar org.xtext.example.math.Math with org.eclipse.xtext.common.Terminals
import "http://www.eclipse.org/emf/2002/Ecore" as ecore
generate math "http://www.eclipse.org/example/math/Math"
FormulaDefinition returns FormulaDefinition:
{FormulaDefinition}
formulaToken=FormulaToken?;
FormulaToken returns FormulaToken:
Prio1Operation;
Prio1Operation returns FormulaToken: // like +
InfixOperand ({FormulaOperator.childToken+=current} code=InfixOperatorPrio1
childToken+=InfixOperand)*;
InfixOperand returns FormulaToken:
'(' FormulaToken ')' | FormulaConstant | PrefixOperation2Operands;
PrefixOperation2Operands returns FormulaOperator:
code=PrefixOperator2Operands '(' childToken+=FormulaToken ',' childToken+=FormulaToken ')';
InfixOperatorPrio1 returns ecore::EString:
('+');
PrefixOperator2Operands returns ecore::EString:
'MAX';
FormulaConstant returns FormulaConstant:
value=INT;
Here is the test which fails:
@Test
def void testTwoArgPrefixOperation() {
val op = MathFactory.eINSTANCE.createFormulaOperator
op.code = 'MAX'
var arg1 = MathFactory.eINSTANCE.createFormulaConstant
arg1.value = 5
op.childToken += arg1
var arg2 = MathFactory.eINSTANCE.createFormulaConstant
arg2.value = 8
op.childToken += arg2
var formulaDef = MathFactory.eINSTANCE.createFormulaDefinition()
formulaDef.formulaToken = op
val formula = serializer.serialize(formulaDef)
assertEquals("MAX ( 5 , 8 )", formula)
}
The serializer returns instead of expected
Xtext is assuming an Prio1Operation instead of PrefixOperator2Operands.
BTW: I formula expressing 5 + 8 is working as expected!
I was already able to solve by either
1.) Create new EMF-Objects which inherit from FormulaOperator. These would be FormulaOperatorInfix and FormulaOperatorPrefix and adapt the test accordingly.
grammar org.xtext.example.math.Math with org.eclipse.xtext.common.Terminals
import "http://www.eclipse.org/emf/2002/Ecore" as ecore
generate math "http://www.eclipse.org/example/math/Math"
FormulaDefinition returns FormulaDefinition:
{FormulaDefinition}
formulaToken=FormulaToken?;
FormulaToken returns FormulaToken:
Prio1Operation;
Prio1Operation returns FormulaToken: // like +
InfixOperand ({FormulaOperatorInfix.childToken+=current} code=InfixOperatorPrio1
childToken+=InfixOperand)*;
InfixOperand returns FormulaToken:
'(' FormulaToken ')' | FormulaConstant | PrefixOperation2Operands;
PrefixOperation2Operands returns FormulaOperatorPrefix:
code=PrefixOperator2Operands '(' childToken+=FormulaToken ',' childToken+=FormulaToken ')';
InfixOperatorPrio1 returns ecore::EString:
('+');
PrefixOperator2Operands returns ecore::EString:
'MAX';
FormulaConstant returns FormulaConstant:
value=INT;
2.) Instead of pointing to rule InfixOperatorPrio1 and PrefixOperator2Operands use the strings directly in Prio1Operation and PrefixOperation2Operands in respect. So the grammar would look like this
grammar org.xtext.example.math.Math with org.eclipse.xtext.common.Terminals
import "http://www.eclipse.org/emf/2002/Ecore" as ecore
generate math "http://www.eclipse.org/example/math/Math"
FormulaDefinition returns FormulaDefinition:
{FormulaDefinition}
formulaToken=FormulaToken?;
FormulaToken returns FormulaToken:
Prio1Operation;
Prio1Operation returns FormulaToken: // like +
InfixOperand ({FormulaOperator.childToken+=current} code=('+')
childToken+=InfixOperand)*;
InfixOperand returns FormulaToken:
'(' FormulaToken ')' | FormulaConstant | PrefixOperation2Operands;
PrefixOperation2Operands returns FormulaOperator:
code='MAX' '(' childToken+=FormulaToken ',' childToken+=FormulaToken ')';
FormulaConstant returns FormulaConstant:
value=INT;
But actally option 1.) I don't want to go.
For option 2.) I wonder why I need to do that. It decreases usability and reuse. I though that there is no difference whether I write a String directly or reference a parser rule (which indeed returns a unique return).
Is there any other solution or way I can force Xtext to kind of "follow" the rules containing the operators.
Thanks, Marcus