예제 #1
0
        private static void EmitNumericConversion(ILGenerator il, Type typeFrom, Type typeTo, bool isChecked)
        {
            if (
                !(typeFrom.IsEnum || TypeUtil.IsNumeric(typeFrom)) ||
                !(typeTo.IsEnum || TypeUtil.IsNumeric(typeTo))
                )
            {
                throw new InvalidOperationException("Unhandled convert");
            }

            bool isFromUnsigned      = TypeUtil.IsUnsigned(typeFrom);
            bool isFromFloatingPoint = TypeUtil.IsFloatingPoint(typeFrom);

            if (typeTo == typeof(Single))
            {
                if (isFromUnsigned)
                {
                    il.Emit(OpCodes.Conv_R_Un);
                }
                il.Emit(OpCodes.Conv_R4);
            }
            else if (typeTo == typeof(Double))
            {
                if (isFromUnsigned)
                {
                    il.Emit(OpCodes.Conv_R_Un);
                }
                il.Emit(OpCodes.Conv_R8);
            }
            else
            {
                TypeCode tc = Type.GetTypeCode(typeTo);
                if (isChecked)
                {
                    // Overflow checking needs to know if the source value on the IL stack is unsigned or not.
                    if (isFromUnsigned)
                    {
                        switch (tc)
                        {
                        case TypeCode.SByte:
                            il.Emit(OpCodes.Conv_Ovf_I1_Un);
                            break;

                        case TypeCode.Int16:
                            il.Emit(OpCodes.Conv_Ovf_I2_Un);
                            break;

                        case TypeCode.Int32:
                            il.Emit(OpCodes.Conv_Ovf_I4_Un);
                            break;

                        case TypeCode.Int64:
                            il.Emit(OpCodes.Conv_Ovf_I8_Un);
                            break;

                        case TypeCode.Byte:
                            il.Emit(OpCodes.Conv_Ovf_U1_Un);
                            break;

                        case TypeCode.UInt16:
                        case TypeCode.Char:
                            il.Emit(OpCodes.Conv_Ovf_U2_Un);
                            break;

                        case TypeCode.UInt32:
                            il.Emit(OpCodes.Conv_Ovf_U4_Un);
                            break;

                        case TypeCode.UInt64:
                            il.Emit(OpCodes.Conv_Ovf_U8_Un);
                            break;

                        default:
                            throw new InvalidOperationException("Unhandled convert");
                        }
                    }
                    else
                    {
                        switch (tc)
                        {
                        case TypeCode.SByte:
                            il.Emit(OpCodes.Conv_Ovf_I1);
                            break;

                        case TypeCode.Int16:
                            il.Emit(OpCodes.Conv_Ovf_I2);
                            break;

                        case TypeCode.Int32:
                            il.Emit(OpCodes.Conv_Ovf_I4);
                            break;

                        case TypeCode.Int64:
                            il.Emit(OpCodes.Conv_Ovf_I8);
                            break;

                        case TypeCode.Byte:
                            il.Emit(OpCodes.Conv_Ovf_U1);
                            break;

                        case TypeCode.UInt16:
                        case TypeCode.Char:
                            il.Emit(OpCodes.Conv_Ovf_U2);
                            break;

                        case TypeCode.UInt32:
                            il.Emit(OpCodes.Conv_Ovf_U4);
                            break;

                        case TypeCode.UInt64:
                            il.Emit(OpCodes.Conv_Ovf_U8);
                            break;

                        default:
                            throw new InvalidOperationException("Unhandled convert");
                        }
                    }
                }
                else
                {
                    switch (tc)
                    {
                    case TypeCode.SByte:
                        il.Emit(OpCodes.Conv_I1);
                        break;

                    case TypeCode.Byte:
                        il.Emit(OpCodes.Conv_U1);
                        break;

                    case TypeCode.Int16:
                        il.Emit(OpCodes.Conv_I2);
                        break;

                    case TypeCode.UInt16:
                    case TypeCode.Char:
                        il.Emit(OpCodes.Conv_U2);
                        break;

                    case TypeCode.Int32:
                        il.Emit(OpCodes.Conv_I4);
                        break;

                    case TypeCode.UInt32:
                        il.Emit(OpCodes.Conv_U4);
                        break;

                    case TypeCode.Int64:
                        if (isFromUnsigned)
                        {
                            il.Emit(OpCodes.Conv_U8);
                        }
                        else
                        {
                            il.Emit(OpCodes.Conv_I8);
                        }
                        break;

                    case TypeCode.UInt64:
                        if (isFromUnsigned || isFromFloatingPoint)
                        {
                            il.Emit(OpCodes.Conv_U8);
                        }
                        else
                        {
                            il.Emit(OpCodes.Conv_I8);
                        }
                        break;

                    default:
                        throw new InvalidOperationException("Unhandled convert");
                    }
                }
            }
        }
