package jeql.syntax.operation;
import java.util.Date;
import jeql.api.error.ExecutionException;
import jeql.std.function.StringFunction;
import jeql.syntax.ParseTreeNode;
import jeql.util.ClassUtil;
import jeql.util.TypeUtil;
public class ArithmeticOperation
extends Operation
{
public ArithmeticOperation(ParseTreeNode e1, ParseTreeNode e2, String opStr, int opCode) {
super(e1, e2, opStr, opCode);
}
public Object compute(Object o1, Object o2)
{
Class exprType = getMostGeneralType(o1, o2);
Object v1 = coerce(o1, exprType);
Object v2 = coerce(o2, exprType);
if (exprType == Double.class)
return computeDouble(v1, v2);
if (exprType == Integer.class)
return computeInteger(v1, v2);
if (exprType == String.class)
return computeString(v1, v2);
if (exprType == Date.class)
return computeDate(v1, v2);
throwOpTypeError(opStr, o1.getClass());
return null;
}
private Object computeDouble(Object v1, Object v2)
{
// null safety
if (v1 == null || v2 == null) return null;
double o1 = ((Double) v1).doubleValue();
double o2 = ((Double) v2).doubleValue();
switch (opCode) {
case Operation.MUL: return new Double(o1 * o2);
case Operation.DIV: return new Double(o1 / o2);
case Operation.ADD: return new Double(o1 + o2);
case Operation.SUB: return new Double(o1 - o2);
case Operation.MOD: return new Double(o1 % o2);
}
throwOpTypeError(opStr, Double.class);
return null;
}
private Object computeInteger(Object v1, Object v2)
{
// null safety
if (v1 == null || v2 == null) return null;
int o1 = ((Integer) v1).intValue();
int o2 = ((Integer) v2).intValue();
switch (opCode) {
case Operation.MUL: return new Integer(o1 * o2);
case Operation.DIV: return new Integer(o1 / o2);
case Operation.ADD: return new Integer(o1 + o2);
case Operation.SUB: return new Integer(o1 - o2);
case Operation.MOD: return new Integer(o1 % o2);
}
throwOpTypeError(opStr, Integer.class);
return null;
}
private Object computeString(Object v1, Object v2)
{
String s1 = (String) v1;
switch (opCode) {
case Operation.ADD: {
String s2 = (String) v2;
if (s1 == null) return s2;
if (s2 == null) return s1;
return s1 + s2;
}
case Operation.MUL: {
if (s1 == null) return null;
if (v2 == null) return "";
int count = (int) TypeUtil.toDouble(v2); // a bit of a hack - need toInt()
return StringFunction.repeat(s1, count);
}
// TODO: provide string * integer
}
throwOpTypeError(opStr, s1.getClass());
return null;
}
private Object computeDate(Object v1, Object v2)
{
// null safety
if (v1 == null || v2 == null) return null;
Date o1 = (Date) v1;
Date o2 = (Date) v2;
// TODO: +, - for Dates and numbers
throwOpTypeError(opStr, Date.class);
return null;
}
private void throwOpTypeError(String opStr, Class expectedClass) {
throw new ExecutionException("Operator '" + opStr
+ "' is undefined for type "
+ ClassUtil.classname(expectedClass));
}
}