Expression ConvertSelector(MethodCallExpression method) { if (method.Arguments.Count != 2) { return(method); } var types = method.Method.DeclaringType == typeof(Enumerable) ? method.Method.GetParameters()[1].ParameterType.GetGenericArguments() : method.Method.GetParameters()[1].ParameterType.GetGenericArguments()[0].GetGenericArguments(); var cm = GetQueriableMethodInfo(method, m => m.Name == method.Method.Name && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType.GetGenericArguments()[0] == types[1]); var sm = method.Method.DeclaringType == typeof(Enumerable) ? EnumerableMethods .Where(m => m.Name == "Select" && m.GetParameters().Length == 2) .First(m => m.GetParameters()[1].ParameterType.GetGenericArguments().Length == 2) : QueryableMethods .Where(m => m.Name == "Select" && m.GetParameters().Length == 2) .First(m => m.GetParameters()[1].ParameterType.GetGenericArguments()[0].GetGenericArguments().Length == 2); var argType = types[0]; sm = sm.MakeGenericMethod(argType, types[1]); return(Expression.Call(null, cm, Expression.Call(null, sm, OptimizeExpression(method.Arguments[0]), OptimizeExpression(method.Arguments[1])))); }
Expression ConvertPredicate(MethodCallExpression method) { if (method.Arguments.Count != 2) { return(method); } var cm = GetQueriableMethodInfo(method, m => m.Name == method.Method.Name && m.GetParameters().Length == 1); var wm = method.Method.DeclaringType == typeof(Enumerable) ? EnumerableMethods .Where(m => m.Name == "Where" && m.GetParameters().Length == 2) .First(m => m.GetParameters()[1].ParameterType.GetGenericArguments().Length == 2) : QueryableMethods .Where(m => m.Name == "Where" && m.GetParameters().Length == 2) .First(m => m.GetParameters()[1].ParameterType.GetGenericArguments()[0].GetGenericArguments().Length == 2); var argType = method.Method.GetGenericArguments()[0]; wm = wm.MakeGenericMethod(argType); cm = cm.MakeGenericMethod(argType); return(Expression.Call(null, cm, Expression.Call(null, wm, OptimizeExpression(method.Arguments[0]), OptimizeExpression(method.Arguments[1])))); }
private static Term MkMGU(StdTerm t, EquivalenceRelation <StdTerm> eqs, Func <int, Term> varCreator) { Term normVar; StdTerm stdRep, stdX; int i, label; bool wasAdded; var varMap = new Map <StdTerm, Term>(StdTerm.Compare); var labelStack = new Stack <int>(); labelStack.Push(t.label); var result = t.term.Compute <Term>( (x, s) => { if (x.Groundness == Groundness.Ground) { labelStack.Push(labelStack.Peek()); return(null); } else if (!x.Symbol.IsVariable) { labelStack.Push(labelStack.Peek()); return(x.Args); } stdX = x.Standardize(labelStack.Peek()); if (eqs.GetTracker(stdX, Track_FreeApply, out stdRep)) { labelStack.Push(stdRep.label); return(EnumerableMethods.GetEnumerable <Term>(stdRep.term)); } else if (StdTerm.Compare(stdRep = eqs.GetRepresentative(stdX), stdX) == 0) { labelStack.Push(labelStack.Peek()); return(null); } else { labelStack.Push(stdRep.label); return(EnumerableMethods.GetEnumerable <Term>(stdRep.term)); } }, (x, c, s) => { label = labelStack.Pop(); if (x.Groundness == Groundness.Ground) { return(x); } else if (!x.Symbol.IsVariable) { i = 0; var args = new Term[x.Symbol.Arity]; foreach (var tp in c) { args[i++] = tp; } return(x.Owner.MkApply(x.Symbol, args, out wasAdded)); } if (c.IsEmpty <Term>()) { if (!varMap.TryFindValue(x.Standardize(label), out normVar)) { normVar = varCreator(varMap.Count); varMap.Add(x.Standardize(label), normVar); } return(normVar); } else { return(c.First <Term>()); } }); Contract.Assert(labelStack.Count == 1); return(result); }
MethodInfo GetQueriableMethodInfo(MethodCallExpression method, Func <MethodInfo, bool> predicate) { return(method.Method.DeclaringType == typeof(Enumerable) ? EnumerableMethods.First(predicate) : QueryableMethods.First(predicate)); }
Expression ConvertSubquery(Expression expr) { var ex = expr; while (ex != null) { switch (ex.NodeType) { default: return(expr); case ExpressionType.MemberAccess: ex = ((MemberExpression)ex).Expression; break; case ExpressionType.Call: { var call = (MethodCallExpression)ex; if (call.Object == null) { if (call.IsQueryable()) { switch (call.Method.Name) { case "Single": case "SingleOrDefault": case "First": case "FirstOrDefault": { var param = Expression.Parameter(call.Type, "p"); var selector = expr.Convert(e => e == call ? param : e); var method = GetQueriableMethodInfo(call, m => m.Name == call.Method.Name && m.GetParameters().Length == 1); var select = call.Method.DeclaringType == typeof(Enumerable) ? EnumerableMethods .Where(m => m.Name == "Select" && m.GetParameters().Length == 2) .First(m => m.GetParameters()[1].ParameterType.GetGenericArguments().Length == 2) : QueryableMethods .Where(m => m.Name == "Select" && m.GetParameters().Length == 2) .First(m => m.GetParameters()[1].ParameterType.GetGenericArguments()[0].GetGenericArguments().Length == 2); call = (MethodCallExpression)OptimizeExpression(call); select = select.MakeGenericMethod(call.Type, expr.Type); method = method.MakeGenericMethod(expr.Type); return(Expression.Call(null, method, Expression.Call(null, select, call.Arguments[0], Expression.Lambda(selector, param)))); } } } return(expr); } ex = call.Object; break; } } } return(expr); }
Expression OptimizeExpression(Expression expression) { return(expression.Convert(expr => { switch (expr.NodeType) { case ExpressionType.MemberAccess: { var me = (MemberExpression)expr; // Replace Count with Count() // if (me.Member.Name == "Count") { var isList = typeof(ICollection).IsAssignableFrom(me.Member.DeclaringType); if (!isList) { isList = me.Member.DeclaringType.GetInterfaces() .Any(t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(IList <>)); } if (isList) { var mi = EnumerableMethods .First(m => m.Name == "Count" && m.GetParameters().Length == 1) .MakeGenericMethod(TypeHelper.GetElementType(me.Expression.Type)); return Expression.Call(null, mi, me.Expression); } } if (CompiledParameters == null && TypeHelper.IsSameOrParent(typeof(IQueryable), expr.Type)) { var ex = ConvertIQueriable(expr); if (ex != expr) { return ConvertExpressionTree(ex); } } return ConvertSubquery(expr); } case ExpressionType.Call: { var call = (MethodCallExpression)expr; if (call.IsQueryable()) { switch (call.Method.Name) { case "GroupBy": return ConvertGroupBy(call); case "SelectMany": return ConvertSelectMany(call); case "LongCount": case "Count": case "Single": case "SingleOrDefault": case "First": case "FirstOrDefault": return ConvertPredicate(call); case "Sum": case "Min": case "Max": case "Average": return ConvertSelector(call); } } return ConvertSubquery(expr); } } return expr; })); }
protected override Expression VisitMethodCall(MethodCallExpression m) { m = base.VisitMethodCall(m) as MethodCallExpression; var lambda = MethodMapping.ConvertMember(m.Method); if (lambda != null) { var ef = lambda.Body.Unwrap(); var parms = new Dictionary <string, ParameterMapping>(lambda.Parameters.Count); var pn = m.Method.IsStatic ? 0 : -1; foreach (var p in lambda.Parameters) { parms.Add(p.Name, new ParameterMapping(pn++, p.Type)); } var pie = ef.Convert(wpi => { if (wpi.NodeType == ExpressionType.Parameter) { ParameterMapping n; if (parms.TryGetValue(((ParameterExpression)wpi).Name, out n)) { var tmp = n.Index < 0 ? m.Object : m.Arguments[n.Index]; if (tmp.Type != n.Type) { return(Expression.Convert(tmp, n.Type)); } return(tmp); } } return(wpi); }); if (m.Method.ReturnType != pie.Type) { pie = Expression.Convert(pie, m.Method.ReturnType); } return(Visit(pie)); } var methodName = m.Method.Name; var declaringType = m.Method.DeclaringType; if (declaringType == typeof(System.Convert)) { Expression operand = null; Type toType = null; if (m.Method.Name.StartsWith("To")) { toType = ClassLoader.Load("System." + m.Method.Name.Replace("To", "")); operand = m.Arguments[0]; } if (operand != null && toType != null && toType != Types.Object) { return(Expression.Call(MethodRepository.GetConvertMethod(operand.Type, toType), operand)); } } if (typeof(TypeConverter).IsAssignableFrom(declaringType)) { Expression operand = null; Type toType = null; if (methodName.StartsWith("ConvertFrom")) { var c = m.Object as ConstantExpression; Type converterType = null; if (c != null) { converterType = (m.Object as ConstantExpression).Value.GetType(); } else { var ma = m.Object as MemberExpression; if (ma != null) { c = ma.Expression as ConstantExpression; if (c == null) { throw new NotSupportedException(string.Format("The method '{0}' is not supported", m.Method.Name)); } converterType = ma.Member.GetGetter()(c.Value).GetType(); } } toType = ClassLoader.Load("System." + converterType.Name.Replace("Converter", "")); if (toType == null) { throw new NotSupportedException(string.Format("The method '{0}' is not supported", m.Method.Name)); } if (methodName == "ConvertFrom" && m.Arguments.Count == 1) { operand = m.Arguments[0]; } else if (methodName == "ConvertFromString" && m.Arguments.Count == 1) { operand = m.Arguments[0]; } else if (methodName == "ConvertFromInvariantString" && m.Arguments.Count == 1) { operand = m.Arguments[0]; } } else if (methodName == "ConvertTo" && m.Arguments.Count == 2) { operand = m.Arguments[0]; toType = (m.Arguments[1] as ConstantExpression).Value as Type; } else if (methodName == "ConvertToInvariantString" && m.Arguments.Count == 1) { operand = m.Arguments[0]; toType = Types.String; } else if (methodName == "ConvertToString" && m.Arguments.Count == 1) { operand = m.Arguments[0]; toType = Types.String; } if (operand != null && toType != null && toType != Types.Object) { return(Expression.Call(MethodRepository.GetConvertMethod(operand.Type, toType), operand)); } throw new NotSupportedException(string.Format("The method '{0}' is not supported", methodName)); } if (methodName == "Parse" && m.Method.IsStatic && (declaringType.IsValueType || declaringType.IsNullable()) && m.Arguments.Count == 1 && m.Method.ReturnType == m.Type) { Expression operand = m.Arguments[0]; Type toType = declaringType.IsNullable() ? Nullable.GetUnderlyingType(declaringType) : declaringType; return(Expression.Call(MethodRepository.GetConvertMethod(operand.Type, toType), operand)); } if (declaringType == Types.String) { if (methodName == "Concat") { return(BindConcat(m.Arguments.ToArray())); } if (methodName == "Join") { return(BindJoin(m)); } } if (methodName == "ContainsValue" && IsSameOrParent(typeof(IDictionary <,>), declaringType)) { var args = GetGenericArguments(declaringType, typeof(IDictionary <,>)); var minf = EnumerableMethods .First(s => s.Name == "Contains" && s.GetParameters().Length == 2) .MakeGenericMethod(args[1]); return(Expression.Call( minf, Expression.PropertyOrField(m.Object, "Values"), m.Arguments[0])); } if (methodName == "ContainsKey" && IsSameOrParent(typeof(IDictionary <,>), declaringType)) { var args = GetGenericArguments(declaringType, typeof(IDictionary <,>)); var minf = EnumerableMethods .First(s => s.Name == "Contains" && s.GetParameters().Length == 2) .MakeGenericMethod(args[1]); return(Expression.Call( minf, Expression.PropertyOrField(m.Object, "Keys"), m.Arguments[0])); } if (declaringType.FullName == DLinq.StrSqlMethhodsType && declaringType.Assembly.GetName().Name == DLinq.StrAssemblyName) { DLinq.Init(declaringType.Assembly); return(Visit(m)); } //if (methodName == "Like" && declaringType == typeof(SqlFunctions) && m.Arguments.Count == 5) //{ // return BindLike( // m.Arguments[0] // , m.Arguments[1] // , (bool)(m.Arguments[2] as ConstantExpression).Value // , (bool)(m.Arguments[3] as ConstantExpression).Value // , (bool)(m.Arguments[4] as ConstantExpression).Value); //} if (typeof(Queryable).IsAssignableFrom(declaringType) || typeof(Enumerable).IsAssignableFrom(declaringType)) { var elementType = NLite.Data.Linq.Internal.ReflectionHelper.GetElementType(m.Arguments[0].Type); switch (methodName) { case "Contains": EntityMapping mapping; if (DbContext.dbConfiguration.mappings.TryGetValue(elementType.TypeHandle.Value, out mapping)) { // Expression left = } break; //case "Aggregate": // { // var type = NLite.Reflection.TypeHelper.GetElementType(m.Arguments[0].Type); // if (type.IsNullable()) // type = Nullable.GetUnderlyingType(type); // if (type.IsClass && type != Types.String) // throw new NotSupportedException("Not support 'Aggregate' function for complex type."); // break; // } //case "ElementAt": // var index = m.Arguments[1]; // var elementType = NLite.Reflection.TypeHelper.GetElementType(m.Arguments[0].Type); // var c = index as ConstantExpression; // if (c != null) // { // if((int)c.Value == 0) // return Expression.Call(typeof(Enumerable), "Take", new Type[] { elementType }, m.Arguments[0], Expression.Constant(1, Types.Int32)); // index = Expression.Constant((int)c.Value + 1, Types.Int32); // } // else // index = Expression.Add(index, Expression.Constant(1, Types.Int32)); // var s = Expression.Call(typeof(Enumerable), "Skip", new Type[] { elementType },m.Arguments[0], index); // return Expression.Call(typeof(Enumerable), "Take", new Type[] { elementType },s, Expression.Constant(1,Types.Int32)); } } if (IsSameOrParent(typeof(IEnumerable <>), declaringType) && !declaringType.IsArray && m.Object != null && m.Object.NodeType == ExpressionType.Constant && !typeof(IQueryable).IsAssignableFrom(declaringType)) { switch (methodName) { case "Contains": var elementType = NLite.Data.Linq.Internal.ReflectionHelper.GetElementType(declaringType); if (!DbContext.dbConfiguration.HasClass(elementType) && elementType != Types.Char) { var lst = (m.Object as ConstantExpression).Value as IEnumerable; if (lst != null) { var items = lst.Cast <object>().ToArray(); var arry = Array.CreateInstance(elementType, items.Length); for (int i = 0; i < items.Length; i++) { arry.SetValue(items[i], i); } Expression array = Expression.Constant(arry); var containsMethod = EnumerableMethods .First(s => s.Name == "Contains" && s.GetParameters().Length == 2) .MakeGenericMethod(elementType); m = Expression.Call(containsMethod, array, m.Arguments[0]); } } break; } } return(m); }
protected override Expression <Func <TFrom, TTo, bool> > CompileToExpression() { var from = Expression.Parameter(typeof(IEnumerable <>).MakeGenericType(EnumerableReflection <TFrom> .ItemType), "from"); var to = Expression.Parameter(typeof(IEnumerable <>).MakeGenericType(EnumerableReflection <TTo> .ItemType), "to"); var fromEnumeratorVariable = Expression.Parameter(typeof(IEnumerator <>).MakeGenericType(EnumerableReflection <TFrom> .ItemType), "fromEnumerator"); var toEnumeratorVariable = Expression.Parameter(typeof(IEnumerator <>).MakeGenericType(EnumerableReflection <TTo> .ItemType), "toEnumerator"); var hasFromVariable = Expression.Parameter(typeof(bool), "hasFrom"); var hasToVariable = Expression.Parameter(typeof(bool), "hasTo"); var end = Expression.Label(typeof(bool)); Expression nullHandling; if (this.aMapNullToEmpty) { nullHandling = Expression.IfThen( Expression.Equal(from, Expression.Constant(null, from.Type)), Expression.Return( end, Expression.Not( Expression.Call(LinqMethods.Any(EnumerableReflection <TTo> .ItemType), to) ) ) ); } else { nullHandling = Expression.Empty(); } return(Expression.Lambda <Func <TFrom, TTo, bool> >( Expression.Block( new[] { fromEnumeratorVariable, toEnumeratorVariable, hasFromVariable, hasToVariable }, nullHandling, Expression.Assign(fromEnumeratorVariable, Expression.Call(from, EnumerableMethods.GetEnumerable(EnumerableReflection <TFrom> .ItemType))), Expression.Assign(toEnumeratorVariable, Expression.Call(to, EnumerableMethods.GetEnumerable(EnumerableReflection <TTo> .ItemType))), Expression.Loop( Expression.Block( Expression.Assign(hasFromVariable, Expression.Call(fromEnumeratorVariable, EnumerableMethods.MoveNext(EnumerableReflection <TFrom> .ItemType))), Expression.Assign(hasToVariable, Expression.Call(toEnumeratorVariable, EnumerableMethods.MoveNext(EnumerableReflection <TTo> .ItemType))), Expression.IfThen( Expression.AndAlso( Expression.Not(hasFromVariable), Expression.Not(hasToVariable) ), Expression.Return(end, Expression.Constant(true)) ), Expression.IfThen( Expression.OrElse( Expression.Not(hasFromVariable), Expression.Not(hasToVariable) ), Expression.Return(end, Expression.Constant(false)) ), Expression.IfThen( Expression.Not( this.CreateItemEqualityExpression( Expression.Property(fromEnumeratorVariable, EnumerableMethods.Current(EnumerableReflection <TFrom> .ItemType)), Expression.Property(toEnumeratorVariable, EnumerableMethods.Current(EnumerableReflection <TTo> .ItemType)) ) ), Expression.Return(end, Expression.Constant(false)) ) ) ), Expression.Label(end, Expression.Constant(true)) ), from, to )); }
public bool Validate(List <Flag> flags, CancellationToken cancel, bool isCompilerAction = false) { if (myComprData != null && myComprData.Depth > MaxDepth) { var flag = new Flag( SeverityKind.Error, AST.Node, Constants.BadSyntax.ToString( string.Format("Comprehension nesting too deep. Maximum nesting depth is {0}.", MaxDepth)), Constants.BadSyntax.Code); flags.Add(flag); return(RecordValidationResult(false)); } IEnumerable <Node> heads = null; IEnumerable <Body> bodies = null; switch (AST.Node.NodeKind) { case NodeKind.Compr: heads = ((Compr)AST.Node).Heads; bodies = ((Compr)AST.Node).Bodies; break; case NodeKind.Rule: heads = ((Rule)AST.Node).Heads; bodies = ((Rule)AST.Node).Bodies; break; default: throw new NotImplementedException(); } if (heads.IsEmpty <Node>()) { var flag = new Flag( SeverityKind.Error, AST.Node, Constants.BadSyntax.ToString("The expression has no heads."), Constants.BadSyntax.Code); flags.Add(flag); return(RecordValidationResult(false)); } //// Step 1.a. If the body is empty, treat it like a TRUE body. var result = true; if (bodies.IsEmpty <Body>()) { bodies = EnumerableMethods.GetEnumerable <Body>(MkTrueBody(heads.First <Node>().Span)); } //// Step 1.b. Otherwise, find all the variables (possibly) with selectors //// occurring in all the heads. These will be registered with the bodies. var varList = new LinkedList <Id>(); foreach (var h in heads) { FindVarLikeIds(h, varList); } //// Step 2. Expand heads / bodies. Term type; TypeEnvironment bodyEnv; foreach (var b in bodies) { bodyEnv = TypeEnvironment.AddChild(b); var cs = new ConstraintSystem(Index, b, bodyEnv, myComprData); if (!cs.Validate(flags, varList, cancel)) { result = false; continue; } foreach (var v in cs.Variables) { if (cs.TryGetType(v, out type)) { bodyEnv.SetType(v, type); } } foreach (var h in heads) { var act = new Action(h, cs, TypeEnvironment, myComprData, AST.Node); if (act.Validate(flags, cancel, isCompilerAction)) { actions.AddLast(act); } else { result = false; } if (cancel.IsCancellationRequested) { return(RecordValidationResult(false)); } } } if (result && !cancel.IsCancellationRequested) { TypeEnvironment.JoinTypes(); Contract.Assert(AST.Node.CompilerData == null); AST.Node.CompilerData = TypeEnvironment; return(RecordValidationResult(true)); } else { return(RecordValidationResult(false)); } }