예제 #2
0
            public void MethodCall(MethodCall methodCall)
            {
                bool isStatic = methodCall.Operand is TypeAccess;

                if (!isStatic)
                {
                    bool emitBox       = false;
                    bool emitStoreLoad = false;

                    if (
                        (methodCall.Operand is FieldAccess || methodCall.Operand is Constant) &&
                        methodCall.Operand.Type.IsValueType &&
                        !methodCall.MethodInfo.DeclaringType.IsValueType
                        )
                    {
                        emitBox = true;
                    }
                    else if (
                        methodCall.Operand.Type.IsValueType && (
                            !(methodCall.Operand is FieldAccess) ||
                            methodCall.MethodInfo.DeclaringType.IsValueType
                            )
                        )
                    {
                        emitStoreLoad = true;
                    }

                    // Signal field access that we're using the field as a
                    // parameter.

                    _fieldAsParameter =
                        methodCall.Operand is FieldAccess &&
                        methodCall.MethodInfo.DeclaringType.IsValueType &&
                        !emitStoreLoad;

                    try
                    {
                        methodCall.Operand.Accept(this);
                    }
                    finally
                    {
                        _fieldAsParameter = false;
                    }

                    if (emitBox)
                    {
                        _il.Emit(OpCodes.Box, methodCall.Operand.Type);
                    }
                    else if (emitStoreLoad)
                    {
                        Debug.Assert(methodCall.Operand.Type == methodCall.MethodInfo.DeclaringType);

                        var builder = _il.DeclareLocal(methodCall.Operand.Type);

                        _il.Emit(OpCodes.Stloc, builder);
                        _il.Emit(OpCodes.Ldloca, builder);
                    }
                }

                var parameters = methodCall.MethodInfo.GetParameters();
                var arguments  = methodCall.Arguments;

                bool paramsMethod =
                    parameters.Length > 0 &&
                    parameters[parameters.Length - 1].GetCustomAttributes(typeof(ParamArrayAttribute), true).Length == 1;

                int mandatoryParameterCount =
                    paramsMethod
                    ? parameters.Length - 1
                    : parameters.Length;

                for (int i = 0; i < mandatoryParameterCount; i++)
                {
                    Emit(arguments[i], parameters[i].ParameterType);
                }

                if (paramsMethod)
                {
                    var  paramsType  = parameters[parameters.Length - 1].ParameterType;
                    var  elementType = paramsType.GetElementType();
                    bool emitted     = false;

                    // When the params argument is missing, a new array is issued.

                    if (arguments.Count == mandatoryParameterCount)
                    {
                        ILUtil.EmitEmptyArray(_il, elementType);
                        emitted = true;
                    }
                    else if (arguments.Count == mandatoryParameterCount + 1)
                    {
                        var lastArgument = arguments[arguments.Count - 1];

                        // Null arguments are passed blindly.
                        if (lastArgument is Constant constant && constant.Value == null)
                        {
                            ILUtil.EmitNull(_il);
                            emitted = true;
                        }
                        else
                        {
                            // So are array arguments that can be casted.

                            if (
                                lastArgument.Type.IsArray &&
                                TypeUtil.CanCastImplicitely(lastArgument.Type, paramsType, false)
                                )
                            {
                                Emit(lastArgument, paramsType);
                                emitted = true;
                            }
                        }
                    }

                    // If we didn't find a shortcut, emit the array with all
                    // arguments.

                    if (!emitted)
                    {
                        ILUtil.EmitArray(
                            _il,
                            elementType,
                            arguments.Count - mandatoryParameterCount,
                            p => Emit(arguments[mandatoryParameterCount + p], elementType)
                            );
                    }
                }
예제 #3
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));
        }
