package oclastview.visitors.arithSimp;
import java.util.List;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EEnumLiteral;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EOperation;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EParameter;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.ocl.Environment;
import org.eclipse.ocl.ecore.CallOperationAction;
import org.eclipse.ocl.ecore.Constraint;
import org.eclipse.ocl.ecore.EcoreEnvironmentFactory;
import org.eclipse.ocl.ecore.SendSignalAction;
import org.eclipse.ocl.expressions.ExpressionsFactory;
import org.eclipse.ocl.expressions.IntegerLiteralExp;
import org.eclipse.ocl.expressions.NumericLiteralExp;
import org.eclipse.ocl.expressions.OCLExpression;
import org.eclipse.ocl.expressions.OperationCallExp;
import org.eclipse.ocl.expressions.RealLiteralExp;
import org.eclipse.ocl.utilities.PredefinedType;
import org.eclipse.ocl.utilities.UtilitiesPackage;
import org.eclipse.ocl.utilities.Visitable;
import org.eclipse.uml2.uml.Class;
import org.eclipse.uml2.uml.Classifier;
import org.eclipse.uml2.uml.EnumerationLiteral;
import org.eclipse.uml2.uml.Operation;
import org.eclipse.uml2.uml.Package;
import org.eclipse.uml2.uml.Parameter;
import org.eclipse.uml2.uml.Property;
import org.eclipse.uml2.uml.State;
public class OCLArithSimplifier<C, O, P, EL, PM, S, COA, SSA, CT> extends OCLCloner<C, O, P, EL, PM, S, COA, SSA, CT> {
protected OCLArithSimplifier(Environment env) {
super(env);
}
public static OCLArithSimplifier<EClassifier, EOperation, EStructuralFeature, EEnumLiteral, EParameter, EObject, CallOperationAction, SendSignalAction, Constraint> getEcoreVersion() {
Environment<EPackage, EClassifier, EOperation, EStructuralFeature, EEnumLiteral, EParameter, EObject, CallOperationAction, SendSignalAction, Constraint, EClass, EObject> auxEnv = EcoreEnvironmentFactory.INSTANCE
.createEnvironment();
OCLArithSimplifier<EClassifier, EOperation, EStructuralFeature, EEnumLiteral, EParameter, EObject, CallOperationAction, SendSignalAction, Constraint> res = new OCLArithSimplifier<EClassifier, EOperation, EStructuralFeature, EEnumLiteral, EParameter, EObject, CallOperationAction, SendSignalAction, Constraint>(
auxEnv);
return res;
}
public static OCLArithSimplifier<Classifier, Operation, Property, EnumerationLiteral, Parameter, State, CallOperationAction, SendSignalAction, org.eclipse.uml2.uml.Constraint> getUML2Version() {
org.eclipse.ocl.uml.OCL umlocl = org.eclipse.ocl.uml.OCL.newInstance();
Environment<Package, Classifier, Operation, Property, EnumerationLiteral, Parameter, State, org.eclipse.uml2.uml.CallOperationAction, org.eclipse.uml2.uml.SendSignalAction, org.eclipse.uml2.uml.Constraint, Class, EObject> auxEnv = umlocl
.getEnvironment();
OCLArithSimplifier<Classifier, Operation, Property, EnumerationLiteral, Parameter, State, CallOperationAction, SendSignalAction, org.eclipse.uml2.uml.Constraint> res = new OCLArithSimplifier(
auxEnv);
return res;
}
@Override
protected Visitable handleOperationCallExp(
OperationCallExp<C, O> callExp, Visitable sourceResult,
List<Visitable> argumentResults) {
int opcode = callExp.getOperationCode();
if (!isArithmeticOp(callExp)) {
return super.handleOperationCallExp(callExp, sourceResult, argumentResults);
}
OCLExpression<C> newSource = (OCLExpression<C>) sourceResult;
OCLExpression<C> newArg = (OCLExpression<C>) argumentResults.get(0);
if (!(newSource instanceof NumericLiteralExp)
|| !(newArg instanceof NumericLiteralExp)) {
return super.handleOperationCallExp(callExp, sourceResult, argumentResults);
}
/*
* if one of source or arg is not IntegerLiteralExp then promotion to
* Real takes place
*/
if (newSource instanceof IntegerLiteralExp
&& newArg instanceof IntegerLiteralExp) {
Integer intSource = ((IntegerLiteralExp<C>) newSource).getIntegerSymbol();
Integer intArg = ((IntegerLiteralExp<C>) newArg).getIntegerSymbol();
OCLExpression<C> res = simplifyInteger(opcode, intSource, intArg, ((IntegerLiteralExp<C>) newSource).getType());
return res;
}
/* promote to Double, compute, and return */
Double dSource = null;
Double dArg = null;
C type = null;
if (newSource instanceof IntegerLiteralExp) {
dSource = ((IntegerLiteralExp<C>) newSource).getIntegerSymbol()
.doubleValue();
} else {
dSource = ((RealLiteralExp<C>) newSource).getRealSymbol().doubleValue();
type = ((RealLiteralExp<C>) newSource).getType();
}
if (newArg instanceof IntegerLiteralExp) {
dArg = ((IntegerLiteralExp<C>) newArg).getIntegerSymbol().doubleValue();
} else {
dArg = ((RealLiteralExp<C>) newArg).getRealSymbol().doubleValue();
type = ((RealLiteralExp<C>) newArg).getType();
}
OCLExpression<C> res = simplifyDouble(opcode, dSource, dArg, type);
return res;
}
/**
*
* Returns either a RealLiteralExp or InvalidLiteralExp
* @param type
*
*/
private OCLExpression<C> simplifyDouble(int opcode, Double source, Double arg, C type) {
RealLiteralExp<C> res = ExpressionsFactory.eINSTANCE
.createRealLiteralExp();
if ((opcode == PredefinedType.PLUS) || (opcode == PredefinedType.MINUS)
|| (opcode == PredefinedType.TIMES)) {
switch (opcode) {
case PredefinedType.PLUS:
res.setRealSymbol(source + arg);
break;
case PredefinedType.MINUS:
res.setRealSymbol(source - arg);
break;
case PredefinedType.TIMES:
res.setRealSymbol(source * arg);
break;
}
return res;
}
// denominator of 0 means undefined
double num = source;
double denom = arg;
Double d = (denom == 0.0) ? null : new Double(num / denom);
if (d == null) {
return ExpressionsFactory.eINSTANCE.createInvalidLiteralExp();
}
res.setRealSymbol(d);
res.setType(type);
return res;
}
/**
*
* Returns either an IntegerLiteralExp, RealLiteralExp, or InvalidLiteralExp
* @param type
*
*/
private OCLExpression<C> simplifyInteger(int opcode, int intSource, int intArg, C type) {
if ((opcode == PredefinedType.PLUS) || (opcode == PredefinedType.MINUS)
|| (opcode == PredefinedType.TIMES)) {
IntegerLiteralExp<C> res = ExpressionsFactory.eINSTANCE
.createIntegerLiteralExp();
switch (opcode) {
case PredefinedType.PLUS:
res.setIntegerSymbol(intSource + intArg);
break;
case PredefinedType.MINUS:
res.setIntegerSymbol(intSource - intArg);
break;
case PredefinedType.TIMES:
res.setIntegerSymbol(intSource * intArg);
break;
}
res.setType(type);
return res;
}
// denominator of 0 means undefined
double num = intSource;
double denom = intArg;
Double d = (denom == 0.0) ? null : new Double(num / denom);
if (d == null) {
return ExpressionsFactory.eINSTANCE.createInvalidLiteralExp();
}
if (opcode == PredefinedType.DIVIDE) {
RealLiteralExp<C> rle = ExpressionsFactory.eINSTANCE
.createRealLiteralExp();
rle.setRealSymbol(d);
return rle;
}
if (opcode == PredefinedType.DIV) {
IntegerLiteralExp<C> res = ExpressionsFactory.eINSTANCE
.createIntegerLiteralExp();
res.setIntegerSymbol(intSource / intArg);
return res;
}
// we won't get to this point, just to make the compiler happy
return null;
}
private boolean isArithmeticOp(OperationCallExp<C, O> oc) {
int opcode = oc.getOperationCode();
boolean res = (opcode == PredefinedType.PLUS)
|| (opcode == PredefinedType.MINUS)
|| (opcode == PredefinedType.TIMES)
|| (opcode == PredefinedType.DIVIDE)
|| (opcode == PredefinedType.DIV);
return res;
}
}
|