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 VarExpr var = li.Type as VarExpr;
55 li.Type = var.ResolveLValue (ec, from, var.Location);
58 li.VariableType = li.Type.Type;
61 Expression e = query.BuildQueryClause (ec, this, from, li);
62 return e.Resolve (ec);
65 public override void Emit (EmitContext ec)
67 throw new NotSupportedException ();
71 public abstract class ALinqExpression : Expression
73 // Dictionary of method name -> MethodGroupExpr
74 static Hashtable methods = new Hashtable ();
75 static Type enumerable_class;
77 protected abstract string MethodName { get; }
79 // TODO: Linq methods are context specific
80 protected MethodGroupExpr MethodGroup {
82 MethodGroupExpr method_group = (MethodGroupExpr)methods [MethodName];
83 if (method_group != null)
86 if (enumerable_class == null)
87 enumerable_class = TypeManager.CoreLookupType ("System.Linq", "Enumerable");
89 MemberList ml = TypeManager.FindMembers (enumerable_class,
90 MemberTypes.Method, BindingFlags.Static | BindingFlags.Public,
91 Type.FilterName, MethodName);
93 method_group = new MethodGroupExpr (ArrayList.Adapter (ml), enumerable_class, loc);
94 //methods.Add (MethodName, method_group);
100 public abstract class AQueryClause : ALinqExpression
102 public AQueryClause Next;
103 protected Expression expr;
105 protected AQueryClause (Expression expr, Location loc)
111 public override Expression DoResolve (EmitContext ec)
113 return expr.DoResolve (ec);
116 public override void Emit (EmitContext ec)
118 throw new NotSupportedException ();
121 public Expression BuildQueryClause (EmitContext ec, QueryExpression top, Expression from, LocalInfo li)
123 // TODO: An anonymous method is not enough to infer implicitly typed arguments,
124 // we need lambda expression here
125 Parameters parameters = new Parameters (new Parameter (li.Type, li.Name, Parameter.Modifier.NONE, null, loc));
126 AnonymousMethodExpression ame = new AnonymousMethodExpression (
127 null, null, top.Host,
130 ame.Block = new ToplevelBlock (parameters, loc);
131 ame.Block.AddStatement (new Return (expr, loc));
133 expr = new Invocation (MethodGroup, CreateArguments (ame, from));
135 return Next.BuildQueryClause (ec, top, this, li);
140 protected virtual ArrayList CreateArguments (AnonymousMethodExpression ame, Expression from)
142 ArrayList args = new ArrayList (2);
143 args.Add (new Argument (from));
144 args.Add (new Argument (ame));
149 public class Cast : ALinqExpression
151 readonly Expression expr;
152 readonly Expression cast_type;
154 public Cast (Expression type, Expression expr, Location loc)
156 this.cast_type = type;
161 protected override string MethodName {
162 get { return "Cast"; }
165 public override Expression DoResolve (EmitContext ec)
167 TypeArguments type_arguments = new TypeArguments (loc, cast_type);
168 Expression cast = MethodGroup.ResolveGeneric (ec, type_arguments);
170 ArrayList args = new ArrayList (1);
171 args.Add (new Argument (expr));
172 return new Invocation (cast, args).DoResolve (ec);
175 public override void Emit (EmitContext ec)
177 throw new NotSupportedException ();
181 public class GroupBy : AQueryClause
183 readonly Expression element_selector;
185 public GroupBy (Expression elementSelector, Expression keySelector, Location loc)
186 : base (keySelector, loc)
188 this.element_selector = elementSelector;
191 protected override ArrayList CreateArguments (AnonymousMethodExpression ame, Expression from)
193 ArrayList args = base.CreateArguments (ame, from);
195 // A query can be optimized when selector is not group by specific
196 if (!element_selector.Equals (from)) {
197 AnonymousMethodExpression am_element = new AnonymousMethodExpression (
198 null, null, ame.Host, ame.Parameters, ame.Container, loc);
199 am_element.Block = new ToplevelBlock (ame.Parameters, loc);
200 am_element.Block.AddStatement (new Return (element_selector, loc));
202 args.Add (new Argument (am_element));
207 protected override string MethodName {
208 get { return "GroupBy"; }
212 public class Select : AQueryClause
214 public Select (Expression expr, Location loc)
219 protected override string MethodName {
220 get { return "Select"; }
224 public class Where : AQueryClause
226 public Where (Expression expr, Location loc)
231 protected override string MethodName {
232 get { return "Where"; }
236 public class ImplicitArgument : Expression
238 public static ImplicitArgument Instance = new ImplicitArgument ();
240 private ImplicitArgument ()
244 public override Expression DoResolve (EmitContext ec)
246 throw new NotImplementedException ();
249 public override void Emit (EmitContext ec)
251 throw new NotImplementedException ();