Exemplo n.º 1
0
        protected override Expression VisitMethodCall(MethodCallExpression node)
        {
            var method = node.Method;

            if (method.IsGenericMethod)
            {
                method = method.GetGenericMethodDefinition();
            }
            if (method == MutatorsHelperFunctions.CurrentIndexMethod)
            {
                var item = (MethodCallExpression)node.Arguments.Single();
                if (!item.Method.IsEachMethod() && !item.Method.IsCurrentMethod())
                {
                    throw new InvalidOperationException();
                }
                var collection = Visit(item.Arguments.Single());
                var itemType   = collection.Type.GetItemType();
                return(Expression.Call(method.MakeGenericMethod(itemType), Expression.Call(item.Method.GetGenericMethodDefinition().MakeGenericMethod(itemType), collection)));
            }

            if (method.DeclaringType != typeof(Enumerable))
            {
                return(base.VisitMethodCall(node));
            }
            var obj        = node.Arguments[0];
            var arguments  = node.Arguments.Skip(1).ToArray();
            var visitedObj = Visit(obj);

            if (obj.Type == visitedObj.Type)
            {
                return(node.Update(node.Object, new[] { visitedObj }.Concat(arguments.Select(Visit))));
            }
            var visitedArguments = new List <Expression>();
            var path             = Expression.Call(MutatorsHelperFunctions.CurrentMethod.MakeGenericMethod(obj.Type.GetItemType()), obj);

            foreach (var argument in arguments)
            {
                if (!(argument is LambdaExpression))
                {
                    visitedArguments.Add(Visit(argument));
                }
                else
                {
                    var lambdaArg = (LambdaExpression)argument;
                    if (lambdaArg.Parameters.Count != 1)
                    {
                        throw new NotSupportedException("Unsupported lambda " + ExpressionCompiler.DebugViewGetter(lambdaArg));
                    }
                    lambdaArg = Expression.Lambda(path, path.ExtractParameters()).Merge(lambdaArg);
                    var visitedArg  = Visit(lambdaArg.Body);
                    var parameter   = Expression.Parameter(visitedObj.Type.GetItemType());
                    var resolvedArg = new AliasesResolver(new List <KeyValuePair <Expression, Expression> > {
                        new KeyValuePair <Expression, Expression>(parameter, Expression.Call(MutatorsHelperFunctions.CurrentMethod.MakeGenericMethod(visitedObj.Type.GetItemType()), visitedObj))
                    }).Visit(visitedArg);
                    visitedArguments.Add(Expression.Lambda(resolvedArg, parameter));
                }
            }

            return(Expression.Call(method.MakeGenericMethod(new[] { visitedObj.Type.GetItemType() }.Concat(node.Method.GetGenericArguments().Skip(1)).ToArray()), new[] { visitedObj }.Concat(visitedArguments)));
        }
Exemplo n.º 2
0
        private Expression ConstructByLeaves(Expression path, IEnumerable <KeyValuePair <Expression, Expression> > leaves)
        {
            ParameterExpression parameter = Expression.Parameter(path.Type);
            var resolver = new AliasesResolver(new List <KeyValuePair <Expression, Expression> > {
                new KeyValuePair <Expression, Expression>(parameter, path)
            });
            var tree = new Hashtable();

            foreach (var leaf in leaves)
            {
                var pathToLeaf = resolver.Visit(leaf.Key);
                var shards     = pathToLeaf.SmashToSmithereens();
                var node       = tree;
                for (int i = 1; i < shards.Length; ++i)
                {
                    var    shard = shards[i];
                    object key;
                    switch (shard.NodeType)
                    {
                    case ExpressionType.MemberAccess:
                        key = ((MemberExpression)shard).Member;
                        break;

                    case ExpressionType.ArrayIndex:
                        var index = ((BinaryExpression)shard).Right;
                        if (index.NodeType != ExpressionType.Constant)
                        {
                            throw new NotSupportedException("Node type '" + index.NodeType + "' is not supported");
                        }
                        key = ((ConstantExpression)index).Value;
                        break;

                    default:
                        return(null);
                    }

                    if (i == shards.Length - 1)
                    {
                        node[key] = leaf.Value;
                    }
                    else
                    {
                        if (node[key] == null)
                        {
                            node[key] = new Hashtable();
                        }
                        node = (Hashtable)node[key];
                    }
                }
            }

            return(Construct(path.Type, tree));
        }
        public LambdaExpression Resolve(LambdaExpression expression)
        {
            if (expression == null)
            {
                return(null);
            }
            var aliasesResolver = new AliasesResolver(aliases);
            var result          = (LambdaExpression)aliasesResolver.Visit((Expression)expression);
            var newParameters   = new List <ParameterExpression>();

            foreach (var parameter in expression.Parameters)
            {
                newParameters.Add(aliasesResolver.TargetParameterToReplacementParameterMapping.TryGetValue(parameter, out var newParameter) ? newParameter : parameter);
            }
            return(Expression.Lambda(result.Body, newParameters));
        }
