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;
31 public QueryExpression (TypeContainer host, Block block, Expression from, AQueryClause query)
39 public override Expression DoResolve (EmitContext ec)
41 from = from.DoResolve (ec);
45 ICollection values = Block.Variables.Values;
46 if (values.Count != 1)
47 throw new NotImplementedException ("Count != 1");
49 IEnumerator enumerator = values.GetEnumerator ();
50 enumerator.MoveNext ();
51 LocalInfo li = (LocalInfo)enumerator.Current;
53 Parameter clause_parameter;
54 if (li.Type == ImplicitArgument.Instance) {
55 clause_parameter = new ImplicitLambdaParameter (li.Name, li.Location);
57 clause_parameter = new Parameter (li.Type, li.Name, Parameter.Modifier.NONE, null, li.Location);
60 Expression e = query.BuildQueryClause (ec, this, from, clause_parameter);
67 if (li.VariableType == null)
68 li.VariableType = ec.ReturnType;
73 public override void Emit (EmitContext ec)
75 throw new NotSupportedException ();
79 public abstract class ALinqExpression : Expression
81 // Dictionary of method name -> MethodGroupExpr
82 static Hashtable methods = new Hashtable ();
83 static Type enumerable_class;
85 protected abstract string MethodName { get; }
87 protected MethodGroupExpr MethodGroup {
90 // Even if C# spec indicates that LINQ methods are context specific
91 // in reality they are hardcoded
93 MemberList ml = (MemberList)methods [MethodName];
95 if (enumerable_class == null)
96 enumerable_class = TypeManager.CoreLookupType ("System.Linq", "Enumerable");
98 ml = TypeManager.FindMembers (enumerable_class,
99 MemberTypes.Method, BindingFlags.Static | BindingFlags.Public,
100 Type.FilterName, MethodName);
103 return new MethodGroupExpr (ArrayList.Adapter (ml), enumerable_class, loc);
108 public abstract class AQueryClause : ALinqExpression
110 public AQueryClause Next;
111 protected Expression expr;
113 protected AQueryClause (Expression expr, Location loc)
119 public override Expression DoResolve (EmitContext ec)
121 return expr.DoResolve (ec);
124 public override void Emit (EmitContext ec)
126 throw new NotSupportedException ();
129 public Expression BuildQueryClause (EmitContext ec, QueryExpression top, Expression from, Parameter parameter)
131 Parameters parameters = new Parameters (parameter);
132 LambdaExpression ame = new LambdaExpression (
133 null, null, top.Host,
136 ame.Block = new ToplevelBlock (parameters, loc);
137 ame.Block.AddStatement (new Return (expr, loc));
139 expr = new Invocation (MethodGroup, CreateArguments (ame, from));
141 return Next.BuildQueryClause (ec, top, this, parameter);
146 protected virtual ArrayList CreateArguments (AnonymousMethodExpression ame, Expression from)
148 ArrayList args = new ArrayList (2);
149 args.Add (new Argument (from));
150 args.Add (new Argument (ame));
154 public AQueryClause Tail {
156 return Next == null ? this : Next.Tail;
161 public class Cast : ALinqExpression
163 readonly Expression expr;
164 readonly Expression cast_type;
166 public Cast (Expression type, Expression expr, Location loc)
168 this.cast_type = type;
173 protected override string MethodName {
174 get { return "Cast"; }
177 public override Expression DoResolve (EmitContext ec)
179 TypeArguments type_arguments = new TypeArguments (loc, cast_type);
180 Expression cast = MethodGroup.ResolveGeneric (ec, type_arguments);
182 ArrayList args = new ArrayList (1);
183 args.Add (new Argument (expr));
184 return new Invocation (cast, args).DoResolve (ec);
187 public override void Emit (EmitContext ec)
189 throw new NotSupportedException ();
193 public class GroupBy : AQueryClause
195 readonly Expression element_selector;
197 public GroupBy (Expression elementSelector, Expression keySelector, Location loc)
198 : base (keySelector, loc)
200 this.element_selector = elementSelector;
203 protected override ArrayList CreateArguments (AnonymousMethodExpression ame, Expression from)
205 ArrayList args = base.CreateArguments (ame, from);
207 // A query can be optimized when selector is not group by specific
208 if (!element_selector.Equals (from)) {
209 LambdaExpression am_element = new LambdaExpression (
210 null, null, ame.Host, ame.Parameters, ame.Container, loc);
211 am_element.Block = new ToplevelBlock (ame.Parameters, loc);
212 am_element.Block.AddStatement (new Return (element_selector, loc));
214 args.Add (new Argument (am_element));
219 protected override string MethodName {
220 get { return "GroupBy"; }
224 public class Select : AQueryClause
226 public Select (Expression expr, Location loc)
231 protected override string MethodName {
232 get { return "Select"; }
236 public class Where : AQueryClause
238 public Where (Expression expr, Location loc)
243 protected override string MethodName {
244 get { return "Where"; }
248 public class OrderByAscending : AQueryClause
250 public OrderByAscending (Expression expr)
251 : base (expr, expr.Location)
255 protected override string MethodName {
256 get { return "OrderBy"; }
260 public class OrderByDescending : AQueryClause
262 public OrderByDescending (Expression expr)
263 : base (expr, expr.Location)
267 protected override string MethodName {
268 get { return "OrderByDescending"; }
272 public class ThenByAscending : OrderByAscending
274 public ThenByAscending (Expression expr)
279 protected override string MethodName {
280 get { return "ThenBy"; }
284 public class ThenByDescending : OrderByDescending
286 public ThenByDescending (Expression expr)
291 protected override string MethodName {
292 get { return "ThenByDescending"; }
297 // Only helper for implicit query type expression
299 public class ImplicitArgument : Expression
301 public static ImplicitArgument Instance = new ImplicitArgument ();
303 private ImplicitArgument ()
307 public override Expression DoResolve (EmitContext ec)
309 throw new NotImplementedException ();
312 public override void Emit (EmitContext ec)
314 throw new NotImplementedException ();