Example #1
0
        private static Func <Closure, object> Binary(BinaryExpression binaryExpression,
                                                     ConstantExpression[] constantsExprs, ParameterExpression[] localsExprs)
        {
            var leftFn               = Expression(binaryExpression.Left, constantsExprs, localsExprs);
            var rightFn              = Expression(binaryExpression.Right, constantsExprs, localsExprs);
            var opAddition           = WrapBinaryOperation(binaryExpression.Method) ?? WrapBinaryOperation(binaryExpression.Left.Type, "op_Addition");
            var opBitwiseAnd         = WrapBinaryOperation(binaryExpression.Method) ?? WrapBinaryOperation(binaryExpression.Left.Type, "op_BitwiseAnd");
            var opDivision           = WrapBinaryOperation(binaryExpression.Method) ?? WrapBinaryOperation(binaryExpression.Left.Type, "op_Division");
            var opEquality           = WrapBinaryOperation(binaryExpression.Method) ?? WrapBinaryOperation(binaryExpression.Left.Type, "op_Equality");
            var opExclusiveOr        = WrapBinaryOperation(binaryExpression.Method) ?? WrapBinaryOperation(binaryExpression.Left.Type, "op_ExclusiveOr");
            var opGreaterThan        = WrapBinaryOperation(binaryExpression.Method) ?? WrapBinaryOperation(binaryExpression.Left.Type, "op_GreaterThan");
            var opGreaterThanOrEqual = WrapBinaryOperation(binaryExpression.Method) ?? WrapBinaryOperation(binaryExpression.Left.Type, "op_GreaterThanOrEqual");
            var opLessThan           = WrapBinaryOperation(binaryExpression.Method) ?? WrapBinaryOperation(binaryExpression.Left.Type, "op_LessThan");
            var opLessThanOrEqual    = WrapBinaryOperation(binaryExpression.Method) ?? WrapBinaryOperation(binaryExpression.Left.Type, "op_LessThanOrEqual");
            var opModulus            = WrapBinaryOperation(binaryExpression.Method) ?? WrapBinaryOperation(binaryExpression.Left.Type, "op_Modulus");
            var opMultiply           = WrapBinaryOperation(binaryExpression.Method) ?? WrapBinaryOperation(binaryExpression.Left.Type, "op_Multiply");
            var opBitwiseOr          = WrapBinaryOperation(binaryExpression.Method) ?? WrapBinaryOperation(binaryExpression.Left.Type, "op_BitwiseOr");
            var opSubtraction        = WrapBinaryOperation(binaryExpression.Method) ?? WrapBinaryOperation(binaryExpression.Left.Type, "op_Subtraction");
            var isNullable           = IsNullable(binaryExpression.Left) || IsNullable(binaryExpression.Right);

            return(closure =>
            {
                switch (binaryExpression.NodeType)
                {
                case ExpressionType.AndAlso:
                    return closure.Unbox <bool>(leftFn(closure)) && closure.Unbox <bool>(rightFn(closure));

                case ExpressionType.OrElse:
                    return closure.Unbox <bool>(leftFn(closure)) || closure.Unbox <bool>(rightFn(closure));
                }

                var left = leftFn(closure);
                var right = rightFn(closure);

                if
                (
                    isNullable &&
                    (left == null || right == null) &&
                    binaryExpression.NodeType != ExpressionType.Coalesce &&
                    binaryExpression.NodeType != ExpressionType.ArrayIndex
                )
                {
                    // ReSharper disable once SwitchStatementMissingSomeCases
                    switch (binaryExpression.NodeType)
                    {
                    case ExpressionType.Equal: return closure.Box(left == right);

                    case ExpressionType.NotEqual: return closure.Box(left != right);

                    case ExpressionType.GreaterThan:
                    case ExpressionType.GreaterThanOrEqual:
                    case ExpressionType.LessThan:
                    case ExpressionType.LessThanOrEqual: return closure.Box(false);

                    default: return null;
                    }
                }

                switch (binaryExpression.NodeType)
                {
                case ExpressionType.Add:
                case ExpressionType.AddChecked:
                    return Intrinsics.BinaryOperation(closure, left, right, binaryExpression.NodeType, opAddition);

                case ExpressionType.And:
                    return Intrinsics.BinaryOperation(closure, left, right, binaryExpression.NodeType, opBitwiseAnd);

                case ExpressionType.ArrayIndex:
                    return closure.Is <int[]>(right)
                                                        ? closure.Unbox <Array>(left).GetValue(closure.Unbox <int[]>(right))
                                                        : closure.Unbox <Array>(left).GetValue(closure.Unbox <int>(right));

                case ExpressionType.Coalesce:
                    return left ?? right;

                case ExpressionType.Divide:
                    return Intrinsics.BinaryOperation(closure, left, right, binaryExpression.NodeType, opDivision);

                case ExpressionType.Equal:
                    return Intrinsics.BinaryOperation(closure, left, right, binaryExpression.NodeType, opEquality);

                case ExpressionType.NotEqual:
                    return closure.Box(closure.Unbox <bool>(Intrinsics.BinaryOperation(closure, left, right, ExpressionType.Equal, opEquality)) == false);

                case ExpressionType.ExclusiveOr:
                    return Intrinsics.BinaryOperation(closure, left, right, binaryExpression.NodeType, opExclusiveOr);

                case ExpressionType.GreaterThan:
                    return Intrinsics.BinaryOperation(closure, left, right, binaryExpression.NodeType, opGreaterThan);

                case ExpressionType.GreaterThanOrEqual:
                    return Intrinsics.BinaryOperation(closure, left, right, binaryExpression.NodeType, opGreaterThanOrEqual);

                case ExpressionType.LeftShift:
                case ExpressionType.Power:
                case ExpressionType.RightShift:
                    return Intrinsics.BinaryOperation(closure, left, right, binaryExpression.NodeType, null);

                case ExpressionType.LessThan:
                    return Intrinsics.BinaryOperation(closure, left, right, binaryExpression.NodeType, opLessThan);

                case ExpressionType.LessThanOrEqual:
                    return Intrinsics.BinaryOperation(closure, left, right, binaryExpression.NodeType, opLessThanOrEqual);

                case ExpressionType.Modulo:
                    return Intrinsics.BinaryOperation(closure, left, right, binaryExpression.NodeType, opModulus);

                case ExpressionType.Multiply:
                case ExpressionType.MultiplyChecked:
                    return Intrinsics.BinaryOperation(closure, left, right, binaryExpression.NodeType, opMultiply);

                case ExpressionType.Or:
                    return Intrinsics.BinaryOperation(closure, left, right, binaryExpression.NodeType, opBitwiseOr);

                case ExpressionType.Subtract:
                case ExpressionType.SubtractChecked:
                    return Intrinsics.BinaryOperation(closure, left, right, binaryExpression.NodeType, opSubtraction);
                }

                throw new InvalidOperationException(string.Format(Properties.Resources.EXCEPTION_COMPIL_UNKNOWNBINARYEXPRTYPE, binaryExpression.Type));
            });
        }