예제 #1
0
        private void ExtendedConvertToType(Type fromType, Type toType, bool allowExplicit)
        {
            try
            {
                // See whether we can find a constructor on target type.

                var constructor = _resolver.ResolveMethodGroup(
                    toType.GetConstructors(_resolver.Options.AccessBindingFlags | BindingFlags.CreateInstance),
                    new[] { fromType },
                    new[] { false }
                    );

                if (constructor != null)
                {
                    ILUtil.EmitNew(_il, (ConstructorInfo)constructor);

                    return;
                }

                // See whether we have an implicit cast.

                var castMethod = _resolver.FindOperatorMethod(
                    "op_Implicit",
                    new[] { fromType, toType },
                    toType,
                    new[] { fromType }
                    );

                if (castMethod == null && allowExplicit)
                {
                    castMethod = _resolver.FindOperatorMethod(
                        "op_Explicit",
                        new[] { fromType, toType },
                        toType,
                        new[] { fromType }
                        );
                }

                if (castMethod != null)
                {
                    var parameterType = castMethod.GetParameters()[0].ParameterType;

                    if (fromType != parameterType)
                    {
                        ILUtil.EmitConvertToType(_il, fromType, parameterType, _resolver.Options.Checked);
                    }

                    _il.Emit(OpCodes.Call, castMethod);

                    if (toType != castMethod.ReturnType)
                    {
                        ILUtil.EmitConvertToType(_il, castMethod.ReturnType, toType, _resolver.Options.Checked);
                    }

                    return;
                }

                // Let ILUtill handle it.

                ILUtil.EmitConvertToType(_il, fromType, toType, _resolver.Options.Checked);
            }
            catch (Exception ex)
            {
                throw new ExpressionsException(
                          "Invalid explicit cast",
                          ExpressionsExceptionType.InvalidExplicitCast,
                          ex
                          );
            }
        }
예제 #2
0
        public override IExpression Cast(Cast cast)
        {
            if (cast.CastType == CastType.Convert)
            {
                var constant = cast.Operand as Constant;

                if (TypeUtil.CanCastImplicitely(
                        cast.Operand.Type,
                        cast.Type,
                        constant != null && constant.Value == null
                        ))
                {
                    return(new Cast(cast.Operand, cast.Type));
                }

                string methodName = null;

                switch (Type.GetTypeCode(cast.Type))
                {
                case TypeCode.Boolean: methodName = "ToBoolean"; break;

                case TypeCode.Byte: methodName = "ToByte"; break;

                case TypeCode.Char: methodName = "ToChar"; break;

                case TypeCode.DateTime: methodName = "ToDate"; break;

                case TypeCode.Decimal: methodName = "ToDecimal"; break;

                case TypeCode.Double: methodName = "ToDouble"; break;

                case TypeCode.Int32: methodName = "ToInteger"; break;

                case TypeCode.Int64: methodName = "ToLong"; break;

                case TypeCode.SByte: methodName = "ToSByte"; break;

                case TypeCode.Int16: methodName = "ToShort"; break;

                case TypeCode.Single: methodName = "ToSingle"; break;

                case TypeCode.String: methodName = "ToString"; break;

                case TypeCode.UInt32: methodName = "ToUInteger"; break;

                case TypeCode.UInt64: methodName = "ToULong"; break;

                case TypeCode.UInt16: methodName = "ToUShort"; break;
                }

                if (methodName != null)
                {
                    var method = _resolver.FindOperatorMethod(
                        methodName,
                        Array.Empty <Type>(),
                        null,
                        new[] { cast.Operand.Type }
                        );

                    Debug.Assert(method != null && method.ReturnType == cast.Type);

                    return(new MethodCall(
                               new TypeAccess(method.DeclaringType),
                               method,
                               new[]
                    {
                        cast.Operand
                    }
                               ));
                }
                else
                {
                    return(new Cast(cast.Operand, cast.Type));
                }
            }

            return(base.Cast(cast));
        }
