public static bool TryPromoteUnaryOperation(ref Expression operand, ExpressionType type, out Expression operation)
        {
            if (operand == null)
            {
                throw new ArgumentNullException("operand");
            }

            operation = null;
            var operandType       = TypeDescription.GetTypeDescription(operand.Type);
            var operandTypeUnwrap = operandType.IsNullable ? operandType.UnderlyingType : operandType;
            var promoteToNullable = operandType.IsNullable;

            if (operandTypeUnwrap.IsEnum)
            {
                MorphType(ref operand, promoteToNullable ? operandTypeUnwrap.UnderlyingType.GetNullableType() : operandTypeUnwrap.UnderlyingType);
            }
            else if (operandTypeUnwrap.TypeCode >= TypeCode.SByte && operandTypeUnwrap.TypeCode <= TypeCode.UInt16)
            {
                MorphType(ref operand, promoteToNullable ? typeof(int?) : typeof(int));
            }
            else if (operandTypeUnwrap.TypeCode == TypeCode.UInt32 && type == ExpressionType.Not)
            {
                MorphType(ref operand, promoteToNullable ? typeof(long?) : typeof(long));
            }

            return(false);
        }
        public static bool TryMorphType(ref Expression expression, Type toType, out float quality)
        {
            if (expression == null)
            {
                throw new ArgumentNullException("expression");
            }
            if (toType == null)
            {
                throw new ArgumentNullException("toType");
            }

            if (expression.Type == toType)
            {
                quality = TypeConversion.QUALITY_SAME_TYPE;
                return(true);
            }

            var actualType = TypeDescription.GetTypeDescription(expression.Type);
            var targetType = TypeDescription.GetTypeDescription(toType);

            if (TryConvertInPlace(ref expression, targetType, out quality) || TryFindConversion(ref expression, actualType, targetType, out quality))
            {
                return(true);
            }

            quality = TypeConversion.QUALITY_NO_CONVERSION;
            return(false);
        }
Beispiel #3
0
        /// <summary>
        /// Creates new binder for expressions with <paramref name="lambdaType"/> signature. Optionally specifying <paramref name="typeResolver"/> to reference additional types during binding.
        /// </summary>
        /// <param name="lambdaType">Signature of bound expression.</param>
        /// <param name="typeResolver">Type resolver used for type resolution during binding process.
        /// When not specified then new instance of <see cref="KnownTypeResolver"/> is created using <paramref name="lambdaType"/> parameter types and result type.</param>
        public Binder(Type lambdaType, ITypeResolver typeResolver = null)
        {
            if (lambdaType == null)
            {
                throw new ArgumentNullException("lambdaType");
            }

            var lambdaTypeDescription = TypeDescription.GetTypeDescription(lambdaType);

            if (lambdaTypeDescription.IsDelegate == false || lambdaTypeDescription.HasGenericParameters)
            {
                throw new ArgumentException(string.Format(Resources.EXCEPTION_BIND_VALIDDELEGATETYPEISEXPECTED, lambdaType), "lambdaType");
            }

            var invokeMethod = lambdaTypeDescription.GetMembers(Constants.DELEGATE_INVOKE_NAME).FirstOrDefault(m => !m.IsStatic && m.IsMethod);

            if (invokeMethod == null)
            {
                throw new MissingMethodException(string.Format(Resources.EXCEPTION_BIND_MISSINGMETHOD, lambdaType.ToString(), Constants.DELEGATE_INVOKE_NAME));
            }

            var parametersArray = new ParameterExpression[invokeMethod.GetParametersCount()];

            for (var i = 0; i < invokeMethod.GetParametersCount(); i++)
            {
                parametersArray[i] = Expression.Parameter(invokeMethod.GetParameterType(i), invokeMethod.GetParameterName(i));
            }

            this.lambdaType   = lambdaType;
            this.parameters   = new ReadOnlyCollection <ParameterExpression>(parametersArray);
            this.resultType   = TypeDescription.GetTypeDescription(invokeMethod.ResultType);
            this.typeResolver = typeResolver ?? new KnownTypeResolver(GetTypes(this.resultType, this.parameters), DefaultTypeResolver);
        }
