package org.geogebra.common.kernel.arithmetic;
import org.geogebra.common.kernel.Kernel;
import org.geogebra.common.kernel.geos.GeoCurveCartesian;
import org.geogebra.common.kernel.kernelND.GeoCurveCartesianND;
import org.geogebra.common.plugin.Operation;
/**
* Possible value types of expression after evaluation
*
*/
public enum ValueType {
/**
* Has no algebraic properties, eg a button
*/
VOID,
/**
* cannot be determined (eg a variable)
*/
UNKNOWN,
/**
* Bool
*/
BOOLEAN,
/**
* Number
*/
NUMBER,
/**
* 2D point or vector (cartesian or polar)
*/
NONCOMPLEX2D,
/**
* Complex point or vector
*/
COMPLEX,
/**
* 3D point or vector
*/
VECTOR3D,
/**
* Equation
*/
EQUATION,
/**
* Text
*/
TEXT,
/**
* List of objects
*/
LIST,
/**
* Function R^n -> R
*/
FUNCTION,
/**
* Function R^n -> R^2
*/
PARAMETRIC2D,
/**
* Function R^n -> R^3
*/
PARAMETRIC3D;
/**
* @param op
* operation
* @param left
* left argument
* @param right
* right argument
* @param res
* resulution to keep list depth if we have a list
* @return expected type
*/
public static ValueType resolve(Operation op, ExpressionValue left,
ExpressionValue right, Resolution res) {
ValueType ret = doResolve(op, left, right);
if (ret == ValueType.LIST && left != null) {
res.setListDepth(left.getListDepth());
}
return ret;
}
private static ValueType doResolve(Operation op, ExpressionValue left,
ExpressionValue right) {
switch (op) {
case PLUS:
if (right.evaluatesToText()) {
return ValueType.TEXT;
}
return plusMinusType(left, right);
case MINUS:
return plusMinusType(left, right);
case MULTIPLY:
ValueType rightType = right.getValueType();
if (rightType == ValueType.TEXT || rightType == ValueType.LIST) {
return rightType;
}
// scalar product
if ((rightType == ValueType.NONCOMPLEX2D
|| rightType == ValueType.VECTOR3D)
&& (left.getValueType() == ValueType.NONCOMPLEX2D
|| left.getValueType() == ValueType.VECTOR3D)) {
return ValueType.NUMBER;
}
// number * vector
if (rightType == ValueType.NONCOMPLEX2D
|| rightType == ValueType.VECTOR3D) {
return rightType;
}
return left.getValueType();
case DIVIDE:
if (right.evaluatesToList()) {
return ValueType.LIST;
}
return left.getValueType();
case $VAR_COL:
case $VAR_ROW:
case $VAR_ROW_COL:
case NO_OPERATION:
return left.getValueType();
case SGN:
case ABS:
case ALT:
case ARG:
return ValueType.LIST.check(left, ValueType.NUMBER);
case ARBCOMPLEX:
return ValueType.COMPLEX;
case CONJUGATE:
return ValueType.LIST.check(left, ValueType.COMPLEX);
case LOGB:
case NROOT:
case ROUND2:
case ARCTAN2:
return ValueType.COMPLEX.check(left, ValueType.LIST.check(left,
ValueType.LIST.check(right, ValueType.NUMBER)));
case ACOSH:
case ASINH:
case ARCCOS:
case ARCSIN:
case ARCSIND:
case ARCTAN:
case ATANH:
case ROUND:
case SI:
case SIN:
case SINH:
case SQRT:
case SQRT_SHORT:
case BETA:
case BETA_INCOMPLETE:
case BETA_INCOMPLETE_REGULARIZED:
case CBRT:
case CI:
case CEIL:
case COS:
case COSH:
case COT:
case COTH:
case SEC:
case SECH:
case CSC:
case CSCH:
case EI:
case TAN:
case TANH:
case ERF:
case EXP:
case FACTORIAL:
case FLOOR:
case FRACTIONAL_PART:
case GAMMA:
case GAMMA_INCOMPLETE:
case GAMMA_INCOMPLETE_REGULARIZED:
case LOG:
case LOG10:
case LOG2:
return ValueType.COMPLEX.check(left,
ValueType.LIST.check(left, ValueType.NUMBER));
case FUNCTION:
return ValueType.COMPLEX.check(right,
ValueType.LIST.check(right, ValueType.NUMBER));
case FUNCTION_NVAR:
case FREEHAND:
case DATA:
case ARBCONST:
case ARBINT:
return ValueType.NUMBER;
case DIFF:
case DERIVATIVE:
return ValueType.FUNCTION;
case IF:
return right.getValueType();
case IF_ELSE:
return right.getValueType();
case IF_LIST:
if (right instanceof ListValue && ((ListValue) right).size() > 0) {
return ((ListValue) right).getListElement(0).getValueType();
}
break;
case INTEGRAL:
break;
case MATRIXTOVECTOR:
if (!(left.unwrap() instanceof MyList)) {
return left.getValueType();
}
MyList list = (MyList) left.unwrap();
return list.size() == 3 ? ValueType.VECTOR3D
: ValueType.NONCOMPLEX2D;
case MULTIPLY_OR_FUNCTION:
break;
case IS_ELEMENT_OF:
case IS_SUBSET_OF:
case IS_SUBSET_OF_STRICT:
case NOT_EQUAL:
case EQUAL_BOOLEAN:
case ELEMENT_OF:
return ValueType.BOOLEAN;
case NOT:
return ValueType.LIST.check(left, ValueType.BOOLEAN);
case OR:
case AND:
case IMPLICATION:
case AND_INTERVAL:
case PARALLEL:
case PERPENDICULAR:
case LESS:
case LESS_EQUAL:
case GREATER:
case GREATER_EQUAL:
return ValueType.LIST.check(left,
ValueType.LIST.check(right, ValueType.BOOLEAN));
case POLYGAMMA:
break;
case POWER:
if ((left.getValueType() == ValueType.NONCOMPLEX2D
|| left.getValueType() == ValueType.VECTOR3D)
&& Kernel.isEqual(2, right.evaluateDouble())) {
return ValueType.NUMBER;
}
return left.getValueType();
case PSI:
break;
case SET_DIFFERENCE:
return ValueType.LIST;
case SUBSTITUTION:
break;
case SUM:
break;
case SEQUENCE:
return ValueType.LIST;
case VECTORPRODUCT:
return ValueType.VECTOR3D.check(left, ValueType.NUMBER);
case VEC_FUNCTION:
if (left.unwrap() instanceof GeoCurveCartesian) {
return ValueType.NONCOMPLEX2D;
}
if (left.unwrap() instanceof GeoCurveCartesianND) {
return ValueType.VECTOR3D;
}
break;
case XCOORD:
case YCOORD:
case ZCOORD:
case REAL:
case IMAGINARY:
case RANDOM:
return ValueType.NUMBER;
case ZETA:
break;
}
return ValueType.NUMBER;
}
private static ValueType plusMinusType(ExpressionValue left,
ExpressionValue right) {
if (right.evaluatesToList()) {
return ValueType.LIST;
}
if (right.getValueType() == ValueType.VECTOR3D
|| left.getValueType() == ValueType.VECTOR3D) {
return ValueType.VECTOR3D;
}
if (right.getValueType() == ValueType.NONCOMPLEX2D
|| left.getValueType() == ValueType.NONCOMPLEX2D) {
return ValueType.NONCOMPLEX2D;
}
return left.getValueType();
}
private ValueType check(ExpressionValue arg, ValueType fallback) {
return arg.getValueType() == this ? this : fallback;
}
}