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))); }
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)); }
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); }
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); }