package edu.washington.escience.myria.expression; import java.util.List; import java.util.Objects; import com.fasterxml.jackson.annotation.JsonProperty; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import edu.washington.escience.myria.Type; import edu.washington.escience.myria.expression.evaluate.ExpressionOperatorParameter; /** * An ExpressionOperator with one child. */ public abstract class UnaryExpression extends ExpressionOperator { /***/ private static final long serialVersionUID = 1L; /** * This is not really unused, it's used automagically by Jackson deserialization. */ protected UnaryExpression() { operand = null; } /** * The child expression. */ @JsonProperty private final ExpressionOperator operand; /** * @param operand the operand. */ protected UnaryExpression(final ExpressionOperator operand) { this.operand = operand; } /** * @return the child expression. */ public final ExpressionOperator getOperand() { return operand; } @Override public List<ExpressionOperator> getChildren() { ImmutableList.Builder<ExpressionOperator> children = ImmutableList.builder(); return children.add(getOperand()).build(); } /** * Returns the function call unary string: functionName + '(' + child + ")". E.g, for {@link SqrtExpression}, * <code>functionName</code> is <code>"Math.sqrt"</code>. * * @param functionName the string representation of the Java function name. * @param parameters parameters that are needed to determine the output type * @return the Java string for this operator. */ protected final String getFunctionCallUnaryString( final String functionName, final ExpressionOperatorParameter parameters) { return new StringBuilder(functionName) .append('(') .append(operand.getJavaString(parameters)) .append(')') .toString(); } /** * Returns the function call unary string: child + functionName. E.g, for {@link ToUpperCaseExpression}, * <code>functionName</code> is <code>".toUpperCase()"</code>. * * @param functionName the string representation of the Java function name. * @param parameters parameters that are needed to determine the output type * @return the Java string for this operator. */ protected final String getDotFunctionCallUnaryString( final String functionName, final ExpressionOperatorParameter parameters) { return new StringBuilder(operand.getJavaString(parameters)).append(functionName).toString(); } /** * A function that could be used as the default hash code for a unary expression. * * @return a hash of (getClass().getCanonicalName(), operand). */ protected final int defaultHashCode() { return Objects.hash(getClass().getCanonicalName(), operand); } @Override public int hashCode() { return defaultHashCode(); } @Override public boolean equals(final Object other) { if (other == null || !getClass().equals(other.getClass())) { return false; } UnaryExpression otherExp = (UnaryExpression) other; return Objects.equals(operand, otherExp.operand); } /** * A function that could be used as the default type checker for a unary expression where the operand must be numeric. * * @param parameters parameters that are needed to determine the output type * @return the default numeric type, based on the type of the operand and Java type precedence. */ protected Type checkAndReturnDefaultNumericType(final ExpressionOperatorParameter parameters) { Type operandType = getOperand().getOutputType(parameters); ImmutableList<Type> validTypes = ImmutableList.of(Type.DOUBLE_TYPE, Type.FLOAT_TYPE, Type.LONG_TYPE, Type.INT_TYPE); Preconditions.checkArgument( validTypes.contains(operandType), "%s cannot handle operand [%s] of Type %s", getClass().getSimpleName(), getOperand(), operandType); return operandType; } /** * A function that could be used as the default type checker for a unary expression where the operand must be of a * specified type. * * @param expectedType expected type of operand * @param parameters parameters that are needed to determine the output type */ protected final void checkOperandType( final Type expectedType, final ExpressionOperatorParameter parameters) { Type type = getOperand().getOutputType(parameters); Preconditions.checkArgument( type == expectedType, "%s cannot handle operand [%s] of Type %s", getClass().getSimpleName(), getOperand()); } /** * A function that could be used as the default type checker for a unary expression where the operand must be boolean. * * @param parameters parameters that are needed to determine the output type */ protected void checkBooleanType(final ExpressionOperatorParameter parameters) { checkOperandType(Type.BOOLEAN_TYPE, parameters); } }