Exemplo n.º 4
0
        private List <KeyValuePair <Expression, Expression> > GetConditionalSettersInternal(Expression node, out bool onlyLeavesAreConvertible)
        {
            onlyLeavesAreConvertible = false;
            var traverseResult   = ModelConfigurationTreeTraveler.Traverse(convertationTree, node, subRoot: null, create: false);
            var convertationNode = traverseResult.Child;
            var arrayAliases     = traverseResult.ArrayAliases;

            if (convertationNode == null)
            {
                return(null);
            }
            var resolver = new AliasesResolver(arrayAliases);
            var setters  = convertationNode.GetMutators().OfType <EqualsToConfiguration>().ToArray();

            if (setters.Length == 0)
            {
                onlyLeavesAreConvertible = true;
                if (node.Type.IsArray /* || node.Type.IsDictionary()*/)
                {
                    var        arrays = convertationNode.GetArrays();
                    Expression array;
                    if (arrays.TryGetValue(To, out array) && array != null)
                    {
                        var arrayItemConvertationNode = convertationNode.GotoEachArrayElement(false);
                        if (arrayItemConvertationNode != null)
                        {
                            var setter = (EqualsToConfiguration)arrayItemConvertationNode.GetMutators().SingleOrDefault(mutator => mutator is EqualsToConfiguration);
                            if (setter != null)
                            {
                                var convertedArray = ConvertArray(array, setter.Value.Body);
                                return(new List <KeyValuePair <Expression, Expression> > {
                                    new KeyValuePair <Expression, Expression>(convertedArray, null)
                                });
                            }
                        }

                        return(new List <KeyValuePair <Expression, Expression> > {
                            new KeyValuePair <Expression, Expression>(array, null)
                        });
                    }
                }

                var children = new List <ModelConfigurationNode>();
                convertationNode.FindSubNodes(children);
                children = children.Where(child => child.GetMutators().Any(mutator => mutator is EqualsToConfiguration)).ToList();
                if (children.Count > 0)
                {
                    var leaves = new List <KeyValuePair <Expression, Expression> >();
                    foreach (var child in children)
                    {
                        var leaf = Perform(child.Path);
                        if (leaf != null)
                        {
                            leaves.Add(new KeyValuePair <Expression, Expression>(child.Path, leaf));
                        }
                    }

                    var constructedByLeaves = ConstructByLeaves(node, leaves);
                    if (constructedByLeaves == null)
                    {
                        return(null);
                    }
                    return(new List <KeyValuePair <Expression, Expression> > {
                        new KeyValuePair <Expression, Expression>(constructedByLeaves, null)
                    });
                }

                return(null);
            }

            var  result = new List <KeyValuePair <Expression, Expression> >();
            bool wasUnconditionalSetter = false;

            for (int index = setters.Length - 1; index >= 0; --index)
            {
                var mutator = setters[index];
                LambdaExpression             value;
                Expression                   condition;
                StaticValidatorConfiguration validator;
                var equalsToIfConfiguration = mutator as EqualsToIfConfiguration;
                if (equalsToIfConfiguration == null)
                {
                    if (wasUnconditionalSetter)
                    {
                        continue;
                    }
                    wasUnconditionalSetter = true;
                    value     = mutator.Value;
                    condition = null;
                    validator = mutator.Validator;
                }
                else
                {
                    value     = equalsToIfConfiguration.Value;
                    condition = lambda.Merge(Perform(equalsToIfConfiguration.Condition)).Body;
                    validator = equalsToIfConfiguration.Validator;
                }

                if (validator != null)
                {
                    if (arrayAliases != null)
                    {
                        var validationResult = validator.Apply(mutator.ConverterType, arrayAliases);
                        if (validationResult != null)
                        {
                            validationResult = Expression.Coalesce(validationResult, Expression.Constant(ValidationResult.Ok));
                            var valueIsValid = Expression.NotEqual(Expression.MakeMemberAccess(validationResult, validationResultTypeProperty), Expression.Constant(ValidationResultType.Error));
                            condition = condition == null ? valueIsValid : Expression.AndAlso(Convert(condition, typeof(bool)), valueIsValid).CanonizeParameters();
                        }
                    }
                }

                result.Add(new KeyValuePair <Expression, Expression>(resolver.Visit(lambda.Merge(Perform(value)).Body), resolver.Visit(condition)));
            }

            return(result);
        }