예제 #4
0
        public override IExpression BinaryExpression(BinaryExpression binaryExpression)
        {
            var left  = binaryExpression.Left.Accept(this);
            var right = binaryExpression.Right.Accept(this);

            if (
                (
                    binaryExpression.ExpressionType == ExpressionType.Add &&
                    (left.Type == typeof(string) || right.Type == typeof(string))
                ) ||
                binaryExpression.ExpressionType == ExpressionType.Concat
                )
            {
                return(_resolver.ResolveMethod(
                           new TypeAccess(typeof(string)),
                           "Concat",
                           FlattenConcatArguments(binaryExpression.Left, binaryExpression.Right)
                           ));
            }
            else if (binaryExpression.ExpressionType == ExpressionType.Power)
            {
                return(_resolver.ResolveMethod(
                           new TypeAccess(typeof(Math)),
                           "Pow",
                           new[] { left, right }
                           ));
            }
            else if (_resolver.DynamicExpression.Language == ExpressionLanguage.VisualBasic)
            {
                // Special handling for Visual Basic.

                string methodName = null;

                switch (binaryExpression.ExpressionType)
                {
                case ExpressionType.Compares: methodName = "CompareObjectEqual"; break;

                case ExpressionType.NotCompares: methodName = "CompareObjectNotEqual"; break;

                case ExpressionType.Greater: methodName = "CompareObjectGreater"; break;

                case ExpressionType.GreaterOrEquals: methodName = "CompareObjectGreaterEqual"; break;

                case ExpressionType.Less: methodName = "CompareObjectLess"; break;

                case ExpressionType.LessOrEquals: methodName = "CompareObjectLessEqual"; break;
                }

                // Is this an operator for which we have a method?

                if (methodName != null)
                {
                    // Should we output a normal comparison anyway?

                    if (TypeUtil.IsConvertible(left.Type) && TypeUtil.IsConvertible(right.Type))
                    {
                        var expressionType = binaryExpression.ExpressionType;

                        // Coerce Compares/NotCompares to Equals/NotEquals.

                        if (expressionType == ExpressionType.Compares)
                        {
                            expressionType = ExpressionType.Equals;
                        }
                        else if (expressionType == ExpressionType.NotCompares)
                        {
                            expressionType = ExpressionType.NotEquals;
                        }

                        if (
                            left == binaryExpression.Left &&
                            right == binaryExpression.Right &&
                            expressionType == binaryExpression.ExpressionType
                            )
                        {
                            return(binaryExpression);
                        }
                        else
                        {
                            return(new BinaryExpression(left, right, expressionType, binaryExpression.Type, binaryExpression.CommonType));
                        }
                    }
                    else
                    {
                        var method = typeof(Operators).GetMethod(methodName);

                        Debug.Assert(method.ReturnType == typeof(object));

                        return(new Cast(
                                   new MethodCall(
                                       new TypeAccess(typeof(Operators)),
                                       method,
                                       new[]
                        {
                            left,
                            right,
                            new Constant(false)
                        }
                                       ),
                                   typeof(bool)
                                   ));
                    }
                }
            }

            if (left == binaryExpression.Left && right == binaryExpression.Right)
            {
                return(binaryExpression);
            }
            else
            {
                return(new BinaryExpression(left, right, binaryExpression.ExpressionType, binaryExpression.Type));
            }
        }
