co.streamx.fluent.extree.expression.Expression Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ex-tree Show documentation
Show all versions of ex-tree Show documentation
Build AST from the bytecode
The newest version!
package co.streamx.fluent.extree.expression;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.function.Supplier;
import lombok.Getter;
import lombok.NonNull;
/**
* Provides the base class from which the classes that represent expression tree
* nodes are derived. It also contains static factory methods to create the
* various node types.
*
*
*/
@Getter
public abstract class Expression {
private final int expressionType;
private final Class> resultType;
static private final HashMap> _boxers;
static private final HashMap> _unboxers;
static {
HashMap> unboxers = new HashMap>();
try {
unboxers.put(Boolean.class.getMethod("booleanValue"), Boolean.TYPE);
unboxers.put(Byte.class.getMethod("byteValue"), Byte.TYPE);
unboxers.put(Character.class.getMethod("charValue"), Character.TYPE);
unboxers.put(Double.class.getMethod("doubleValue"), Double.TYPE);
unboxers.put(Float.class.getMethod("floatValue"), Float.TYPE);
unboxers.put(Integer.class.getMethod("intValue"), Integer.TYPE);
unboxers.put(Long.class.getMethod("longValue"), Long.TYPE);
unboxers.put(Short.class.getMethod("shortValue"), Short.TYPE);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
HashMap> boxers = new HashMap>();
try {
boxers.put(Boolean.class.getMethod("valueOf", Boolean.TYPE), Boolean.class);
boxers.put(Byte.class.getMethod("valueOf", Byte.TYPE), Byte.class);
boxers.put(Character.class.getMethod("valueOf", Character.TYPE), Character.class);
boxers.put(Double.class.getMethod("valueOf", Double.TYPE), Double.class);
boxers.put(Float.class.getMethod("valueOf", Float.TYPE), Float.class);
boxers.put(Integer.class.getMethod("valueOf", Integer.TYPE), Integer.class);
boxers.put(Long.class.getMethod("valueOf", Long.TYPE), Long.class);
boxers.put(Short.class.getMethod("valueOf", Short.TYPE), Short.class);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
_unboxers = unboxers;
_boxers = boxers;
}
private boolean isComparable() {
return Comparable.class.isAssignableFrom(getResultType());
}
private boolean isNumeric() {
return isNumeric(getResultType());
}
private boolean isIntegral() {
return isIntegral(getResultType());
}
private static boolean isNumeric(Class> type) {
if (isIntegral(type))
return true;
if (type.isPrimitive())
return type == Float.TYPE || type == Double.TYPE;
return type == Float.class || type == Double.class || type == BigDecimal.class;
}
private static boolean isIntegral(Class> type) {
if (!type.isPrimitive())
return type == Byte.class || type == Integer.class || type == Long.class || type == Short.class
|| type == BigInteger.class;
return type == Byte.TYPE || type == Integer.TYPE || type == Long.TYPE || type == Short.TYPE;
}
private boolean isBoolean() {
return isBoolean(getResultType());
}
private boolean isIntBooleanTrue() {
return getResultType() == Integer.TYPE && getExpressionType() == ExpressionType.Constant
&& (int) ((ConstantExpression) this).getValue() == 1;
}
private boolean isIntBooleanFalse() {
return getResultType() == Integer.TYPE && getExpressionType() == ExpressionType.Constant
&& (int) ((ConstantExpression) this).getValue() == 0;
}
private static boolean isBoolean(Class> type) {
return type == Boolean.TYPE || type == Boolean.class;
}
private static Expression stripQuotesAndConverts(Expression e) {
while (e.getExpressionType() == ExpressionType.Convert)
e = ((UnaryExpression) e).getFirst();
return e;
}
/**
* Initializes a new instance of the {@link Expression} class.
*
* @param expressionType The {@link ExpressionType} to set as the node type.
* @param resultType The {@link Class} to set as the type of the expression
* that this Expression represents.
*/
protected Expression(int expressionType, @NonNull Class> resultType) {
this.expressionType = expressionType;
this.resultType = resultType;
}
/**
* Creates a {@link BinaryExpression} that represents an arithmetic addition
* operation that does not have overflow checking.
*
* @param first An {@link Expression} to set the getFirst() method equal to.
* @param second An {@link Expression} to set the getSecond() method equal to.
* @return A {@link BinaryExpression} that has the {@link ExpressionType}
* property equal to Add and the getFirst() and getSecond() methods set
* to the specified values.
*/
public static BinaryExpression add(Expression first,
Expression second) {
return createNumeric(ExpressionType.Add, first, second);
}
/**
* Creates a {@link BinaryExpression} that represents an arithmetic division
* operation.
*
* @param first An {@link Expression} to set the getFirst() method equal to.
* @param second An {@link Expression} to set the getSecond() method equal to.
* @return A {@link BinaryExpression} that has the {@link ExpressionType}
* property equal to Divide and the getFirst() and getSecond() methods
* set to the specified values.
*/
public static BinaryExpression divide(Expression first,
Expression second) {
return createNumeric(ExpressionType.Divide, first, second);
}
/**
* Creates a {@link BinaryExpression} that represents an arithmetic subtract
* operation.
*
* @param first An {@link Expression} to set the getFirst() method equal to.
* @param second An {@link Expression} to set the getSecond() method equal to.
* @return A {@link BinaryExpression} that has the {@link ExpressionType}
* property equal to Subtract and the getFirst() and getSecond() methods
* set to the specified values.
*/
public static BinaryExpression subtract(Expression first,
Expression second) {
return createNumeric(ExpressionType.Subtract, first, second);
}
/**
* Creates a {@link BinaryExpression} that represents an arithmetic multiply
* operation.
*
* @param first An {@link Expression} to set the getFirst() method equal to.
* @param second An {@link Expression} to set the getSecond() method equal to.
* @return A {@link BinaryExpression} that has the {@link ExpressionType}
* property equal to Multiply and the getFirst() and getSecond() methods
* set to the specified values.
*/
public static BinaryExpression multiply(Expression first,
Expression second) {
return createNumeric(ExpressionType.Multiply, first, second);
}
/**
* Creates a {@link BinaryExpression} that represents an arithmetic remainder
* operation.
*
* @param first An {@link Expression} to set the getFirst() method equal to.
* @param second An {@link Expression} to set the getSecond() method equal to.
* @return A {@link BinaryExpression} that has the {@link ExpressionType}
* property equal to Modulo and the getFirst() and getSecond() methods
* set to the specified values.
*/
public static BinaryExpression modulo(Expression first,
Expression second) {
return createNumeric(ExpressionType.Modulo, first, second);
}
/**
* Creates a {@link BinaryExpression} that represents a "greater than" numeric
* comparison.
*
* @param first An {@link Expression} to set the getFirst() method equal to.
* @param second An {@link Expression} to set the getSecond() method equal to.
* @return A {@link BinaryExpression} that has the {@link ExpressionType}
* property equal to GreaterThan and the getFirst() and getSecond()
* methods set to the specified values.
*/
public static BinaryExpression greaterThan(Expression first,
Expression second) {
return createNumericComparison(ExpressionType.GreaterThan, first, second);
}
/**
* Creates a {@link BinaryExpression} that represents a "greater than or equal"
* numeric comparison.
*
* @param first An {@link Expression} to set the getFirst() method equal to.
* @param second An {@link Expression} to set the getSecond() method equal to.
* @return A {@link BinaryExpression} that has the {@link ExpressionType}
* property equal to GreaterThanOrEqual and the getFirst() and
* getSecond() methods set to the specified values.
*/
public static BinaryExpression greaterThanOrEqual(Expression first,
Expression second) {
return createNumericComparison(ExpressionType.GreaterThanOrEqual, first, second);
}
/**
* Creates a {@link BinaryExpression} that represents a "less than" numeric
* comparison.
*
* @param first An {@link Expression} to set the getFirst() method equal to.
* @param second An {@link Expression} to set the getSecond() method equal to.
* @return A {@link BinaryExpression} that has the {@link ExpressionType}
* property equal to LessThan and the getFirst() and getSecond() methods
* set to the specified values.
*/
public static BinaryExpression lessThan(Expression first,
Expression second) {
return createNumericComparison(ExpressionType.LessThan, first, second);
}
/**
* Creates a {@link BinaryExpression} that represents a "less than or equal"
* numeric comparison.
*
* @param first An {@link Expression} to set the getFirst() method equal to.
* @param second An {@link Expression} to set the getSecond() method equal to.
* @return A {@link BinaryExpression} that has the {@link ExpressionType}
* property equal to LessThanOrEqual and the getFirst() and getSecond()
* methods set to the specified values.
*/
public static BinaryExpression lessThanOrEqual(Expression first,
Expression second) {
return createNumericComparison(ExpressionType.LessThanOrEqual, first, second);
}
private static BinaryExpression createNumericComparison(int expressionType,
Expression first,
Expression second) {
if (!first.isComparable() || !second.isComparable()) {
if (!first.isNumeric())
throw new IllegalArgumentException(first.getResultType().toString());
if (!second.isNumeric())
throw new IllegalArgumentException(second.getResultType().toString());
}
return new BinaryExpression(expressionType, Boolean.TYPE, null, first, second);
}
private static BinaryExpression createNumeric(int expressionType,
Expression first,
Expression second) {
boolean fnumeric = first.isNumeric();
boolean snumeric = second.isNumeric();
if (!fnumeric || !snumeric) {
if (!fnumeric && !snumeric)
throw new IllegalArgumentException("At least one argument must be numeric, got: "
+ first.getResultType().toString() + "," + second.getResultType().toString());
if (!fnumeric)
first = TypeConverter.convert(first, second.getResultType());
else
second = TypeConverter.convert(second, first.getResultType());
}
return new BinaryExpression(expressionType, first.getResultType(), null, first, second);
}
private static BinaryExpression createIntegral(int expressionType,
Expression first,
Expression second) {
if (!first.isIntegral())
throw new IllegalArgumentException(first.getResultType().toString());
if (!second.isIntegral())
throw new IllegalArgumentException(second.getResultType().toString());
return new BinaryExpression(expressionType, first.getResultType(), null, first, second);
}
/**
* Creates a {@link BinaryExpression} that represents an arithmetic left-shift
* operation.
*
* @param first An {@link Expression} to set the getFirst() method equal to.
* @param second An {@link Expression} to set the getSecond() method equal to.
* @return A {@link BinaryExpression} that has the {@link ExpressionType}
* property equal to LeftShift and the getFirst() and getSecond()
* methods set to the specified values.
*/
public static BinaryExpression leftShift(Expression first,
Expression second) {
return createIntegral(ExpressionType.LeftShift, first, second);
}
/**
* Creates a {@link BinaryExpression} that represents an arithmetic right-shift
* operation.
*
* @param first An {@link Expression} to set the getFirst() method equal to.
* @param second An {@link Expression} to set the getSecond() method equal to.
* @return A {@link BinaryExpression} that has the {@link ExpressionType}
* property equal to RightShift and the getFirst() and getSecond()
* methods set to the specified values.
*/
public static BinaryExpression rightShift(Expression first,
Expression second) {
return createIntegral(ExpressionType.RightShift, first, second);
}
/**
* Creates a {@link BinaryExpression} that represents a coalescing operation.
*
* @param first An {@link Expression} to set the getFirst() method equal to.
* @param second An {@link Expression} to set the getSecond() method equal to.
* @return A {@link BinaryExpression} that has the {@link ExpressionType}
* property equal to Coalesce and the getFirst() and getSecond() methods
* set to the specified values.
*/
public static BinaryExpression coalesce(Expression first,
Expression second) {
if (first.getResultType().isPrimitive())
throw new IllegalArgumentException(first.getResultType().toString());
if (second.getResultType().isPrimitive())
throw new IllegalArgumentException(second.getResultType().toString());
return new BinaryExpression(ExpressionType.Coalesce, first.getResultType(), null, first, second);
}
/**
* Creates a {@link Expression} that represents an equality comparison. The
* expression will be simplified if one of parameters is constant
* {@link Boolean}.
*
* @param first An {@link Expression} to set the getFirst() method equal to.
* @param second An {@link Expression} to set the getSecond() method equal to.
* @return A {@link BinaryExpression} that has the {@link ExpressionType} method
* equal to Equal and the getFirst() and getSecond() methods set to the
* specified values, or one of the parameters if they one of them is
* constant {@link Boolean}.
*/
public static Expression equal(Expression first,
Expression second) {
// if (first.getResultType() != second.getResultType())
// throw new IllegalArgumentException(
// first.getResultType().toString() + " != " + second.getResultType().toString());
return createBooleanExpression(ExpressionType.Equal, first, second);
}
/**
* Creates a {@link Expression} that represents an inequality comparison. The
* expression will be simplified if one of parameters is constant
* {@link Boolean}.
*
* @param first An {@link Expression} to set the getFirst() method equal to.
* @param second An {@link Expression} to set the getSecond() method equal to.
* @return A {@link BinaryExpression} that has the {@link ExpressionType} method
* equal to Equal and the getFirst() and getSecond() methods set to the
* specified values, or one of the parameters if they one of them is
* constant {@link Boolean}.
*/
public static Expression notEqual(Expression first,
Expression second) {
// if (first.getResultType() != second.getResultType())
// throw new IllegalArgumentException(
// first.getResultType().toString() + " != " + second.getResultType().toString());
return createBooleanExpression(ExpressionType.NotEqual, first, second);
}
/**
* Creates a {@link Expression} that represents a conditional AND operation that
* evaluates the second operand only if it has to. The expression will be
* simplified if one of parameters is constant.
*
* @param first An {@link Expression} to set the getFirst() method equal to.
* @param second An {@link Expression} to set the getSecond() method equal to.
* @return A {@link BinaryExpression} that has the {@link ExpressionType} method
* equal to LogicalAnd and the getFirst() and getSecond() methods set to
* the specified values, or one of the parameters if they one of them is
* constant.
*/
public static Expression logicalAnd(Expression first,
Expression second) {
if (!first.isBoolean())
throw new IllegalArgumentException(first.getResultType().toString());
if (!second.isBoolean())
throw new IllegalArgumentException(second.getResultType().toString());
return createBooleanExpression(ExpressionType.LogicalAnd, first, second);
}
/**
* Creates a {@link BinaryExpression} that represents a bitwise AND operation.
*
* @param first An {@link Expression} to set the getFirst() method equal to.
* @param second An {@link Expression} to set the getSecond() method equal to.
* @return A {@link BinaryExpression} that has the {@link ExpressionType} method
* equal to BitwiseAnd and the getFirst() and getSecond() properties set
* to the specified values.
*/
public static BinaryExpression bitwiseAnd(Expression first,
Expression second) {
return createIntegral(ExpressionType.BitwiseAnd, first, second);
}
/**
* Creates a {@link Expression} that represents a conditional OR operation that
* evaluates the second operand only if it has to. The expression will be
* simplified if one of parameters is constant.
*
* @param first An {@link Expression} to set the getFirst() method equal to.
* @param second An {@link Expression} to set the getSecond() method equal to.
* @return A {@link BinaryExpression} that has the {@link ExpressionType} method
* equal to LogicalOr and the getFirst() and getSecond() methods set to
* the specified values, or one of the parameters if they one of them is
* constant.
*/
public static Expression logicalOr(Expression first,
Expression second) {
if (!first.isBoolean())
throw new IllegalArgumentException(first.getResultType().toString());
if (!second.isBoolean())
throw new IllegalArgumentException(second.getResultType().toString());
return createBooleanExpression(ExpressionType.LogicalOr, first, second);
}
/**
* Creates a {@link BinaryExpression} that represents a bitwise OR operation.
*
* @param first An {@link Expression} to set the getFirst() method equal to.
* @param second An {@link Expression} to set the getSecond() method equal to.
* @return A {@link BinaryExpression} that has the {@link ExpressionType} method
* equal to BitwiseOr and the getFirst() and getSecond() properties set
* to the specified values.
*/
public static BinaryExpression bitwiseOr(Expression first,
Expression second) {
return createIntegral(ExpressionType.BitwiseOr, first, second);
}
/**
* Creates a {@link BinaryExpression} that represents a bitwise XOR operation,
* or {@link UnaryExpression} that represents a bitwise NOT in case the second
* parameter equals to -1.
*
* @param first An {@link Expression} to set the getFirst() method equal to.
* @param second An {@link Expression} to set the getSecond() method equal to.
* @return A {@link BinaryExpression} that has the {@link ExpressionType} method
* equal to ExclusiveOr and the getFirst() and getSecond() properties
* set to the specified values, or {@link UnaryExpression} that
* represents a bitwise NOT in case the second parameter equals to -1.
*/
public static Expression exclusiveOr(Expression first,
Expression second) {
if (second.getExpressionType() == ExpressionType.Constant) {
ConstantExpression csecond = (ConstantExpression) second;
if (isIntegral(csecond.getResultType())) {
if (((Number) csecond.getValue()).intValue() == -1)
return bitwiseNot(first);
}
}
return createIntegral(ExpressionType.ExclusiveOr, first, second);
}
/**
* Creates a {@link UnaryExpression} that represents getting the length of an
* array.
*
* @param array An {@link Expression} to set the getFirst method equal to.
* @return A {@link UnaryExpression} that has the {@link ExpressionType}
* property equal to ArrayLength and the getFirst() method set to array.
*/
public static UnaryExpression arrayLength(Expression array) {
if (!array.getResultType().isArray())
throw new IllegalArgumentException(array.getResultType().toString());
return new UnaryExpression(ExpressionType.ArrayLength, Integer.TYPE, array);
}
/**
* Creates a {@link BinaryExpression} that represents applying an array index
* operator to an array.
*
* @param array An Expression to set the getFirst method equal to.
* @param index An Expression to set the getSecond method equal to.
* @return A {@link BinaryExpression} that has the {@link ExpressionType} method
* equal to ArrayIndex and the getFirst() and getSecond() methods set to
* the specified values.
*/
public static BinaryExpression arrayIndex(Expression array,
Expression index) {
Class> arrayType = array.getResultType();
if (!arrayType.isArray())
throw new IllegalArgumentException(arrayType.toString());
if (index.getResultType() != Integer.TYPE)
throw new IllegalArgumentException("index:" + index.getResultType().toString());
return new BinaryExpression(ExpressionType.ArrayIndex, arrayType.getComponentType(), null, array, index);
}
/**
* Creates a {@link UnaryExpression} that represents a conversion operation, or
* 'e' if its ResultType equals to 'to'.
*
* @param e An Expression to set the getFirst() method equal to.
* @param to The {@link Class} to set as the type of the expression that this
* Expression represents.
* @return A {@link UnaryExpression} that has the {@link ExpressionType}
* property equal to Convert, or 'e'.
*/
public static Expression convert(Expression e,
Class> to) {
if (to.isAssignableFrom(e.getResultType()))
return e;
return new UnaryExpression(ExpressionType.Convert, to, e);
}
/**
* Creates a {@link ConstantExpression} that has the getValue() method set to
* the specified value and resultType is assignable from its type.
*
* @param value An Object to set the getValue() method equal to.
* @param resultType The {@link Class} to set as the type of the expression that
* this Expression represents.
* @return A {@link ConstantExpression} that has the {@link ExpressionType}
* property equal to Constant and the getValue() method set to the
* specified value.
*/
public static ConstantExpression constant(Object value,
Class> resultType) {
return new ConstantExpression(resultType, value);
}
/**
* Creates a {@link ConstantExpression} that has the getValue() method set to
* the specified value.
*
* @param value An Object to set the getValue() method equal to.
* @return A {@link ConstantExpression} that has the {@link ExpressionType}
* property equal to Constant and the getValue() method set to the
* specified value.
*/
public static ConstantExpression constant(Object value) {
Class> type = value == null ? Object.class : value.getClass();
return constant(value, type);
}
/**
* Creates a {@link UnaryExpression} that represents an arithmetic negation
* operation.
*
* @param e An {@link Expression} to set the getValue() method equal to.
* @return A {@link UnaryExpression} that has the {@link ExpressionType}
* property equal to Negate and the getValue() method set to the
* specified value.
*/
public static UnaryExpression negate(Expression e) {
if (!e.isNumeric())
throw new IllegalArgumentException(e.getResultType().toString());
return new UnaryExpression(ExpressionType.Negate, e.getResultType(), e);
}
/**
* Creates a {@link ParameterExpression}.
*
* @param resultType The {@link Class} to set as the type of the expression that
* this Expression represents.
* @param index Parameter index in the method signature.
* @return A {@link ParameterExpression} that has the getExpressionType() method
* equal to Parameter and the getResultType() and getIndex() methods set
* to the specified values.
*/
public static ParameterExpression parameter(Class> resultType,
int index) {
return new ParameterExpression(resultType, index);
}
/**
* Creates a {@link BinaryExpression} that represents an instanceOf test.
*
* @param e An {@link Expression} to set the getFirst() method equal to.
* @param type The {@link Class} that assignability is tested with.
* @return A {@link BinaryExpression} that has the getExpressionType() equal to
* InstanceOf, the getFirst() set to 'e' and getSecond() set to
* {@link ConstantExpression} with value equals to 'type'.
*/
public static BinaryExpression instanceOf(Expression e,
Class> type) {
return instanceOf(e, constant(type));
}
/**
* Creates a {@link BinaryExpression} that represents an instanceOf test.
*
* @param e An {@link Expression} to set the getFirst() method equal to.
* @param type The {@link Expression} that evaluates to Class assignability is
* tested with.
* @return A {@link BinaryExpression} that has the getExpressionType() equal to
* InstanceOf, the getFirst() set to 'e' and getSecond() set to
* {@link ConstantExpression} with value equals to 'type'.
*/
public static BinaryExpression instanceOf(Expression e,
Expression type) {
return new BinaryExpression(ExpressionType.InstanceOf, Boolean.TYPE, null, e, type);
}
/**
* Creates a {@link Expression}, given an operand and unary operator, by calling
* the appropriate factory method.
*
* @param expressionType The {@link ExpressionType} that specifies the type of
* unary operation.
* @param resultType The {@link Class} that specifies the type to be
* converted to (pass null if not applicable).
* @param operand An {@link Expression} that represents the operand.
* @return The {@link Expression} that results from calling the appropriate
* factory method.
*/
public static Expression unary(int expressionType,
Class> resultType,
Expression operand) {
switch (expressionType) {
case ExpressionType.Convert:
return convert(operand, resultType);
case ExpressionType.ArrayLength:
return arrayLength(operand);
case ExpressionType.Negate:
return negate(operand);
case ExpressionType.BitwiseNot:
return bitwiseNot(operand);
case ExpressionType.LogicalNot:
return logicalNot(operand);
case ExpressionType.IsNull:
return isNull(operand);
case ExpressionType.IsNonNull:
return isNonNull(operand);
default:
throw new IllegalArgumentException("expressionType");
}
}
/**
* Creates a {@link Expression}, given an operand and binary operator, by
* calling the appropriate factory method.
*
* @param expressionType The {@link ExpressionType} that specifies the type of
* binary operation.
* @param first An {@link Expression} that represents the left operand.
* @param second An {@link Expression} that represents the right
* operand.
* @return The {@link Expression} that results from calling the appropriate
* factory method.
*/
public static Expression binary(int expressionType,
Expression first,
Expression second) {
return binary(expressionType, null, first, second);
}
/**
* Creates a {@link Expression}, given an operand and binary operator, by
* calling the appropriate factory method.
*
* @param expressionType The {@link ExpressionType} that specifies the type of
* binary operation.
* @param operator An {@link Expression} that represents the operator.
* @param first An {@link Expression} that represents the left operand.
* @param second An {@link Expression} that represents the right
* operand.
* @return The {@link Expression} that results from calling the appropriate
* factory method.
*/
public static Expression binary(int expressionType,
Expression operator,
Expression first,
Expression second) {
switch (expressionType) {
case ExpressionType.Add:
return add(first, second);
case ExpressionType.BitwiseAnd:
return bitwiseAnd(first, second);
case ExpressionType.LogicalAnd:
return logicalAnd(first, second);
case ExpressionType.ArrayIndex:
return arrayIndex(first, second);
case ExpressionType.Coalesce:
return coalesce(first, second);
case ExpressionType.Conditional:
return condition(operator, first, second);
case ExpressionType.Divide:
return divide(first, second);
case ExpressionType.Equal:
return equal(first, second);
case ExpressionType.ExclusiveOr:
return exclusiveOr(first, second);
case ExpressionType.GreaterThan:
return greaterThan(first, second);
case ExpressionType.GreaterThanOrEqual:
return greaterThanOrEqual(first, second);
case ExpressionType.LeftShift:
return leftShift(first, second);
case ExpressionType.LessThan:
return lessThan(first, second);
case ExpressionType.LessThanOrEqual:
return lessThanOrEqual(first, second);
case ExpressionType.Modulo:
return modulo(first, second);
case ExpressionType.Multiply:
return multiply(first, second);
case ExpressionType.NotEqual:
return notEqual(first, second);
case ExpressionType.BitwiseOr:
return bitwiseOr(first, second);
case ExpressionType.LogicalOr:
return logicalOr(first, second);
case ExpressionType.RightShift:
return rightShift(first, second);
case ExpressionType.Subtract:
return subtract(first, second);
case ExpressionType.InstanceOf:
return instanceOf(first, second);
default:
throw new IllegalArgumentException("expressionType");
}
}
private static Expression createBooleanExpression(int expressionType,
Expression first,
Expression second) {
Expression toReduce;
Expression toLeave;
if (first.getExpressionType() == ExpressionType.Constant) {
toReduce = first;
toLeave = second;
} else if (second.getExpressionType() == ExpressionType.Constant) {
toReduce = second;
toLeave = first;
} else {
toReduce = null;
toLeave = null;
}
if (toLeave != null && toLeave.isBoolean()) {
toReduce = TypeConverter.convert(toReduce, Boolean.TYPE);
switch (expressionType) {
case ExpressionType.Equal:
return (Boolean) ((ConstantExpression) toReduce).getValue() ? toLeave : logicalNot(toLeave);
case ExpressionType.NotEqual:
return (Boolean) ((ConstantExpression) toReduce).getValue() ? logicalNot(toLeave) : toLeave;
case ExpressionType.LogicalAnd:
return (Boolean) ((ConstantExpression) toReduce).getValue() ? toLeave : toReduce;
case ExpressionType.LogicalOr:
return (Boolean) ((ConstantExpression) toReduce).getValue() ? toReduce : toLeave;
}
}
return new BinaryExpression(expressionType, Boolean.TYPE, null, first, second);
}
/**
* Creates a {@link LambdaExpression} as a method receiving the specified {@code arguments}, returning the
* {@code resultType} and having {@code body} for its implementation.
*
* @param resultType The method return value.
* @param body The method implementation.
* @param parameters The method parameters.
* @param locals The method locals.
* @param key Deduplication key
* @return A {@link LambdaExpression} as a method receiving the specified {@code arguments}, returning the
* {@code resultType} and having {@code body} for its implementation.
*/
public static LambdaExpression> lambda(Class> resultType,
Expression body,
List parameters,
List locals,
Object key) {
return new LambdaExpression