File: lambda.cs

package info (click to toggle)
nrefactory 5.3.0%2B20130718.73b6d0f-4.1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye
  • size: 15,720 kB
  • sloc: cs: 296,018; makefile: 24; ansic: 7; sh: 2
file content (229 lines) | stat: -rw-r--r-- 5,934 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
//
// lambda.cs: support for lambda expressions
//
// Authors: Miguel de Icaza (miguel@gnu.org)
//          Marek Safar (marek.safar@gmail.com)
//
// Dual licensed under the terms of the MIT X11 or GNU GPL
//
// Copyright 2007-2008 Novell, Inc
// Copyright 2011 Xamarin Inc
//

#if STATIC
using IKVM.Reflection.Emit;
#else
using System.Reflection.Emit;
#endif

namespace Mono.CSharp {
	public class LambdaExpression : AnonymousMethodExpression
	{
		//
		// The parameters can either be:
		//    A list of Parameters (explicitly typed parameters)
		//    An ImplicitLambdaParameter
		//
		public LambdaExpression (Location loc)
			: base (loc)
		{
		}

		protected override Expression CreateExpressionTree (ResolveContext ec, TypeSpec delegate_type)
		{
			if (ec.IsInProbingMode)
				return this;

			BlockContext bc = new BlockContext (ec.MemberContext, ec.ConstructorBlock, ec.BuiltinTypes.Void) {
				CurrentAnonymousMethod = ec.CurrentAnonymousMethod
			};

			Expression args = Parameters.CreateExpressionTree (bc, loc);
			Expression expr = Block.CreateExpressionTree (ec);
			if (expr == null)
				return null;

			Arguments arguments = new Arguments (2);
			arguments.Add (new Argument (expr));
			arguments.Add (new Argument (args));
			return CreateExpressionFactoryCall (ec, "Lambda",
				new TypeArguments (new TypeExpression (delegate_type, loc)),
				arguments);
		}

		public override bool HasExplicitParameters {
			get {
				return Parameters.Count > 0 && !(Parameters.FixedParameters [0] is ImplicitLambdaParameter);
			}
		}

		protected override ParametersCompiled ResolveParameters (ResolveContext ec, TypeInferenceContext tic, TypeSpec delegateType)
		{
			if (!delegateType.IsDelegate)
				return null;

			AParametersCollection d_params = Delegate.GetParameters (delegateType);

			if (HasExplicitParameters) {
				if (!VerifyExplicitParameters (ec, delegateType, d_params))
					return null;

				return Parameters;
			}

			//
			// If L has an implicitly typed parameter list we make implicit parameters explicit
			// Set each parameter of L is given the type of the corresponding parameter in D
			//
			if (!VerifyParameterCompatibility (ec, delegateType, d_params, ec.IsInProbingMode))
				return null;

			TypeSpec [] ptypes = new TypeSpec [Parameters.Count];
			for (int i = 0; i < d_params.Count; i++) {
				// D has no ref or out parameters
				if ((d_params.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask) != 0)
					return null;

				TypeSpec d_param = d_params.Types [i];

				//
				// When type inference context exists try to apply inferred type arguments
				//
				if (tic != null) {
					d_param = tic.InflateGenericArgument (ec, d_param);
				}

				ptypes [i] = d_param;
				ImplicitLambdaParameter ilp = (ImplicitLambdaParameter) Parameters.FixedParameters [i];
				ilp.SetParameterType (d_param);
				ilp.Resolve (null, i);
			}

			Parameters.Types = ptypes;
			return Parameters;
		}

		protected override AnonymousMethodBody CompatibleMethodFactory (TypeSpec returnType, TypeSpec delegateType, ParametersCompiled p, ParametersBlock b)
		{
			return new LambdaMethod (p, b, returnType, delegateType, loc);
		}

		protected override bool DoResolveParameters (ResolveContext rc)
		{
			//
			// Only explicit parameters can be resolved at this point
			//
			if (HasExplicitParameters) {
				return Parameters.Resolve (rc);
			}

			return true;
		}

		public override string GetSignatureForError ()
		{
			return "lambda expression";
		}
		
		public override object Accept (StructuralVisitor visitor)
		{
			return visitor.Visit (this);
		}
	}

	class LambdaMethod : AnonymousMethodBody
	{
		public LambdaMethod (ParametersCompiled parameters,
					ParametersBlock block, TypeSpec return_type, TypeSpec delegate_type,
					Location loc)
			: base (parameters, block, return_type, delegate_type, loc)
		{
		}

		#region Properties

		public override string ContainerType {
			get {
				return "lambda expression";
			}
		}

		#endregion

		protected override void CloneTo (CloneContext clonectx, Expression target)
		{
			// TODO: nothing ??
		}

		public override Expression CreateExpressionTree (ResolveContext ec)
		{
			BlockContext bc = new BlockContext (ec.MemberContext, Block, ReturnType);
			Expression args = parameters.CreateExpressionTree (bc, loc);
			Expression expr = Block.CreateExpressionTree (ec);
			if (expr == null)
				return null;

			Arguments arguments = new Arguments (2);
			arguments.Add (new Argument (expr));
			arguments.Add (new Argument (args));
			return CreateExpressionFactoryCall (ec, "Lambda",
				new TypeArguments (new TypeExpression (type, loc)),
				arguments);
		}
	}

	//
	// This is a return statement that is prepended lambda expression bodies that happen
	// to be expressions.  Depending on the return type of the delegate this will behave
	// as either { expr (); return (); } or { return expr (); }
	//
	public class ContextualReturn : Return
	{
		ExpressionStatement statement;

		public ContextualReturn (Expression expr)
			: base (expr, expr.StartLocation)
		{
		}

		public override Expression CreateExpressionTree (ResolveContext ec)
		{
			return Expr.CreateExpressionTree (ec);
		}

		protected override void DoEmit (EmitContext ec)
		{
			if (statement != null) {
				statement.EmitStatement (ec);
				if (unwind_protect)
					ec.Emit (OpCodes.Leave, ec.CreateReturnLabel ());
				else {
					ec.Emit (OpCodes.Ret);
				}
				return;
			}

			base.DoEmit (ec);
		}

		protected override bool DoResolve (BlockContext ec)
		{
			//
			// When delegate returns void, only expression statements can be used
			//
			if (ec.ReturnType.Kind == MemberKind.Void) {
				Expr = Expr.Resolve (ec);
				if (Expr == null)
					return false;

				statement = Expr as ExpressionStatement;
				if (statement == null)
					Expr.Error_InvalidExpressionStatement (ec);

				return true;
			}

			return base.DoResolve (ec);
		}
	}
}