예제 #1
0
        protected override Expression VisitConditionalExpression(ConditionalExpressionBindingParserNode node)
        {
            var condition = HandleErrors(node.ConditionExpression, n => TypeConversion.ImplicitConversion(Visit(n), typeof(bool), true));
            var trueExpr  = HandleErrors(node.TrueExpression, Visit);
            var falseExpr = HandleErrors(node.FalseExpression, Visit);

            ThrowOnErrors();

            return(Expression.Condition(condition, trueExpr, falseExpr));
        }
        protected override Expression VisitBinary(BinaryExpression node)
        {
            Expression createExpr(Expression left)
            {
                return(CheckForNull(Visit(node.Right), right =>
                                    Expression.MakeBinary(node.NodeType, left, right, false, node.Method, node.Conversion),
                                    checkReferenceTypes: false));
            }

            if (node.NodeType.ToString().EndsWith("Assign"))
            {
                // only check for left target's null, assignment to null is perfectly valid
                if (node.Left is MemberExpression memberExpression)
                {
                    return(CheckForNull(Visit(memberExpression.Expression), memberTarget =>
                                        createExpr(memberExpression.Update(memberTarget))));
                }
                else if (node.Left is IndexExpression indexer)
                {
                    return(CheckForNull(Visit(indexer.Object), memberTarget =>
                                        createExpr(indexer.Update(memberTarget, indexer.Arguments))));
                }
                // this should only be ParameterExpression
                else
                {
                    return(createExpr(node.Left));
                }
            }
            else
            {
                if (true)
                {
                    var left     = Visit(node.Left);
                    var right    = Visit(node.Right);
                    var nullable = left.Type.IsNullable() ? left.Type : right.Type;
                    left  = TypeConversion.ImplicitConversion(left, nullable);
                    right = TypeConversion.ImplicitConversion(right, nullable);

                    if (right != null && left != null)
                    {
                        return(Expression.MakeBinary(node.NodeType, left, right, left.Type.IsNullable() && node.NodeType != ExpressionType.Equal && node.NodeType != ExpressionType.NotEqual, node.Method));
                    }
                    else
                    {
                        return(CheckForNull(base.Visit(node.Left), left2 =>
                                            createExpr(left2),
                                            checkReferenceTypes: false));
                    }
                }
                else
                {
                }
            }
        }
예제 #3
0
        public CastedExpressionBindingProperty ConvertExpressionToType(ParsedExpressionBindingProperty expr, ExpectedTypeBindingProperty expectedType = null)
        {
            var destType      = expectedType?.Type ?? typeof(object);
            var convertedExpr = TypeConversion.ImplicitConversion(expr.Expression, destType, throwException: false, allowToString: true);

            return(new CastedExpressionBindingProperty(
                       // if the expression is of type object (i.e. null literal) try the lambda conversion.
                       convertedExpr != null && expr.Expression.Type != typeof(object) ? convertedExpr :
                       TypeConversion.MagicLambdaConversion(expr.Expression, destType) ??
                       TypeConversion.ImplicitConversion(expr.Expression, destType, throwException: true, allowToString: true)
                       ));
        }
 protected override Expression VisitConditional(ConditionalExpression node)
 {
     return(CheckForNull(Visit(node.Test), test => {
         var ifTrue = Visit(node.IfTrue);
         var ifFalse = Visit(node.IfFalse);
         if (ifTrue.Type != ifFalse.Type)
         {
             var nullable = ifTrue.Type.IsNullable() ? ifTrue.Type : ifFalse.Type;
             ifTrue = TypeConversion.ImplicitConversion(ifTrue, nullable);
             ifFalse = TypeConversion.ImplicitConversion(ifFalse, nullable);
         }
         return Expression.Condition(test, ifTrue, ifFalse);
     }));
 }
예제 #5
0
        protected override Expression VisitConditionalExpression(ConditionalExpressionBindingParserNode node)
        {
            var condition = HandleErrors(node.ConditionExpression, n => TypeConversion.ImplicitConversion(Visit(n), typeof(bool), true));
            var trueExpr  = HandleErrors(node.TrueExpression, Visit);
            var falseExpr = HandleErrors(node.FalseExpression, Visit);

            ThrowOnErrors();

            if (trueExpr.Type != falseExpr.Type)
            {
                trueExpr  = TypeConversion.ImplicitConversion(trueExpr, falseExpr.Type, allowToString: true) ?? trueExpr;
                falseExpr = TypeConversion.ImplicitConversion(falseExpr, trueExpr.Type, allowToString: true) ?? falseExpr;
            }

            return(Expression.Condition(condition, trueExpr, falseExpr));
        }