Beispiel #4
0
        public TypeAsNode(UnaryExpression typeAsExpression, ConstantExpression[] constExpressions, ParameterExpression[] parameterExpressions)
        {
            if (typeAsExpression == null)
            {
                throw new ArgumentNullException("typeAsExpression");
            }
            if (constExpressions == null)
            {
                throw new ArgumentNullException("constExpressions");
            }
            if (parameterExpressions == null)
            {
                throw new ArgumentNullException("parameterExpressions");
            }

            this.typeAsExpression = typeAsExpression;

            this.targetType = TypeDescription.GetTypeDescription(typeAsExpression.Type);
            if (this.targetType.IsValueType)
            {
                this.convertNode = new ConvertNode(typeAsExpression, constExpressions, parameterExpressions);
            }
            else
            {
                this.targetNode = AotCompiler.Compile(typeAsExpression.Operand, constExpressions, parameterExpressions);
            }
        }
        public static Expression Unpack(IDictionary <string, object> packedExpression, ITypeResolver typeResolver = null, Expression global = null, Type expectedType = null)
        {
            if (packedExpression == null)
            {
                throw new ArgumentNullException("packedExpression");
            }
            if (typeResolver == null)
            {
                typeResolver = KnownTypeResolver.Default;
            }
            if (expectedType == null)
            {
                expectedType = typeof(object);
            }

            var syntaxTree      = new SyntaxTreeNode(packedExpression);
            var bindingContext  = new BindingContext(typeResolver, Constants.EmptyReadonlyParameters, expectedType, global);
            var boundExpression = default(Expression);
            var bindingError    = default(Exception);

            if (AnyBinder.TryBindInNewScope(syntaxTree, bindingContext, TypeDescription.GetTypeDescription(expectedType), out boundExpression, out bindingError) == false)
            {
                throw bindingError;
            }

            return(boundExpression);
        }
        public ConvertNode(UnaryExpression convertExpression, ConstantExpression[] constExpressions, ParameterExpression[] parameterExpressions)
        {
            this.convertExpression = convertExpression;
            this.operandNode       = AotCompiler.Compile(convertExpression.Operand, constExpressions, parameterExpressions);
            this.sourceType        = TypeDescription.GetTypeDescription(convertExpression.Operand.Type);
            this.targetType        = TypeDescription.GetTypeDescription(convertExpression.Type);
            if (this.sourceType.IsNullable)
            {
                this.sourceType           = this.sourceType.UnderlyingType;
                this.isSourceTypeNullable = true;
            }
            if (this.targetType.IsNullable)
            {
                this.targetType           = this.targetType.UnderlyingType;
                this.isTargetTypeNullable = true;
            }

            this.operation = Intrinsic.WrapUnaryOperation(convertExpression.Method) ??
                             Intrinsic.WrapUnaryOperation
                             (
                this.targetType.ExplicitConvertFrom.FindConversion(this.sourceType, this.targetType) ??
                this.targetType.ImplicitConvertFrom.FindConversion(this.sourceType, this.targetType) ??
                this.sourceType.ExplicitConvertTo.FindConversion(this.sourceType, this.targetType) ??
                this.sourceType.ImplicitConvertTo.FindConversion(this.sourceType, this.targetType)
                             );
        }
        public static bool TryPromoteBinaryOperation(ref Expression leftOperand, ref Expression rightOperand, ExpressionType type, out Expression operation)
        {
            if (leftOperand == null)
            {
                throw new ArgumentNullException("leftOperand");
            }
            if (rightOperand == null)
            {
                throw new ArgumentNullException("rightOperand");
            }

            operation = null;

            var leftType  = TypeDescription.GetTypeDescription(leftOperand.Type);
            var rightType = TypeDescription.GetTypeDescription(rightOperand.Type);

            var leftTypeUnwrap  = leftType.IsNullable ? leftType.UnderlyingType : leftType;
            var rightTypeUnwrap = rightType.IsNullable ? rightType.UnderlyingType : rightType;

            // enum + enum
            if (leftTypeUnwrap.IsEnum || rightTypeUnwrap.IsEnum)
            {
                return(TryPromoteEnumBinaryOperation(ref leftOperand, leftType, ref rightOperand, rightType, type, out operation));
            }
            // number + number
            else if (leftTypeUnwrap.IsNumber && rightTypeUnwrap.IsNumber)
            {
                return(TryPromoteNumberBinaryOperation(ref leftOperand, leftType, ref rightOperand, rightType, type, out operation));
            }
            // null + nullable
            else if (IsNull(leftOperand) && rightType.CanBeNull)
            {
                leftType    = rightType;
                leftOperand = rightType.DefaultExpression;
            }
            // nullable + null
            else if (IsNull(rightOperand) && leftType.CanBeNull)
            {
                rightType    = leftType;
                rightOperand = leftType.DefaultExpression;
            }
            // [not]nullable + [not]nullable
            else if (leftType.IsNullable != rightType.IsNullable)
            {
                leftOperand = ConvertToNullable(leftOperand, leftType);
                if (type != ExpressionType.Coalesce)
                {
                    rightOperand = ConvertToNullable(rightOperand, rightType);
                }
            }

            return(false);
        }
