2 // linq.cs: support for query expressions
4 // Authors: Marek Safar (marek.safar@gmail.com)
6 // Licensed under the terms of the GNU GPL
8 // (C) 2007 Novell, Inc
12 using System.Reflection;
13 using System.Collections;
15 namespace Mono.CSharp.Linq
18 // Expression should be IExpression to save some memory and make a few things
23 public class QueryExpression : Expression
25 public readonly Block Block;
26 public readonly TypeContainer Host;
29 public Expression From;
31 public QueryExpression (TypeContainer host, Block block, Expression from, AQueryClause query)
39 public override Expression DoResolve (EmitContext ec)
42 foreach (LocalInfo li_temp in Block.Variables.Values)
48 Expression e = query.BuildQueryClause (ec, this, From, li);
49 return e.Resolve (ec);
52 public override void Emit (EmitContext ec)
54 throw new NotSupportedException ();
58 public abstract class ALinqExpression : Expression
60 // Dictionary of method name -> MethodGroupExpr
61 static Hashtable methods = new Hashtable ();
62 static Type enumerable_class;
64 protected abstract string MethodName { get; }
66 protected MethodGroupExpr MethodGroup {
68 MethodGroupExpr method_group = (MethodGroupExpr)methods [MethodName];
69 if (method_group != null)
72 if (enumerable_class == null)
73 enumerable_class = TypeManager.CoreLookupType ("System.Linq", "Enumerable");
75 MemberList ml = TypeManager.FindMembers (enumerable_class,
76 MemberTypes.Method, BindingFlags.Static | BindingFlags.Public,
77 Type.FilterName, MethodName);
79 method_group = new MethodGroupExpr (ArrayList.Adapter (ml), loc);
80 methods.Add (MethodName, method_group);
86 public abstract class AQueryClause : ALinqExpression
88 public AQueryClause Next;
89 protected Expression expr;
91 protected AQueryClause (Expression expr, Location loc)
97 public override Expression DoResolve (EmitContext ec)
99 return expr.DoResolve (ec);
102 public override void Emit (EmitContext ec)
104 throw new NotSupportedException ();
107 public Expression BuildQueryClause (EmitContext ec, QueryExpression top, Expression from, LocalInfo li)
109 Parameters parameters = new Parameters (new Parameter (li.Type, li.Name, Parameter.Modifier.NONE, null, loc));
110 AnonymousMethodExpression ame = new AnonymousMethodExpression (
111 null, null, top.Host,
114 ame.Block = new ToplevelBlock (parameters, loc);
115 ame.Block.AddStatement (new Return (expr, loc));
117 expr = new Invocation (MethodGroup, CreateArguments (ame, from));
119 return Next.BuildQueryClause (ec, top, this, li);
124 protected virtual ArrayList CreateArguments (AnonymousMethodExpression ame, Expression from)
126 ArrayList args = new ArrayList (2);
127 args.Add (new Argument (from));
128 args.Add (new Argument (ame));
133 public class Cast : ALinqExpression
135 readonly Expression expr;
136 readonly Expression cast_type;
138 public Cast (Expression type, Expression expr, Location loc)
140 this.cast_type = type;
145 protected override string MethodName {
146 get { return "Cast"; }
149 public override Expression DoResolve (EmitContext ec)
151 TypeArguments type_arguments = new TypeArguments (loc, cast_type);
152 Expression cast = MethodGroup.ResolveGeneric (ec, type_arguments);
154 ArrayList args = new ArrayList (1);
155 args.Add (new Argument (expr));
156 return new Invocation (cast, args).DoResolve (ec);
159 public override void Emit (EmitContext ec)
161 throw new NotSupportedException ();
165 public class GroupBy : AQueryClause
167 readonly Expression element_selector;
169 public GroupBy (Expression elementSelector, Expression keySelector, Location loc)
170 : base (keySelector, loc)
172 this.element_selector = elementSelector;
175 protected override ArrayList CreateArguments (AnonymousMethodExpression ame, Expression from)
177 ArrayList args = base.CreateArguments (ame, from);
179 // A query can be optimized when selector is not group by specific
180 if (!element_selector.Equals (from)) {
181 AnonymousMethodExpression am_element = new AnonymousMethodExpression (
182 null, null, ame.Host, ame.Parameters, ame.Container, loc);
183 am_element.Block = new ToplevelBlock (ame.Parameters, loc);
184 am_element.Block.AddStatement (new Return (element_selector, loc));
186 args.Add (new Argument (am_element));
191 protected override string MethodName {
192 get { return "GroupBy"; }
196 public class Select : AQueryClause
198 public Select (Expression expr, Location loc)
203 protected override string MethodName {
204 get { return "Select"; }
208 public class Where : AQueryClause
210 public Where (Expression expr, Location loc)
215 protected override string MethodName {
216 get { return "Where"; }