예제 #5
0
            private void BinaryArithicExpression(BinaryExpression binaryExpression)
            {
                // Reference compares.

                if (
                    !binaryExpression.Left.Type.IsValueType &&
                    !binaryExpression.Right.Type.IsValueType && (
                        binaryExpression.ExpressionType == ExpressionType.Equals ||
                        binaryExpression.ExpressionType == ExpressionType.NotEquals
                        )
                    )
                {
                    binaryExpression.Left.Accept(this);
                    binaryExpression.Right.Accept(this);

                    _il.Emit(OpCodes.Ceq);

                    if (binaryExpression.ExpressionType == ExpressionType.NotEquals)
                    {
                        _il.Emit(OpCodes.Ldc_I4_0);
                        _il.Emit(OpCodes.Ceq);
                    }

                    return;
                }

                Emit(binaryExpression.Left, binaryExpression.CommonType);
                Emit(binaryExpression.Right, binaryExpression.CommonType);

                switch (binaryExpression.ExpressionType)
                {
                case ExpressionType.Equals:
                case ExpressionType.NotEquals:
                    _il.Emit(OpCodes.Ceq);

                    if (binaryExpression.ExpressionType == ExpressionType.NotEquals)
                    {
                        _il.Emit(OpCodes.Ldc_I4_0);
                        _il.Emit(OpCodes.Ceq);
                    }
                    break;

                case ExpressionType.Greater:
                case ExpressionType.LessOrEquals:
                    if (TypeUtil.IsUnsigned(binaryExpression.CommonType))
                    {
                        _il.Emit(OpCodes.Cgt_Un);
                    }
                    else
                    {
                        _il.Emit(OpCodes.Cgt);
                    }

                    if (binaryExpression.ExpressionType == ExpressionType.LessOrEquals)
                    {
                        _il.Emit(OpCodes.Ldc_I4_0);
                        _il.Emit(OpCodes.Ceq);
                    }
                    break;

                case ExpressionType.Less:
                case ExpressionType.GreaterOrEquals:
                    if (TypeUtil.IsUnsigned(binaryExpression.CommonType))
                    {
                        _il.Emit(OpCodes.Clt_Un);
                    }
                    else
                    {
                        _il.Emit(OpCodes.Clt);
                    }

                    if (binaryExpression.ExpressionType == ExpressionType.GreaterOrEquals)
                    {
                        _il.Emit(OpCodes.Ldc_I4_0);
                        _il.Emit(OpCodes.Ceq);
                    }
                    break;

                case ExpressionType.Add:
                    if (_compiler._resolver.Options.Checked && TypeUtil.IsInteger(binaryExpression.CommonType))
                    {
                        if (TypeUtil.IsUnsigned(binaryExpression.CommonType))
                        {
                            _il.Emit(OpCodes.Add_Ovf_Un);
                        }
                        else
                        {
                            _il.Emit(OpCodes.Add_Ovf);
                        }
                    }
                    else
                    {
                        _il.Emit(OpCodes.Add);
                    }
                    break;

                case ExpressionType.Divide:
                    if (TypeUtil.IsUnsigned(binaryExpression.CommonType))
                    {
                        _il.Emit(OpCodes.Div_Un);
                    }
                    else
                    {
                        _il.Emit(OpCodes.Div);
                    }
                    break;

                case ExpressionType.Multiply:
                    if (_compiler._resolver.Options.Checked && TypeUtil.IsInteger(binaryExpression.CommonType))
                    {
                        if (TypeUtil.IsUnsigned(binaryExpression.CommonType))
                        {
                            _il.Emit(OpCodes.Mul_Ovf_Un);
                        }
                        else
                        {
                            _il.Emit(OpCodes.Mul_Ovf);
                        }
                    }
                    else
                    {
                        _il.Emit(OpCodes.Mul);
                    }
                    break;

                case ExpressionType.Subtract:
                    if (_compiler._resolver.Options.Checked && TypeUtil.IsInteger(binaryExpression.CommonType))
                    {
                        if (TypeUtil.IsUnsigned(binaryExpression.CommonType))
                        {
                            _il.Emit(OpCodes.Sub_Ovf_Un);
                        }
                        else
                        {
                            _il.Emit(OpCodes.Sub_Ovf);
                        }
                    }
                    else
                    {
                        _il.Emit(OpCodes.Sub);
                    }
                    break;


                case ExpressionType.Modulo:
                    if (TypeUtil.IsUnsigned(binaryExpression.CommonType))
                    {
                        _il.Emit(OpCodes.Rem_Un);
                    }
                    else
                    {
                        _il.Emit(OpCodes.Rem);
                    }
                    break;

                default:
                    throw new InvalidOperationException();
                }
            }
