Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* BinaryExpression.java
*
* Copyright (c) 2012 Mike Strobel
*
* This source code is based on the Dynamic Language Runtime from Microsoft,
* Copyright (c) Microsoft Corporation.
*
* This source code is subject to terms and conditions of the Apache License, Version 2.0.
* A copy of the license can be found in the License.html file at the root of this distribution.
* By using this source code in any fashion, you are agreeing to be bound by the terms of the
* Apache License, Version 2.0.
*
* You must not remove this notice, or any other, from this software.
*/
package com.strobel.expressions;
import com.strobel.reflection.*;
import com.strobel.util.TypeUtils;
/**
* @author Mike Strobel
*/
public class BinaryExpression extends Expression {
private final Expression _left;
private final Expression _right;
BinaryExpression(final Expression left, final Expression right) {
_left = left;
_right = right;
}
public final Expression getRight() {
return _right;
}
public final Expression getLeft() {
return _left;
}
public MethodInfo getMethod() {
return null;
}
public LambdaExpression> getConversion() {
return null;
}
@Override
public boolean canReduce() {
return isOpAssignment(getNodeType());
}
@Override
protected Expression accept(final ExpressionVisitor visitor) {
return visitor.visitBinary(this);
}
@Override
public Expression reduce() {
// Only reduce OpAssignment expressions.
if (isOpAssignment(getNodeType())) {
switch (_left.getNodeType()) {
case MemberAccess:
return reduceMember();
default:
return reduceVariable();
}
}
return this;
}
static Expression create(
final ExpressionType nodeType,
final Expression left,
final Expression right,
final Type type,
final MethodInfo method,
final LambdaExpression> conversion) {
if (nodeType == ExpressionType.Assign) {
assert method == null &&
TypeUtils.hasIdentityPrimitiveOrBoxingConversion(type, left.getType());
return new AssignBinaryExpression(left, right);
}
if (conversion != null) {
assert method == null &&
TypeUtils.hasIdentityPrimitiveOrBoxingConversion(type, right.getType()) &&
nodeType == ExpressionType.Coalesce;
return new CoalesceConversionBinaryExpression(left, right, conversion);
}
if (method != null) {
return new MethodBinaryExpression(nodeType, left, right, type, method);
}
if (TypeUtils.hasIdentityPrimitiveOrBoxingConversion(type, PrimitiveTypes.Boolean)) {
return new LogicalBinaryExpression(nodeType, left, right);
}
return new SimpleBinaryExpression(nodeType, left, right, type);
}
public BinaryExpression update(final Expression left, final LambdaExpression> conversion, final Expression right) {
if (left == getLeft() && right == getRight() && conversion == getConversion()) {
return this;
}
if (isReferenceComparison()) {
if (getNodeType() == ExpressionType.Equal) {
return Expression.referenceEqual(left, right);
}
else {
return Expression.referenceNotEqual(left, right);
}
}
return Expression.makeBinary(getNodeType(), left, right, getMethod(), conversion);
}
boolean isReferenceComparison() {
final Type left = _left.getType();
final Type right = _right.getType();
final MethodInfo method = getMethod();
final ExpressionType kind = getNodeType();
return (kind == ExpressionType.Equal || kind == ExpressionType.NotEqual) &&
method == null &&
!left.isPrimitive() &&
!right.isPrimitive();
}
private Expression reduceVariable() {
// v (op)= r => v = v (op) r
final ExpressionType op = getBinaryOpFromAssignmentOp(getNodeType());
Expression r = Expression.makeBinary(op, _left, _right, getMethod());
final LambdaExpression> conversion = getConversion();
if (conversion != null) {
r = Expression.invoke(conversion, r);
}
return Expression.assign(_left, r);
}
private Expression reduceMember() {
final MemberExpression member = (MemberExpression)_left;
if (member.getTarget() == null) {
// Static member; reduce the same as variable
return reduceVariable();
}
else {
// left.b (op)= r => temp1 = left; temp2 = temp1.b (op) r; temp1.b = temp2; temp2
final ParameterExpression temp1 = variable(member.getTarget().getType(), "temp1");
// 1. temp1 = left
final Expression temp1EqualsLeft = Expression.assign(temp1, member.getTarget());
// 2. temp2 = temp1.b (op) r
final ExpressionType op = getBinaryOpFromAssignmentOp(getNodeType());
Expression temp2EqualsTemp1Member = Expression.makeBinary(
op,
Expression.makeMemberAccess(temp1, member.getMember()),
_right,
getMethod()
);
final LambdaExpression> conversion = getConversion();
if (conversion != null) {
temp2EqualsTemp1Member = Expression.invoke(conversion, temp2EqualsTemp1Member);
}
final ParameterExpression temp2 = variable(temp2EqualsTemp1Member.getType(), "temp2");
temp2EqualsTemp1Member = Expression.assign(temp2, temp2EqualsTemp1Member);
// 3. temp1.b = temp2
final Expression temp1MemberEqualsTemp2 = Expression.assign(
Expression.makeMemberAccess(temp1, member.getMember()),
temp2
);
return Expression.block(
new ParameterExpression[]{temp1, temp2},
temp1EqualsLeft,
temp2EqualsTemp1Member,
temp1MemberEqualsTemp2,
temp2
);
}
}
private static boolean isOpAssignment(final ExpressionType operation) {
switch (operation) {
case AddAssign:
case SubtractAssign:
case MultiplyAssign:
case DivideAssign:
case ModuloAssign:
case AndAssign:
case OrAssign:
case RightShiftAssign:
case LeftShiftAssign:
case ExclusiveOrAssign:
return true;
}
return false;
}
private static ExpressionType getBinaryOpFromAssignmentOp(final ExpressionType operator) {
assert isOpAssignment(operator);
switch (operator) {
case AddAssign:
return ExpressionType.Add;
case SubtractAssign:
return ExpressionType.Subtract;
case MultiplyAssign:
return ExpressionType.Multiply;
case DivideAssign:
return ExpressionType.Divide;
case ModuloAssign:
return ExpressionType.Modulo;
case AndAssign:
return ExpressionType.And;
case OrAssign:
return ExpressionType.Or;
case RightShiftAssign:
return ExpressionType.RightShift;
case LeftShiftAssign:
return ExpressionType.LeftShift;
case ExclusiveOrAssign:
return ExpressionType.ExclusiveOr;
default:
throw Error.invalidOperator(operator);
}
}
}
/**
* Optimized representation of simple logical expressions:
* {@code && || == != > < >= <=}
*/
class LogicalBinaryExpression extends BinaryExpression {
private final ExpressionType _operator;
public LogicalBinaryExpression(final ExpressionType operator, final Expression left, final Expression right) {
super(left, right);
_operator = operator;
}
@Override
public final Type> getType() {
return PrimitiveTypes.Boolean;
}
@Override
public final ExpressionType getNodeType() {
return _operator;
}
}
final class CompareMethodBasedLogicalBinaryExpression extends BinaryExpression {
private final ExpressionType _operator;
private final MethodInfo _method;
public CompareMethodBasedLogicalBinaryExpression(
final ExpressionType operator,
final Expression left,
final Expression right,
final MethodInfo method) {
super(left, right);
_operator = operator;
_method = method;
}
@Override
public final Type> getType() {
return PrimitiveTypes.Boolean;
}
@Override
public final ExpressionType getNodeType() {
return _operator;
}
@Override
public final MethodInfo getMethod() {
return _method;
}
@Override
public final Expression reduce() {
if (canReduce()) {
switch (_operator) {
case GreaterThan:
return greaterThan(call(_method, getLeft(), getRight()), constant(0));
case GreaterThanOrEqual:
return greaterThanOrEqual(call(_method, getLeft(), getRight()), constant(0));
case LessThan:
return lessThan(call(_method, getLeft(), getRight()), constant(0));
case LessThanOrEqual:
return lessThanOrEqual(call(_method, getLeft(), getRight()), constant(0));
}
}
return this;
}
@Override
public final boolean canReduce() {
return _method.getReturnType() == PrimitiveTypes.Integer;
}
}
final class EqualsMethodBasedLogicalBinaryExpression extends BinaryExpression {
private final ExpressionType _operator;
private final MethodInfo _method;
public EqualsMethodBasedLogicalBinaryExpression(
final ExpressionType operator,
final Expression left,
final Expression right,
final MethodInfo method) {
super(left, right);
_operator = operator;
if (method != null) {
_method = method;
}
else {
final MethodInfo equalsMethod = Types.Comparer.getMethod(
operator == ExpressionType.Equal ? "equals" : "notEqual",
BindingFlags.PublicStatic,
Types.Object,
Types.Object
);
if (TypeUtils.areEquivalent(left.getType(), right.getType())) {
_method = equalsMethod.makeGenericMethod(left.getType());
}
else {
_method = equalsMethod.makeGenericMethod(Types.Object);
}
}
}
@Override
public final Type> getType() {
return PrimitiveTypes.Boolean;
}
@Override
public final ExpressionType getNodeType() {
return _operator;
}
@Override
public MethodInfo getMethod() {
return _method;
}
}
/**
* Optimized assignment node; only holds onto children.
*/
final class AssignBinaryExpression extends BinaryExpression {
public AssignBinaryExpression(final Expression left, final Expression right) {
super(left, right);
}
@Override
public final Type> getType() {
return getLeft().getType();
}
@Override
public final ExpressionType getNodeType() {
return ExpressionType.Assign;
}
}
/**
* Coalesce with conversion. This is not a frequently used node, but
* rather we want to save every other BinaryExpression from holding onto the
* null conversion lambda.
*/
final class CoalesceConversionBinaryExpression extends BinaryExpression {
private final LambdaExpression> _conversion;
CoalesceConversionBinaryExpression(final Expression left, final Expression right, final LambdaExpression> conversion) {
super(left, right);
_conversion = conversion;
}
@Override
public final LambdaExpression> getConversion() {
return _conversion;
}
@Override
public final Type> getType() {
return getRight().getType();
}
@Override
public final ExpressionType getNodeType() {
return ExpressionType.Coalesce;
}
}
final class OpAssignMethodConversionBinaryExpression extends MethodBinaryExpression {
private final LambdaExpression> _conversion;
OpAssignMethodConversionBinaryExpression(
final ExpressionType nodeType,
final Expression left,
final Expression right,
final Type type,
final MethodInfo method,
final LambdaExpression> conversion) {
super(nodeType, left, right, type, method);
_conversion = conversion;
}
@Override
public final LambdaExpression> getConversion() {
return _conversion;
}
}
class SimpleBinaryExpression extends BinaryExpression {
private final ExpressionType _nodeType;
private final Type _type;
SimpleBinaryExpression(
final ExpressionType nodeType,
final Expression left,
final Expression right,
final Type type) {
super(left, right);
_nodeType = nodeType;
_type = type;
}
@Override
public final ExpressionType getNodeType() {
return _nodeType;
}
@Override
public final Type> getType() {
return _type;
}
}
class MethodBinaryExpression extends SimpleBinaryExpression {
private final MethodInfo _method;
public MethodBinaryExpression(
final ExpressionType operator,
final Expression left,
final Expression right,
final Type type,
final MethodInfo method) {
super(operator, left, right, type);
_method = method;
}
@Override
public final MethodInfo getMethod() {
return _method;
}
}