private Expression MakeSelect(CurrentDependencies current, LambdaExpression selector) { var subExtractor = new DependenciesExtractor(selector, parameters.Concat(selector.Parameters)); LambdaExpression[] primarySubDependencies; LambdaExpression[] additionalSubDependencies; subExtractor.Extract(out primarySubDependencies, out additionalSubDependencies); var prefixCurrent = MakeLambda(GotoCurrent(current.Prefix)); current.AddSubDependencies(prefixCurrent, additionalSubDependencies); if (primarySubDependencies.Length > 1) { return(Expression.NewArrayInit(typeof(object), primarySubDependencies.Select(exp => Expression.Convert(prefixCurrent.Merge(exp).Body, typeof(object))))); } var primarySubDependency = primarySubDependencies.SingleOrDefault(); if (primarySubDependency == null) { return(Expression.NewArrayInit(typeof(object))); } if (!selector.ReturnType.IsAssignableFrom(primarySubDependency.ReturnType)) { return(null); } if (!(primarySubDependency.Body is NewExpression)) { return(new AnonymousTypeEliminator().Eliminate(prefixCurrent.Merge(primarySubDependency)).Body); } var newExpression = (NewExpression)primarySubDependency.Body; return(Expression.New(newExpression.Constructor, newExpression.Arguments.Select(arg => prefixCurrent.Merge(Expression.Lambda(arg, primarySubDependency.Parameters)).Body))); }
private void DefaultMethodProcessor(MethodInfo method, CurrentDependencies current, Expression[] arguments) { foreach (var argument in arguments) { Visit(argument); } }
private void DistinctMethodProcessor(MethodInfo method, CurrentDependencies current, Expression[] arguments) { if (arguments.Any()) { throw new NotSupportedException("Distinct method with arguments is not supported"); } current.AddDependency(MakeLambda(current.Prefix)); current.ReplaceCurrentWithEach(); }
private void ProcessLinqCount(MethodInfo method, CurrentDependencies current, Expression[] arguments) { var selector = (LambdaExpression)arguments.SingleOrDefault(); if (selector != null) { throw new NotSupportedException("Count method with predicate is not supported"); } current.AddDependency(MakeLambda(current.Prefix)); current.ReplaceCurrentWithEach(); }
private void ProcessExternalCurrent(MethodInfo method, CurrentDependencies current, Expression[] arguments) { var prefix = current.Prefix; if (prefix.IsAnonymousTypeCreation() || prefix.IsTupleCreation() || IsExternalCurrentCall(prefix)) { return; } if (IsEachOrCurrentCall(prefix)) { prefix = ((MethodCallExpression)prefix).Arguments[0]; } current.Prefix = Expression.Call(DependenciesExtractorHelper.ExternalCurrentMethod.MakeGenericMethod(prefix.Type.GetItemType()), prefix); }
private void ProcessLinqSum(MethodInfo method, CurrentDependencies current, Expression[] arguments) { var selector = (LambdaExpression)arguments.SingleOrDefault(); if (selector != null) { current.Prefix = MakeSelect(current, selector); } else { current.Prefix = GotoEach(current.Prefix); current.AddDependency(MakeLambda(current.Prefix)); } current.ReplaceCurrentWithEach(); }
private void ProcessLinqAggregate(MethodInfo method, CurrentDependencies current, Expression[] arguments) { switch (arguments.Length) { case 2: { var seed = arguments[0]; var selector = (LambdaExpression)arguments[1]; current.AddDependency(MakeLambda(seed)); current.Prefix = MakeSelect(current, Expression.Lambda(selector.Body, selector.Parameters[1])); current.ReplaceCurrentWithEach(); break; } default: throw new NotSupportedException(string.Format("Method '{0}' is not supported", method)); } }
private void ProcessLinqWhere(MethodInfo method, CurrentDependencies current, Expression[] arguments) { if (current.Prefix.Type == typeof(string)) { return; } var prefixCurrent = MakeLambda(GotoCurrent(current.Prefix)); var predicate = (LambdaExpression)arguments.SingleOrDefault(); if (predicate == null) { current.AddDependency(prefixCurrent); } else { var subDependencies = predicate.ExtractDependencies(parameters.Concat(predicate.Parameters)); current.AddSubDependencies(prefixCurrent, subDependencies); } }
private void ProcessLinqFirst(MethodInfo method, CurrentDependencies current, Expression[] arguments) { if (current.Prefix.Type.IsArray && method.ReturnType == current.Prefix.Type.GetItemType()) { current.Prefix = GotoEach(current.Prefix); } var predicate = (LambdaExpression)arguments.SingleOrDefault(); if (predicate == null) { current.AddDependency(MakeLambda(current.Prefix)); } else { var subDependencies = predicate.ExtractDependencies(parameters.Concat(predicate.Parameters)); current.AddSubDependencies(MakeLambda(current.Prefix), subDependencies); } current.ReplaceCurrentWithEach(); }
private void ProcessLinqSelectMany(MethodInfo method, CurrentDependencies current, Expression[] arguments) { var collectionSelector = (LambdaExpression)arguments[0]; var collection = MakeSelect(current, collectionSelector); if (collection == null) { current.Prefix = null; return; } if (arguments.Length == 1) { current.Prefix = collection; return; } var resultSelector = (LambdaExpression)arguments[1]; var subExtractor = new DependenciesExtractor(resultSelector, parameters.Concat(resultSelector.Parameters)); LambdaExpression[] primarySubDependencies; LambdaExpression[] additionalSubDependencies; subExtractor.Extract(out primarySubDependencies, out additionalSubDependencies); var prefixCurrent = MakeLambda(GotoCurrent(current.Prefix)); var collectionCurrent = MakeLambda(GotoCurrent(collection)); current.AddSubDependencies(prefixCurrent, collectionCurrent, additionalSubDependencies); var primarySubDependency = primarySubDependencies.Single(); if (!(primarySubDependency.Body is NewExpression)) { current.Prefix = new AnonymousTypeEliminator().Eliminate(new ExpressionMerger(prefixCurrent, collectionCurrent).Merge(primarySubDependency)).Body; } else { var newExpression = (NewExpression)primarySubDependency.Body; current.Prefix = Expression.New(newExpression.Constructor, newExpression.Arguments.Select(arg => new ExpressionMerger(prefixCurrent, collectionCurrent).Merge(Expression.Lambda(arg, primarySubDependency.Parameters)).Body)); } }
private void ProcessLinqAny(CurrentDependencies current, Expression[] arguments, bool emptyPredicateIsDependency) { if (current.Prefix.Type == typeof(string)) { return; } var prefixEach = MakeLambda(GotoEach(current.Prefix)); var predicate = (LambdaExpression)arguments.SingleOrDefault(); if (predicate != null) { var subDependencies = predicate.ExtractDependencies(parameters.Concat(predicate.Parameters)); current.AddSubDependencies(prefixEach, subDependencies); } else if (emptyPredicateIsDependency) { current.AddDependency(prefixEach); } current.Prefix = prefixEach.Body; current.ReplaceCurrentWithEach(); }
private void ProcessCurrentIndex(MethodInfo method, CurrentDependencies current, Expression[] arguments) { current.Prefix = Expression.ArrayLength(((MethodCallExpression)current.Prefix).Arguments.Single()); }
private void ProcessLinqSelect(MethodInfo method, CurrentDependencies current, Expression[] arguments) { current.Prefix = MakeSelect(current, (LambdaExpression)arguments.Single()); }
private void ProcessLinqToArray(MethodInfo method, CurrentDependencies current, Expression[] arguments) { ProcessLinqAny(current, arguments, false); }
private void ProcessIndexer(MethodInfo method, CurrentDependencies current, Expression[] arguments) { current.Prefix = Expression.Call(current.Prefix, method, arguments); }
private Expression VisitChain(Expression node) { var smithereens = node.SmashToSmithereens(); if (smithereens.Last().IsStringLengthPropertyAccess()) { smithereens = smithereens.Take(smithereens.Length - 1).ToArray(); } if (smithereens[0].NodeType == ExpressionType.Constant) { return(Expression.NewArrayInit(typeof(object))); } if (smithereens[0].NodeType != ExpressionType.Parameter) { return(base.Visit(node)); } var index = 0; while (index < smithereens.Length && smithereens[index].NodeType != ExpressionType.Call) { ++index; } var current = new CurrentDependencies { Prefix = smithereens[index - 1], AdditionalDependencies = new List <LambdaExpression>() }; while (index < smithereens.Length && current.Prefix != null) { var shard = smithereens[index]; var prevPrefix = current.Prefix; switch (shard.NodeType) { case ExpressionType.Call: { var methodCallExpression = (MethodCallExpression)shard; var method = methodCallExpression.Method; var arguments = (method.IsExtension() ? methodCallExpression.Arguments.Skip(1) : methodCallExpression.Arguments).ToArray(); if (method.IsGenericMethod) { method = method.GetGenericMethodDefinition(); } var methodProcessor = GetMethodProcessor(method); if (methodProcessor == null) { throw new NotSupportedException("Method '" + method + "' is not supported"); } methodProcessor(methodCallExpression.Method, current, arguments); break; } case ExpressionType.MemberAccess: { var member = ((MemberExpression)shard).Member; if (!(current.Prefix is NewExpression)) { current.Prefix = Expression.MakeMemberAccess(current.Prefix, member); } else { if (!current.Prefix.IsAnonymousTypeCreation() && !current.Prefix.IsTupleCreation()) { throw new NotSupportedException("An anonymous type or a tuple creation expected but was " + ExpressionCompiler.DebugViewGetter(current.Prefix)); } var newExpression = (NewExpression)current.Prefix; var type = newExpression.Type; MemberInfo[] members; if (member is PropertyInfo) { members = type.GetProperties(BindingFlags.Instance | BindingFlags.Public); } else { throw new NotSupportedException(); } var i = Array.IndexOf(members, member); if (i < 0 || i >= newExpression.Arguments.Count) { throw new InvalidOperationException(); } var newArrayExpression = (NewArrayExpression)ClearConverts(newExpression.Arguments[i]); current.Prefix = newArrayExpression.Expressions.Count == 1 ? ClearConverts(newArrayExpression.Expressions[0]) : newArrayExpression; } } break; case ExpressionType.ArrayIndex: if (current.Prefix.Type.IsArray) { current.Prefix = Expression.MakeBinary(ExpressionType.ArrayIndex, current.Prefix, ((BinaryExpression)shard).Right); } break; case ExpressionType.Convert: if (current.Prefix.Type == typeof(object)) { current.Prefix = Expression.Convert(current.Prefix, shard.Type); } break; default: throw new InvalidOperationException("Node type '" + shard.NodeType + "' is not supported"); } if (current.Prefix == null) { current.Prefix = prevPrefix; break; } ++index; } var primaryDependencies = new List <Expression>(); if (current.Prefix != null) { if (current.Prefix is NewExpression) { if (!current.Prefix.IsAnonymousTypeCreation() && !current.Prefix.IsTupleCreation()) { primaryDependencies.AddRange(((NewExpression)current.Prefix).Arguments); } else { foreach (var expression in ((NewExpression)current.Prefix).Arguments.Select(ClearConverts)) { primaryDependencies.AddRange(((NewArrayExpression)expression).Expressions.Select(ClearConverts)); } } } else if (current.Prefix is NewArrayExpression) { primaryDependencies.AddRange(((NewArrayExpression)current.Prefix).Expressions.Select(ClearConverts)); } else if (IsPrimary(smithereens.Last())) { primaryDependencies.Add(current.Prefix); } } dependencies.AddRange(current.AdditionalDependencies); return(Expression.NewArrayInit(typeof(object), primaryDependencies.Select(dependency => Expression.Convert(dependency, typeof(object))))); }