package com.sap.furcas.parser.tcs.scenario;
import java.io.File;
import org.eclipse.emf.ecore.EObject;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import com.sap.furcas.parsergenerator.TCSSyntaxContainerBean;
import com.sap.furcas.runtime.parser.ModelParsingResult;
import com.sap.furcas.runtime.parser.ParserFacade;
import com.sap.furcas.runtime.parser.testbase.EMFParsingHelper;
import com.sap.furcas.runtime.parser.testbase.GeneratedParserBasedTest;
import com.sap.furcas.runtime.parser.testbase.GeneratedParserTestConfiguration;
import com.sap.furcas.test.fixture.ScenarioFixtureData;
/**
* A simple expression language with a built-in calculator.
*
* Introductory courses to attribute grammars often feature
* the idea of an expression language that is evaluated
* during parsing. The evaluation is performed bottom-up and
* solely based on synthesized attributes.
*
* The same is realized here with the help of OCL and property-inits.
* After parsing, the "calculatedValue" property holds the value of
* an (sub)-expression.
*
* @author Stephan Erb
*
*/
public class TestSynthesizedAttributeGrammar extends GeneratedParserBasedTest {
private static final String LANGUAGE = "ExpressionWithSynthesizedAttributes";
private static final File TCS = ScenarioFixtureData.EXPRESSION_WITH_SYNTHESIZED_ATTRIBUTE_TCS;
private static final File[] METAMODELS = { ScenarioFixtureData.EXPRESSION_WITH_SYNTHESIZED_ATTRIBUTE_METAMODEL };
private static final String PACKAGE_URI = ScenarioFixtureData.EXPRESSION_WITH_SYNTHESIZED_ATTRIBUTE_METAMODEL_PACKAGE_URI;
private static EMFParsingHelper parsingHelper;
@BeforeClass
public static void setupParser() throws Exception {
GeneratedParserTestConfiguration testConfig = new GeneratedParserTestConfiguration(LANGUAGE, TCS, METAMODELS);
TCSSyntaxContainerBean syntaxBean = parseSyntax(testConfig);
ParserFacade facade = generateParserForLanguage(syntaxBean, testConfig, new ClassLookupImpl());
parsingHelper = new EMFParsingHelper(facade, testConfig, PACKAGE_URI);
}
@Test
public void testSimpleCaluclations() throws Exception {
assertEquals(1, calculate("1"));
assertEquals(2, calculate("1+1"));
assertEquals(15, calculate("1+2+3+4+5"));
assertEquals(25, calculate("5*5"));
assertEquals(27, calculate("3*3*3"));
assertEquals(4, calculate("8/2"));
assertEquals(1, calculate("1/1/1"));
}
@Test
public void testParentheses() throws Exception {
assertEquals(1, calculate("(1)"));
assertEquals(2, calculate("(1+1)"));
assertEquals(6, calculate("1+(2+3)"));
assertEquals(1, calculate("(((1)))"));
}
@Test
public void testNegation() throws Exception {
assertEquals(-1, calculate("-1"));
assertEquals(-2, calculate("-1*2"));
assertEquals(2, calculate("-1*-2"));
assertEquals(-10, calculate("2*-5"));
assertEquals(-10, calculate("-2*5"));
assertEquals(1, calculate("-(-1)"));
}
@Test
public void testDoubleNegation() throws Exception {
assertEquals(1, calculate("--1"));
assertEquals(1, calculate("-(-1)"));
}
@Test
public void testPreceedenceSimple() throws Exception {
assertEquals(9, calculate("(1+2)*3"));
assertEquals(7, calculate("1+(2*3)"));
assertEquals(7, calculate("1+2*3"));
}
@Test
public void testPreceedenceComplex() throws Exception {
// Test indivudually
assertEquals(20, calculate("2*10"));
assertEquals(-10, calculate("2*-5"));
assertEquals(0, calculate("10+-10"));
// Test in total
assertEquals(0, calculate("2*10+2*-5+-10"));
}
@Test
public void testPreceedenceLeftAssociative() throws Exception {
// Division is a left-associative operator.
// If associativity is mistaken as 8/(4/2),
// the result would be 4 which is of course wrong
assertEquals(1, calculate("8/4/2"));
}
private double calculate(String expressionToCalculate) throws Exception {
ModelParsingResult result = parsingHelper.parseString(expressionToCalculate, /*expected errors*/ 0);
EObject exprStatement = (EObject) result.getParsedModelElement();
EObject expression = (EObject) exprStatement.eGet(exprStatement.eClass().getEStructuralFeature("expression"));
return (Double) expression.eGet(expression.eClass().getEStructuralFeature("calculatedValue"));
}
private void assertEquals(int expected, Double result) {
Assert.assertEquals(expected, result, 0.001);
}
}