예제 #3
0
        public IExpression BinaryExpression(Ast.BinaryExpression binaryExpression)
        {
            // In expressions are converted to method calls.

            if (binaryExpression.Type == ExpressionType.In)
            {
                return(BinaryInExpression(binaryExpression));
            }

            // We need to do this here and not in the conversion phase because
            // we need the return type of the method to fully bind the tree.

            var left  = binaryExpression.Left.Accept(this);
            var right = binaryExpression.Right.Accept(this);

            string operatorName = null;

            switch (binaryExpression.Type)
            {
            case ExpressionType.Add: operatorName = "op_Addition"; break;

            case ExpressionType.Divide: operatorName = "op_Division"; break;

            case ExpressionType.Multiply: operatorName = "op_Multiply"; break;

            case ExpressionType.Subtract: operatorName = "op_Subtraction"; break;

            case ExpressionType.Equals: operatorName = "op_Equality"; break;

            case ExpressionType.NotEquals: operatorName = "op_Inequality"; break;

            case ExpressionType.Greater: operatorName = "op_GreaterThan"; break;

            case ExpressionType.GreaterOrEquals: operatorName = "op_GreaterThanOrEqual"; break;

            case ExpressionType.Less: operatorName = "op_LessThan"; break;

            case ExpressionType.LessOrEquals: operatorName = "op_LessThanOrEqual"; break;

            case ExpressionType.ShiftLeft: operatorName = "op_LeftShift"; break;

            case ExpressionType.ShiftRight: operatorName = "op_RightShift"; break;

            case ExpressionType.Modulo: operatorName = "op_Modulus"; break;

            case ExpressionType.LogicalAnd: operatorName = "op_LogicalAnd"; break;

            case ExpressionType.AndBoth: operatorName = "op_LogicalAnd"; break;

            case ExpressionType.LogicalOr: operatorName = "op_LogicalOr"; break;

            case ExpressionType.OrBoth: operatorName = "op_LogicalOr"; break;

            case ExpressionType.BitwiseAnd: operatorName = "op_BitwiseAnd"; break;

            case ExpressionType.BitwiseOr: operatorName = "op_BitwiseOr"; break;

            case ExpressionType.And:
                if (left.Type == typeof(bool) && right.Type == typeof(bool))
                {
                    operatorName = "op_LogicalAnd";
                }
                else
                {
                    operatorName = "op_BitwiseAnd";
                }
                break;

            case ExpressionType.Or:
                if (left.Type == typeof(bool) && right.Type == typeof(bool))
                {
                    operatorName = "op_LogicalOr";
                }
                else
                {
                    operatorName = "op_BitwiseOr";
                }
                break;

            case ExpressionType.Xor:
                operatorName = "op_ExclusiveOr";
                break;
            }

            if (operatorName != null)
            {
                var method = _resolver.FindOperatorMethod(
                    operatorName,
                    new[] { left.Type, right.Type },
                    null,
                    new[] { left.Type, right.Type },
                    new[] { left is Expressions.Constant && ((Expressions.Constant)left).Value == null, right is Expressions.Constant && ((Expressions.Constant)right).Value == null }
                    );

                if (method != null)
                {
                    return(new Expressions.MethodCall(
                               new TypeAccess(typeof(string)),
                               method,
                               new[]
                    {
                        left,
                        right
                    }
                               ));
                }
            }

            Type commonType;

            switch (binaryExpression.Type)
            {
            case ExpressionType.ShiftLeft:
            case ExpressionType.ShiftRight:
                if (!TypeUtil.IsInteger(left.Type))
                {
                    throw new ExpressionsException("Left operand of shift operations must be of an integer type", ExpressionsExceptionType.TypeMismatch);
                }
                if (right.Type != typeof(int) && right.Type != typeof(byte))
                {
                    throw new ExpressionsException("Right operand of shift operations must be integer or byte type", ExpressionsExceptionType.TypeMismatch);
                }
                commonType = left.Type;
                break;

            case ExpressionType.Power:
                commonType = typeof(double);
                break;

            case ExpressionType.Greater:
            case ExpressionType.GreaterOrEquals:
            case ExpressionType.Less:
            case ExpressionType.LessOrEquals:
                commonType = ResolveExpressionCommonType(left.Type, right.Type, false, true, false);
                break;

            case ExpressionType.Equals:
            case ExpressionType.NotEquals:
            case ExpressionType.Compares:
            case ExpressionType.NotCompares:
                if (left.Type.IsValueType != right.Type.IsValueType)
                {
                    throw new ExpressionsException("Cannot resolve expression type", ExpressionsExceptionType.TypeMismatch);
                }

                commonType = ResolveExpressionCommonType(left.Type, right.Type, false, false, true);
                break;

            default:
                commonType = ResolveExpressionCommonType(left.Type, right.Type, binaryExpression.Type == ExpressionType.Add, false, false);
                break;
            }

            var type = ResolveExpressionType(left.Type, right.Type, commonType, binaryExpression.Type);

            var expressionType = binaryExpression.Type;

            if (type != typeof(bool))
            {
                if (expressionType == ExpressionType.AndBoth)
                {
                    expressionType = ExpressionType.BitwiseAnd;
                }
                else if (expressionType == ExpressionType.OrBoth)
                {
                    expressionType = ExpressionType.BitwiseOr;
                }
            }

            return(new Expressions.BinaryExpression(left, right, expressionType, type, commonType));
        }