예제 #6
0
 private bool IsAllowableImplicit(Type a, Type b)
 {
     return(TypeUtil.IsInteger(a) == TypeUtil.IsInteger(b));
 }
예제 #7
0
        private Type ResolveExpressionType(Type left, Type right, Type commonType, ExpressionType type)
        {
            Require.NotNull(left, "left");
            Require.NotNull(right, "right");

            // TODO: Implicit/explicit operators and operators for the expression type.

            // Boolean operators.

            switch (type)
            {
            case ExpressionType.And:
            case ExpressionType.Or:
            case ExpressionType.Xor:
            case ExpressionType.AndBoth:
            case ExpressionType.OrBoth:
                if (TypeUtil.IsInteger(commonType))
                {
                    return(commonType);
                }

                else if (left != typeof(bool) || right != typeof(bool))
                {
                    throw new ExpressionsException("Invalid operand for expression type", ExpressionsExceptionType.TypeMismatch);
                }

                return(typeof(bool));

            case ExpressionType.Greater:
            case ExpressionType.GreaterOrEquals:
            case ExpressionType.Less:
            case ExpressionType.LessOrEquals:
                if (
                    !(left.IsEnum || TypeUtil.IsNumeric(left)) ||
                    !(right.IsEnum || TypeUtil.IsNumeric(right))
                    )
                {
                    throw new ExpressionsException("Invalid operand for expression type", ExpressionsExceptionType.TypeMismatch);
                }

                return(typeof(bool));

            case ExpressionType.Equals:
            case ExpressionType.NotEquals:
            case ExpressionType.In:
            case ExpressionType.LogicalAnd:
            case ExpressionType.LogicalOr:
            case ExpressionType.Compares:
            case ExpressionType.NotCompares:
                return(typeof(bool));

            case ExpressionType.Add:
                if (
                    !(left == typeof(string) || right == typeof(string)) &&
                    !(TypeUtil.IsNumeric(left) && TypeUtil.IsNumeric(right))
                    )
                {
                    throw new ExpressionsException("Invalid operand for expression type", ExpressionsExceptionType.TypeMismatch);
                }

                return(commonType);

            case ExpressionType.Subtract:
            case ExpressionType.Multiply:
            case ExpressionType.Divide:
            case ExpressionType.Power:
                if (!TypeUtil.IsNumeric(left) || !TypeUtil.IsNumeric(right))
                {
                    throw new ExpressionsException("Invalid operand for expression type", ExpressionsExceptionType.TypeMismatch);
                }

                return(commonType);

            default:
                return(commonType);
            }
        }
