-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Expand file tree
/
Copy pathCompiledExpressionInvoker.cs
More file actions
360 lines (311 loc) · 14.8 KB
/
Copy pathCompiledExpressionInvoker.cs
File metadata and controls
360 lines (311 loc) · 14.8 KB
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
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
//-----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
namespace System.Activities.Expressions
{
using System;
using System.Activities.XamlIntegration;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Xaml;
public class CompiledExpressionInvoker
{
private static readonly AttachableMemberIdentifier compiledExpressionRootProperty =
new AttachableMemberIdentifier(typeof(CompiledExpressionInvoker), "CompiledExpressionRoot");
private static readonly AttachableMemberIdentifier compiledExpressionRootForImplementationProperty =
new AttachableMemberIdentifier(typeof(CompiledExpressionInvoker), "CompiledExpressionRootForImplementation");
int expressionId;
Activity expressionActivity;
bool isReference;
ITextExpression textExpression;
Activity metadataRoot;
ICompiledExpressionRoot compiledRoot;
IList<LocationReference> locationReferences;
CodeActivityMetadata metadata;
CodeActivityPublicEnvironmentAccessor accessor;
public bool IsStaticallyCompiled
{
get;
private set;
}
public CompiledExpressionInvoker(ITextExpression expression, bool isReference, CodeActivityMetadata metadata)
{
if (expression == null)
{
throw FxTrace.Exception.ArgumentNull("expression");
}
if (metadata == null)
{
throw FxTrace.Exception.ArgumentNull("metadata");
}
this.expressionId = -1;
this.textExpression = expression;
this.expressionActivity = expression as Activity;
this.isReference = isReference;
this.locationReferences = new List<LocationReference>();
this.metadata = metadata;
this.accessor = CodeActivityPublicEnvironmentAccessor.Create(this.metadata);
if (this.expressionActivity == null)
{
throw FxTrace.Exception.Argument("expression", SR.ITextExpressionParameterMustBeActivity);
}
ActivityWithResult resultActivity = this.expressionActivity as ActivityWithResult;
this.metadataRoot = metadata.Environment.Root;
this.ProcessLocationReferences();
}
public object InvokeExpression(ActivityContext activityContext)
{
if (activityContext == null)
{
throw FxTrace.Exception.ArgumentNull("activityContext");
}
if (this.compiledRoot == null || this.expressionId < 0)
{
if (!TryGetCompiledExpressionRoot(this.expressionActivity, this.metadataRoot, out this.compiledRoot) ||
!CanExecuteExpression(this.compiledRoot, out expressionId))
{
if (!TryGetCurrentCompiledExpressionRoot(activityContext, out this.compiledRoot, out this.expressionId))
{
throw FxTrace.Exception.AsError(new NotSupportedException(SR.TextExpressionMetadataRequiresCompilation(this.expressionActivity.GetType().Name)));
}
}
}
return this.compiledRoot.InvokeExpression(this.expressionId, this.locationReferences, activityContext);
}
//
// Attached property setter for the compiled expression root for the public surface area of an activity
public static void SetCompiledExpressionRoot(object target, ICompiledExpressionRoot compiledExpressionRoot)
{
if (compiledExpressionRoot == null)
{
AttachablePropertyServices.RemoveProperty(target, compiledExpressionRootProperty);
}
else
{
AttachablePropertyServices.SetProperty(target, compiledExpressionRootProperty, compiledExpressionRoot);
}
}
//
// Attached property getter for the compiled expression root for the public surface area of an activity
public static object GetCompiledExpressionRoot(object target)
{
object value = null;
AttachablePropertyServices.TryGetProperty(target, compiledExpressionRootProperty, out value);
return value;
}
//
// Attached property setter for the compiled expression root for the implementation surface area of an activity
public static void SetCompiledExpressionRootForImplementation(object target, ICompiledExpressionRoot compiledExpressionRoot)
{
if (compiledExpressionRoot == null)
{
AttachablePropertyServices.RemoveProperty(target, compiledExpressionRootForImplementationProperty);
}
else
{
AttachablePropertyServices.SetProperty(target, compiledExpressionRootForImplementationProperty, compiledExpressionRoot);
}
}
//
// Attached property getter for the compiled expression root for the implementation surface area of an activity
public static object GetCompiledExpressionRootForImplementation(object target)
{
object value = null;
AttachablePropertyServices.TryGetProperty(target, compiledExpressionRootForImplementationProperty, out value);
return value;
}
//
// Internal helper to find the correct ICER for a given expression.
internal static bool TryGetCompiledExpressionRoot(Activity expression, Activity target, out ICompiledExpressionRoot compiledExpressionRoot)
{
bool forImplementation = expression.MemberOf != expression.RootActivity.MemberOf;
return TryGetCompiledExpressionRoot(target, forImplementation, out compiledExpressionRoot);
}
//
// Helper to find the correct ICER for a given expression.
// This is separate from the above because within this class we switch forImplementation for the same target Activity
// to matched the ICER model of using one ICER for all expressions in the implementation and root argument defaults.
internal static bool TryGetCompiledExpressionRoot(Activity target, bool forImplementation, out ICompiledExpressionRoot compiledExpressionRoot)
{
if (!forImplementation)
{
compiledExpressionRoot = GetCompiledExpressionRoot(target) as ICompiledExpressionRoot;
if (compiledExpressionRoot != null)
{
return true;
}
//
// Default expressions for Arguments show up in the public surface area
// If we didn't find an ICER for the public surface area continue
// and try to use the implementation ICER
}
if (target is ICompiledExpressionRoot)
{
compiledExpressionRoot = (ICompiledExpressionRoot)target;
return true;
}
compiledExpressionRoot = GetCompiledExpressionRootForImplementation(target) as ICompiledExpressionRoot;
if (compiledExpressionRoot != null)
{
return true;
}
compiledExpressionRoot = null;
return false;
}
internal Expression GetExpressionTree()
{
if (this.compiledRoot == null || this.expressionId < 0)
{
if (!TryGetCompiledExpressionRootAtDesignTime(this.expressionActivity, this.metadataRoot, out this.compiledRoot, out this.expressionId))
{
return null;
}
}
return this.compiledRoot.GetExpressionTreeForExpression(this.expressionId, this.locationReferences);
}
bool TryGetCurrentCompiledExpressionRoot(ActivityContext activityContext, out ICompiledExpressionRoot compiledExpressionRoot, out int expressionId)
{
ActivityInstance current = activityContext.CurrentInstance;
while (current != null && current.Activity != this.metadataRoot)
{
ICompiledExpressionRoot currentCompiledExpressionRoot = null;
if (CompiledExpressionInvoker.TryGetCompiledExpressionRoot(current.Activity, true, out currentCompiledExpressionRoot))
{
if (CanExecuteExpression(currentCompiledExpressionRoot, out expressionId))
{
compiledExpressionRoot = currentCompiledExpressionRoot;
return true;
}
}
current = current.Parent;
}
compiledExpressionRoot = null;
expressionId = -1;
return false;
}
bool CanExecuteExpression(ICompiledExpressionRoot compiledExpressionRoot, out int expressionId)
{
if (compiledExpressionRoot.CanExecuteExpression(this.textExpression.ExpressionText, this.isReference, locationReferences, out expressionId))
{
return true;
}
return false;
}
void ProcessLocationReferences()
{
Stack<LocationReferenceEnvironment> environments = new Stack<LocationReferenceEnvironment>();
//
// Build list of location by enumerating environments
// in top down order to match the traversal pattern of TextExpressionCompiler
LocationReferenceEnvironment current = this.accessor.ActivityMetadata.Environment;
while (current != null)
{
environments.Push(current);
current = current.Parent;
}
foreach (LocationReferenceEnvironment environment in environments)
{
foreach (LocationReference reference in environment.GetLocationReferences())
{
if (this.textExpression.RequiresCompilation)
{
this.accessor.CreateLocationArgument(reference, false);
}
this.locationReferences.Add(new InlinedLocationReference(reference, this.metadata.CurrentActivity));
}
}
// Scenarios like VBV/R needs to know if they should run their own compiler
// during CacheMetadata. If we find a compiled expression root, means we're
// already compiled. So set the IsStaticallyCompiled flag to true
bool foundCompiledExpressionRoot = this.TryGetCompiledExpressionRootAtDesignTime(this.expressionActivity,
this.metadataRoot,
out this.compiledRoot,
out this.expressionId);
if (foundCompiledExpressionRoot)
{
this.IsStaticallyCompiled = true;
// For compiled C# expressions we create temp auto generated arguments
// for all locations whether they are used in the expressions or not.
// The TryGetReferenceToPublicLocation method call above also generates
// temp arguments for all locations.
// However for VB expressions, this leads to inconsistency between build
// time and run time as during build time VB only generates temp arguments
// for locations that are referenced in the expressions. To maintain
// consistency the we call the CreateRequiredArguments method seperately to
// generates auto arguments only for locations that are referenced.
if (!this.textExpression.RequiresCompilation)
{
IList<string> requiredLocationNames = this.compiledRoot.GetRequiredLocations(this.expressionId);
this.CreateRequiredArguments(requiredLocationNames);
}
}
}
bool TryGetCompiledExpressionRootAtDesignTime(Activity expression, Activity target, out ICompiledExpressionRoot compiledExpressionRoot, out int exprId)
{
exprId = -1;
compiledExpressionRoot = null;
if (!CompiledExpressionInvoker.TryGetCompiledExpressionRoot(expression, target, out compiledExpressionRoot) ||
!CanExecuteExpression(compiledExpressionRoot, out exprId))
{
return FindCompiledExpressionRoot(out exprId, out compiledExpressionRoot);
}
return true;
}
bool FindCompiledExpressionRoot(out int exprId, out ICompiledExpressionRoot compiledExpressionRoot)
{
Activity root = this.metadata.CurrentActivity.Parent;
while (root != null)
{
ICompiledExpressionRoot currentCompiledExpressionRoot = null;
if (CompiledExpressionInvoker.TryGetCompiledExpressionRoot(metadata.CurrentActivity, root, out currentCompiledExpressionRoot))
{
if (CanExecuteExpression(currentCompiledExpressionRoot, out exprId))
{
compiledExpressionRoot = currentCompiledExpressionRoot;
return true;
}
}
root = root.Parent;
}
exprId = -1;
compiledExpressionRoot = null;
return false;
}
void CreateRequiredArguments(IList<string> requiredLocationNames)
{
LocationReference reference;
if (requiredLocationNames != null && requiredLocationNames.Count > 0)
{
foreach (string name in requiredLocationNames)
{
reference = FindLocationReference(name);
if (reference != null)
{
if (this.isReference)
{
this.accessor.CreateLocationArgument(reference, true);
}
else
{
this.accessor.CreateArgument(reference, ArgumentDirection.In, true);
}
}
}
}
}
LocationReference FindLocationReference(string name)
{
LocationReference returnValue = null;
LocationReferenceEnvironment current = this.accessor.ActivityMetadata.Environment;
while (current != null)
{
if (current.TryGetLocationReference(name, out returnValue))
{
return returnValue;
}
current = current.Parent;
}
return returnValue;
}
}
}