~ubuntu-branches/ubuntu/trusty/monodevelop/trusty-proposed

« back to all changes in this revision

Viewing changes to external/nrefactory/ICSharpCode.NRefactory.CSharp/Parser/mcs/linq.cs

  • Committer: Package Import Robot
  • Author(s): Jo Shields
  • Date: 2013-05-12 09:46:03 UTC
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20130512094603-mad323bzcxvmcam0
Tags: upstream-4.0.5+dfsg
ImportĀ upstreamĀ versionĀ 4.0.5+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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, TypeManager.CSharpName (a.Type));
 
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)
 
840
                {
 
841
                        flags |= Flags.CompilerGenerated;
 
842
                }
 
843
 
 
844
                public void AddRangeVariable (RangeVariable variable)
 
845
                {
 
846
                        variable.Block = this;
 
847
                        TopBlock.AddLocalName (variable.Name, variable, true);
 
848
                }
 
849
 
 
850
                public override void Error_AlreadyDeclared (string name, INamedBlockVariable variable, string reason)
 
851
                {
 
852
                        TopBlock.Report.Error (1931, variable.Location,
 
853
                                "A range variable `{0}' conflicts with a previous declaration of `{0}'",
 
854
                                name);
 
855
                }
 
856
 
 
857
                public override void Error_AlreadyDeclared (string name, INamedBlockVariable variable)
 
858
                {
 
859
                        TopBlock.Report.Error (1930, variable.Location,
 
860
                                "A range variable `{0}' has already been declared in this scope",
 
861
                                name);          
 
862
                }
 
863
 
 
864
                public override void Error_AlreadyDeclaredTypeParameter (string name, Location loc)
 
865
                {
 
866
                        TopBlock.Report.Error (1948, loc,
 
867
                                "A range variable `{0}' conflicts with a method type parameter",
 
868
                                name);
 
869
                }
 
870
 
 
871
                public void SetParameter (Parameter parameter)
 
872
                {
 
873
                        base.parameters = new ParametersCompiled (parameter);
 
874
                        base.parameter_info = new ParameterInfo[] {
 
875
                                new ParameterInfo (this, 0)
 
876
                        };
 
877
                }
 
878
 
 
879
                public void SetParameters (Parameter first, Parameter second)
 
880
                {
 
881
                        base.parameters = new ParametersCompiled (first, second);
 
882
                        base.parameter_info = new ParameterInfo[] {
 
883
                                new ParameterInfo (this, 0),
 
884
                                new ParameterInfo (this, 1)
 
885
                        };
 
886
                }
 
887
        }
 
888
 
 
889
        sealed class TransparentMemberAccess : MemberAccess
 
890
        {
 
891
                public TransparentMemberAccess (Expression expr, string name)
 
892
                        : base (expr, name)
 
893
                {
 
894
                }
 
895
 
 
896
                public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
 
897
                {
 
898
                        rc.Report.Error (1947, loc,
 
899
                                "A range variable `{0}' cannot be assigned to. Consider using `let' clause to store the value",
 
900
                                Name);
 
901
 
 
902
                        return null;
 
903
                }
 
904
        }
 
905
}