예제 #8
0
        private Type ResolveExpressionCommonType(Type left, Type right, bool allowStringConcat, bool allowBothImplicit, bool allowObjectCoercion)
        {
            Require.NotNull(left, "left");
            Require.NotNull(right, "right");

            // No casting required.

            if (left == right)
            {
                return(left);
            }

            if (allowObjectCoercion)
            {
                if (left == typeof(object))
                {
                    return(right);
                }
                if (right == typeof(object))
                {
                    return(left);
                }
            }

            // Special cast for adding strings.

            if (allowStringConcat && (left == typeof(string) || right == typeof(string)))
            {
                return(typeof(string));
            }

            // Can we cast implicitly?

            var leftTable  = TypeUtil.GetImplicitCastingTable(left);
            var rightTable = TypeUtil.GetImplicitCastingTable(right);

            if (leftTable != null && rightTable != null)
            {
                // See whether one of the types appears in the other.

                foreach (var leftType in leftTable)
                {
                    if (leftType == right)
                    {
                        return(leftType);
                    }
                }

                foreach (var rightType in rightTable)
                {
                    if (rightType == left)
                    {
                        return(rightType);
                    }
                }

                // Otherwise, find the first common type.

                int lowest = int.MaxValue;

                for (int i = 0; i < leftTable.Count; i++)
                {
                    for (int j = 0; j < rightTable.Count; j++)
                    {
                        if (leftTable[i] == rightTable[j])
                        {
                            lowest = Math.Min(lowest, j);
                        }
                    }
                }

                if (lowest != int.MaxValue)
                {
                    if (
                        allowBothImplicit ||
                        (IsAllowableImplicit(left, rightTable[lowest]) && IsAllowableImplicit(right, rightTable[lowest]))
                        )
                    {
                        return(rightTable[lowest]);
                    }
                }
            }

            // We can't cast implicitly.

            throw new ExpressionsException("Cannot resolve expression type", ExpressionsExceptionType.TypeMismatch);
        }
예제 #9
0
        public IExpression UnaryExpression(Ast.UnaryExpression unaryExpression)
        {
            var operand = unaryExpression.Operand.Accept(this);

            string operatorName = null;

            switch (unaryExpression.Type)
            {
            case ExpressionType.Plus: operatorName = "op_UnaryPlus"; break;

            case ExpressionType.Minus: operatorName = "op_UnaryNegation"; break;

            case ExpressionType.Not:
            case ExpressionType.LogicalNot:
                operatorName = "op_Negation"; break;
            }

            if (operatorName != null)
            {
                var method = _resolver.FindOperatorMethod(
                    operatorName,
                    new[] { operand.Type },
                    null,
                    new[] { operand.Type }
                    );

                if (method != null)
                {
                    return(new Expressions.MethodCall(
                               new TypeAccess(method.DeclaringType),
                               method,
                               new[]
                    {
                        operand
                    }
                               ));
                }
            }

            Type type;

            switch (unaryExpression.Type)
            {
            case ExpressionType.Plus:
                if (!TypeUtil.IsValidUnaryArgument(operand.Type))
                {
                    throw new ExpressionsException("Operand of plus operation must be an integer type", ExpressionsExceptionType.TypeMismatch);
                }

                type = operand.Type;
                break;

            case ExpressionType.Group:
                type = operand.Type;
                break;

            case ExpressionType.Minus:
                if (!TypeUtil.IsValidUnaryArgument(operand.Type))
                {
                    throw new ExpressionsException("Operand of minus operation must be an integer type", ExpressionsExceptionType.TypeMismatch);
                }

                // TODO: Make constants signed and handle minus on unsigned's.

                type = operand.Type;
                break;

            case ExpressionType.LogicalNot:
                if (operand.Type != typeof(bool))
                {
                    throw new ExpressionsException("Operand of not operation must be a boolean type", ExpressionsExceptionType.TypeMismatch);
                }

                type = typeof(bool);
                break;

            case ExpressionType.BitwiseNot:
                if (!TypeUtil.IsInteger(operand.Type))
                {
                    throw new ExpressionsException(
                              "Cannot not bitwise not boolean types",
                              ExpressionsExceptionType.TypeMismatch
                              );
                }

                type = operand.Type;
                break;

            case ExpressionType.Not:
                if (TypeUtil.IsInteger(operand.Type))
                {
                    type = operand.Type;
                }
                else
                {
                    if (operand.Type != typeof(bool))
                    {
                        throw new ExpressionsException("Operand of not operation must be a boolean type", ExpressionsExceptionType.TypeMismatch);
                    }

                    type = typeof(bool);
                }
                break;

            default:
                throw new InvalidOperationException();
            }

            return(new Expressions.UnaryExpression(operand, type, unaryExpression.Type));
        }