예제 #6
0
        public static Expression GetBinaryOperator(Expression left, Expression right, ExpressionType operation)
        {
            if (operation == ExpressionType.Coalesce)
            {
                return(Expression.Coalesce(left, right));
            }
            if (operation == ExpressionType.Assign)
            {
                return(Expression.Assign(left, TypeConversion.ImplicitConversion(right, left.Type, true, true)));
            }

            // TODO: type conversions
            if (operation == ExpressionType.AndAlso)
            {
                return(Expression.AndAlso(left, right));
            }
            else if (operation == ExpressionType.OrElse)
            {
                return(Expression.OrElse(left, right));
            }

            var binder = (DynamicMetaObjectBinder)Microsoft.CSharp.RuntimeBinder.Binder.BinaryOperation(
                CSharpBinderFlags.None, operation, typeof(object), GetBinderArguments(2));
            var result = ApplyBinder(binder, false, left, right);

            if (result != null)
            {
                return(result);
            }
            if (operation == ExpressionType.Equal)
            {
                return(EqualsMethod(left, right));
            }
            if (operation == ExpressionType.NotEqual)
            {
                return(Expression.Not(EqualsMethod(left, right)));
            }

            // lift the operator
            if (left.Type.IsNullable() || right.Type.IsNullable())
            {
                return(GetBinaryOperator(left.UnwrapNullable(), right.UnwrapNullable(), operation));
            }

            throw new Exception($"could not apply { operation } binary operator to { left } and { right }");
            // TODO: comparison operators
        }
예제 #7
0
        public static Expression EqualsMethod(Expression left, Expression right)
        {
            Expression equatable = null;
            Expression theOther  = null;

            if (typeof(IEquatable <>).IsAssignableFrom(left.Type))
            {
                equatable = left;
                theOther  = right;
            }
            else if (typeof(IEquatable <>).IsAssignableFrom(right.Type))
            {
                equatable = right;
                theOther  = left;
            }

            if (equatable != null)
            {
                var m = CallMethod(equatable, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.FlattenHierarchy, "Equals", null, new[] { theOther });
                if (m != null)
                {
                    return(m);
                }
            }

            if (left.Type.GetTypeInfo().IsValueType)
            {
                equatable = left;
                theOther  = right;
            }
            else if (left.Type.GetTypeInfo().IsValueType)
            {
                equatable = right;
                theOther  = left;
            }

            if (equatable != null)
            {
                theOther = TypeConversion.ImplicitConversion(theOther, equatable.Type);
                if (theOther != null)
                {
                    return(Expression.Equal(equatable, theOther));
                }
            }

            return(CallMethod(left, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.FlattenHierarchy, "Equals", null, new[] { right }));
        }
        protected Expression CheckForNull(Expression parameter, Func <Expression, Expression> callback, bool checkReferenceTypes = true, bool suppress = false)
        {
            if (suppress || parameter == null || (parameter.Type.GetTypeInfo().IsValueType&& !parameter.Type.IsNullable()) || !checkReferenceTypes && !parameter.Type.GetTypeInfo().IsValueType)
            {
                return(callback(parameter));
            }
            var p2      = Expression.Parameter(parameter.Type, "tmp" + tmpCounter++);
            var eresult = callback(p2.Type.IsNullable() ? (Expression)Expression.Property(p2, "Value") : p2);

            eresult = TypeConversion.ImplicitConversion(eresult, eresult.Type.MakeNullableType());
            return(Expression.Block(
                       new[] { p2 },
                       Expression.Assign(p2, parameter),
                       Expression.Condition(parameter.Type.IsNullable() ? (Expression)Expression.Property(p2, "HasValue") : Expression.NotEqual(p2, Expression.Constant(null, p2.Type)),
                                            eresult,
                                            Expression.Default(eresult.Type))));
        }
예제 #9
0
 /// Performs conversions by wrapping or unwrapping results to/from <see cref="Task" />
 public static Expression TaskConversion(Expression expr, Type expectedType)
 {
     if (typeof(Task).IsAssignableFrom(expectedType))
     {
         if (!typeof(Task).IsAssignableFrom(expr.Type))
         {
             // return dummy completed task
             if (expectedType == typeof(Task))
             {
                 return(Expression.Block(expr, Expression.Call(typeof(TaskUtils), "GetCompletedTask", Type.EmptyTypes)));
             }
             else if (expectedType.GetGenericTypeDefinition() == typeof(Task <>))
             {
                 var taskType  = GetTaskType(expectedType);
                 var converted = TypeConversion.ImplicitConversion(expr, taskType);
                 if (converted != null)
                 {
                     return(Expression.Call(typeof(Task), "FromResult", new Type[] { taskType }, converted));
                 }
                 else
                 {
                     return(null);
                 }
             }
             else
             {
                 return(null);
             }
         }
         else
         {
             return(null);
         }
         // TODO: convert Task<> to another Task<>
     }
     else
     {
         return(null);
     }
 }
