1 | // |
---|
2 | // linq.cs: support for query expressions |
---|
3 | // |
---|
4 | // Authors: Marek Safar (marek.safar@gmail.com) |
---|
5 | // |
---|
6 | // Dual licensed under the terms of the MIT X11 or GNU GPL |
---|
7 | // |
---|
8 | // Copyright 2007-2008 Novell, Inc |
---|
9 | // Copyright 2011 Xamarin Inc |
---|
10 | // |
---|
11 | |
---|
12 | using System; |
---|
13 | using System.Collections.Generic; |
---|
14 | |
---|
15 | namespace Mono.CSharp.Linq |
---|
16 | { |
---|
17 | public class QueryExpression : AQueryClause |
---|
18 | { |
---|
19 | public QueryExpression (AQueryClause start) |
---|
20 | : base (null, null, start.Location) |
---|
21 | { |
---|
22 | this.next = start; |
---|
23 | } |
---|
24 | |
---|
25 | public override Expression BuildQueryClause (ResolveContext ec, Expression lSide, Parameter parentParameter) |
---|
26 | { |
---|
27 | return next.BuildQueryClause (ec, lSide, parentParameter); |
---|
28 | } |
---|
29 | |
---|
30 | protected override Expression DoResolve (ResolveContext ec) |
---|
31 | { |
---|
32 | int counter = QueryBlock.TransparentParameter.Counter; |
---|
33 | |
---|
34 | Expression e = BuildQueryClause (ec, null, null); |
---|
35 | if (e != null) |
---|
36 | e = e.Resolve (ec); |
---|
37 | |
---|
38 | // |
---|
39 | // Reset counter in probing mode to ensure that all transparent |
---|
40 | // identifier anonymous types are created only once |
---|
41 | // |
---|
42 | if (ec.IsInProbingMode) |
---|
43 | QueryBlock.TransparentParameter.Counter = counter; |
---|
44 | |
---|
45 | return e; |
---|
46 | } |
---|
47 | |
---|
48 | protected override string MethodName { |
---|
49 | get { throw new NotSupportedException (); } |
---|
50 | } |
---|
51 | |
---|
52 | public override object Accept (StructuralVisitor visitor) |
---|
53 | { |
---|
54 | return visitor.Visit (this); |
---|
55 | } |
---|
56 | } |
---|
57 | |
---|
58 | public abstract class AQueryClause : ShimExpression |
---|
59 | { |
---|
60 | protected class QueryExpressionAccess : MemberAccess |
---|
61 | { |
---|
62 | public QueryExpressionAccess (Expression expr, string methodName, Location loc) |
---|
63 | : base (expr, methodName, loc) |
---|
64 | { |
---|
65 | } |
---|
66 | |
---|
67 | public QueryExpressionAccess (Expression expr, string methodName, TypeArguments typeArguments, Location loc) |
---|
68 | : base (expr, methodName, typeArguments, loc) |
---|
69 | { |
---|
70 | } |
---|
71 | |
---|
72 | protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name) |
---|
73 | { |
---|
74 | ec.Report.Error (1935, loc, "An implementation of `{0}' query expression pattern could not be found. " + |
---|
75 | "Are you missing `System.Linq' using directive or `System.Core.dll' assembly reference?", |
---|
76 | name); |
---|
77 | } |
---|
78 | } |
---|
79 | |
---|
80 | protected class QueryExpressionInvocation : Invocation, OverloadResolver.IErrorHandler |
---|
81 | { |
---|
82 | public QueryExpressionInvocation (QueryExpressionAccess expr, Arguments arguments) |
---|
83 | : base (expr, arguments) |
---|
84 | { |
---|
85 | } |
---|
86 | |
---|
87 | protected override MethodGroupExpr DoResolveOverload (ResolveContext ec) |
---|
88 | { |
---|
89 | MethodGroupExpr rmg = mg.OverloadResolve (ec, ref arguments, this, OverloadResolver.Restrictions.None); |
---|
90 | return rmg; |
---|
91 | } |
---|
92 | |
---|
93 | protected override Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr) |
---|
94 | { |
---|
95 | ec.Report.Error (1979, loc, |
---|
96 | "Query expressions with a source or join sequence of type `dynamic' are not allowed"); |
---|
97 | return null; |
---|
98 | } |
---|
99 | |
---|
100 | #region IErrorHandler Members |
---|
101 | |
---|
102 | bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext ec, MemberSpec best, MemberSpec ambiguous) |
---|
103 | { |
---|
104 | ec.Report.SymbolRelatedToPreviousError (best); |
---|
105 | ec.Report.SymbolRelatedToPreviousError (ambiguous); |
---|
106 | ec.Report.Error (1940, loc, "Ambiguous implementation of the query pattern `{0}' for source type `{1}'", |
---|
107 | best.Name, mg.InstanceExpression.GetSignatureForError ()); |
---|
108 | return true; |
---|
109 | } |
---|
110 | |
---|
111 | bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index) |
---|
112 | { |
---|
113 | return false; |
---|
114 | } |
---|
115 | |
---|
116 | bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best) |
---|
117 | { |
---|
118 | return false; |
---|
119 | } |
---|
120 | |
---|
121 | bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best) |
---|
122 | { |
---|
123 | var ms = (MethodSpec) best; |
---|
124 | TypeSpec source_type = ms.Parameters.ExtensionMethodType; |
---|
125 | if (source_type != null) { |
---|
126 | Argument a = arguments[0]; |
---|
127 | |
---|
128 | if (TypeManager.IsGenericType (source_type) && InflatedTypeSpec.ContainsTypeParameter (source_type)) { |
---|
129 | TypeInferenceContext tic = new TypeInferenceContext (source_type.TypeArguments); |
---|
130 | tic.OutputTypeInference (rc, a.Expr, source_type); |
---|
131 | if (tic.FixAllTypes (rc)) { |
---|
132 | source_type = source_type.GetDefinition ().MakeGenericType (rc, tic.InferredTypeArguments); |
---|
133 | } |
---|
134 | } |
---|
135 | |
---|
136 | if (!Convert.ImplicitConversionExists (rc, a.Expr, source_type)) { |
---|
137 | rc.Report.Error (1936, loc, "An implementation of `{0}' query expression pattern for source type `{1}' could not be found", |
---|
138 | best.Name, a.Type.GetSignatureForError ()); |
---|
139 | return true; |
---|
140 | } |
---|
141 | } |
---|
142 | |
---|
143 | if (best.Name == "SelectMany") { |
---|
144 | rc.Report.Error (1943, loc, |
---|
145 | "An expression type is incorrect in a subsequent `from' clause in a query expression with source type `{0}'", |
---|
146 | arguments[0].GetSignatureForError ()); |
---|
147 | } else { |
---|
148 | rc.Report.Error (1942, loc, |
---|
149 | "An expression type in `{0}' clause is incorrect. Type inference failed in the call to `{1}'", |
---|
150 | best.Name.ToLowerInvariant (), best.Name); |
---|
151 | } |
---|
152 | |
---|
153 | return true; |
---|
154 | } |
---|
155 | |
---|
156 | #endregion |
---|
157 | } |
---|
158 | |
---|
159 | public AQueryClause next; |
---|
160 | public QueryBlock block; |
---|
161 | |
---|
162 | protected AQueryClause (QueryBlock block, Expression expr, Location loc) |
---|
163 | : base (expr) |
---|
164 | { |
---|
165 | this.block = block; |
---|
166 | this.loc = loc; |
---|
167 | } |
---|
168 | |
---|
169 | protected override void CloneTo (CloneContext clonectx, Expression target) |
---|
170 | { |
---|
171 | base.CloneTo (clonectx, target); |
---|
172 | |
---|
173 | AQueryClause t = (AQueryClause) target; |
---|
174 | |
---|
175 | if (block != null) |
---|
176 | t.block = (QueryBlock) clonectx.LookupBlock (block); |
---|
177 | |
---|
178 | if (next != null) |
---|
179 | t.next = (AQueryClause) next.Clone (clonectx); |
---|
180 | } |
---|
181 | |
---|
182 | protected override Expression DoResolve (ResolveContext ec) |
---|
183 | { |
---|
184 | return expr.Resolve (ec); |
---|
185 | } |
---|
186 | |
---|
187 | public virtual Expression BuildQueryClause (ResolveContext ec, Expression lSide, Parameter parameter) |
---|
188 | { |
---|
189 | Arguments args = null; |
---|
190 | CreateArguments (ec, parameter, ref args); |
---|
191 | lSide = CreateQueryExpression (lSide, args); |
---|
192 | if (next != null) { |
---|
193 | parameter = CreateChildrenParameters (parameter); |
---|
194 | |
---|
195 | Select s = next as Select; |
---|
196 | if (s == null || s.IsRequired (parameter)) |
---|
197 | return next.BuildQueryClause (ec, lSide, parameter); |
---|
198 | |
---|
199 | // Skip transparent select clause if any clause follows |
---|
200 | if (next.next != null) |
---|
201 | return next.next.BuildQueryClause (ec, lSide, parameter); |
---|
202 | } |
---|
203 | |
---|
204 | return lSide; |
---|
205 | } |
---|
206 | |
---|
207 | protected virtual Parameter CreateChildrenParameters (Parameter parameter) |
---|
208 | { |
---|
209 | // Have to clone the parameter for any children use, it carries block sensitive data |
---|
210 | return parameter.Clone (); |
---|
211 | } |
---|
212 | |
---|
213 | protected virtual void CreateArguments (ResolveContext ec, Parameter parameter, ref Arguments args) |
---|
214 | { |
---|
215 | args = new Arguments (2); |
---|
216 | |
---|
217 | LambdaExpression selector = new LambdaExpression (loc); |
---|
218 | |
---|
219 | block.SetParameter (parameter); |
---|
220 | selector.Block = block; |
---|
221 | selector.Block.AddStatement (new ContextualReturn (expr)); |
---|
222 | |
---|
223 | args.Add (new Argument (selector)); |
---|
224 | } |
---|
225 | |
---|
226 | protected Invocation CreateQueryExpression (Expression lSide, Arguments arguments) |
---|
227 | { |
---|
228 | return new QueryExpressionInvocation ( |
---|
229 | new QueryExpressionAccess (lSide, MethodName, loc), arguments); |
---|
230 | } |
---|
231 | |
---|
232 | protected abstract string MethodName { get; } |
---|
233 | |
---|
234 | public AQueryClause Next { |
---|
235 | set { |
---|
236 | next = value; |
---|
237 | } |
---|
238 | } |
---|
239 | |
---|
240 | public AQueryClause Tail { |
---|
241 | get { |
---|
242 | return next == null ? this : next.Tail; |
---|
243 | } |
---|
244 | } |
---|
245 | } |
---|
246 | |
---|
247 | // |
---|
248 | // A query clause with an identifier (range variable) |
---|
249 | // |
---|
250 | public abstract class ARangeVariableQueryClause : AQueryClause |
---|
251 | { |
---|
252 | sealed class RangeAnonymousTypeParameter : AnonymousTypeParameter |
---|
253 | { |
---|
254 | public RangeAnonymousTypeParameter (Expression initializer, RangeVariable parameter) |
---|
255 | : base (initializer, parameter.Name, parameter.Location) |
---|
256 | { |
---|
257 | } |
---|
258 | |
---|
259 | protected override void Error_InvalidInitializer (ResolveContext ec, string initializer) |
---|
260 | { |
---|
261 | ec.Report.Error (1932, loc, "A range variable `{0}' cannot be initialized with `{1}'", |
---|
262 | Name, initializer); |
---|
263 | } |
---|
264 | } |
---|
265 | |
---|
266 | class RangeParameterReference : ParameterReference |
---|
267 | { |
---|
268 | Parameter parameter; |
---|
269 | |
---|
270 | public RangeParameterReference (Parameter p) |
---|
271 | : base (null, p.Location) |
---|
272 | { |
---|
273 | this.parameter = p; |
---|
274 | } |
---|
275 | |
---|
276 | protected override Expression DoResolve (ResolveContext ec) |
---|
277 | { |
---|
278 | pi = ec.CurrentBlock.ParametersBlock.GetParameterInfo (parameter); |
---|
279 | return base.DoResolve (ec); |
---|
280 | } |
---|
281 | } |
---|
282 | |
---|
283 | protected RangeVariable identifier; |
---|
284 | |
---|
285 | public RangeVariable IntoVariable { |
---|
286 | get { |
---|
287 | return identifier; |
---|
288 | } |
---|
289 | } |
---|
290 | |
---|
291 | protected ARangeVariableQueryClause (QueryBlock block, RangeVariable identifier, Expression expr, Location loc) |
---|
292 | : base (block, expr, loc) |
---|
293 | { |
---|
294 | this.identifier = identifier; |
---|
295 | } |
---|
296 | |
---|
297 | public RangeVariable Identifier { |
---|
298 | get { |
---|
299 | return identifier; |
---|
300 | } |
---|
301 | } |
---|
302 | |
---|
303 | public FullNamedExpression IdentifierType { get; set; } |
---|
304 | |
---|
305 | protected Invocation CreateCastExpression (Expression lSide) |
---|
306 | { |
---|
307 | return new QueryExpressionInvocation ( |
---|
308 | new QueryExpressionAccess (lSide, "Cast", new TypeArguments (IdentifierType), loc), null); |
---|
309 | } |
---|
310 | |
---|
311 | protected override Parameter CreateChildrenParameters (Parameter parameter) |
---|
312 | { |
---|
313 | return new QueryBlock.TransparentParameter (parameter.Clone (), GetIntoVariable ()); |
---|
314 | } |
---|
315 | |
---|
316 | protected static Expression CreateRangeVariableType (ResolveContext rc, Parameter parameter, RangeVariable name, Expression init) |
---|
317 | { |
---|
318 | var args = new List<AnonymousTypeParameter> (2); |
---|
319 | |
---|
320 | // |
---|
321 | // The first argument is the reference to the parameter |
---|
322 | // |
---|
323 | args.Add (new AnonymousTypeParameter (new RangeParameterReference (parameter), parameter.Name, parameter.Location)); |
---|
324 | |
---|
325 | // |
---|
326 | // The second argument is the linq expression |
---|
327 | // |
---|
328 | args.Add (new RangeAnonymousTypeParameter (init, name)); |
---|
329 | |
---|
330 | // |
---|
331 | // Create unique anonymous type |
---|
332 | // |
---|
333 | return new NewAnonymousType (args, rc.MemberContext.CurrentMemberDefinition.Parent, name.Location); |
---|
334 | } |
---|
335 | |
---|
336 | protected virtual RangeVariable GetIntoVariable () |
---|
337 | { |
---|
338 | return identifier; |
---|
339 | } |
---|
340 | } |
---|
341 | |
---|
342 | public sealed class RangeVariable : INamedBlockVariable |
---|
343 | { |
---|
344 | Block block; |
---|
345 | |
---|
346 | public RangeVariable (string name, Location loc) |
---|
347 | { |
---|
348 | Name = name; |
---|
349 | Location = loc; |
---|
350 | } |
---|
351 | |
---|
352 | #region Properties |
---|
353 | |
---|
354 | public Block Block { |
---|
355 | get { |
---|
356 | return block; |
---|
357 | } |
---|
358 | set { |
---|
359 | block = value; |
---|
360 | } |
---|
361 | } |
---|
362 | |
---|
363 | public bool IsDeclared { |
---|
364 | get { |
---|
365 | return true; |
---|
366 | } |
---|
367 | } |
---|
368 | |
---|
369 | public bool IsParameter { |
---|
370 | get { |
---|
371 | return false; |
---|
372 | } |
---|
373 | } |
---|
374 | |
---|
375 | public Location Location { get; private set; } |
---|
376 | |
---|
377 | public string Name { get; private set; } |
---|
378 | |
---|
379 | #endregion |
---|
380 | |
---|
381 | public Expression CreateReferenceExpression (ResolveContext rc, Location loc) |
---|
382 | { |
---|
383 | // |
---|
384 | // We know the variable name is somewhere in the scope. This generates |
---|
385 | // an access expression from current block |
---|
386 | // |
---|
387 | var pb = rc.CurrentBlock.ParametersBlock; |
---|
388 | while (true) { |
---|
389 | if (pb is QueryBlock) { |
---|
390 | for (int i = pb.Parameters.Count - 1; i >= 0; --i) { |
---|
391 | var p = pb.Parameters[i]; |
---|
392 | if (p.Name == Name) |
---|
393 | return pb.GetParameterReference (i, loc); |
---|
394 | |
---|
395 | Expression expr = null; |
---|
396 | var tp = p as QueryBlock.TransparentParameter; |
---|
397 | while (tp != null) { |
---|
398 | if (expr == null) |
---|
399 | expr = pb.GetParameterReference (i, loc); |
---|
400 | else |
---|
401 | expr = new TransparentMemberAccess (expr, tp.Name); |
---|
402 | |
---|
403 | if (tp.Identifier == Name) |
---|
404 | return new TransparentMemberAccess (expr, Name); |
---|
405 | |
---|
406 | if (tp.Parent.Name == Name) |
---|
407 | return new TransparentMemberAccess (expr, Name); |
---|
408 | |
---|
409 | tp = tp.Parent as QueryBlock.TransparentParameter; |
---|
410 | } |
---|
411 | } |
---|
412 | } |
---|
413 | |
---|
414 | if (pb == block) |
---|
415 | return null; |
---|
416 | |
---|
417 | pb = pb.Parent.ParametersBlock; |
---|
418 | } |
---|
419 | } |
---|
420 | } |
---|
421 | |
---|
422 | public class QueryStartClause : ARangeVariableQueryClause |
---|
423 | { |
---|
424 | public QueryStartClause (QueryBlock block, Expression expr, RangeVariable identifier, Location loc) |
---|
425 | : base (block, identifier, expr, loc) |
---|
426 | { |
---|
427 | block.AddRangeVariable (identifier); |
---|
428 | } |
---|
429 | |
---|
430 | public override Expression BuildQueryClause (ResolveContext ec, Expression lSide, Parameter parameter) |
---|
431 | { |
---|
432 | if (IdentifierType != null) |
---|
433 | expr = CreateCastExpression (expr); |
---|
434 | |
---|
435 | if (parameter == null) |
---|
436 | lSide = expr; |
---|
437 | |
---|
438 | return next.BuildQueryClause (ec, lSide, new ImplicitLambdaParameter (identifier.Name, identifier.Location)); |
---|
439 | } |
---|
440 | |
---|
441 | protected override Expression DoResolve (ResolveContext ec) |
---|
442 | { |
---|
443 | Expression e = BuildQueryClause (ec, null, null); |
---|
444 | return e.Resolve (ec); |
---|
445 | } |
---|
446 | |
---|
447 | protected override string MethodName { |
---|
448 | get { throw new NotSupportedException (); } |
---|
449 | } |
---|
450 | |
---|
451 | public override object Accept (StructuralVisitor visitor) |
---|
452 | { |
---|
453 | return visitor.Visit (this); |
---|
454 | } |
---|
455 | } |
---|
456 | |
---|
457 | |
---|
458 | public class GroupBy : AQueryClause |
---|
459 | { |
---|
460 | Expression element_selector; |
---|
461 | QueryBlock element_block; |
---|
462 | |
---|
463 | public Expression ElementSelector { |
---|
464 | get { return this.element_selector; } |
---|
465 | } |
---|
466 | |
---|
467 | public GroupBy (QueryBlock block, Expression elementSelector, QueryBlock elementBlock, Expression keySelector, Location loc) |
---|
468 | : base (block, keySelector, loc) |
---|
469 | { |
---|
470 | // |
---|
471 | // Optimizes clauses like `group A by A' |
---|
472 | // |
---|
473 | if (!elementSelector.Equals (keySelector)) { |
---|
474 | this.element_selector = elementSelector; |
---|
475 | this.element_block = elementBlock; |
---|
476 | } |
---|
477 | } |
---|
478 | |
---|
479 | public Expression SelectorExpression { |
---|
480 | get { |
---|
481 | return element_selector; |
---|
482 | } |
---|
483 | } |
---|
484 | |
---|
485 | protected override void CreateArguments (ResolveContext ec, Parameter parameter, ref Arguments args) |
---|
486 | { |
---|
487 | base.CreateArguments (ec, parameter, ref args); |
---|
488 | |
---|
489 | if (element_selector != null) { |
---|
490 | LambdaExpression lambda = new LambdaExpression (element_selector.Location); |
---|
491 | |
---|
492 | element_block.SetParameter (parameter.Clone ()); |
---|
493 | lambda.Block = element_block; |
---|
494 | lambda.Block.AddStatement (new ContextualReturn (element_selector)); |
---|
495 | args.Add (new Argument (lambda)); |
---|
496 | } |
---|
497 | } |
---|
498 | |
---|
499 | protected override void CloneTo (CloneContext clonectx, Expression target) |
---|
500 | { |
---|
501 | GroupBy t = (GroupBy) target; |
---|
502 | if (element_selector != null) { |
---|
503 | t.element_selector = element_selector.Clone (clonectx); |
---|
504 | t.element_block = (QueryBlock) element_block.Clone (clonectx); |
---|
505 | } |
---|
506 | |
---|
507 | base.CloneTo (clonectx, t); |
---|
508 | } |
---|
509 | |
---|
510 | protected override string MethodName { |
---|
511 | get { return "GroupBy"; } |
---|
512 | } |
---|
513 | |
---|
514 | public override object Accept (StructuralVisitor visitor) |
---|
515 | { |
---|
516 | return visitor.Visit (this); |
---|
517 | } |
---|
518 | } |
---|
519 | |
---|
520 | public class Join : SelectMany |
---|
521 | { |
---|
522 | QueryBlock inner_selector, outer_selector; |
---|
523 | |
---|
524 | public RangeVariable JoinVariable { |
---|
525 | get { return this.GetIntoVariable (); } |
---|
526 | } |
---|
527 | |
---|
528 | public Join (QueryBlock block, RangeVariable lt, Expression inner, QueryBlock outerSelector, QueryBlock innerSelector, Location loc) |
---|
529 | : base (block, lt, inner, loc) |
---|
530 | { |
---|
531 | this.outer_selector = outerSelector; |
---|
532 | this.inner_selector = innerSelector; |
---|
533 | } |
---|
534 | |
---|
535 | public QueryBlock InnerSelector { |
---|
536 | get { |
---|
537 | return inner_selector; |
---|
538 | } |
---|
539 | } |
---|
540 | |
---|
541 | public QueryBlock OuterSelector { |
---|
542 | get { |
---|
543 | return outer_selector; |
---|
544 | } |
---|
545 | } |
---|
546 | |
---|
547 | protected override void CreateArguments (ResolveContext ec, Parameter parameter, ref Arguments args) |
---|
548 | { |
---|
549 | args = new Arguments (4); |
---|
550 | |
---|
551 | if (IdentifierType != null) |
---|
552 | expr = CreateCastExpression (expr); |
---|
553 | |
---|
554 | args.Add (new Argument (expr)); |
---|
555 | |
---|
556 | outer_selector.SetParameter (parameter.Clone ()); |
---|
557 | var lambda = new LambdaExpression (outer_selector.StartLocation); |
---|
558 | lambda.Block = outer_selector; |
---|
559 | args.Add (new Argument (lambda)); |
---|
560 | |
---|
561 | inner_selector.SetParameter (new ImplicitLambdaParameter (identifier.Name, identifier.Location)); |
---|
562 | lambda = new LambdaExpression (inner_selector.StartLocation); |
---|
563 | lambda.Block = inner_selector; |
---|
564 | args.Add (new Argument (lambda)); |
---|
565 | |
---|
566 | base.CreateArguments (ec, parameter, ref args); |
---|
567 | } |
---|
568 | |
---|
569 | protected override void CloneTo (CloneContext clonectx, Expression target) |
---|
570 | { |
---|
571 | Join t = (Join) target; |
---|
572 | t.inner_selector = (QueryBlock) inner_selector.Clone (clonectx); |
---|
573 | t.outer_selector = (QueryBlock) outer_selector.Clone (clonectx); |
---|
574 | base.CloneTo (clonectx, t); |
---|
575 | } |
---|
576 | |
---|
577 | protected override string MethodName { |
---|
578 | get { return "Join"; } |
---|
579 | } |
---|
580 | |
---|
581 | public override object Accept (StructuralVisitor visitor) |
---|
582 | { |
---|
583 | return visitor.Visit (this); |
---|
584 | } |
---|
585 | } |
---|
586 | |
---|
587 | public class GroupJoin : Join |
---|
588 | { |
---|
589 | readonly RangeVariable into; |
---|
590 | |
---|
591 | public GroupJoin (QueryBlock block, RangeVariable lt, Expression inner, |
---|
592 | QueryBlock outerSelector, QueryBlock innerSelector, RangeVariable into, Location loc) |
---|
593 | : base (block, lt, inner, outerSelector, innerSelector, loc) |
---|
594 | { |
---|
595 | this.into = into; |
---|
596 | } |
---|
597 | |
---|
598 | protected override RangeVariable GetIntoVariable () |
---|
599 | { |
---|
600 | return into; |
---|
601 | } |
---|
602 | |
---|
603 | protected override string MethodName { |
---|
604 | get { return "GroupJoin"; } |
---|
605 | } |
---|
606 | |
---|
607 | public override object Accept (StructuralVisitor visitor) |
---|
608 | { |
---|
609 | return visitor.Visit (this); |
---|
610 | } |
---|
611 | } |
---|
612 | |
---|
613 | public class Let : ARangeVariableQueryClause |
---|
614 | { |
---|
615 | public Let (QueryBlock block, RangeVariable identifier, Expression expr, Location loc) |
---|
616 | : base (block, identifier, expr, loc) |
---|
617 | { |
---|
618 | } |
---|
619 | |
---|
620 | protected override void CreateArguments (ResolveContext ec, Parameter parameter, ref Arguments args) |
---|
621 | { |
---|
622 | expr = CreateRangeVariableType (ec, parameter, identifier, expr); |
---|
623 | base.CreateArguments (ec, parameter, ref args); |
---|
624 | } |
---|
625 | |
---|
626 | protected override string MethodName { |
---|
627 | get { return "Select"; } |
---|
628 | } |
---|
629 | |
---|
630 | public override object Accept (StructuralVisitor visitor) |
---|
631 | { |
---|
632 | return visitor.Visit (this); |
---|
633 | } |
---|
634 | } |
---|
635 | |
---|
636 | public class Select : AQueryClause |
---|
637 | { |
---|
638 | public Select (QueryBlock block, Expression expr, Location loc) |
---|
639 | : base (block, expr, loc) |
---|
640 | { |
---|
641 | } |
---|
642 | |
---|
643 | // |
---|
644 | // For queries like `from a orderby a select a' |
---|
645 | // the projection is transparent and select clause can be safely removed |
---|
646 | // |
---|
647 | public bool IsRequired (Parameter parameter) |
---|
648 | { |
---|
649 | SimpleName sn = expr as SimpleName; |
---|
650 | if (sn == null) |
---|
651 | return true; |
---|
652 | |
---|
653 | return sn.Name != parameter.Name; |
---|
654 | } |
---|
655 | |
---|
656 | protected override string MethodName { |
---|
657 | get { return "Select"; } |
---|
658 | } |
---|
659 | |
---|
660 | public override object Accept (StructuralVisitor visitor) |
---|
661 | { |
---|
662 | return visitor.Visit (this); |
---|
663 | } |
---|
664 | |
---|
665 | } |
---|
666 | |
---|
667 | public class SelectMany : ARangeVariableQueryClause |
---|
668 | { |
---|
669 | public SelectMany (QueryBlock block, RangeVariable identifier, Expression expr, Location loc) |
---|
670 | : base (block, identifier, expr, loc) |
---|
671 | { |
---|
672 | } |
---|
673 | |
---|
674 | protected override void CreateArguments (ResolveContext ec, Parameter parameter, ref Arguments args) |
---|
675 | { |
---|
676 | if (args == null) { |
---|
677 | if (IdentifierType != null) |
---|
678 | expr = CreateCastExpression (expr); |
---|
679 | |
---|
680 | base.CreateArguments (ec, parameter.Clone (), ref args); |
---|
681 | } |
---|
682 | |
---|
683 | Expression result_selector_expr; |
---|
684 | QueryBlock result_block; |
---|
685 | |
---|
686 | var target = GetIntoVariable (); |
---|
687 | var target_param = new ImplicitLambdaParameter (target.Name, target.Location); |
---|
688 | |
---|
689 | // |
---|
690 | // When select follows use it as a result selector |
---|
691 | // |
---|
692 | if (next is Select) { |
---|
693 | result_selector_expr = next.Expr; |
---|
694 | |
---|
695 | result_block = next.block; |
---|
696 | result_block.SetParameters (parameter, target_param); |
---|
697 | |
---|
698 | next = next.next; |
---|
699 | } else { |
---|
700 | result_selector_expr = CreateRangeVariableType (ec, parameter, target, new SimpleName (target.Name, target.Location)); |
---|
701 | |
---|
702 | result_block = new QueryBlock (block.Parent, block.StartLocation); |
---|
703 | result_block.SetParameters (parameter, target_param); |
---|
704 | } |
---|
705 | |
---|
706 | LambdaExpression result_selector = new LambdaExpression (Location); |
---|
707 | result_selector.Block = result_block; |
---|
708 | result_selector.Block.AddStatement (new ContextualReturn (result_selector_expr)); |
---|
709 | |
---|
710 | args.Add (new Argument (result_selector)); |
---|
711 | } |
---|
712 | |
---|
713 | protected override string MethodName { |
---|
714 | get { return "SelectMany"; } |
---|
715 | } |
---|
716 | |
---|
717 | public override object Accept (StructuralVisitor visitor) |
---|
718 | { |
---|
719 | return visitor.Visit (this); |
---|
720 | } |
---|
721 | } |
---|
722 | |
---|
723 | public class Where : AQueryClause |
---|
724 | { |
---|
725 | public Where (QueryBlock block, Expression expr, Location loc) |
---|
726 | : base (block, expr, loc) |
---|
727 | { |
---|
728 | } |
---|
729 | |
---|
730 | protected override string MethodName { |
---|
731 | get { return "Where"; } |
---|
732 | } |
---|
733 | |
---|
734 | public override object Accept (StructuralVisitor visitor) |
---|
735 | { |
---|
736 | return visitor.Visit (this); |
---|
737 | } |
---|
738 | } |
---|
739 | |
---|
740 | public class OrderByAscending : AQueryClause |
---|
741 | { |
---|
742 | public OrderByAscending (QueryBlock block, Expression expr) |
---|
743 | : base (block, expr, expr.Location) |
---|
744 | { |
---|
745 | } |
---|
746 | |
---|
747 | protected override string MethodName { |
---|
748 | get { return "OrderBy"; } |
---|
749 | } |
---|
750 | |
---|
751 | public override object Accept (StructuralVisitor visitor) |
---|
752 | { |
---|
753 | return visitor.Visit (this); |
---|
754 | } |
---|
755 | } |
---|
756 | |
---|
757 | public class OrderByDescending : AQueryClause |
---|
758 | { |
---|
759 | public OrderByDescending (QueryBlock block, Expression expr) |
---|
760 | : base (block, expr, expr.Location) |
---|
761 | { |
---|
762 | } |
---|
763 | |
---|
764 | protected override string MethodName { |
---|
765 | get { return "OrderByDescending"; } |
---|
766 | } |
---|
767 | |
---|
768 | public override object Accept (StructuralVisitor visitor) |
---|
769 | { |
---|
770 | return visitor.Visit (this); |
---|
771 | } |
---|
772 | } |
---|
773 | |
---|
774 | public class ThenByAscending : OrderByAscending |
---|
775 | { |
---|
776 | public ThenByAscending (QueryBlock block, Expression expr) |
---|
777 | : base (block, expr) |
---|
778 | { |
---|
779 | } |
---|
780 | |
---|
781 | protected override string MethodName { |
---|
782 | get { return "ThenBy"; } |
---|
783 | } |
---|
784 | |
---|
785 | public override object Accept (StructuralVisitor visitor) |
---|
786 | { |
---|
787 | return visitor.Visit (this); |
---|
788 | } |
---|
789 | } |
---|
790 | |
---|
791 | public class ThenByDescending : OrderByDescending |
---|
792 | { |
---|
793 | public ThenByDescending (QueryBlock block, Expression expr) |
---|
794 | : base (block, expr) |
---|
795 | { |
---|
796 | } |
---|
797 | |
---|
798 | protected override string MethodName { |
---|
799 | get { return "ThenByDescending"; } |
---|
800 | } |
---|
801 | |
---|
802 | public override object Accept (StructuralVisitor visitor) |
---|
803 | { |
---|
804 | return visitor.Visit (this); |
---|
805 | } |
---|
806 | } |
---|
807 | |
---|
808 | // |
---|
809 | // Implicit query block |
---|
810 | // |
---|
811 | public class QueryBlock : ParametersBlock |
---|
812 | { |
---|
813 | // |
---|
814 | // Transparent parameters are used to package up the intermediate results |
---|
815 | // and pass them onto next clause |
---|
816 | // |
---|
817 | public sealed class TransparentParameter : ImplicitLambdaParameter |
---|
818 | { |
---|
819 | public static int Counter; |
---|
820 | const string ParameterNamePrefix = "<>__TranspIdent"; |
---|
821 | |
---|
822 | public readonly Parameter Parent; |
---|
823 | public readonly string Identifier; |
---|
824 | |
---|
825 | public TransparentParameter (Parameter parent, RangeVariable identifier) |
---|
826 | : base (ParameterNamePrefix + Counter++, identifier.Location) |
---|
827 | { |
---|
828 | Parent = parent; |
---|
829 | Identifier = identifier.Name; |
---|
830 | } |
---|
831 | |
---|
832 | public static void Reset () |
---|
833 | { |
---|
834 | Counter = 0; |
---|
835 | } |
---|
836 | } |
---|
837 | |
---|
838 | public QueryBlock (Block parent, Location start) |
---|
839 | : base (parent, ParametersCompiled.EmptyReadOnlyParameters, start, Flags.CompilerGenerated) |
---|
840 | { |
---|
841 | } |
---|
842 | |
---|
843 | public void AddRangeVariable (RangeVariable variable) |
---|
844 | { |
---|
845 | variable.Block = this; |
---|
846 | TopBlock.AddLocalName (variable.Name, variable, true); |
---|
847 | } |
---|
848 | |
---|
849 | public override void Error_AlreadyDeclared (string name, INamedBlockVariable variable, string reason) |
---|
850 | { |
---|
851 | TopBlock.Report.Error (1931, variable.Location, |
---|
852 | "A range variable `{0}' conflicts with a previous declaration of `{0}'", |
---|
853 | name); |
---|
854 | } |
---|
855 | |
---|
856 | public override void Error_AlreadyDeclared (string name, INamedBlockVariable variable) |
---|
857 | { |
---|
858 | TopBlock.Report.Error (1930, variable.Location, |
---|
859 | "A range variable `{0}' has already been declared in this scope", |
---|
860 | name); |
---|
861 | } |
---|
862 | |
---|
863 | public override void Error_AlreadyDeclaredTypeParameter (string name, Location loc) |
---|
864 | { |
---|
865 | TopBlock.Report.Error (1948, loc, |
---|
866 | "A range variable `{0}' conflicts with a method type parameter", |
---|
867 | name); |
---|
868 | } |
---|
869 | |
---|
870 | public void SetParameter (Parameter parameter) |
---|
871 | { |
---|
872 | base.parameters = new ParametersCompiled (parameter); |
---|
873 | base.parameter_info = new ParameterInfo[] { |
---|
874 | new ParameterInfo (this, 0) |
---|
875 | }; |
---|
876 | } |
---|
877 | |
---|
878 | public void SetParameters (Parameter first, Parameter second) |
---|
879 | { |
---|
880 | base.parameters = new ParametersCompiled (first, second); |
---|
881 | base.parameter_info = new ParameterInfo[] { |
---|
882 | new ParameterInfo (this, 0), |
---|
883 | new ParameterInfo (this, 1) |
---|
884 | }; |
---|
885 | } |
---|
886 | } |
---|
887 | |
---|
888 | sealed class TransparentMemberAccess : MemberAccess |
---|
889 | { |
---|
890 | public TransparentMemberAccess (Expression expr, string name) |
---|
891 | : base (expr, name) |
---|
892 | { |
---|
893 | } |
---|
894 | |
---|
895 | public override Expression DoResolveLValue (ResolveContext rc, Expression right_side) |
---|
896 | { |
---|
897 | rc.Report.Error (1947, loc, |
---|
898 | "A range variable `{0}' cannot be assigned to. Consider using `let' clause to store the value", |
---|
899 | Name); |
---|
900 | |
---|
901 | return null; |
---|
902 | } |
---|
903 | } |
---|
904 | } |
---|