예제 #10
0
        public IExpression IdentifierAccess(IdentifierAccess identifierAccess)
        {
            // First try variables.

            var identifiers = _resolver.DynamicExpression.ParseResult.Identifiers;

            for (int i = 0; i < _resolver.IdentifierTypes.Length; i++)
            {
                if (
                    _resolver.IdentifierTypes[i] != null &&
                    _resolver.IdentifiersEqual(identifiers[i].Name, identifierAccess.Name)
                    )
                {
                    return(VariableAccess(_resolver.IdentifierIndexes[i], _resolver.IdentifierTypes[i]));
                }
            }

            // Next, we go through the owner type.

            if (_resolver.OwnerType != null)
            {
                var result = Resolve(new VariableAccess(_resolver.OwnerType, 0), identifierAccess.Name);

                if (result == null)
                {
                    result = Resolve(new TypeAccess(_resolver.OwnerType), identifierAccess.Name);
                }

                if (result != null)
                {
                    return(result);
                }
            }

            // Next, imports. Namespaces have precedence.

            foreach (var import in _resolver.Imports)
            {
                if (
                    import.Namespace != null &&
                    _resolver.IdentifiersEqual(import.Namespace, identifierAccess.Name)
                    )
                {
                    if (import.Type != null)
                    {
                        return(new TypeAccess(import.Type));
                    }
                    else
                    {
                        return(new ImportAccess(import));
                    }
                }
            }

            // Next, members of the imports.

            foreach (var import in _resolver.Imports)
            {
                if (import.Namespace == null)
                {
                    var result = Resolve(new TypeAccess(import.Type), identifierAccess.Name);

                    if (result != null)
                    {
                        return(result);
                    }
                }
            }

            // Last, see whether the identifier is a built in type.

            var type = TypeUtil.GetBuiltInType(identifierAccess.Name, _resolver.DynamicExpression.Language);

            if (type != null)
            {
                return(new TypeAccess(type));
            }

            throw new ExpressionsException(
                      String.Format("Unresolved identifier '{0}'", identifierAccess.Name),
                      ExpressionsExceptionType.UndefinedName
                      );
        }
예제 #11
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));
        }
예제 #12
0
        internal MethodInfo FindOperatorMethod(string methodName, Type[] sourceTypes, Type returnType, Type[] parameterTypes, bool[] parametersNull)
        {
            var candidates = new List <MethodInfo>();

            foreach (var sourceType in sourceTypes)
            {
                foreach (var method in sourceType.GetMethods(BindingFlags.Static | BindingFlags.Public))
                {
                    if (method.Name != methodName)
                    {
                        continue;
                    }

                    var parameters = method.GetParameters();

                    if (parameters.Length != parameterTypes.Length)
                    {
                        continue;
                    }

                    bool match         = true;
                    bool implicitMatch = true;

                    if (returnType != null)
                    {
                        match         = returnType == method.ReturnType;
                        implicitMatch = TypeUtil.CanCastImplicitely(
                            method.ReturnType, returnType, false
                            );
                    }

                    for (int i = 0; i < parameterTypes.Length; i++)
                    {
                        if (parameters[i].ParameterType != parameterTypes[i])
                        {
                            match = false;
                        }

                        if (!TypeUtil.CanCastImplicitely(
                                parameterTypes[i],
                                parameters[i].ParameterType,
                                parametersNull != null && parametersNull[i]
                                ))
                        {
                            implicitMatch = false;
                        }
                    }

                    if (match)
                    {
                        return(method);
                    }
                    if (implicitMatch)
                    {
                        candidates.Add(method);
                    }
                }
            }

            return(candidates.Count == 1 ? candidates[0] : null);
        }