/*
* Copyright (c) 2009-2011, IETR/INSA of Rennes
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of the IETR/INSA of Rennes nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
* WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
package net.sf.orcc.cal.services;
import java.util.Iterator;
import java.util.List;
import net.sf.orcc.cache.Cache;
import net.sf.orcc.cache.CacheManager;
import net.sf.orcc.cache.CachePackage;
import net.sf.orcc.cal.cal.AstExpression;
import net.sf.orcc.cal.cal.ExpressionBinary;
import net.sf.orcc.cal.cal.ExpressionBoolean;
import net.sf.orcc.cal.cal.ExpressionCall;
import net.sf.orcc.cal.cal.ExpressionElsif;
import net.sf.orcc.cal.cal.ExpressionFloat;
import net.sf.orcc.cal.cal.ExpressionIf;
import net.sf.orcc.cal.cal.ExpressionIndex;
import net.sf.orcc.cal.cal.ExpressionInteger;
import net.sf.orcc.cal.cal.ExpressionList;
import net.sf.orcc.cal.cal.ExpressionString;
import net.sf.orcc.cal.cal.ExpressionUnary;
import net.sf.orcc.cal.cal.ExpressionVariable;
import net.sf.orcc.cal.cal.Function;
import net.sf.orcc.cal.cal.Generator;
import net.sf.orcc.cal.cal.Variable;
import net.sf.orcc.cal.cal.util.CalSwitch;
import net.sf.orcc.ir.ExprBool;
import net.sf.orcc.ir.ExprInt;
import net.sf.orcc.ir.ExprList;
import net.sf.orcc.ir.Expression;
import net.sf.orcc.ir.IrFactory;
import net.sf.orcc.ir.OpBinary;
import net.sf.orcc.ir.OpUnary;
import net.sf.orcc.ir.util.ValueUtil;
import net.sf.orcc.util.OrccUtil;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.util.EcoreUtil;
/**
* This class defines an expression evaluator.
*
* @author Matthieu Wipliez
*
*/
public class Evaluator extends CalSwitch<Expression> {
/**
* Returns the integer value associated with the given object using its URI.
*
* @param eObject
* an AST node
* @return the integer value associated with the given object
*/
public static int getIntValue(EObject eObject) {
Expression value = getValue(eObject);
if (value != null && value.isExprInt()) {
ExprInt intExpr = (ExprInt) value;
if (!intExpr.isLong()) {
return intExpr.getIntValue();
}
}
// evaluated ok, but not as an integer
return -1;
}
/**
* Returns the value associated with the given object using its URI.
*
* @param eObject
* an AST node
* @return the value associated with the given object
*/
public static Expression getValue(EObject eObject) {
if (eObject instanceof Variable) {
return CacheManager.instance.getOrCompute(eObject, new Evaluator(),
CachePackage.eINSTANCE.getCache_ExpressionsMap());
} else {
return new Evaluator().doSwitch(eObject);
}
}
private static void setValue(EObject eObject, Expression value) {
Resource resource = eObject.eResource();
if (resource != null) {
Cache cache = CacheManager.instance.getCache(resource);
cache.getExpressionsMap().put(eObject, value);
}
}
@Override
public Expression caseExpressionBinary(ExpressionBinary expression) {
OpBinary op = OpBinary.getOperator(expression.getOperator());
Expression e1 = getValue(expression.getLeft());
Expression e2 = getValue(expression.getRight());
Object val1 = ValueUtil.getValue(e1);
Object val2 = ValueUtil.getValue(e2);
if (val1 == null || val2 == null) {
return null;
}
Object result = ValueUtil.compute(val1, op, val2);
return ValueUtil.getExpression(result);
}
@Override
public Expression caseExpressionBoolean(ExpressionBoolean expression) {
return IrFactory.eINSTANCE.createExprBool(expression.isValue());
}
@Override
public Expression caseExpressionCall(ExpressionCall expression) {
Function function = expression.getFunction();
if (expression.getParameters().size() != function.getParameters()
.size()) {
return null;
}
// set the value of parameters
Iterator<Variable> itFormal = function.getParameters().iterator();
Iterator<AstExpression> itActual = expression.getParameters()
.iterator();
while (itFormal.hasNext() && itActual.hasNext()) {
Variable paramV = itFormal.next();
AstExpression paramE = itActual.next();
setValue(paramV, doSwitch(paramE));
}
// set the value of variables
for (Variable variable : function.getVariables()) {
setValue(variable, doSwitch(variable.getValue()));
}
// do not cache value because it is influenced by variables
return doSwitch(function.getExpression());
}
@Override
public Expression caseExpressionFloat(ExpressionFloat expression) {
return IrFactory.eINSTANCE.createExprFloat(expression.getValue());
}
@Override
public Expression caseExpressionIf(ExpressionIf expression) {
Expression condition = getValue(expression.getCondition());
if (condition != null && condition.isExprBool()) {
if (((ExprBool) condition).isValue()) {
return getValue(expression.getThen());
} else {
for (ExpressionElsif elsif : expression.getElsifs()) {
condition = getValue(elsif.getCondition());
if (condition != null && condition.isExprBool()) {
if (((ExprBool) condition).isValue()) {
return getValue(elsif.getThen());
}
}
}
return getValue(expression.getElse());
}
} else {
return null;
}
}
@Override
public Expression caseExpressionIndex(ExpressionIndex expression) {
Variable variable = expression.getSource().getVariable();
Expression value = getValue(variable.getValue());
if (value == null) {
return null;
}
List<AstExpression> indexes = expression.getIndexes();
for (AstExpression index : indexes) {
Expression indexValue = getValue(index);
if (value != null && value.isExprList()) {
ExprList list = (ExprList) value;
if (indexValue != null && indexValue.isExprInt()) {
ExprInt intExpr = (ExprInt) indexValue;
if (!intExpr.isLong()) {
try {
value = list.get(intExpr.getIntValue());
} catch (IndexOutOfBoundsException e) {
e.printStackTrace();
}
}
}
}
}
return EcoreUtil.copy(value);
}
@Override
public Expression caseExpressionInteger(ExpressionInteger expression) {
return IrFactory.eINSTANCE.createExprInt(expression.getValue());
}
@Override
public Expression caseExpressionList(ExpressionList expression) {
List<AstExpression> expressions = expression.getExpressions();
List<Generator> generators = expression.getGenerators();
ExprList list = IrFactory.eINSTANCE.createExprList();
computeList(list, expressions, generators, 0);
return list;
}
@Override
public Expression caseExpressionString(ExpressionString expression) {
return IrFactory.eINSTANCE.createExprString(OrccUtil
.getEscapedString(expression.getValue()));
}
@Override
public Expression caseExpressionUnary(ExpressionUnary expression) {
OpUnary op = OpUnary.getOperator(expression.getUnaryOperator());
Expression expr = getValue(expression.getExpression());
if (expr == null) {
return null;
}
Object value = ValueUtil.getValue(expr);
Object result = ValueUtil.compute(op, value);
return ValueUtil.getExpression(result);
}
@Override
public Expression caseExpressionVariable(ExpressionVariable expression) {
Variable variable = expression.getValue().getVariable();
Expression value = getValue(variable);
return EcoreUtil.copy(value);
}
@Override
public Expression caseVariable(Variable variable) {
AstExpression expression = variable.getValue();
if (expression == null) {
return null;
}
Expression value = getValue(expression);
return value;
}
private void computeList(ExprList list, List<AstExpression> expressions,
List<Generator> generators, int index) {
if (index < generators.size()) {
Generator generator = generators.get(index);
int lower = getIntValue(generator.getLower());
int higher = getIntValue(generator.getHigher());
for (int i = lower; i <= higher; i++) {
ExprInt value = IrFactory.eINSTANCE.createExprInt(i);
setValue(generator.getVariable(), value);
computeList(list, expressions, generators, index + 1);
}
setValue(generator.getVariable(), null);
} else {
for (AstExpression subExpression : expressions) {
// do not cache value because it is influenced by variables
Expression value = doSwitch(subExpression);
if (value != null) {
list.getValue().add(EcoreUtil.copy(value));
}
}
}
}
@Override
public Expression doSwitch(EObject eObject) {
if (eObject == null) {
return null;
}
return super.doSwitch(eObject);
}
}