Exemplo n.º 5
0
        private Expression ApplyFilters(Expression node, List <LambdaExpression> filters)
        {
            if (filters.All(exp => exp == null))
            {
                return(node);
            }
            var shards = node.SmashToSmithereens();
            var result = shards[0];
            int index  = 0;

            for (int i = 1; i < shards.Length; ++i)
            {
                var shard = shards[i];
                switch (shard.NodeType)
                {
                case ExpressionType.MemberAccess:
                    result = Expression.MakeMemberAccess(result, ((MemberExpression)shard).Member);
                    break;

                case ExpressionType.ArrayIndex:
                    result = Expression.ArrayIndex(result, ((BinaryExpression)shard).Right);
                    break;

                case ExpressionType.Call:
                    var methodCallExpression = (MethodCallExpression)shard;
                    if (methodCallExpression.Method.IsCurrentMethod() || methodCallExpression.Method.IsEachMethod())
                    {
                        var filter = filters[index++];
                        if (filter != null)
                        {
                            var performedFilter = Perform(filter.Body);
                            var parameter       = Expression.Parameter(result.Type.GetItemType());
                            var aliasez         = new List <KeyValuePair <Expression, Expression> > {
                                new KeyValuePair <Expression, Expression>(parameter, methodCallExpression)
                            };
                            var resolvedPerformedFilter = new AliasesResolver(aliasez).Visit(performedFilter);
                            result = Expression.Call(whereMethod.MakeGenericMethod(result.Type.GetItemType()), result, Expression.Lambda(resolvedPerformedFilter, parameter));
                            result = Expression.Call(methodCallExpression.Method, result);
                            break;
                        }
                    }

                    result = methodCallExpression.Method.IsStatic
                                 ? Expression.Call(methodCallExpression.Method, new[] { result }.Concat(methodCallExpression.Arguments.Skip(1)))
                                 : Expression.Call(result, methodCallExpression.Method, methodCallExpression.Arguments);
                    break;

                default:
                    throw new NotSupportedException("Node type '" + shard.NodeType + "' is not supported");
                }
            }

            if (index < filters.Count)
            {
                var filter          = filters[index++];
                var performedFilter = Perform(filter.Body);
                var parameter       = Expression.Parameter(result.Type.GetItemType());
                var aliasez         = new List <KeyValuePair <Expression, Expression> > {
                    new KeyValuePair <Expression, Expression>(parameter, Expression.Call(MutatorsHelperFunctions.EachMethod.MakeGenericMethod(node.Type.GetItemType()), node))
                };
                var resolvedPerformedFilter = new AliasesResolver(aliasez).Visit(performedFilter);
                result = Expression.Call(whereMethod.MakeGenericMethod(result.Type.GetItemType()), result, Expression.Lambda(resolvedPerformedFilter, parameter));
            }

            if (index < filters.Count)
            {
                throw new InvalidOperationException("Too many filters to apply");
            }
            return(result);
        }