Beispiel #8
0
        /// <summary>
        /// Creates new binder for expressions with signature contains <paramref name="parameters"/>(up to 4) and <paramref name="resultType"/>. Optionally specifying <paramref name="typeResolver"/> to reference additional types during binding.
        /// </summary>
        /// <param name="parameters">List of parameter for bound expression. Maximum number of parameters is 4.</param>
        /// <param name="resultType">Result type of bound expression.</param>
        /// <param name="typeResolver">Type resolver used for type resolution during binding process.
        /// When not specified then new instance of <see cref="KnownTypeResolver"/> is created using <paramref name="parameters"/> parameter types and result type.</param>
        public Binder(IList <ParameterExpression> parameters, Type resultType, ITypeResolver typeResolver = null)
        {
            if (parameters == null)
            {
                throw new ArgumentNullException("parameters");
            }
            if (resultType == null)
            {
                throw new ArgumentNullException("resultType");
            }
            if (resultType.IsGenericParameter)
            {
                throw new ArgumentException("A value can't be generic parameter type.", "resultType");
            }
            if (parameters.Count > 4)
            {
                throw new ArgumentOutOfRangeException("parameters");
            }
            if (parameters.Any(p => p == null || p.Type.IsGenericParameter))
            {
                throw new ArgumentException("Collection can't contain nulls or generic parameter types.", "parameters");
            }

            if (parameters is ReadOnlyCollection <ParameterExpression> == false)
            {
                parameters = new ReadOnlyCollection <ParameterExpression>(parameters);
            }

            if (resultType == typeof(void))
            {
                var funcParams = new Type[parameters.Count];
                for (var i = 0; i < parameters.Count; i++)
                {
                    funcParams[i] = parameters[i].Type;
                }
                this.lambdaType = Expression.GetActionType(funcParams);
            }
            else
            {
                var funcParams = new Type[parameters.Count + 1];
                for (var i = 0; i < parameters.Count; i++)
                {
                    funcParams[i] = parameters[i].Type;
                }
                funcParams[funcParams.Length - 1] = resultType;
                this.lambdaType = Expression.GetFuncType(funcParams);
            }

            this.parameters   = (ReadOnlyCollection <ParameterExpression>)parameters;
            this.resultType   = TypeDescription.GetTypeDescription(resultType);
            this.typeResolver = typeResolver ?? new KnownTypeResolver(GetTypes(resultType, parameters), DefaultTypeResolver);
        }
        public static Expression MakeNullPropagationExpression(List <Expression> nullTestExpressions, Expression ifNotNullExpression)
        {
            if (nullTestExpressions == null)
            {
                throw new ArgumentNullException("nullTestExpressions");
            }
            if (ifNotNullExpression == null)
            {
                throw new ArgumentNullException("ifNotNullExpression");
            }

            var notNullTestTreeExpression = default(Expression);

            foreach (var nullTestExpression in nullTestExpressions)
            {
                var testTypeDescription = TypeDescription.GetTypeDescription(nullTestExpression.Type);
                var notEqualDefault     = Expression.NotEqual(nullTestExpression, testTypeDescription.DefaultExpression);
                if (notNullTestTreeExpression == null)
                {
                    notNullTestTreeExpression = notEqualDefault;
                }
                else
                {
                    notNullTestTreeExpression = Expression.AndAlso(notNullTestTreeExpression, notEqualDefault);
                }
            }
            if (notNullTestTreeExpression == null)
            {
                notNullTestTreeExpression = TrueConstant;
            }

            var ifNotNullTypeDescription = TypeDescription.GetTypeDescription(ifNotNullExpression.Type);
            var resultType = ifNotNullTypeDescription.CanBeNull == false?TypeDescription.GetTypeDescription(typeof(Nullable <>).MakeGenericType(ifNotNullExpression.Type)) : ifNotNullTypeDescription;

            if (resultType != ifNotNullExpression.Type)
            {
                ifNotNullExpression = Expression.Convert(ifNotNullExpression, resultType);
            }

            return(Expression.Condition
                   (
                       test: notNullTestTreeExpression,
                       ifTrue: ifNotNullExpression,
                       ifFalse: resultType.DefaultExpression
                   ));
        }
        public TypeIsNode(TypeBinaryExpression typeBinaryExpression, ConstantExpression[] constExpressions, ParameterExpression[] parameterExpressions)
        {
            if (typeBinaryExpression == null)
            {
                throw new ArgumentNullException("typeBinaryExpression");
            }
            if (constExpressions == null)
            {
                throw new ArgumentNullException("constExpressions");
            }
            if (parameterExpressions == null)
            {
                throw new ArgumentNullException("parameterExpressions");
            }

            this.typeBinaryExpression = typeBinaryExpression;
            this.targetType           = TypeDescription.GetTypeDescription(this.typeBinaryExpression.TypeOperand);
            this.targetNode           = AotCompiler.Compile(typeBinaryExpression.Expression, constExpressions, parameterExpressions);
        }
        private static Expression ConvertToNullable(Expression notNullableExpression, TypeDescription typeDescription)
        {
            if (notNullableExpression == null)
            {
                throw new ArgumentNullException("notNullableExpression");
            }
            if (typeDescription != null && notNullableExpression.Type != typeDescription)
            {
                throw new ArgumentException("Wrong type description.", "typeDescription");
            }
            if (typeDescription == null)
            {
                typeDescription = TypeDescription.GetTypeDescription(notNullableExpression.Type);
            }

            if (typeDescription.CanBeNull == false)
            {
                return(Expression.Convert(notNullableExpression, typeDescription.GetNullableType()));
            }
            else
            {
                return(notNullableExpression);
            }
        }
        private static bool TryConvertInPlace(ref Expression expression, TypeDescription targetType, out float quality)
        {
            if (expression == null)
            {
                throw new ArgumentNullException("expression");
            }
            if (targetType == null)
            {
                throw new ArgumentNullException("targetType");
            }

            quality = TypeConversion.QUALITY_NO_CONVERSION;
            var targetTypeUnwrap = targetType.IsNullable ? targetType.UnderlyingType : targetType;
            // try to convert value of constant
            var constantExpression = default(ConstantExpression);

            if (TryExposeConstant(expression, out constantExpression) == false)
            {
                return(false);
            }

            var constantValue      = constantExpression.Value;
            var constantType       = TypeDescription.GetTypeDescription(constantExpression.Type);
            var constantTypeUnwrap = constantType.IsNullable ? constantType.UnderlyingType : constantType;

            if (constantValue == null && constantType.DefaultExpression != constantExpression && targetType.CanBeNull)
            {
                quality    = TypeConversion.QUALITY_SAME_TYPE;
                expression = Expression.Constant(null, targetType);
                return(true);
            }
            else if (constantValue == null)
            {
                return(false);
            }

            var constantTypeCode          = constantTypeUnwrap.TypeCode;
            var convertibleToExpectedType = default(bool);

            // ReSharper disable RedundantCast
            // ReSharper disable once SwitchStatementMissingSomeCases
            switch (targetTypeUnwrap.TypeCode)
            {
            case TypeCode.Byte: convertibleToExpectedType = IsInRange(constantValue, constantTypeCode, byte.MinValue, byte.MaxValue); break;

            case TypeCode.SByte: convertibleToExpectedType = IsInRange(constantValue, constantTypeCode, sbyte.MinValue, (ulong)sbyte.MaxValue); break;

            case TypeCode.Char:
            case TypeCode.UInt16: convertibleToExpectedType = IsInRange(constantValue, constantTypeCode, ushort.MinValue, ushort.MaxValue); break;

            case TypeCode.Int16: convertibleToExpectedType = IsInRange(constantValue, constantTypeCode, short.MinValue, (ulong)short.MaxValue); break;

            case TypeCode.UInt32: convertibleToExpectedType = IsInRange(constantValue, constantTypeCode, uint.MinValue, uint.MaxValue); break;

            case TypeCode.Int32: convertibleToExpectedType = IsInRange(constantValue, constantTypeCode, int.MinValue, int.MaxValue); break;

            case TypeCode.UInt64: convertibleToExpectedType = IsInRange(constantValue, constantTypeCode, (long)ulong.MinValue, ulong.MaxValue); break;

            case TypeCode.Int64: convertibleToExpectedType = IsInRange(constantValue, constantTypeCode, long.MinValue, long.MaxValue); break;

            case TypeCode.Double:
            case TypeCode.Decimal:
            case TypeCode.Single: convertibleToExpectedType = NumberUtils.IsSignedInteger(constantTypeCode) || NumberUtils.IsUnsignedInteger(constantTypeCode); break;

            default: convertibleToExpectedType = false; break;
            }
            // ReSharper restore RedundantCast

            if (!convertibleToExpectedType)
            {
                return(false);
            }

            var newValue = Convert.ChangeType(constantValue, targetTypeUnwrap.TypeCode, Constants.DefaultFormatProvider);

            expression = Expression.Constant(newValue, targetType);
            quality    = TypeConversion.QUALITY_IN_PLACE_CONVERSION;          // converted in-place
            return(true);
        }