예제 #10
0
        /// This is a strange conversion that wraps the entire expression into a Lambda
        /// and makes an invokable delegate from a normal expression.
        /// It also replaces special ExtensionParameters attached to the expression for lambda parameters
        public static Expression MagicLambdaConversion(Expression expr, Type expectedType)
        {
            if (expectedType.IsDelegate())
            {
                var resultType   = expectedType.GetMethod("Invoke").ReturnType;
                var delegateArgs = expectedType
                                   .GetMethod("Invoke")
                                   .GetParameters()
                                   .Select(p => Expression.Parameter(p.ParameterType, p.Name))
                                   .ToArray();

                var convertedToResult = TypeConversion.ImplicitConversion(expr, resultType) ?? TaskConversion(expr, resultType);
                // TODO: convert delegates to another delegates

                if (convertedToResult == null)
                {
                    return(null);
                }
                else
                {
                    var replacedArgs = convertedToResult.ReplaceAll(arg =>
                                                                    arg?.GetParameterAnnotation()?.ExtensionParameter is MagicLambdaConversionExtensionParameter extensionParam ?
                                                                    delegateArgs.Single(a => a.Name == extensionParam.Identifier)
                                                                    .Assert(p => p.Type == ResolvedTypeDescriptor.ToSystemType(extensionParam.ParameterType)) :
                                                                    arg
                                                                    );
                    return(Expression.Lambda(
                               expectedType,
                               replacedArgs,
                               delegateArgs
                               ));
                }
            }
            else
            {
                return(null);
            }
        }
예제 #11
0
        public static Expression GetIndexer(Expression expr, Expression index)
        {
            if (expr.Type.IsArray)
            {
                return(Expression.ArrayIndex(expr, index));
            }

            var indexProp = (from p in expr.Type.GetProperties(BindingFlags.Instance | BindingFlags.Public)
                             let param = p.GetIndexParameters()
                                         where param.Length == 1
                                         let indexConvert = TypeConversion.ImplicitConversion(index, param[0].ParameterType)
                                                            where indexConvert != null
                                                            select Expression.MakeIndex(expr, p, new[] { indexConvert })).ToArray();

            if (indexProp.Length == 0)
            {
                throw new Exception($"could not find and indexer property on type { expr.Type } that accepts { index.Type } as argument");
            }
            if (indexProp.Length > 1)
            {
                throw new Exception($"more than one indexer found on type { expr.Type } that accepts { index.Type } as argument");
            }
            return(indexProp[0]);
        }
예제 #12
0
        private static MethodRecognitionResult TryCallMethod(MethodInfo method, Type[] typeArguments, Expression[] positionalArguments, IDictionary <string, Expression> namedArguments)
        {
            var parameters = method.GetParameters();

            int castCount = 0;

            if (parameters.Length < positionalArguments.Length)
            {
                return(null);
            }
            var args = new Expression[parameters.Length];

            Array.Copy(positionalArguments, args, positionalArguments.Length);
            int namedArgCount = 0;

            for (int i = positionalArguments.Length; i < args.Length; i++)
            {
                if (namedArguments?.ContainsKey(parameters[i].Name) == true)
                {
                    args[i] = namedArguments[parameters[i].Name];
                    namedArgCount++;
                }
                else if (parameters[i].HasDefaultValue)
                {
                    castCount++;
                    args[i] = Expression.Constant(parameters[i].DefaultValue, parameters[i].ParameterType);
                }
                else
                {
                    return(null);
                }
            }

            // some named arguments were not used
            if (namedArguments != null && namedArgCount != namedArguments.Count)
            {
                return(null);
            }

            int automaticTypeArgs = 0;

            // resolve generic parameters
            if (method.ContainsGenericParameters)
            {
                var typeArgs = new Type[method.GetGenericArguments().Length];
                if (typeArguments != null)
                {
                    if (typeArguments.Length > typeArgs.Length)
                    {
                        return(null);
                    }
                    Array.Copy(typeArguments, typeArgs, typeArgs.Length);
                }
                for (int i = 0; i < typeArgs.Length; i++)
                {
                    if (typeArgs[i] == null)
                    {
                        // try to resolve from arguments
                        var arg = Array.FindIndex(parameters, p => p.ParameterType.IsGenericParameter && p.ParameterType.GenericParameterPosition == i);
                        automaticTypeArgs++;
                        if (arg >= 0)
                        {
                            typeArgs[i] = args[arg].Type;
                        }
                        else
                        {
                            return(null);
                        }
                    }
                }
                method     = method.MakeGenericMethod(typeArgs);
                parameters = method.GetParameters();
            }
            else if (typeArguments != null)
            {
                return(null);
            }

            // cast arguments
            for (int i = 0; i < args.Length; i++)
            {
                var casted = TypeConversion.ImplicitConversion(args[i], parameters[i].ParameterType);
                if (casted == null)
                {
                    return(null);
                }
                if (casted != args[i])
                {
                    castCount++;
                    args[i] = casted;
                }
            }

            return(new MethodRecognitionResult {
                CastCount = castCount,
                AutomaticTypeArgCount = automaticTypeArgs,
                Method = method,
                Arguments = args
            });
        }
예제 #13
0
 public CastedExpressionBindingProperty ConvertExpressionToType(ParsedExpressionBindingProperty expr, ExpectedTypeBindingProperty expectedType = null) =>
 new CastedExpressionBindingProperty(TypeConversion.ImplicitConversion(expr.Expression, expectedType?.Type ?? typeof(object), throwException: true, allowToString: true));