You've already forked linux-packaging-mono
Rewrite with hard-coded offsets into the PE file format to discern if a binary is PE32 or PE32+, and then to determine if it contains a "CLR Data Directory" entry that looks valid. Tested with PE32 and PE32+ compiled Mono binaries, PE32 and PE32+ native binaries, and a random assortment of garbage files. Former-commit-id: 9e7ac86ec84f653a2f79b87183efd5b0ebda001b
2900 lines
124 KiB
C#
2900 lines
124 KiB
C#
//-----------------------------------------------------------------------------
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
namespace System.Activities.XamlIntegration
|
|
{
|
|
using System;
|
|
using System.Text;
|
|
using System.Activities;
|
|
using System.Activities.Statements;
|
|
using System.Activities.Validation;
|
|
using System.Reflection;
|
|
using System.CodeDom;
|
|
using System.CodeDom.Compiler;
|
|
using System.ComponentModel;
|
|
using System.Collections.Generic;
|
|
using Microsoft.VisualBasic.Activities;
|
|
using Microsoft.VisualBasic;
|
|
using System.Windows.Markup;
|
|
using System.Xaml;
|
|
using System.Activities.Debugger;
|
|
using System.IO;
|
|
using System.Activities.Expressions;
|
|
using System.Runtime;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using System.Security;
|
|
using System.Security.Permissions;
|
|
using System.Globalization;
|
|
using System.Activities.Debugger.Symbol;
|
|
using System.Linq.Expressions;
|
|
using System.Diagnostics;
|
|
|
|
public class TextExpressionCompiler
|
|
{
|
|
static string typedDataContextName = "_TypedDataContext";
|
|
static string expressionGetString = "__Expr{0}Get";
|
|
static string expressionSetString = "__Expr{0}Set";
|
|
static string expressionStatementString = "__Expr{0}Statement";
|
|
static string expressionGetTreeString = "__Expr{0}GetTree";
|
|
static string getValueTypeValuesString = "GetValueTypeValues";
|
|
static string setValueTypeValuesString = "SetValueTypeValues";
|
|
static string valueTypeAccessorString = "ValueType_";
|
|
static string forReadOnly = "_ForReadOnly";
|
|
static string xamlIntegrationNamespace = "System.Activities.XamlIntegration";
|
|
static string rootActivityFieldName = "rootActivity";
|
|
static string dataContextActivitiesFieldName = "dataContextActivities";
|
|
static string forImplementationName = "forImplementation";
|
|
static CodeAttributeDeclaration generatedCodeAttribute;
|
|
static CodeAttributeDeclaration browsableCodeAttribute;
|
|
static CodeAttributeDeclaration editorBrowsableCodeAttribute;
|
|
static string csharpLambdaString = "() => ";
|
|
static string vbLambdaString = "Function() ";
|
|
static string locationsOffsetFieldName = "locationsOffset";
|
|
static string expectedLocationsCountFieldName = "expectedLocationsCount";
|
|
|
|
Dictionary<int, IList<string>> expressionIdToLocationReferences = new Dictionary<int, IList<string>>();
|
|
|
|
string activityFullName;
|
|
int nextContextId;
|
|
bool? isCS = null;
|
|
bool? isVB = null;
|
|
bool generateSource;
|
|
|
|
TextExpressionCompilerSettings settings;
|
|
|
|
List<CompiledExpressionDescriptor> expressionDescriptors;
|
|
Stack<CompiledDataContextDescriptor> compiledDataContexts;
|
|
|
|
CodeNamespace codeNamespace;
|
|
CodeTypeDeclaration classDeclaration;
|
|
CodeCompileUnit compileUnit;
|
|
|
|
Dictionary<object, SourceLocation> symbols = null;
|
|
string fileName = null;
|
|
|
|
// Dictionary of namespace name => [Line#]
|
|
Dictionary<string, int> lineNumbersForNSes;
|
|
Dictionary<string, int> lineNumbersForNSesForImpl;
|
|
|
|
public TextExpressionCompiler(TextExpressionCompilerSettings settings)
|
|
{
|
|
if (settings == null)
|
|
{
|
|
throw FxTrace.Exception.ArgumentNull("settings");
|
|
}
|
|
|
|
if (settings.Activity == null)
|
|
{
|
|
throw FxTrace.Exception.Argument("settings", SR.TextExpressionCompilerActivityRequired);
|
|
}
|
|
|
|
if (settings.ActivityName == null)
|
|
{
|
|
throw FxTrace.Exception.Argument("settings", SR.TextExpressionCompilerActivityNameRequired);
|
|
}
|
|
|
|
if (settings.Language == null)
|
|
{
|
|
throw FxTrace.Exception.Argument("settings", SR.TextExpressionCompilerLanguageRequired);
|
|
}
|
|
|
|
this.expressionDescriptors = new List<CompiledExpressionDescriptor>();
|
|
this.compiledDataContexts = new Stack<CompiledDataContextDescriptor>();
|
|
this.nextContextId = 0;
|
|
|
|
this.settings = settings;
|
|
|
|
this.activityFullName = activityFullName = GetActivityFullName(settings);
|
|
|
|
this.generateSource = this.settings.AlwaysGenerateSource;
|
|
|
|
this.lineNumbersForNSes = new Dictionary<string, int>();
|
|
this.lineNumbersForNSesForImpl = new Dictionary<string, int>();
|
|
}
|
|
|
|
bool IsCS
|
|
{
|
|
get
|
|
{
|
|
if (!isCS.HasValue)
|
|
{
|
|
isCS = TextExpression.LanguagesAreEqual(this.settings.Language, "C#");
|
|
}
|
|
return isCS.Value;
|
|
}
|
|
}
|
|
|
|
bool IsVB
|
|
{
|
|
get
|
|
{
|
|
if (!isVB.HasValue)
|
|
{
|
|
isVB = TextExpression.LanguagesAreEqual(this.settings.Language, "VB");
|
|
}
|
|
return isVB.Value;
|
|
}
|
|
}
|
|
|
|
bool InVariableScopeArgument
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
static CodeAttributeDeclaration GeneratedCodeAttribute
|
|
{
|
|
get
|
|
{
|
|
if (generatedCodeAttribute == null)
|
|
{
|
|
AssemblyName currentAssemblyName = new AssemblyName(Assembly.GetExecutingAssembly().FullName);
|
|
generatedCodeAttribute = new CodeAttributeDeclaration(
|
|
new CodeTypeReference(typeof(GeneratedCodeAttribute)),
|
|
new CodeAttributeArgument(new CodePrimitiveExpression(currentAssemblyName.Name)),
|
|
new CodeAttributeArgument(new CodePrimitiveExpression(currentAssemblyName.Version.ToString())));
|
|
}
|
|
|
|
return generatedCodeAttribute;
|
|
}
|
|
}
|
|
|
|
static CodeAttributeDeclaration BrowsableCodeAttribute
|
|
{
|
|
get
|
|
{
|
|
if (browsableCodeAttribute == null)
|
|
{
|
|
browsableCodeAttribute = new CodeAttributeDeclaration(
|
|
new CodeTypeReference(typeof(BrowsableAttribute)),
|
|
new CodeAttributeArgument(new CodePrimitiveExpression(false)));
|
|
}
|
|
return browsableCodeAttribute;
|
|
}
|
|
}
|
|
|
|
static CodeAttributeDeclaration EditorBrowsableCodeAttribute
|
|
{
|
|
get
|
|
{
|
|
if (editorBrowsableCodeAttribute == null)
|
|
{
|
|
editorBrowsableCodeAttribute = new CodeAttributeDeclaration(
|
|
new CodeTypeReference(typeof(EditorBrowsableAttribute)),
|
|
new CodeAttributeArgument(new CodeFieldReferenceExpression(
|
|
new CodeTypeReferenceExpression(
|
|
new CodeTypeReference(typeof(EditorBrowsableState))), "Never")));
|
|
}
|
|
return editorBrowsableCodeAttribute;
|
|
}
|
|
}
|
|
|
|
|
|
public bool GenerateSource(TextWriter textWriter)
|
|
{
|
|
if (textWriter == null)
|
|
{
|
|
throw FxTrace.Exception.ArgumentNull("textWriter");
|
|
}
|
|
|
|
Parse();
|
|
|
|
if (this.generateSource)
|
|
{
|
|
WriteCode(textWriter);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public TextExpressionCompilerResults Compile()
|
|
{
|
|
Parse();
|
|
|
|
if (this.generateSource)
|
|
{
|
|
return CompileInMemory();
|
|
}
|
|
|
|
return new TextExpressionCompilerResults();
|
|
}
|
|
|
|
void Parse()
|
|
{
|
|
if (!this.settings.Activity.IsMetadataCached)
|
|
{
|
|
IList<ValidationError> validationErrors = null;
|
|
try
|
|
{
|
|
ActivityUtilities.CacheRootMetadata(this.settings.Activity, new ActivityLocationReferenceEnvironment(), ProcessActivityTreeOptions.FullCachingOptions, null, ref validationErrors);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
if (Fx.IsFatal(e))
|
|
{
|
|
throw;
|
|
}
|
|
|
|
throw FxTrace.Exception.AsError(new InvalidOperationException(SR.CompiledExpressionsCacheMetadataException(this.settings.Activity.GetType().AssemblyQualifiedName, e.ToString())));
|
|
}
|
|
}
|
|
|
|
// Get the source location for an activity
|
|
if (this.TryGetSymbols(this.settings.Activity, out this.symbols, out this.fileName))
|
|
{
|
|
// Get line number info for namespaces
|
|
TextExpressionCompilerHelper.GetNamespacesLineInfo(this.fileName, this.lineNumbersForNSes, this.lineNumbersForNSesForImpl);
|
|
}
|
|
|
|
this.compileUnit = new CodeCompileUnit();
|
|
this.codeNamespace = GenerateCodeNamespace();
|
|
this.classDeclaration = GenerateClass();
|
|
|
|
this.codeNamespace.Types.Add(classDeclaration);
|
|
this.compileUnit.Namespaces.Add(this.codeNamespace);
|
|
|
|
//
|
|
// Generate data contexts with properties and expression methods
|
|
// Use the shared, public tree walk for expressions routine for consistency.
|
|
ExpressionCompilerActivityVisitor visitor = new ExpressionCompilerActivityVisitor(this)
|
|
{
|
|
NextExpressionId = 0,
|
|
};
|
|
|
|
try
|
|
{
|
|
visitor.Visit(this.settings.Activity, this.settings.ForImplementation);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
if (Fx.IsFatal(e))
|
|
{
|
|
throw;
|
|
}
|
|
//
|
|
// Note that unlike the above where the exception from CacheMetadata is always going to be from the user's code
|
|
// an exception here is more likely to be from our code and unexpected. However it could be from user code in some cases.
|
|
// Output a message that attempts to normalize this and presents enough info to the user to determine if they can take action.
|
|
throw FxTrace.Exception.AsError(new InvalidOperationException(SR.CompiledExpressionsActivityException(e.GetType().FullName, this.settings.Activity.GetType().AssemblyQualifiedName, e.ToString())));
|
|
}
|
|
|
|
if (this.generateSource)
|
|
{
|
|
GenerateInvokeExpressionMethod(true);
|
|
GenerateInvokeExpressionMethod(false);
|
|
|
|
GenerateCanExecuteMethod();
|
|
|
|
GenerateGetRequiredLocationsMethod();
|
|
|
|
GenerateGetExpressionTreeForExpressionMethod();
|
|
}
|
|
|
|
}
|
|
|
|
void OnRootActivity()
|
|
{
|
|
//
|
|
// Always generate a CDC for the root
|
|
// This will contain expressions for the default value of the root arguments
|
|
// These expressions cannot see other root arguments or variables so they need
|
|
// to be at the very root, before we add any properties
|
|
PushDataContextDescriptor();
|
|
}
|
|
|
|
void OnAfterRootActivity()
|
|
{
|
|
//
|
|
// First pop the root arguments descriptor pushed in OnAfterRootArguments
|
|
PopDataContextDescriptor();
|
|
//
|
|
// If we are walking the implementation there will be a second root context descriptor
|
|
// that holds the member declarations for root arguments.
|
|
// This isn't generatedwhen walking the public surface
|
|
if (this.settings.ForImplementation)
|
|
{
|
|
PopDataContextDescriptor();
|
|
}
|
|
}
|
|
|
|
void OnAfterRootArguments(Activity activity)
|
|
{
|
|
//
|
|
// Generate the properties for root arguments in a context below the context
|
|
// that contains the default expressions for the root arguments
|
|
CompiledDataContextDescriptor contextDescriptor = PushDataContextDescriptor();
|
|
if (activity.RuntimeArguments != null && activity.RuntimeArguments.Count > 0)
|
|
{
|
|
//
|
|
// Walk the arguments
|
|
foreach (RuntimeArgument runtimeArgument in activity.RuntimeArguments)
|
|
{
|
|
if (runtimeArgument.IsBound)
|
|
{
|
|
AddMember(runtimeArgument.Name, runtimeArgument.Type, contextDescriptor);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void OnActivityDelegateScope()
|
|
{
|
|
PushDataContextDescriptor();
|
|
}
|
|
|
|
void OnDelegateArgument(RuntimeDelegateArgument delegateArgument)
|
|
{
|
|
AddMember(delegateArgument.BoundArgument.Name, delegateArgument.BoundArgument.Type, this.compiledDataContexts.Peek());
|
|
}
|
|
|
|
void OnAfterActivityDelegateScope()
|
|
{
|
|
PopDataContextDescriptor();
|
|
}
|
|
|
|
void OnVariableScope(Activity activity)
|
|
{
|
|
CompiledDataContextDescriptor contextDescriptor = PushDataContextDescriptor();
|
|
//
|
|
// Generate the variable accessors
|
|
foreach (Variable v in activity.RuntimeVariables)
|
|
{
|
|
AddMember(v.Name, v.Type, contextDescriptor);
|
|
}
|
|
}
|
|
|
|
void OnRootImplementationScope(Activity activity, out CompiledDataContextDescriptor rootArgumentAccessorContext)
|
|
{
|
|
Fx.Assert(this.compiledDataContexts.Count == 2, "The stack of data contexts should contain the root argument default expression and accessor contexts");
|
|
|
|
rootArgumentAccessorContext = this.compiledDataContexts.Pop();
|
|
|
|
if (activity.RuntimeVariables != null && activity.RuntimeVariables.Count > 0)
|
|
{
|
|
this.OnVariableScope(activity);
|
|
}
|
|
}
|
|
|
|
void OnAfterRootImplementationScope(Activity activity, CompiledDataContextDescriptor rootArgumentAccessorContext)
|
|
{
|
|
if (activity.RuntimeVariables != null && activity.RuntimeVariables.Count > 0)
|
|
{
|
|
OnAfterVariableScope();
|
|
}
|
|
|
|
this.compiledDataContexts.Push(rootArgumentAccessorContext);
|
|
}
|
|
|
|
void AddMember(string name, Type type, CompiledDataContextDescriptor contextDescriptor)
|
|
{
|
|
if (IsValidTextIdentifierName(name))
|
|
{
|
|
//
|
|
// These checks will be invariantlowercase if the language is VB
|
|
if (contextDescriptor.Fields.ContainsKey(name) || contextDescriptor.Properties.ContainsKey(name))
|
|
{
|
|
if (!contextDescriptor.Duplicates.Contains(name))
|
|
{
|
|
contextDescriptor.Duplicates.Add(name.ToUpperInvariant());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MemberData memberData = new MemberData();
|
|
memberData.Type = type;
|
|
memberData.Name = name;
|
|
memberData.Index = contextDescriptor.NextMemberIndex;
|
|
|
|
if (type.IsValueType)
|
|
{
|
|
contextDescriptor.Fields.Add(name, memberData);
|
|
}
|
|
else
|
|
{
|
|
contextDescriptor.Properties.Add(name, memberData);
|
|
}
|
|
}
|
|
}
|
|
//
|
|
// Regardless of whether or not this member name is an invalid, duplicate, or valid identifier
|
|
// always increment the member count so that the indexes we generate always match
|
|
// the list that the runtime gives to the ITextExpression
|
|
// The exception here is if the name is null
|
|
if (name != null)
|
|
{
|
|
contextDescriptor.NextMemberIndex++;
|
|
}
|
|
}
|
|
|
|
void GenerateMembers(CompiledDataContextDescriptor descriptor)
|
|
{
|
|
foreach (KeyValuePair<string, MemberData> property in descriptor.Properties)
|
|
{
|
|
GenerateProperty(property.Value, descriptor);
|
|
}
|
|
|
|
if (descriptor.Fields.Count > 0)
|
|
{
|
|
foreach (KeyValuePair<string, MemberData> field in descriptor.Fields)
|
|
{
|
|
GenerateField(field.Value, descriptor);
|
|
}
|
|
|
|
CodeMemberMethod getValueTypeValuesMethod = GenerateGetValueTypeValues(descriptor);
|
|
|
|
descriptor.CodeTypeDeclaration.Members.Add(getValueTypeValuesMethod);
|
|
descriptor.CodeTypeDeclaration.Members.Add(GenerateSetValueTypeValues(descriptor));
|
|
|
|
descriptor.CodeTypeDeclarationForReadOnly.Members.Add(getValueTypeValuesMethod);
|
|
}
|
|
|
|
if (descriptor.Duplicates.Count > 0 && this.IsVB)
|
|
{
|
|
foreach (string duplicate in descriptor.Duplicates)
|
|
{
|
|
AddPropertyForDuplicates(duplicate, descriptor);
|
|
}
|
|
}
|
|
}
|
|
|
|
void GenerateField(MemberData memberData, CompiledDataContextDescriptor contextDescriptor)
|
|
{
|
|
if (contextDescriptor.Duplicates.Contains(memberData.Name))
|
|
{
|
|
return;
|
|
}
|
|
|
|
CodeMemberField accessorField = new CodeMemberField();
|
|
accessorField.Attributes = MemberAttributes.Family | MemberAttributes.Final;
|
|
accessorField.Name = memberData.Name;
|
|
accessorField.Type = new CodeTypeReference(memberData.Type);
|
|
|
|
if (IsRedefinition(memberData.Name))
|
|
{
|
|
accessorField.Attributes |= MemberAttributes.New;
|
|
}
|
|
|
|
contextDescriptor.CodeTypeDeclaration.Members.Add(accessorField);
|
|
|
|
contextDescriptor.CodeTypeDeclarationForReadOnly.Members.Add(accessorField);
|
|
}
|
|
|
|
void GenerateProperty(MemberData memberData, CompiledDataContextDescriptor contextDescriptor)
|
|
{
|
|
if (contextDescriptor.Duplicates.Contains(memberData.Name))
|
|
{
|
|
return;
|
|
}
|
|
|
|
bool isRedefinition = IsRedefinition(memberData.Name);
|
|
|
|
CodeMemberProperty accessorProperty = GenerateCodeMemberProperty(memberData, isRedefinition);
|
|
|
|
//
|
|
// Generate a get accessor that looks like this:
|
|
// return (Foo) this.GetVariableValue(contextId, locationIndexId)
|
|
CodeMethodReturnStatement getterStatement = new CodeMethodReturnStatement(
|
|
new CodeCastExpression(memberData.Type, new CodeMethodInvokeExpression(
|
|
new CodeMethodReferenceExpression(
|
|
new CodeThisReferenceExpression(),
|
|
"GetVariableValue"),
|
|
new CodeBinaryOperatorExpression(
|
|
new CodePrimitiveExpression(memberData.Index),
|
|
CodeBinaryOperatorType.Add,
|
|
new CodeVariableReferenceExpression("locationsOffset")))));
|
|
|
|
accessorProperty.GetStatements.Add(getterStatement);
|
|
|
|
// Generate a set accessor that looks something like this:
|
|
// this.SetVariableValue(contextId, locationIndexId, value)
|
|
accessorProperty.SetStatements.Add(new CodeMethodInvokeExpression(
|
|
new CodeMethodReferenceExpression(
|
|
new CodeThisReferenceExpression(),
|
|
"SetVariableValue"),
|
|
new CodeBinaryOperatorExpression(
|
|
new CodePrimitiveExpression(memberData.Index),
|
|
CodeBinaryOperatorType.Add,
|
|
new CodeVariableReferenceExpression("locationsOffset")),
|
|
new CodePropertySetValueReferenceExpression()));
|
|
|
|
contextDescriptor.CodeTypeDeclaration.Members.Add(accessorProperty);
|
|
|
|
//
|
|
// Create another property for the read only class.
|
|
// This will only have a getter so we can't just re-use the property from above
|
|
CodeMemberProperty accessorPropertyForReadOnly = GenerateCodeMemberProperty(memberData, isRedefinition);
|
|
//
|
|
// OK to share the getter statement from above
|
|
accessorPropertyForReadOnly.GetStatements.Add(getterStatement);
|
|
|
|
contextDescriptor.CodeTypeDeclarationForReadOnly.Members.Add(accessorPropertyForReadOnly);
|
|
}
|
|
|
|
CodeMemberProperty GenerateCodeMemberProperty(MemberData memberData, bool isRedefinition)
|
|
{
|
|
CodeMemberProperty accessorProperty = new CodeMemberProperty();
|
|
accessorProperty.Attributes = MemberAttributes.Family | MemberAttributes.Final;
|
|
accessorProperty.Name = memberData.Name;
|
|
accessorProperty.Type = new CodeTypeReference(memberData.Type);
|
|
|
|
if (isRedefinition)
|
|
{
|
|
accessorProperty.Attributes |= MemberAttributes.New;
|
|
}
|
|
|
|
return accessorProperty;
|
|
}
|
|
|
|
void AddPropertyForDuplicates(string name, CompiledDataContextDescriptor contextDescriptor)
|
|
{
|
|
CodeMemberProperty accessorProperty = new CodeMemberProperty();
|
|
accessorProperty.Attributes = MemberAttributes.Family | MemberAttributes.Final;
|
|
accessorProperty.Name = name;
|
|
accessorProperty.Type = new CodeTypeReference(typeof(object));
|
|
|
|
CodeThrowExceptionStatement exception = new CodeThrowExceptionStatement(
|
|
new CodeObjectCreateExpression(typeof(InvalidOperationException), new CodePrimitiveExpression(SR.CompiledExpressionsDuplicateName(name))));
|
|
|
|
accessorProperty.GetStatements.Add(exception);
|
|
accessorProperty.SetStatements.Add(exception);
|
|
|
|
contextDescriptor.CodeTypeDeclaration.Members.Add(accessorProperty);
|
|
|
|
//
|
|
// Create another property for the read only class.
|
|
// This will only have a getter so we can't just re-use the property from above
|
|
CodeMemberProperty accessorPropertyForReadOnly = new CodeMemberProperty();
|
|
accessorPropertyForReadOnly.Attributes = MemberAttributes.Family | MemberAttributes.Final;
|
|
accessorPropertyForReadOnly.Name = name;
|
|
accessorPropertyForReadOnly.Type = new CodeTypeReference(typeof(object));
|
|
//
|
|
// OK to share the exception from above
|
|
accessorPropertyForReadOnly.GetStatements.Add(exception);
|
|
|
|
contextDescriptor.CodeTypeDeclarationForReadOnly.Members.Add(accessorPropertyForReadOnly);
|
|
}
|
|
|
|
[Fx.Tag.SecurityNote(Critical = "Critical because we are accessing CodeDom.",
|
|
Safe = "Safe because we are demanding FullTrust")]
|
|
[SecuritySafeCritical]
|
|
[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
|
|
bool IsValidTextIdentifierName(string name)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(name))
|
|
{
|
|
if (this.settings.LogSourceGenerationMessage != null)
|
|
{
|
|
this.settings.LogSourceGenerationMessage(SR.CompiledExpressionsIgnoringUnnamedVariable);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
if (!CodeDomProvider.CreateProvider(this.settings.Language).IsValidIdentifier(name))
|
|
{
|
|
if (this.settings.LogSourceGenerationMessage != null)
|
|
{
|
|
this.settings.LogSourceGenerationMessage(SR.CompiledExpressionsIgnoringInvalidIdentifierVariable(name));
|
|
}
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool IsRedefinition(string variableName)
|
|
{
|
|
if (this.compiledDataContexts == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
foreach (CompiledDataContextDescriptor contextDescriptor in this.compiledDataContexts)
|
|
{
|
|
foreach (KeyValuePair<string, MemberData> field in contextDescriptor.Fields)
|
|
{
|
|
if (NamesMatch(variableName, field.Key))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
foreach (KeyValuePair<string, MemberData> property in contextDescriptor.Properties)
|
|
{
|
|
if (NamesMatch(variableName, property.Key))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool NamesMatch(string toCheck, string current)
|
|
{
|
|
if (IsVB && string.Compare(toCheck, current, true, CultureInfo.CurrentCulture) == 0)
|
|
{
|
|
return true;
|
|
}
|
|
else if (!IsVB && toCheck == current)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void OnAfterVariableScope()
|
|
{
|
|
PopDataContextDescriptor();
|
|
}
|
|
|
|
void OnITextExpressionFound(Activity activity, ExpressionCompilerActivityVisitor visitor)
|
|
{
|
|
CompiledDataContextDescriptor contextDescriptor = null;
|
|
CompiledDataContextDescriptor currentContextDescriptor = this.compiledDataContexts.Peek();
|
|
|
|
if (this.InVariableScopeArgument)
|
|
{
|
|
//
|
|
// Temporarily popping the stack so don't use PopDataContextDescriptor
|
|
// because that is for when the descriptor is done being built
|
|
this.compiledDataContexts.Pop();
|
|
contextDescriptor = PushDataContextDescriptor();
|
|
}
|
|
else
|
|
{
|
|
contextDescriptor = currentContextDescriptor;
|
|
}
|
|
|
|
|
|
if (TryGenerateExpressionCode(activity, contextDescriptor, visitor.NextExpressionId, this.settings.Language))
|
|
{
|
|
expressionIdToLocationReferences.Add(visitor.NextExpressionId, this.FindLocationReferences(activity));
|
|
visitor.NextExpressionId++;
|
|
this.generateSource = true;
|
|
}
|
|
|
|
if (this.InVariableScopeArgument)
|
|
{
|
|
PopDataContextDescriptor();
|
|
this.compiledDataContexts.Push(currentContextDescriptor);
|
|
}
|
|
}
|
|
|
|
IList<string> FindLocationReferences(Activity activity)
|
|
{
|
|
ActivityWithResult boundExpression;
|
|
LocationReference locationReference;
|
|
List<string> requiredLocationReferences = new List<string>();
|
|
|
|
foreach (RuntimeArgument runtimeArgument in activity.RuntimeArguments)
|
|
{
|
|
boundExpression = runtimeArgument.BoundArgument.Expression;
|
|
|
|
if (boundExpression != null && boundExpression is ILocationReferenceWrapper)
|
|
{
|
|
locationReference = ((ILocationReferenceWrapper)boundExpression).LocationReference;
|
|
|
|
if (locationReference != null)
|
|
{
|
|
requiredLocationReferences.Add(locationReference.Name);
|
|
}
|
|
}
|
|
}
|
|
return requiredLocationReferences;
|
|
}
|
|
|
|
CodeTypeDeclaration GenerateClass()
|
|
{
|
|
CodeTypeDeclaration classDeclaration = new CodeTypeDeclaration(this.settings.ActivityName);
|
|
classDeclaration.BaseTypes.Add(new CodeTypeReference(typeof(ICompiledExpressionRoot)));
|
|
classDeclaration.IsPartial = this.settings.GenerateAsPartialClass;
|
|
|
|
CodeMemberField compiledRootField = new CodeMemberField(new CodeTypeReference(typeof(Activity)), rootActivityFieldName);
|
|
classDeclaration.Members.Add(compiledRootField);
|
|
|
|
CodeMemberMethod languageProperty = new CodeMemberMethod();
|
|
languageProperty.Attributes = MemberAttributes.Final | MemberAttributes.Public;
|
|
languageProperty.Name = "GetLanguage";
|
|
languageProperty.ReturnType = new CodeTypeReference(typeof(string));
|
|
languageProperty.Statements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression(this.settings.Language)));
|
|
languageProperty.ImplementationTypes.Add(new CodeTypeReference(typeof(ICompiledExpressionRoot)));
|
|
languageProperty.CustomAttributes.Add(GeneratedCodeAttribute);
|
|
languageProperty.CustomAttributes.Add(BrowsableCodeAttribute);
|
|
languageProperty.CustomAttributes.Add(EditorBrowsableCodeAttribute);
|
|
|
|
classDeclaration.Members.Add(languageProperty);
|
|
|
|
CodeMemberField dataContextActivitiesField = new CodeMemberField();
|
|
dataContextActivitiesField.Attributes = MemberAttributes.Private;
|
|
dataContextActivitiesField.Name = dataContextActivitiesFieldName;
|
|
dataContextActivitiesField.Type = new CodeTypeReference(typeof(object));
|
|
|
|
classDeclaration.Members.Add(dataContextActivitiesField);
|
|
|
|
CodeMemberField forImplementationField = new CodeMemberField();
|
|
forImplementationField.Attributes = MemberAttributes.Private;
|
|
forImplementationField.Name = forImplementationName;
|
|
forImplementationField.Type = new CodeTypeReference(typeof(bool));
|
|
forImplementationField.InitExpression = new CodePrimitiveExpression(this.settings.ForImplementation);
|
|
|
|
classDeclaration.Members.Add(forImplementationField);
|
|
|
|
if (!this.settings.GenerateAsPartialClass)
|
|
{
|
|
classDeclaration.Members.Add(GenerateCompiledExpressionRootConstructor());
|
|
}
|
|
|
|
return classDeclaration;
|
|
}
|
|
|
|
CodeConstructor GenerateCompiledExpressionRootConstructor()
|
|
{
|
|
CodeConstructor constructor = new CodeConstructor();
|
|
constructor.Attributes = MemberAttributes.Public;
|
|
|
|
constructor.Parameters.Add(
|
|
new CodeParameterDeclarationExpression(
|
|
new CodeTypeReference(typeof(Activity)),
|
|
rootActivityFieldName));
|
|
|
|
CodeBinaryOperatorExpression nullArgumentExpression = new CodeBinaryOperatorExpression(
|
|
new CodeVariableReferenceExpression(rootActivityFieldName),
|
|
CodeBinaryOperatorType.IdentityEquality,
|
|
new CodePrimitiveExpression(null));
|
|
|
|
CodeConditionStatement nullArgumentCondition = new CodeConditionStatement(
|
|
nullArgumentExpression,
|
|
new CodeThrowExceptionStatement(
|
|
new CodeObjectCreateExpression(
|
|
new CodeTypeReference(typeof(ArgumentNullException)),
|
|
new CodePrimitiveExpression(rootActivityFieldName))));
|
|
|
|
constructor.Statements.Add(nullArgumentCondition);
|
|
|
|
constructor.Statements.Add(
|
|
new CodeAssignStatement(
|
|
new CodeFieldReferenceExpression(
|
|
new CodeThisReferenceExpression(),
|
|
rootActivityFieldName),
|
|
new CodeVariableReferenceExpression(rootActivityFieldName)));
|
|
|
|
return constructor;
|
|
}
|
|
|
|
Dictionary<string, int> GetCacheIndicies()
|
|
{
|
|
Dictionary<string, int> contexts = new Dictionary<string, int>();
|
|
int currentIndex = 0;
|
|
|
|
foreach (CompiledExpressionDescriptor descriptor in this.expressionDescriptors)
|
|
{
|
|
string name = descriptor.TypeName;
|
|
if (!contexts.ContainsKey(name))
|
|
{
|
|
contexts.Add(name, currentIndex++);
|
|
}
|
|
}
|
|
|
|
return contexts;
|
|
}
|
|
|
|
void GenerateGetRequiredLocationsMethod()
|
|
{
|
|
CodeMemberMethod getLocationsMethod = new CodeMemberMethod();
|
|
getLocationsMethod.Name = "GetRequiredLocations";
|
|
getLocationsMethod.Attributes = MemberAttributes.Final | MemberAttributes.Public;
|
|
getLocationsMethod.CustomAttributes.Add(GeneratedCodeAttribute);
|
|
getLocationsMethod.CustomAttributes.Add(BrowsableCodeAttribute);
|
|
getLocationsMethod.CustomAttributes.Add(EditorBrowsableCodeAttribute);
|
|
getLocationsMethod.ImplementationTypes.Add(new CodeTypeReference(typeof(ICompiledExpressionRoot)));
|
|
|
|
getLocationsMethod.ReturnType = new CodeTypeReference(typeof(IList<string>));
|
|
|
|
getLocationsMethod.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference(typeof(int)), "expressionId"));
|
|
|
|
if (this.IsVB)
|
|
{
|
|
GenerateRequiredLocationsBody(getLocationsMethod);
|
|
}
|
|
else
|
|
{
|
|
GenerateEmptyRequiredLocationsBody(getLocationsMethod);
|
|
}
|
|
|
|
classDeclaration.Members.Add(getLocationsMethod);
|
|
}
|
|
|
|
void GenerateEmptyRequiredLocationsBody(CodeMemberMethod getLocationsMethod)
|
|
{
|
|
getLocationsMethod.Statements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression(null)));
|
|
}
|
|
|
|
void GenerateRequiredLocationsBody(CodeMemberMethod getLocationsMethod)
|
|
{
|
|
CodeVariableDeclarationStatement returnLocationsVar = new CodeVariableDeclarationStatement(new CodeTypeReference(typeof(List<string>)),
|
|
"returnLocations",
|
|
new CodeObjectCreateExpression(new CodeTypeReference(typeof(List<string>))));
|
|
|
|
getLocationsMethod.Statements.Add(returnLocationsVar);
|
|
foreach (CompiledExpressionDescriptor descriptor in expressionDescriptors)
|
|
{
|
|
IList<string> requiredLocations = null;
|
|
bool found = expressionIdToLocationReferences.TryGetValue(descriptor.Id, out requiredLocations);
|
|
if (!found)
|
|
{
|
|
return;
|
|
}
|
|
CodeStatement[] conditionStatements = null;
|
|
conditionStatements = GetRequiredLocationsConditionStatements(requiredLocations);
|
|
|
|
CodeBinaryOperatorExpression idExpression = new CodeBinaryOperatorExpression(new CodeVariableReferenceExpression("expressionId"), CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(descriptor.Id));
|
|
CodeConditionStatement idCondition = new CodeConditionStatement(idExpression, conditionStatements);
|
|
|
|
getLocationsMethod.Statements.Add(idCondition);
|
|
}
|
|
|
|
getLocationsMethod.Statements.Add(new CodeMethodReturnStatement(new CodeVariableReferenceExpression("returnLocations")));
|
|
}
|
|
|
|
static CodeStatement[] GetRequiredLocationsConditionStatements(IList<string> requiredLocations)
|
|
{
|
|
CodeStatementCollection statementCollection = new CodeStatementCollection();
|
|
foreach (string locationName in requiredLocations)
|
|
{
|
|
CodeMethodInvokeExpression invokeValidateExpression = new CodeMethodInvokeExpression(
|
|
new CodeMethodReferenceExpression(new CodeVariableReferenceExpression("returnLocations"), "Add"),
|
|
new CodePrimitiveExpression(locationName));
|
|
statementCollection.Add(invokeValidateExpression);
|
|
}
|
|
|
|
CodeStatement[] returnStatements = new CodeStatement[statementCollection.Count];
|
|
statementCollection.CopyTo(returnStatements, 0);
|
|
|
|
return returnStatements;
|
|
}
|
|
|
|
void GenerateGetExpressionTreeForExpressionMethod()
|
|
{
|
|
CodeMemberMethod getExpressionTreeForExpressionMethod = new CodeMemberMethod();
|
|
getExpressionTreeForExpressionMethod.Name = "GetExpressionTreeForExpression";
|
|
getExpressionTreeForExpressionMethod.Attributes = MemberAttributes.Final | MemberAttributes.Public;
|
|
getExpressionTreeForExpressionMethod.ReturnType = new CodeTypeReference(typeof(Expression));
|
|
getExpressionTreeForExpressionMethod.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference(typeof(int)), "expressionId"));
|
|
getExpressionTreeForExpressionMethod.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference(typeof(IList<LocationReference>)), "locationReferences"));
|
|
getExpressionTreeForExpressionMethod.ImplementationTypes.Add(new CodeTypeReference(typeof(ICompiledExpressionRoot)));
|
|
|
|
// Mark this type as tool generated code
|
|
getExpressionTreeForExpressionMethod.CustomAttributes.Add(GeneratedCodeAttribute);
|
|
|
|
// Mark it as Browsable(false)
|
|
// Note that this does not prevent intellisense within a single project, just at the metadata level
|
|
getExpressionTreeForExpressionMethod.CustomAttributes.Add(BrowsableCodeAttribute);
|
|
|
|
// Mark it as EditorBrowsable(EditorBrowsableState.Never)
|
|
// Note that this does not prevent intellisense within a single project, just at the metadata level
|
|
getExpressionTreeForExpressionMethod.CustomAttributes.Add(EditorBrowsableCodeAttribute);
|
|
|
|
foreach (CompiledExpressionDescriptor descriptor in expressionDescriptors)
|
|
{
|
|
CodeMethodReturnStatement conditionStatement = new CodeMethodReturnStatement(
|
|
new CodeMethodInvokeExpression(
|
|
new CodeMethodReferenceExpression(
|
|
new CodeObjectCreateExpression(new CodeTypeReference(descriptor.TypeName), new CodeExpression[] { new CodeVariableReferenceExpression("locationReferences") }),
|
|
descriptor.GetExpressionTreeMethodName)));
|
|
|
|
CodeBinaryOperatorExpression idExpression = new CodeBinaryOperatorExpression(new CodeVariableReferenceExpression("expressionId"), CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(descriptor.Id));
|
|
CodeConditionStatement idCondition = new CodeConditionStatement(idExpression, conditionStatement);
|
|
|
|
getExpressionTreeForExpressionMethod.Statements.Add(idCondition);
|
|
}
|
|
|
|
getExpressionTreeForExpressionMethod.Statements.Add(new CodeMethodReturnStatement(
|
|
new CodePrimitiveExpression(null)));
|
|
|
|
classDeclaration.Members.Add(getExpressionTreeForExpressionMethod);
|
|
}
|
|
|
|
void GenerateInvokeExpressionMethod(bool withLocationReferences)
|
|
{
|
|
CodeMemberMethod invokeExpressionMethod = new CodeMemberMethod();
|
|
invokeExpressionMethod.Name = "InvokeExpression";
|
|
invokeExpressionMethod.Attributes = MemberAttributes.Final | MemberAttributes.Public;
|
|
invokeExpressionMethod.CustomAttributes.Add(GeneratedCodeAttribute);
|
|
invokeExpressionMethod.CustomAttributes.Add(BrowsableCodeAttribute);
|
|
invokeExpressionMethod.CustomAttributes.Add(EditorBrowsableCodeAttribute);
|
|
invokeExpressionMethod.ImplementationTypes.Add(new CodeTypeReference(typeof(ICompiledExpressionRoot)));
|
|
|
|
invokeExpressionMethod.ReturnType = new CodeTypeReference(typeof(object));
|
|
|
|
invokeExpressionMethod.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference(typeof(int)), "expressionId"));
|
|
|
|
if (withLocationReferences)
|
|
{
|
|
invokeExpressionMethod.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference(typeof(IList<LocationReference>)), "locations"));
|
|
invokeExpressionMethod.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference(typeof(ActivityContext)), "activityContext"));
|
|
}
|
|
else
|
|
{
|
|
invokeExpressionMethod.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference(typeof(IList<Location>)), "locations"));
|
|
}
|
|
|
|
if (this.settings.GenerateAsPartialClass)
|
|
{
|
|
invokeExpressionMethod.Statements.Add(GenerateInitializeDataContextActivity());
|
|
}
|
|
|
|
if (withLocationReferences)
|
|
{
|
|
if (this.expressionDescriptors != null && this.expressionDescriptors.Count > 0)
|
|
{
|
|
//
|
|
// We only generate the helper method on the root data context/context 0
|
|
// No need to have it on all contexts. This is just a slight of hand
|
|
// so that we don't need to make GetDataContextActivities public on CompiledDataContext.
|
|
invokeExpressionMethod.Statements.Add(GenerateDataContextActivitiesCheck(this.expressionDescriptors[0]));
|
|
}
|
|
}
|
|
|
|
Dictionary<string, int> cacheIndicies = GetCacheIndicies();
|
|
|
|
foreach (CompiledExpressionDescriptor descriptor in expressionDescriptors)
|
|
{
|
|
//
|
|
// if ((expressionId == [descriptor.Id]))
|
|
// {
|
|
// if (!CheckExpressionText(expressionId, activityContext)
|
|
// {
|
|
// throw new Exception();
|
|
// }
|
|
// System.Activities.XamlIntegration.CompiledDataContext[] cachedCompiledDataContext = Workflow1_TypedDataContext1_ForReadOnly.GetCompiledDataContextCacheHelper(this, activityContext, 1);
|
|
// if ((cachedCompiledDataContext[0] == null))
|
|
// {
|
|
// cachedCompiledDataContext[0] = new Workflow1_TypedDataContext1_ForReadOnly(locations, activityContext);
|
|
// }
|
|
// Workflow1_TypedDataContext1_ForReadOnly valDataContext0 = ((Workflow1_TypedDataContext1_ForReadOnly)(cachedCompiledDataContext[0]));
|
|
// return valDataContext0.ValueType___Expr0Get();
|
|
// }
|
|
//
|
|
CodeStatement[] conditionStatements = null;
|
|
if (descriptor.IsReference)
|
|
{
|
|
conditionStatements = GenerateReferenceExpressionInvocation(descriptor, withLocationReferences, cacheIndicies);
|
|
}
|
|
else if (descriptor.IsValue)
|
|
{
|
|
conditionStatements = GenerateValueExpressionInvocation(descriptor, withLocationReferences, cacheIndicies);
|
|
}
|
|
else if (descriptor.IsStatement)
|
|
{
|
|
conditionStatements = GenerateStatementInvocation(descriptor, withLocationReferences, cacheIndicies);
|
|
}
|
|
|
|
CodeBinaryOperatorExpression idExpression = new CodeBinaryOperatorExpression(new CodeVariableReferenceExpression("expressionId"), CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(descriptor.Id));
|
|
CodeConditionStatement idCondition = new CodeConditionStatement(idExpression, conditionStatements);
|
|
|
|
invokeExpressionMethod.Statements.Add(idCondition);
|
|
}
|
|
|
|
invokeExpressionMethod.Statements.Add(new CodeMethodReturnStatement(
|
|
new CodePrimitiveExpression(null)));
|
|
|
|
classDeclaration.Members.Add(invokeExpressionMethod);
|
|
}
|
|
|
|
CodeConditionStatement GenerateDataContextActivitiesCheck(CompiledExpressionDescriptor descriptor)
|
|
{
|
|
CodeBinaryOperatorExpression dataContextActivitiesNullExpression = new CodeBinaryOperatorExpression(
|
|
new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), dataContextActivitiesFieldName),
|
|
CodeBinaryOperatorType.IdentityEquality,
|
|
new CodePrimitiveExpression(null));
|
|
|
|
CodeConditionStatement dataContextActivitiesNullStatement = new CodeConditionStatement(
|
|
dataContextActivitiesNullExpression,
|
|
new CodeAssignStatement(
|
|
new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), dataContextActivitiesFieldName),
|
|
new CodeMethodInvokeExpression(
|
|
new CodeMethodReferenceExpression(
|
|
new CodeTypeReferenceExpression(new CodeTypeReference(descriptor.TypeName)),
|
|
"GetDataContextActivitiesHelper"),
|
|
new CodeFieldReferenceExpression(
|
|
new CodeThisReferenceExpression(),
|
|
rootActivityFieldName),
|
|
new CodeFieldReferenceExpression(
|
|
new CodeThisReferenceExpression(),
|
|
forImplementationName))));
|
|
|
|
return dataContextActivitiesNullStatement;
|
|
}
|
|
|
|
|
|
CodeStatement GenerateInitializeDataContextActivity()
|
|
{
|
|
//
|
|
// if (this.rootActivity == null)
|
|
// {
|
|
// this.rootActivity == this;
|
|
// }
|
|
CodeBinaryOperatorExpression dataContextActivityExpression = new CodeBinaryOperatorExpression(
|
|
new CodeFieldReferenceExpression(
|
|
new CodeThisReferenceExpression(),
|
|
rootActivityFieldName),
|
|
CodeBinaryOperatorType.IdentityEquality,
|
|
new CodePrimitiveExpression(null));
|
|
|
|
CodeConditionStatement dataContextActivityCheck = new CodeConditionStatement(
|
|
dataContextActivityExpression,
|
|
new CodeAssignStatement(
|
|
new CodeFieldReferenceExpression(
|
|
new CodeThisReferenceExpression(),
|
|
rootActivityFieldName),
|
|
new CodeThisReferenceExpression()));
|
|
|
|
return dataContextActivityCheck;
|
|
}
|
|
|
|
void GenerateGetDataContextVariable(CompiledExpressionDescriptor descriptor, CodeVariableDeclarationStatement dataContextVariable, CodeStatementCollection statements, bool withLocationReferences, Dictionary<string, int> cacheIndicies)
|
|
{
|
|
CodeObjectCreateExpression dataContext = GenerateDataContextCreateExpression(descriptor.TypeName, withLocationReferences);
|
|
|
|
if (withLocationReferences)
|
|
{
|
|
//
|
|
// System.Activities.XamlIntegration.CompiledDataContext[] cachedCompiledDataContext = CompiledExpressions_TypedDataContext2.GetCompiledDataContextCacheHelper(this, activityContext, 2);
|
|
// if ((cachedCompiledDataContext[1] == null))
|
|
// {
|
|
// if (!CompiledExpressions_TypedDataContext2.Validate(locations, activityContext))
|
|
// {
|
|
// return false;
|
|
// }
|
|
// cachedCompiledDataContext[1] = new CompiledExpressions_TypedDataContext2(locations, activityContext);
|
|
// }
|
|
//
|
|
CodeVariableDeclarationStatement cachedCompiledDataContextArray = new CodeVariableDeclarationStatement(
|
|
typeof(CompiledDataContext[]),
|
|
"cachedCompiledDataContext",
|
|
new CodeMethodInvokeExpression(
|
|
new CodeMethodReferenceExpression(
|
|
new CodeTypeReferenceExpression(descriptor.TypeName),
|
|
"GetCompiledDataContextCacheHelper"),
|
|
new CodeFieldReferenceExpression(
|
|
new CodeThisReferenceExpression(),
|
|
dataContextActivitiesFieldName),
|
|
new CodeVariableReferenceExpression("activityContext"),
|
|
new CodeFieldReferenceExpression(
|
|
new CodeThisReferenceExpression(),
|
|
rootActivityFieldName),
|
|
new CodeFieldReferenceExpression(
|
|
new CodeThisReferenceExpression(),
|
|
forImplementationName),
|
|
new CodePrimitiveExpression(cacheIndicies.Count)));
|
|
|
|
CodeIndexerExpression compiledDataContextIndexer = new CodeIndexerExpression(
|
|
new CodeVariableReferenceExpression("cachedCompiledDataContext"),
|
|
new CodePrimitiveExpression(cacheIndicies[descriptor.TypeName]));
|
|
|
|
//
|
|
// if (cachedCompiledDataContext[index] == null)
|
|
// {
|
|
// cachedCompiledDataContext[index] = new TCDC(locations, activityContext);
|
|
// }
|
|
//
|
|
|
|
CodeBinaryOperatorExpression nullCacheItemExpression = new CodeBinaryOperatorExpression(
|
|
compiledDataContextIndexer,
|
|
CodeBinaryOperatorType.IdentityEquality,
|
|
new CodePrimitiveExpression(null));
|
|
|
|
CodeAssignStatement cacheIndexInitializer = new CodeAssignStatement(
|
|
compiledDataContextIndexer,
|
|
dataContext);
|
|
|
|
CodeConditionStatement conditionStatement = new CodeConditionStatement(
|
|
nullCacheItemExpression,
|
|
cacheIndexInitializer);
|
|
|
|
//
|
|
// [compiledDataContextVariable] = cachedCompiledDataContext[index]
|
|
//
|
|
|
|
dataContextVariable.InitExpression = new CodeCastExpression(descriptor.TypeName, compiledDataContextIndexer);
|
|
|
|
|
|
statements.Add(cachedCompiledDataContextArray);
|
|
statements.Add(conditionStatement);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// [compiledDataContextVariable] = new [compiledDataContextType](locations);
|
|
//
|
|
|
|
dataContextVariable.InitExpression = dataContext;
|
|
}
|
|
}
|
|
|
|
CodeStatement[] GenerateReferenceExpressionInvocation(CompiledExpressionDescriptor descriptor, bool withLocationReferences, Dictionary<string, int> cacheIndicies)
|
|
{
|
|
string indexString = descriptor.Id.ToString(CultureInfo.InvariantCulture);
|
|
string dataContextVariableName = "refDataContext" + indexString;
|
|
|
|
CodeVariableDeclarationStatement dataContextVariable = new CodeVariableDeclarationStatement(
|
|
new CodeTypeReference(descriptor.TypeName), dataContextVariableName);
|
|
|
|
CodeStatementCollection compiledDataContextStatements = new CodeStatementCollection();
|
|
|
|
GenerateGetDataContextVariable(descriptor, dataContextVariable, compiledDataContextStatements, withLocationReferences, cacheIndicies);
|
|
compiledDataContextStatements.Add(dataContextVariable);
|
|
|
|
CodeExpression getExpression = null;
|
|
CodeExpression setExpression = null;
|
|
|
|
if (this.IsVB)
|
|
{
|
|
getExpression = new CodeDelegateCreateExpression(
|
|
new CodeTypeReference(descriptor.TypeName),
|
|
new CodeVariableReferenceExpression(dataContextVariableName),
|
|
descriptor.GetMethodName);
|
|
setExpression = new CodeDelegateCreateExpression(
|
|
new CodeTypeReference(descriptor.TypeName),
|
|
new CodeVariableReferenceExpression(dataContextVariableName),
|
|
descriptor.SetMethodName);
|
|
}
|
|
else
|
|
{
|
|
getExpression = new CodeMethodReferenceExpression(new CodeVariableReferenceExpression(dataContextVariableName), descriptor.GetMethodName);
|
|
setExpression = new CodeMethodReferenceExpression(new CodeVariableReferenceExpression(dataContextVariableName), descriptor.SetMethodName);
|
|
}
|
|
|
|
CodeMethodReferenceExpression getLocationMethod = new CodeMethodReferenceExpression(
|
|
new CodeVariableReferenceExpression(dataContextVariableName),
|
|
"GetLocation",
|
|
new CodeTypeReference[] { new CodeTypeReference(descriptor.ResultType) });
|
|
|
|
CodeExpression[] getLocationParameters = null;
|
|
if (withLocationReferences)
|
|
{
|
|
getLocationParameters = new CodeExpression[] {
|
|
getExpression,
|
|
setExpression,
|
|
new CodeVariableReferenceExpression("expressionId"),
|
|
new CodeFieldReferenceExpression(
|
|
new CodeThisReferenceExpression(),
|
|
rootActivityFieldName),
|
|
new CodeVariableReferenceExpression("activityContext") };
|
|
}
|
|
else
|
|
{
|
|
getLocationParameters = new CodeExpression[] {
|
|
getExpression,
|
|
setExpression };
|
|
}
|
|
|
|
CodeMethodInvokeExpression getLocationExpression = new CodeMethodInvokeExpression(
|
|
getLocationMethod,
|
|
getLocationParameters);
|
|
|
|
|
|
CodeMethodReturnStatement returnStatement = new CodeMethodReturnStatement(getLocationExpression);
|
|
|
|
compiledDataContextStatements.Add(returnStatement);
|
|
|
|
CodeStatement[] returnStatements = new CodeStatement[compiledDataContextStatements.Count];
|
|
compiledDataContextStatements.CopyTo(returnStatements, 0);
|
|
|
|
return returnStatements;
|
|
}
|
|
|
|
CodeStatement[] GenerateValueExpressionInvocation(CompiledExpressionDescriptor descriptor, bool withLocationReferences, Dictionary<string, int> cacheIndicies)
|
|
{
|
|
CodeStatementCollection compiledDataContextStatements = new CodeStatementCollection();
|
|
|
|
string indexString = descriptor.Id.ToString(CultureInfo.InvariantCulture);
|
|
string dataContextVariableName = "valDataContext" + indexString;
|
|
|
|
CodeVariableDeclarationStatement dataContextVariable = new CodeVariableDeclarationStatement(
|
|
new CodeTypeReference(descriptor.TypeName), dataContextVariableName);
|
|
|
|
GenerateGetDataContextVariable(descriptor, dataContextVariable, compiledDataContextStatements, withLocationReferences, cacheIndicies);
|
|
compiledDataContextStatements.Add(dataContextVariable);
|
|
|
|
CodeMethodInvokeExpression expressionInvoke = new CodeMethodInvokeExpression(
|
|
new CodeMethodReferenceExpression(
|
|
new CodeVariableReferenceExpression(dataContextVariableName), descriptor.GetMethodName));
|
|
|
|
CodeMethodReturnStatement returnStatement = new CodeMethodReturnStatement(expressionInvoke);
|
|
|
|
compiledDataContextStatements.Add(returnStatement);
|
|
|
|
CodeStatement[] returnStatements = new CodeStatement[compiledDataContextStatements.Count];
|
|
compiledDataContextStatements.CopyTo(returnStatements, 0);
|
|
|
|
return returnStatements;
|
|
}
|
|
|
|
CodeStatement[] GenerateStatementInvocation(CompiledExpressionDescriptor descriptor, bool withLocationReferences, Dictionary<string, int> cacheIndicies)
|
|
{
|
|
string indexString = descriptor.Id.ToString(CultureInfo.InvariantCulture);
|
|
string dataContextVariableName = "valDataContext" + indexString;
|
|
|
|
CodeVariableDeclarationStatement dataContextVariable = new CodeVariableDeclarationStatement(
|
|
new CodeTypeReference(descriptor.TypeName), dataContextVariableName);
|
|
|
|
CodeStatementCollection compiledDataContextStatements = new CodeStatementCollection();
|
|
|
|
GenerateGetDataContextVariable(descriptor, dataContextVariable, compiledDataContextStatements, withLocationReferences, cacheIndicies);
|
|
compiledDataContextStatements.Add(dataContextVariable);
|
|
|
|
CodeMethodInvokeExpression expressionInvoke = new CodeMethodInvokeExpression(
|
|
new CodeMethodReferenceExpression(
|
|
new CodeVariableReferenceExpression(dataContextVariableName), descriptor.StatementMethodName));
|
|
|
|
CodeMethodReturnStatement returnStatement = new CodeMethodReturnStatement(new CodePrimitiveExpression(null));
|
|
|
|
compiledDataContextStatements.Add(expressionInvoke);
|
|
compiledDataContextStatements.Add(returnStatement);
|
|
|
|
CodeStatement[] returnStatements = new CodeStatement[compiledDataContextStatements.Count];
|
|
compiledDataContextStatements.CopyTo(returnStatements, 0);
|
|
|
|
return returnStatements;
|
|
}
|
|
|
|
void GenerateCanExecuteMethod()
|
|
{
|
|
CodeMemberMethod isValidMethod = new CodeMemberMethod();
|
|
isValidMethod.Name = "CanExecuteExpression";
|
|
isValidMethod.ReturnType = new CodeTypeReference(typeof(bool));
|
|
isValidMethod.Attributes = MemberAttributes.Public | MemberAttributes.Final;
|
|
isValidMethod.CustomAttributes.Add(GeneratedCodeAttribute);
|
|
isValidMethod.CustomAttributes.Add(BrowsableCodeAttribute);
|
|
isValidMethod.CustomAttributes.Add(EditorBrowsableCodeAttribute);
|
|
isValidMethod.ImplementationTypes.Add(new CodeTypeReference(typeof(ICompiledExpressionRoot)));
|
|
|
|
isValidMethod.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference(typeof(string)), "expressionText"));
|
|
isValidMethod.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference(typeof(bool)), "isReference"));
|
|
isValidMethod.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference(typeof(IList<LocationReference>)), "locations"));
|
|
|
|
CodeParameterDeclarationExpression expressionIdParam = new CodeParameterDeclarationExpression(new CodeTypeReference(typeof(int)), "expressionId");
|
|
expressionIdParam.Direction = FieldDirection.Out;
|
|
isValidMethod.Parameters.Add(expressionIdParam);
|
|
|
|
//
|
|
// if (((isReference == false)
|
|
// && ((expressionText == [expression text])
|
|
// && ([data context type name].Validate(locations, true) == true))))
|
|
// {
|
|
// expressionId = [id for expression text and data context];
|
|
// return true;
|
|
// }
|
|
//
|
|
foreach (CompiledExpressionDescriptor descriptor in expressionDescriptors)
|
|
{
|
|
CodeBinaryOperatorExpression checkIsReferenceExpression = new CodeBinaryOperatorExpression(
|
|
new CodeVariableReferenceExpression("isReference"),
|
|
CodeBinaryOperatorType.ValueEquality,
|
|
new CodePrimitiveExpression(descriptor.IsReference));
|
|
|
|
CodeBinaryOperatorExpression checkTextExpression = new CodeBinaryOperatorExpression(
|
|
new CodeVariableReferenceExpression("expressionText"),
|
|
CodeBinaryOperatorType.ValueEquality,
|
|
new CodePrimitiveExpression(descriptor.ExpressionText));
|
|
|
|
CodeMethodInvokeExpression invokeValidateExpression = new CodeMethodInvokeExpression(
|
|
new CodeMethodReferenceExpression(
|
|
new CodeTypeReferenceExpression(descriptor.TypeName),
|
|
"Validate"),
|
|
new CodeVariableReferenceExpression("locations"),
|
|
new CodePrimitiveExpression(true),
|
|
new CodePrimitiveExpression(0));
|
|
|
|
CodeBinaryOperatorExpression checkValidateExpression = new CodeBinaryOperatorExpression(
|
|
invokeValidateExpression,
|
|
CodeBinaryOperatorType.ValueEquality,
|
|
new CodePrimitiveExpression(true));
|
|
|
|
CodeBinaryOperatorExpression checkTextAndValidateExpression = new CodeBinaryOperatorExpression(
|
|
checkTextExpression,
|
|
CodeBinaryOperatorType.BooleanAnd,
|
|
checkValidateExpression);
|
|
|
|
CodeBinaryOperatorExpression checkIsReferenceAndTextAndValidateExpression = new CodeBinaryOperatorExpression(
|
|
checkIsReferenceExpression,
|
|
CodeBinaryOperatorType.BooleanAnd,
|
|
checkTextAndValidateExpression);
|
|
|
|
CodeAssignStatement assignId = new CodeAssignStatement(
|
|
new CodeVariableReferenceExpression("expressionId"),
|
|
new CodePrimitiveExpression(descriptor.Id));
|
|
|
|
CodeConditionStatement matchCondition = new CodeConditionStatement(
|
|
checkIsReferenceAndTextAndValidateExpression);
|
|
|
|
matchCondition.TrueStatements.Add(assignId);
|
|
matchCondition.TrueStatements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression(true)));
|
|
|
|
isValidMethod.Statements.Add(matchCondition);
|
|
}
|
|
|
|
isValidMethod.Statements.Add(
|
|
new CodeAssignStatement(
|
|
new CodeVariableReferenceExpression("expressionId"),
|
|
new CodePrimitiveExpression(-1)));
|
|
|
|
isValidMethod.Statements.Add(
|
|
new CodeMethodReturnStatement(
|
|
new CodePrimitiveExpression(false)));
|
|
|
|
classDeclaration.Members.Add(isValidMethod);
|
|
}
|
|
|
|
CodeObjectCreateExpression GenerateDataContextCreateExpression(string typeName, bool withLocationReferences)
|
|
{
|
|
if (withLocationReferences)
|
|
{
|
|
return new CodeObjectCreateExpression(
|
|
new CodeTypeReference(typeName),
|
|
new CodeVariableReferenceExpression("locations"),
|
|
new CodeVariableReferenceExpression("activityContext"),
|
|
new CodePrimitiveExpression(true));
|
|
}
|
|
else
|
|
{
|
|
return new CodeObjectCreateExpression(
|
|
new CodeTypeReference(typeName),
|
|
new CodeExpression[] { new CodeVariableReferenceExpression("locations"),
|
|
new CodePrimitiveExpression(true) });
|
|
}
|
|
}
|
|
|
|
bool TryGenerateExpressionCode(Activity activity, CompiledDataContextDescriptor dataContextDescriptor, int nextExpressionId, string language)
|
|
{
|
|
ITextExpression textExpression = (ITextExpression)activity;
|
|
if (!TextExpression.LanguagesAreEqual(textExpression.Language, language)
|
|
|| string.IsNullOrWhiteSpace(textExpression.ExpressionText))
|
|
{
|
|
//
|
|
// We can only compile expressions that match the project's flavor
|
|
// and expression activities with no expressions don't need anything generated.
|
|
return false;
|
|
}
|
|
|
|
Type resultType = (activity is ActivityWithResult) ? ((ActivityWithResult)activity).ResultType : null;
|
|
|
|
string expressionText = textExpression.ExpressionText;
|
|
|
|
bool isReference = false;
|
|
bool isValue = false;
|
|
bool isStatement = false;
|
|
|
|
if (resultType == null)
|
|
{
|
|
isStatement = true;
|
|
}
|
|
else
|
|
{
|
|
isReference = TypeHelper.AreTypesCompatible(resultType, typeof(Location));
|
|
isValue = !isReference;
|
|
}
|
|
|
|
CodeTypeDeclaration typeDeclaration;
|
|
if (isValue)
|
|
{
|
|
typeDeclaration = dataContextDescriptor.CodeTypeDeclarationForReadOnly;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Statement and reference get read/write context
|
|
typeDeclaration = dataContextDescriptor.CodeTypeDeclaration;
|
|
}
|
|
|
|
CompiledExpressionDescriptor descriptor = new CompiledExpressionDescriptor();
|
|
descriptor.TypeName = typeDeclaration.Name;
|
|
descriptor.Id = nextExpressionId;
|
|
descriptor.ExpressionText = textExpression.ExpressionText;
|
|
|
|
if (isReference)
|
|
{
|
|
if (resultType.IsGenericType)
|
|
{
|
|
resultType = resultType.GetGenericArguments()[0];
|
|
}
|
|
else
|
|
{
|
|
resultType = typeof(object);
|
|
}
|
|
}
|
|
|
|
descriptor.ResultType = resultType;
|
|
|
|
GenerateExpressionGetTreeMethod(activity, descriptor, dataContextDescriptor, isValue, isStatement, nextExpressionId);
|
|
|
|
if (isValue || isReference)
|
|
{
|
|
CodeMemberMethod expressionGetMethod = GenerateGetMethod(activity, resultType, expressionText, nextExpressionId);
|
|
typeDeclaration.Members.Add(expressionGetMethod);
|
|
|
|
CodeMemberMethod expressionGetValueTypeAccessorMethod = GenerateGetMethodWrapper(expressionGetMethod);
|
|
typeDeclaration.Members.Add(expressionGetValueTypeAccessorMethod);
|
|
|
|
descriptor.GetMethodName = expressionGetValueTypeAccessorMethod.Name;
|
|
}
|
|
|
|
if (isReference)
|
|
{
|
|
CodeMemberMethod expressionSetMethod = GenerateSetMethod(activity, resultType, expressionText, nextExpressionId);
|
|
dataContextDescriptor.CodeTypeDeclaration.Members.Add(expressionSetMethod);
|
|
|
|
CodeMemberMethod expressionSetValueTypeAccessorMethod = GenerateSetMethodWrapper(expressionSetMethod);
|
|
dataContextDescriptor.CodeTypeDeclaration.Members.Add(expressionSetValueTypeAccessorMethod);
|
|
|
|
descriptor.SetMethodName = expressionSetValueTypeAccessorMethod.Name;
|
|
}
|
|
|
|
if (isStatement)
|
|
{
|
|
CodeMemberMethod statementMethod = GenerateStatementMethod(activity, expressionText, nextExpressionId);
|
|
dataContextDescriptor.CodeTypeDeclaration.Members.Add(statementMethod);
|
|
|
|
CodeMemberMethod expressionSetValueTypeAccessorMethod = GenerateStatementMethodWrapper(statementMethod);
|
|
dataContextDescriptor.CodeTypeDeclaration.Members.Add(expressionSetValueTypeAccessorMethod);
|
|
|
|
descriptor.StatementMethodName = expressionSetValueTypeAccessorMethod.Name;
|
|
}
|
|
|
|
expressionDescriptors.Add(descriptor);
|
|
|
|
return true;
|
|
}
|
|
|
|
void GenerateExpressionGetTreeMethod(Activity activity, CompiledExpressionDescriptor expressionDescriptor, CompiledDataContextDescriptor dataContextDescriptor, bool isValue, bool isStatement, int nextExpressionId)
|
|
{
|
|
CodeMemberMethod expressionMethod = new CodeMemberMethod();
|
|
expressionMethod.Attributes = MemberAttributes.Assembly | MemberAttributes.Final;
|
|
expressionMethod.Name = string.Format(CultureInfo.InvariantCulture, expressionGetTreeString, nextExpressionId);
|
|
expressionMethod.ReturnType = new CodeTypeReference(typeof(Expression));
|
|
expressionDescriptor.GetExpressionTreeMethodName = expressionMethod.Name;
|
|
|
|
if (isStatement)
|
|
{
|
|
// Can't generate expression tree for a statement
|
|
expressionMethod.Statements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression(null)));
|
|
dataContextDescriptor.CodeTypeDeclaration.Members.Add(expressionMethod);
|
|
return;
|
|
}
|
|
|
|
string coreExpressionText = expressionDescriptor.ExpressionText;
|
|
CodeLinePragma pragma;
|
|
AlignText(activity, ref coreExpressionText, out pragma);
|
|
|
|
Type returnType = typeof(Expression<>).MakeGenericType(typeof(Func<>).MakeGenericType(expressionDescriptor.ResultType));
|
|
string expressionText = null;
|
|
if (IsVB)
|
|
{
|
|
expressionText = string.Concat(vbLambdaString, coreExpressionText);
|
|
}
|
|
else if (IsCS)
|
|
{
|
|
expressionText = string.Concat(csharpLambdaString, coreExpressionText);
|
|
}
|
|
|
|
if (expressionText != null)
|
|
{
|
|
CodeVariableDeclarationStatement statement = new CodeVariableDeclarationStatement(returnType, "expression", new CodeSnippetExpression(expressionText));
|
|
statement.LinePragma = pragma;
|
|
expressionMethod.Statements.Add(statement);
|
|
|
|
CodeMethodInvokeExpression invokeExpression = new CodeMethodInvokeExpression(
|
|
new CodeBaseReferenceExpression(),
|
|
"RewriteExpressionTree",
|
|
new CodeExpression[] { new CodeVariableReferenceExpression("expression") });
|
|
|
|
expressionMethod.Statements.Add(new CodeMethodReturnStatement(invokeExpression));
|
|
}
|
|
else
|
|
{
|
|
expressionMethod.Statements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression(null)));
|
|
}
|
|
|
|
if (isValue)
|
|
{
|
|
dataContextDescriptor.CodeTypeDeclarationForReadOnly.Members.Add(expressionMethod);
|
|
}
|
|
else
|
|
{
|
|
dataContextDescriptor.CodeTypeDeclaration.Members.Add(expressionMethod);
|
|
}
|
|
}
|
|
|
|
CodeMemberMethod GenerateGetMethod(Activity activity, Type resultType, string expressionText, int nextExpressionId)
|
|
{
|
|
CodeMemberMethod expressionMethod = new CodeMemberMethod();
|
|
expressionMethod.Attributes = MemberAttributes.Public | MemberAttributes.Final;
|
|
expressionMethod.Name = string.Format(CultureInfo.InvariantCulture, expressionGetString, nextExpressionId);
|
|
expressionMethod.ReturnType = new CodeTypeReference(resultType);
|
|
expressionMethod.CustomAttributes.Add(new CodeAttributeDeclaration(new CodeTypeReference(typeof(DebuggerHiddenAttribute))));
|
|
|
|
CodeLinePragma pragma;
|
|
AlignText(activity, ref expressionText, out pragma);
|
|
CodeStatement statement = new CodeMethodReturnStatement(new CodeSnippetExpression(expressionText));
|
|
statement.LinePragma = pragma;
|
|
expressionMethod.Statements.Add(statement);
|
|
|
|
return expressionMethod;
|
|
}
|
|
|
|
CodeMemberMethod GenerateGetMethodWrapper(CodeMemberMethod expressionMethod)
|
|
{
|
|
CodeMemberMethod wrapperMethod = new CodeMemberMethod();
|
|
wrapperMethod.Attributes = MemberAttributes.Public | MemberAttributes.Final;
|
|
wrapperMethod.Name = valueTypeAccessorString + expressionMethod.Name;
|
|
wrapperMethod.ReturnType = expressionMethod.ReturnType;
|
|
|
|
wrapperMethod.Statements.Add(new CodeMethodInvokeExpression(
|
|
new CodeMethodReferenceExpression(
|
|
new CodeThisReferenceExpression(),
|
|
getValueTypeValuesString)));
|
|
|
|
wrapperMethod.Statements.Add(new CodeMethodReturnStatement(
|
|
new CodeMethodInvokeExpression(
|
|
new CodeMethodReferenceExpression(
|
|
new CodeThisReferenceExpression(),
|
|
expressionMethod.Name))));
|
|
|
|
return wrapperMethod;
|
|
}
|
|
|
|
CodeMemberMethod GenerateSetMethod(Activity activity, Type resultType, string expressionText, int nextExpressionId)
|
|
{
|
|
string paramName = "value";
|
|
|
|
if (string.Compare(expressionText, paramName, true, Globalization.CultureInfo.CurrentCulture) == 0)
|
|
{
|
|
paramName += "1";
|
|
}
|
|
|
|
CodeMemberMethod expressionMethod = new CodeMemberMethod();
|
|
expressionMethod.Attributes = MemberAttributes.Public | MemberAttributes.Final;
|
|
expressionMethod.Name = string.Format(CultureInfo.InvariantCulture, expressionSetString, nextExpressionId);
|
|
expressionMethod.CustomAttributes.Add(new CodeAttributeDeclaration(new CodeTypeReference(typeof(DebuggerHiddenAttribute))));
|
|
|
|
var exprValueParam = new CodeParameterDeclarationExpression(resultType, paramName);
|
|
expressionMethod.Parameters.Add(exprValueParam);
|
|
|
|
CodeLinePragma pragma;
|
|
AlignText(activity, ref expressionText, out pragma);
|
|
CodeAssignStatement statement = new CodeAssignStatement(new CodeSnippetExpression(expressionText), new CodeArgumentReferenceExpression(paramName));
|
|
statement.LinePragma = pragma;
|
|
expressionMethod.Statements.Add(statement);
|
|
|
|
return expressionMethod;
|
|
}
|
|
|
|
CodeMemberMethod GenerateSetMethodWrapper(CodeMemberMethod expressionMethod)
|
|
{
|
|
CodeMemberMethod wrapperMethod = new CodeMemberMethod();
|
|
wrapperMethod.Attributes = MemberAttributes.Public | MemberAttributes.Final;
|
|
wrapperMethod.Name = valueTypeAccessorString + expressionMethod.Name;
|
|
|
|
CodeParameterDeclarationExpression exprValueParam = new CodeParameterDeclarationExpression(expressionMethod.Parameters[0].Type, expressionMethod.Parameters[0].Name);
|
|
wrapperMethod.Parameters.Add(exprValueParam);
|
|
|
|
wrapperMethod.Statements.Add(new CodeMethodInvokeExpression(
|
|
new CodeMethodReferenceExpression(
|
|
new CodeThisReferenceExpression(),
|
|
getValueTypeValuesString)));
|
|
|
|
CodeMethodInvokeExpression setExpression = new CodeMethodInvokeExpression(
|
|
new CodeMethodReferenceExpression(
|
|
new CodeThisReferenceExpression(),
|
|
expressionMethod.Name));
|
|
|
|
setExpression.Parameters.Add(new CodeVariableReferenceExpression(expressionMethod.Parameters[0].Name));
|
|
|
|
wrapperMethod.Statements.Add(setExpression);
|
|
|
|
wrapperMethod.Statements.Add(new CodeMethodInvokeExpression(
|
|
new CodeMethodReferenceExpression(
|
|
new CodeThisReferenceExpression(),
|
|
setValueTypeValuesString)));
|
|
|
|
return wrapperMethod;
|
|
}
|
|
|
|
CodeMemberMethod GenerateStatementMethod(Activity activity, string expressionText, int nextExpressionId)
|
|
{
|
|
CodeMemberMethod expressionMethod = new CodeMemberMethod();
|
|
expressionMethod.Attributes = MemberAttributes.Public | MemberAttributes.Final;
|
|
expressionMethod.Name = string.Format(CultureInfo.InvariantCulture, expressionStatementString, nextExpressionId);
|
|
expressionMethod.CustomAttributes.Add(new CodeAttributeDeclaration(new CodeTypeReference(typeof(DebuggerHiddenAttribute))));
|
|
|
|
CodeLinePragma pragma;
|
|
AlignText(activity, ref expressionText, out pragma);
|
|
CodeStatement statement = new CodeSnippetStatement(expressionText);
|
|
statement.LinePragma = pragma;
|
|
expressionMethod.Statements.Add(statement);
|
|
|
|
return expressionMethod;
|
|
}
|
|
|
|
CodeMemberMethod GenerateStatementMethodWrapper(CodeMemberMethod expressionMethod)
|
|
{
|
|
CodeMemberMethod wrapperMethod = new CodeMemberMethod();
|
|
wrapperMethod.Attributes = MemberAttributes.Public | MemberAttributes.Final;
|
|
wrapperMethod.Name = valueTypeAccessorString + expressionMethod.Name;
|
|
|
|
wrapperMethod.Statements.Add(new CodeMethodInvokeExpression(
|
|
new CodeMethodReferenceExpression(
|
|
new CodeThisReferenceExpression(),
|
|
getValueTypeValuesString)));
|
|
|
|
CodeMethodInvokeExpression setExpression = new CodeMethodInvokeExpression(
|
|
new CodeMethodReferenceExpression(
|
|
new CodeThisReferenceExpression(),
|
|
expressionMethod.Name));
|
|
|
|
wrapperMethod.Statements.Add(setExpression);
|
|
|
|
wrapperMethod.Statements.Add(new CodeMethodInvokeExpression(
|
|
new CodeMethodReferenceExpression(
|
|
new CodeThisReferenceExpression(),
|
|
setValueTypeValuesString)));
|
|
|
|
return wrapperMethod;
|
|
}
|
|
|
|
CodeMemberMethod GenerateGetValueTypeValues(CompiledDataContextDescriptor descriptor)
|
|
{
|
|
CodeMemberMethod fetchMethod = new CodeMemberMethod();
|
|
fetchMethod.Name = getValueTypeValuesString;
|
|
fetchMethod.Attributes = MemberAttributes.Override | MemberAttributes.Family;
|
|
|
|
foreach (KeyValuePair<string, MemberData> valueField in descriptor.Fields)
|
|
{
|
|
if (descriptor.Duplicates.Contains(valueField.Key))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
CodeExpression getValue = new CodeCastExpression(
|
|
valueField.Value.Type,
|
|
new CodeMethodInvokeExpression(
|
|
new CodeMethodReferenceExpression(
|
|
new CodeThisReferenceExpression(),
|
|
"GetVariableValue"),
|
|
new CodeBinaryOperatorExpression(
|
|
new CodePrimitiveExpression(valueField.Value.Index),
|
|
CodeBinaryOperatorType.Add,
|
|
new CodeVariableReferenceExpression("locationsOffset"))));
|
|
|
|
CodeFieldReferenceExpression fieldReference = new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), valueField.Key);
|
|
|
|
fetchMethod.Statements.Add(
|
|
new CodeAssignStatement(fieldReference, getValue));
|
|
}
|
|
|
|
fetchMethod.Statements.Add(new CodeMethodInvokeExpression(
|
|
new CodeMethodReferenceExpression(
|
|
new CodeBaseReferenceExpression(),
|
|
fetchMethod.Name)));
|
|
|
|
return fetchMethod;
|
|
}
|
|
|
|
CodeMemberMethod GenerateSetValueTypeValues(CompiledDataContextDescriptor descriptor)
|
|
{
|
|
CodeMemberMethod pushMethod = new CodeMemberMethod();
|
|
pushMethod.Name = setValueTypeValuesString;
|
|
pushMethod.Attributes = MemberAttributes.Override | MemberAttributes.Family;
|
|
|
|
foreach (KeyValuePair<string, MemberData> valueField in descriptor.Fields)
|
|
{
|
|
if (descriptor.Duplicates.Contains(valueField.Key))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
CodeMethodInvokeExpression setValue = new CodeMethodInvokeExpression(
|
|
new CodeMethodReferenceExpression(
|
|
new CodeThisReferenceExpression(),
|
|
"SetVariableValue"),
|
|
new CodeBinaryOperatorExpression(
|
|
new CodePrimitiveExpression(valueField.Value.Index),
|
|
CodeBinaryOperatorType.Add,
|
|
new CodeVariableReferenceExpression("locationsOffset")),
|
|
new CodeFieldReferenceExpression(
|
|
new CodeThisReferenceExpression(), valueField.Key));
|
|
|
|
pushMethod.Statements.Add(setValue);
|
|
}
|
|
|
|
pushMethod.Statements.Add(new CodeMethodInvokeExpression(
|
|
new CodeMethodReferenceExpression(
|
|
new CodeBaseReferenceExpression(),
|
|
pushMethod.Name)));
|
|
|
|
return pushMethod;
|
|
}
|
|
|
|
CodeTypeDeclaration GenerateCompiledDataContext(bool forReadOnly)
|
|
{
|
|
string forReadOnlyString = forReadOnly ? TextExpressionCompiler.forReadOnly : string.Empty;
|
|
string contextName = string.Concat(this.settings.ActivityName, TextExpressionCompiler.typedDataContextName, this.nextContextId, forReadOnlyString);
|
|
|
|
CodeTypeDeclaration typedDataContext = new CodeTypeDeclaration(contextName);
|
|
typedDataContext.TypeAttributes = TypeAttributes.NestedPrivate;
|
|
//
|
|
// data context classes are declared inside of the main class via the partial class to reduce visibility/surface area.
|
|
this.classDeclaration.Members.Add(typedDataContext);
|
|
|
|
if (this.compiledDataContexts != null && this.compiledDataContexts.Count > 0)
|
|
{
|
|
string baseTypeName = null;
|
|
if (forReadOnly)
|
|
{
|
|
baseTypeName = this.compiledDataContexts.Peek().CodeTypeDeclarationForReadOnly.Name;
|
|
}
|
|
else
|
|
{
|
|
baseTypeName = this.compiledDataContexts.Peek().CodeTypeDeclaration.Name;
|
|
}
|
|
typedDataContext.BaseTypes.Add(baseTypeName);
|
|
}
|
|
else
|
|
{
|
|
typedDataContext.BaseTypes.Add(typeof(CompiledDataContext));
|
|
//
|
|
// We only generate the helper method on the root data context/context 0
|
|
// No need to have it on all contexts. This is just a slight of hand
|
|
// so that we don't need to make GetDataContextActivities public on CompiledDataContext.
|
|
typedDataContext.Members.Add(GenerateDataContextActivitiesHelper());
|
|
}
|
|
|
|
CodeMemberField offsetField = new CodeMemberField();
|
|
offsetField.Attributes = MemberAttributes.Private;
|
|
offsetField.Name = locationsOffsetFieldName;
|
|
offsetField.Type = new CodeTypeReference(typeof(int));
|
|
|
|
typedDataContext.Members.Add(offsetField);
|
|
|
|
CodeMemberField expectedLocationsCountField = new CodeMemberField();
|
|
expectedLocationsCountField.Attributes = MemberAttributes.Private | MemberAttributes.Static;
|
|
expectedLocationsCountField.Name = expectedLocationsCountFieldName;
|
|
expectedLocationsCountField.Type = new CodeTypeReference(typeof(int));
|
|
|
|
typedDataContext.Members.Add(expectedLocationsCountField);
|
|
|
|
typedDataContext.Members.Add(GenerateLocationReferenceActivityContextConstructor());
|
|
typedDataContext.Members.Add(GenerateLocationConstructor());
|
|
typedDataContext.Members.Add(GenerateLocationReferenceConstructor());
|
|
typedDataContext.Members.Add(GenerateCacheHelper());
|
|
typedDataContext.Members.Add(GenerateSetLocationsOffsetMethod());
|
|
|
|
//
|
|
// Mark this type as tool generated code
|
|
typedDataContext.CustomAttributes.Add(GeneratedCodeAttribute);
|
|
//
|
|
// Mark it as Browsable(false)
|
|
// Note that this does not prevent intellisense within a single project, just at the metadata level
|
|
typedDataContext.CustomAttributes.Add(BrowsableCodeAttribute);
|
|
//
|
|
// Mark it as EditorBrowsable(EditorBrowsableState.Never)
|
|
// Note that this does not prevent intellisense within a single project, just at the metadata level
|
|
typedDataContext.CustomAttributes.Add(EditorBrowsableCodeAttribute);
|
|
|
|
return typedDataContext;
|
|
}
|
|
|
|
CodeMemberMethod GenerateDataContextActivitiesHelper()
|
|
{
|
|
CodeMemberMethod dataContextActivitiesHelper = new CodeMemberMethod();
|
|
|
|
dataContextActivitiesHelper.Name = "GetDataContextActivitiesHelper";
|
|
|
|
dataContextActivitiesHelper.Attributes = MemberAttributes.Assembly | MemberAttributes.Final | MemberAttributes.Static;
|
|
|
|
if (this.compiledDataContexts != null && this.compiledDataContexts.Count > 0)
|
|
{
|
|
dataContextActivitiesHelper.Attributes |= MemberAttributes.New;
|
|
}
|
|
|
|
dataContextActivitiesHelper.ReturnType = new CodeTypeReference(typeof(object));
|
|
|
|
dataContextActivitiesHelper.Parameters.Add(
|
|
new CodeParameterDeclarationExpression(
|
|
new CodeTypeReference(typeof(Activity)),
|
|
"compiledRoot"));
|
|
|
|
dataContextActivitiesHelper.Parameters.Add(
|
|
new CodeParameterDeclarationExpression(
|
|
new CodeTypeReference(typeof(bool)),
|
|
forImplementationName));
|
|
|
|
dataContextActivitiesHelper.Statements.Add(
|
|
new CodeMethodReturnStatement(
|
|
new CodeMethodInvokeExpression(
|
|
new CodeMethodReferenceExpression(
|
|
new CodeTypeReferenceExpression(typeof(CompiledDataContext)),
|
|
"GetDataContextActivities"),
|
|
new CodeVariableReferenceExpression("compiledRoot"),
|
|
new CodeVariableReferenceExpression(forImplementationName))));
|
|
|
|
return dataContextActivitiesHelper;
|
|
}
|
|
|
|
CodeMemberMethod GenerateSetLocationsOffsetMethod()
|
|
{
|
|
CodeMemberMethod setLocationsOffsetMethod = new CodeMemberMethod();
|
|
setLocationsOffsetMethod.Name = "SetLocationsOffset";
|
|
setLocationsOffsetMethod.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference(typeof(int)),
|
|
"locationsOffsetValue"));
|
|
setLocationsOffsetMethod.Attributes = MemberAttributes.Public;
|
|
if (this.compiledDataContexts.Count > 0)
|
|
{
|
|
setLocationsOffsetMethod.Attributes |= MemberAttributes.New;
|
|
}
|
|
|
|
CodeAssignStatement assignLocationsOffsetStatement = new CodeAssignStatement(
|
|
new CodeVariableReferenceExpression("locationsOffset"),
|
|
new CodeVariableReferenceExpression("locationsOffsetValue"));
|
|
setLocationsOffsetMethod.Statements.Add(assignLocationsOffsetStatement);
|
|
|
|
if (this.nextContextId > 0)
|
|
{
|
|
CodeMethodInvokeExpression baseSetLocationsOffsetMethod = new CodeMethodInvokeExpression(
|
|
new CodeBaseReferenceExpression(), "SetLocationsOffset", new CodeVariableReferenceExpression("locationsOffset"));
|
|
setLocationsOffsetMethod.Statements.Add(baseSetLocationsOffsetMethod);
|
|
}
|
|
|
|
return setLocationsOffsetMethod;
|
|
}
|
|
|
|
CodeMemberMethod GenerateCacheHelper()
|
|
{
|
|
CodeMemberMethod cacheHelper = new CodeMemberMethod();
|
|
cacheHelper.Name = "GetCompiledDataContextCacheHelper";
|
|
cacheHelper.Attributes = MemberAttributes.Assembly | MemberAttributes.Final | MemberAttributes.Static;
|
|
|
|
if (this.compiledDataContexts != null && this.compiledDataContexts.Count > 0)
|
|
{
|
|
cacheHelper.Attributes |= MemberAttributes.New;
|
|
}
|
|
|
|
cacheHelper.Parameters.Add(new CodeParameterDeclarationExpression(typeof(object), dataContextActivitiesFieldName));
|
|
cacheHelper.Parameters.Add(new CodeParameterDeclarationExpression(typeof(ActivityContext), "activityContext"));
|
|
cacheHelper.Parameters.Add(new CodeParameterDeclarationExpression(typeof(Activity), "compiledRoot"));
|
|
cacheHelper.Parameters.Add(new CodeParameterDeclarationExpression(typeof(bool), forImplementationName));
|
|
cacheHelper.Parameters.Add(new CodeParameterDeclarationExpression(typeof(int), "compiledDataContextCount"));
|
|
|
|
cacheHelper.ReturnType = new CodeTypeReference(typeof(CompiledDataContext[]));
|
|
|
|
cacheHelper.Statements.Add(
|
|
new CodeMethodReturnStatement(
|
|
new CodeMethodInvokeExpression(
|
|
new CodeMethodReferenceExpression(
|
|
new CodeTypeReferenceExpression(typeof(CompiledDataContext)),
|
|
"GetCompiledDataContextCache"),
|
|
new CodeVariableReferenceExpression(dataContextActivitiesFieldName),
|
|
new CodeVariableReferenceExpression("activityContext"),
|
|
new CodeVariableReferenceExpression("compiledRoot"),
|
|
new CodeVariableReferenceExpression(forImplementationName),
|
|
new CodeVariableReferenceExpression("compiledDataContextCount"))));
|
|
|
|
return cacheHelper;
|
|
}
|
|
|
|
CodeConstructor GenerateLocationReferenceActivityContextConstructor()
|
|
{
|
|
//
|
|
// public [typename](IList<LocationReference> locations, ActivityContext activityContext)
|
|
// : base(locations, activityContext)
|
|
//
|
|
CodeConstructor constructor = new CodeConstructor();
|
|
constructor.Attributes = MemberAttributes.Public;
|
|
|
|
CodeParameterDeclarationExpression constructorLocationsParam =
|
|
new CodeParameterDeclarationExpression(typeof(IList<LocationReference>), "locations");
|
|
constructor.Parameters.Add(constructorLocationsParam);
|
|
|
|
constructor.BaseConstructorArgs.Add(new CodeArgumentReferenceExpression("locations"));
|
|
|
|
CodeParameterDeclarationExpression constructorActivityContextParam =
|
|
new CodeParameterDeclarationExpression(typeof(ActivityContext), "activityContext");
|
|
constructor.Parameters.Add(constructorActivityContextParam);
|
|
|
|
constructor.BaseConstructorArgs.Add(new CodeArgumentReferenceExpression("activityContext"));
|
|
|
|
CodeParameterDeclarationExpression computelocationsOffsetParam =
|
|
new CodeParameterDeclarationExpression(typeof(bool), "computelocationsOffset");
|
|
constructor.Parameters.Add(computelocationsOffsetParam);
|
|
|
|
if (this.nextContextId > 0)
|
|
{
|
|
constructor.BaseConstructorArgs.Add(new CodePrimitiveExpression(false));
|
|
}
|
|
|
|
InvokeSetLocationsOffsetMethod(constructor);
|
|
|
|
return constructor;
|
|
}
|
|
|
|
CodeConstructor GenerateLocationConstructor()
|
|
{
|
|
//
|
|
// public [typename](IList<Location> locations, ActivityContext activityContext)
|
|
// : base(locations)
|
|
//
|
|
CodeConstructor constructor = new CodeConstructor();
|
|
constructor.Attributes = MemberAttributes.Public;
|
|
|
|
CodeParameterDeclarationExpression constructorLocationsParam =
|
|
new CodeParameterDeclarationExpression(typeof(IList<Location>), "locations");
|
|
constructor.Parameters.Add(constructorLocationsParam);
|
|
|
|
constructor.BaseConstructorArgs.Add(new CodeArgumentReferenceExpression("locations"));
|
|
|
|
CodeParameterDeclarationExpression computelocationsOffsetParam =
|
|
new CodeParameterDeclarationExpression(typeof(bool), "computelocationsOffset");
|
|
constructor.Parameters.Add(computelocationsOffsetParam);
|
|
|
|
if (this.nextContextId > 0)
|
|
{
|
|
constructor.BaseConstructorArgs.Add(new CodePrimitiveExpression(false));
|
|
}
|
|
|
|
InvokeSetLocationsOffsetMethod(constructor);
|
|
|
|
return constructor;
|
|
}
|
|
|
|
CodeConstructor GenerateLocationReferenceConstructor()
|
|
{
|
|
//
|
|
// public [typename](IList<LocationReference> locationReferences)
|
|
// : base(locationReferences)
|
|
//
|
|
CodeConstructor constructor = new CodeConstructor();
|
|
constructor.Attributes = MemberAttributes.Public;
|
|
|
|
CodeParameterDeclarationExpression constructorLocationsParam = new CodeParameterDeclarationExpression(typeof(IList<LocationReference>), "locationReferences");
|
|
constructor.Parameters.Add(constructorLocationsParam);
|
|
|
|
constructor.BaseConstructorArgs.Add(new CodeArgumentReferenceExpression("locationReferences"));
|
|
|
|
return constructor;
|
|
}
|
|
|
|
void InvokeSetLocationsOffsetMethod(CodeConstructor constructor)
|
|
{
|
|
CodeExpressionStatement setLocationsOffsetMethod = new CodeExpressionStatement(
|
|
new CodeMethodInvokeExpression(
|
|
new CodeThisReferenceExpression(),
|
|
"SetLocationsOffset",
|
|
new CodeBinaryOperatorExpression(
|
|
new CodePropertyReferenceExpression(new CodeVariableReferenceExpression("locations"), "Count"),
|
|
CodeBinaryOperatorType.Subtract,
|
|
new CodeVariableReferenceExpression("expectedLocationsCount"))));
|
|
|
|
CodeConditionStatement offsetCheckStatement = new CodeConditionStatement(new CodeBinaryOperatorExpression(
|
|
new CodeVariableReferenceExpression("computelocationsOffset"),
|
|
CodeBinaryOperatorType.ValueEquality,
|
|
new CodePrimitiveExpression(true)),
|
|
new CodeStatement[] { setLocationsOffsetMethod });
|
|
|
|
constructor.Statements.Add(offsetCheckStatement);
|
|
}
|
|
|
|
CodeNamespace GenerateCodeNamespace()
|
|
{
|
|
CodeNamespace codeNamespace = new CodeNamespace(this.settings.ActivityNamespace);
|
|
|
|
bool seenXamlIntegration = false;
|
|
foreach (string nsReference in GetNamespaceReferences())
|
|
{
|
|
if (!seenXamlIntegration && nsReference == xamlIntegrationNamespace)
|
|
{
|
|
seenXamlIntegration = true;
|
|
}
|
|
codeNamespace.Imports.Add(new CodeNamespaceImport(nsReference)
|
|
{
|
|
LinePragma = GenerateLinePragmaForNamespace(nsReference),
|
|
});
|
|
}
|
|
|
|
if (!seenXamlIntegration)
|
|
{
|
|
codeNamespace.Imports.Add(new CodeNamespaceImport(xamlIntegrationNamespace)
|
|
{
|
|
LinePragma = GenerateLinePragmaForNamespace(xamlIntegrationNamespace),
|
|
});
|
|
}
|
|
|
|
return codeNamespace;
|
|
}
|
|
|
|
bool AssemblyContainsTypeWithActivityNamespace()
|
|
{
|
|
// We need to include the ActivityNamespace in the imports if there are any types in
|
|
// the Activity's assembly that are contained in that namespace.
|
|
Type[] types;
|
|
try
|
|
{
|
|
types = this.settings.Activity.GetType().Assembly.GetTypes();
|
|
}
|
|
catch (ReflectionTypeLoadException)
|
|
{
|
|
// We had a problem loading all the types. Take the safe route and assume we need to include the ActivityNamespace.
|
|
return true;
|
|
}
|
|
|
|
if (types != null)
|
|
{
|
|
foreach (Type type in types)
|
|
{
|
|
if (type.Namespace == this.settings.ActivityNamespace)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
IEnumerable<string> GetNamespaceReferences()
|
|
{
|
|
HashSet<string> nsReferences = new HashSet<string>();
|
|
// Add some namespace imports, use the same base set for C# as for VB, they aren't lang specific
|
|
foreach (string nsReference in TextExpression.DefaultNamespaces)
|
|
{
|
|
nsReferences.Add(nsReference);
|
|
}
|
|
|
|
|
|
VisualBasicSettings vbSettings = null;
|
|
if (IsVB)
|
|
{
|
|
vbSettings = VisualBasic.GetSettings(this.settings.Activity);
|
|
}
|
|
if (vbSettings != null)
|
|
{
|
|
foreach (VisualBasicImportReference nsReference in vbSettings.ImportReferences)
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(nsReference.Import))
|
|
{
|
|
// For VB, the ActivityNamespace has the RootNamespace stripped off. We don't need an Imports reference
|
|
// to ActivityNamespace, if this reference is in the same assembly and there is a RootNamespace specified.
|
|
// We check both Assembly.FullName and
|
|
// Assembly.GetName().Name because testing has shown that nsReference.Assembly sometimes gives fully qualified
|
|
// names and sometimes not.
|
|
if (
|
|
(nsReference.Import == this.settings.ActivityNamespace)
|
|
&&
|
|
((nsReference.Assembly == this.settings.Activity.GetType().Assembly.FullName) ||
|
|
(nsReference.Assembly == this.settings.Activity.GetType().Assembly.GetName().Name))
|
|
&&
|
|
!string.IsNullOrWhiteSpace(this.settings.RootNamespace)
|
|
&&
|
|
!AssemblyContainsTypeWithActivityNamespace()
|
|
)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
nsReferences.Add(nsReference.Import);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
IList<string> references = this.settings.ForImplementation ?
|
|
TextExpression.GetNamespacesForImplementation(this.settings.Activity) :
|
|
TextExpression.GetNamespaces(this.settings.Activity);
|
|
|
|
foreach (string nsReference in references)
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(nsReference))
|
|
{
|
|
nsReferences.Add(nsReference);
|
|
}
|
|
}
|
|
}
|
|
|
|
return nsReferences;
|
|
}
|
|
|
|
CompiledDataContextDescriptor PushDataContextDescriptor()
|
|
{
|
|
CompiledDataContextDescriptor contextDescriptor = new CompiledDataContextDescriptor(() => this.IsVB)
|
|
{
|
|
CodeTypeDeclaration = GenerateCompiledDataContext(false),
|
|
CodeTypeDeclarationForReadOnly = GenerateCompiledDataContext(true),
|
|
NextMemberIndex = GetStartMemberIndex()
|
|
};
|
|
this.compiledDataContexts.Push(contextDescriptor);
|
|
this.nextContextId++;
|
|
|
|
return contextDescriptor;
|
|
}
|
|
|
|
void PopDataContextDescriptor()
|
|
{
|
|
CompiledDataContextDescriptor descriptor = this.compiledDataContexts.Pop();
|
|
if (descriptor != null)
|
|
{
|
|
GenerateMembers(descriptor);
|
|
GenerateValidate(descriptor, true);
|
|
GenerateValidate(descriptor, false);
|
|
}
|
|
}
|
|
|
|
int GetStartMemberIndex()
|
|
{
|
|
if (this.compiledDataContexts == null || this.compiledDataContexts.Count == 0)
|
|
{
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
return this.compiledDataContexts.Peek().NextMemberIndex;
|
|
}
|
|
}
|
|
|
|
void GenerateValidate(CompiledDataContextDescriptor descriptor, bool forReadOnly)
|
|
{
|
|
//
|
|
//
|
|
// Validate the locations at runtime match the set at compile time
|
|
//
|
|
// protected override bool Validate(IList<LocationReference> locationReferences)
|
|
// {
|
|
// if (validateLocationCount && locationReferences.Count != [generated count of location references])
|
|
// {
|
|
// return false;
|
|
// }
|
|
// if (locationReferences[0].Name != [generated name for index] ||
|
|
// locationReferences[0].Type != typeof([generated type for index]))
|
|
// {
|
|
// return false;
|
|
// }
|
|
//
|
|
// ...
|
|
//
|
|
// }
|
|
CodeMemberMethod validateMethod = new CodeMemberMethod();
|
|
validateMethod.Name = "Validate";
|
|
validateMethod.Attributes = MemberAttributes.Public | MemberAttributes.Static;
|
|
|
|
if (this.compiledDataContexts.Count > 0)
|
|
{
|
|
validateMethod.Attributes |= MemberAttributes.New;
|
|
}
|
|
|
|
|
|
validateMethod.ReturnType = new CodeTypeReference(typeof(bool));
|
|
|
|
validateMethod.Parameters.Add(
|
|
new CodeParameterDeclarationExpression(
|
|
new CodeTypeReference(typeof(IList<LocationReference>)),
|
|
"locationReferences"));
|
|
|
|
validateMethod.Parameters.Add(
|
|
new CodeParameterDeclarationExpression(
|
|
new CodeTypeReference(typeof(bool)),
|
|
"validateLocationCount"));
|
|
|
|
validateMethod.Parameters.Add(
|
|
new CodeParameterDeclarationExpression(
|
|
new CodeTypeReference(typeof(int)),
|
|
"offset") );
|
|
|
|
CodeBinaryOperatorExpression shouldCheckLocationCountExpression = new CodeBinaryOperatorExpression(
|
|
new CodeVariableReferenceExpression("validateLocationCount"),
|
|
CodeBinaryOperatorType.ValueEquality,
|
|
new CodePrimitiveExpression(true));
|
|
|
|
CodeBinaryOperatorExpression compareLocationCountExpression = new CodeBinaryOperatorExpression(
|
|
new CodePropertyReferenceExpression(
|
|
new CodeVariableReferenceExpression("locationReferences"),
|
|
"Count"),
|
|
CodeBinaryOperatorType.LessThan,
|
|
new CodePrimitiveExpression(descriptor.NextMemberIndex)
|
|
);
|
|
|
|
CodeBinaryOperatorExpression checkLocationCountExpression = new CodeBinaryOperatorExpression(
|
|
shouldCheckLocationCountExpression,
|
|
CodeBinaryOperatorType.BooleanAnd,
|
|
compareLocationCountExpression);
|
|
|
|
CodeConditionStatement checkLocationCountStatement = new CodeConditionStatement(
|
|
checkLocationCountExpression,
|
|
new CodeMethodReturnStatement(
|
|
new CodePrimitiveExpression(false)));
|
|
|
|
validateMethod.Statements.Add(checkLocationCountStatement);
|
|
|
|
if (descriptor.NextMemberIndex > 0)
|
|
{
|
|
CodeConditionStatement generateNewOffset = new CodeConditionStatement(shouldCheckLocationCountExpression,
|
|
new CodeStatement[]
|
|
{
|
|
new CodeAssignStatement(new CodeVariableReferenceExpression("offset"),
|
|
new CodeBinaryOperatorExpression(
|
|
new CodePropertyReferenceExpression(new CodeVariableReferenceExpression("locationReferences"), "Count"),
|
|
CodeBinaryOperatorType.Subtract,
|
|
new CodePrimitiveExpression(descriptor.NextMemberIndex)))
|
|
});
|
|
validateMethod.Statements.Add(generateNewOffset);
|
|
}
|
|
|
|
CodeAssignStatement setexpectedLocationsCountStatement = new CodeAssignStatement(
|
|
new CodeVariableReferenceExpression("expectedLocationsCount"),
|
|
new CodePrimitiveExpression(descriptor.NextMemberIndex));
|
|
|
|
validateMethod.Statements.Add(setexpectedLocationsCountStatement);
|
|
|
|
foreach (KeyValuePair<string, MemberData> kvp in descriptor.Properties)
|
|
{
|
|
validateMethod.Statements.Add(GenerateLocationReferenceCheck(kvp.Value));
|
|
}
|
|
|
|
foreach (KeyValuePair<string, MemberData> kvp in descriptor.Fields)
|
|
{
|
|
validateMethod.Statements.Add(GenerateLocationReferenceCheck(kvp.Value));
|
|
}
|
|
|
|
if (this.compiledDataContexts.Count >= 1)
|
|
{
|
|
CompiledDataContextDescriptor baseDescriptor = this.compiledDataContexts.Peek();
|
|
CodeTypeDeclaration baseType = forReadOnly ? baseDescriptor.CodeTypeDeclarationForReadOnly : baseDescriptor.CodeTypeDeclaration;
|
|
|
|
CodeMethodInvokeExpression invokeBase = new CodeMethodInvokeExpression(
|
|
new CodeMethodReferenceExpression(
|
|
new CodeTypeReferenceExpression(baseType.Name),
|
|
"Validate"),
|
|
new CodeVariableReferenceExpression("locationReferences"),
|
|
new CodePrimitiveExpression(false),
|
|
new CodeVariableReferenceExpression("offset"));
|
|
|
|
validateMethod.Statements.Add(
|
|
new CodeMethodReturnStatement(invokeBase));
|
|
}
|
|
else
|
|
{
|
|
validateMethod.Statements.Add(
|
|
new CodeMethodReturnStatement(
|
|
new CodePrimitiveExpression(true)));
|
|
}
|
|
|
|
if (forReadOnly)
|
|
{
|
|
descriptor.CodeTypeDeclarationForReadOnly.Members.Add(validateMethod);
|
|
}
|
|
else
|
|
{
|
|
descriptor.CodeTypeDeclaration.Members.Add(validateMethod);
|
|
}
|
|
}
|
|
|
|
CodeConditionStatement GenerateLocationReferenceCheck(MemberData memberData)
|
|
{
|
|
CodeIndexerExpression indexer = new CodeIndexerExpression(
|
|
new CodeVariableReferenceExpression("locationReferences"),
|
|
new CodeBinaryOperatorExpression(new CodeVariableReferenceExpression("offset"),
|
|
CodeBinaryOperatorType.Add,
|
|
new CodePrimitiveExpression(memberData.Index)));
|
|
|
|
CodeBinaryOperatorExpression locationNameExpression = new CodeBinaryOperatorExpression(
|
|
new CodePropertyReferenceExpression(indexer, "Name"),
|
|
CodeBinaryOperatorType.IdentityInequality,
|
|
new CodePrimitiveExpression(memberData.Name));
|
|
|
|
CodeBinaryOperatorExpression locationTypeExpression = new CodeBinaryOperatorExpression(
|
|
new CodePropertyReferenceExpression(indexer, "Type"),
|
|
CodeBinaryOperatorType.IdentityInequality,
|
|
new CodeTypeOfExpression(memberData.Type));
|
|
|
|
CodeBinaryOperatorExpression locationExpression = new CodeBinaryOperatorExpression(
|
|
locationNameExpression,
|
|
CodeBinaryOperatorType.BooleanOr,
|
|
locationTypeExpression);
|
|
|
|
CodeMethodReturnStatement returnStatement = new CodeMethodReturnStatement();
|
|
|
|
returnStatement.Expression = new CodePrimitiveExpression(false);
|
|
|
|
CodeConditionStatement locationStatement = new CodeConditionStatement(
|
|
locationExpression,
|
|
returnStatement);
|
|
|
|
return locationStatement;
|
|
}
|
|
|
|
[Fx.Tag.SecurityNote(Critical = "Critical because we are accessing CodeDom.",
|
|
Safe = "Safe because we are demanding FullTrust")]
|
|
[SecuritySafeCritical]
|
|
[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
|
|
void WriteCode(TextWriter textWriter)
|
|
{
|
|
using (CodeDomProvider codeDomProvider = CodeDomProvider.CreateProvider(this.settings.Language))
|
|
{
|
|
using (IndentedTextWriter indentedTextWriter = new IndentedTextWriter(textWriter))
|
|
{
|
|
codeDomProvider.GenerateCodeFromNamespace(this.codeNamespace, indentedTextWriter, new CodeGeneratorOptions());
|
|
}
|
|
}
|
|
}
|
|
|
|
[Fx.Tag.SecurityNote(Critical = "Critical because we are using the CodeDomProvider class, which has a link demand for Full Trust.",
|
|
Safe = "Safe because we are demanding FullTrust")]
|
|
[SecuritySafeCritical]
|
|
[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
|
|
TextExpressionCompilerResults CompileInMemory()
|
|
{
|
|
List<TextExpressionCompilerError> messages = new List<TextExpressionCompilerError>();
|
|
CompilerParameters compilerParameters = GetCompilerParameters(messages);
|
|
|
|
CompilerResults compilerResults = null;
|
|
using (CodeDomProvider codeDomProvider = CodeDomProvider.CreateProvider(this.settings.Language))
|
|
{
|
|
compilerResults = codeDomProvider.CompileAssemblyFromDom(compilerParameters, this.compileUnit);
|
|
}
|
|
|
|
TextExpressionCompilerResults results = new TextExpressionCompilerResults();
|
|
|
|
if (compilerResults.Errors == null || !compilerResults.Errors.HasErrors)
|
|
{
|
|
results.ResultType = compilerResults.CompiledAssembly.GetType(this.activityFullName);
|
|
}
|
|
|
|
results.HasSourceInfo = this.symbols != null;
|
|
|
|
bool hasErrors = false;
|
|
if (compilerResults.Errors != null && (compilerResults.Errors.HasWarnings || compilerResults.Errors.HasErrors))
|
|
{
|
|
|
|
foreach (CompilerError ce in compilerResults.Errors)
|
|
{
|
|
TextExpressionCompilerError message = new TextExpressionCompilerError();
|
|
|
|
message.Message = ce.ErrorText;
|
|
message.Number = ce.ErrorNumber;
|
|
|
|
if (results.HasSourceInfo)
|
|
{
|
|
message.SourceLineNumber = ce.Line;
|
|
}
|
|
else
|
|
{
|
|
message.SourceLineNumber = -1;
|
|
}
|
|
|
|
message.IsWarning = ce.IsWarning;
|
|
|
|
messages.Add(message);
|
|
|
|
hasErrors |= !message.IsWarning;
|
|
}
|
|
}
|
|
|
|
if (messages != null && messages.Count > 0)
|
|
{
|
|
results.SetMessages(messages, hasErrors);
|
|
}
|
|
|
|
return results;
|
|
}
|
|
|
|
[Fx.Tag.SecurityNote(Critical = "Critical because we are using the CompilerParameters class, which has a link demand for Full Trust.",
|
|
Safe = "Safe because we are demanding FullTrust")]
|
|
[SecuritySafeCritical]
|
|
[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
|
|
CompilerParameters GetCompilerParameters(IList<TextExpressionCompilerError> messages)
|
|
{
|
|
CompilerParameters compilerParameters = new CompilerParameters();
|
|
compilerParameters.GenerateExecutable = false;
|
|
compilerParameters.GenerateInMemory = false;
|
|
|
|
if (this.IsVB && !string.IsNullOrWhiteSpace(this.settings.RootNamespace))
|
|
{
|
|
compilerParameters.CompilerOptions = string.Concat("/rootnamespace:", this.settings.RootNamespace);
|
|
}
|
|
|
|
List<AssemblyReference> assemblies = this.settings.ForImplementation ?
|
|
new List<AssemblyReference>(TextExpression.GetReferencesForImplementation(this.settings.Activity)) :
|
|
new List<AssemblyReference>(TextExpression.GetReferences(this.settings.Activity));
|
|
|
|
assemblies.AddRange(TextExpression.DefaultReferences);
|
|
|
|
foreach (AssemblyReference assemblyReference in assemblies)
|
|
{
|
|
if (assemblyReference == null)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
assemblyReference.LoadAssembly();
|
|
|
|
if (assemblyReference.Assembly == null)
|
|
{
|
|
TextExpressionCompilerError warning = new TextExpressionCompilerError();
|
|
warning.IsWarning = true;
|
|
warning.Message = SR.TextExpressionCompilerUnableToLoadAssembly(assemblyReference.AssemblyName);
|
|
|
|
messages.Add(warning);
|
|
|
|
continue;
|
|
}
|
|
|
|
if (assemblyReference.Assembly.CodeBase == null)
|
|
{
|
|
TextExpressionCompilerError warning = new TextExpressionCompilerError();
|
|
warning.IsWarning = true;
|
|
warning.Message = SR.TextExpressionCompilerNoCodebase(assemblyReference.AssemblyName);
|
|
|
|
messages.Add(warning);
|
|
|
|
continue;
|
|
}
|
|
|
|
string fileName = new Uri(assemblyReference.Assembly.CodeBase).LocalPath;
|
|
compilerParameters.ReferencedAssemblies.Add(fileName);
|
|
}
|
|
|
|
return compilerParameters;
|
|
}
|
|
|
|
void AlignText(Activity activity, ref string expressionText, out CodeLinePragma pragma)
|
|
{
|
|
pragma = null;
|
|
if (this.symbols != null)
|
|
{
|
|
SourceLocation sourceLocation = null;
|
|
|
|
Activity currentActivity = activity;
|
|
while (currentActivity != null && !symbols.TryGetValue(currentActivity, out sourceLocation))
|
|
{
|
|
currentActivity = currentActivity.Parent;
|
|
}
|
|
|
|
if (sourceLocation != null && !string.IsNullOrWhiteSpace(sourceLocation.FileName))
|
|
{
|
|
int startLine = sourceLocation.StartLine;
|
|
if (startLine > 1)
|
|
{
|
|
bool aligned = TryAlign(sourceLocation.StartColumn, ref expressionText);
|
|
if (aligned)
|
|
{
|
|
// Alignment inserts an extra blank line at the beginning of the expression
|
|
startLine--;
|
|
}
|
|
}
|
|
|
|
pragma = new CodeLinePragma(sourceLocation.FileName, startLine);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool TryAlign(int alignment, ref string expressionText)
|
|
{
|
|
if (!this.IsVB && !this.IsCS)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
StringBuilder builder = new StringBuilder();
|
|
if (this.IsVB)
|
|
{
|
|
builder.Append('_');
|
|
}
|
|
builder.Append(Environment.NewLine);
|
|
builder.Append(new string(' ', alignment - 1));
|
|
builder.Append(expressionText);
|
|
expressionText = builder.ToString();
|
|
return true;
|
|
}
|
|
|
|
CodeLinePragma GenerateLinePragmaForNamespace(string namespaceName)
|
|
{
|
|
if (this.fileName != null)
|
|
{
|
|
// if source xaml file doesn't exist or it doesn't contain TextExpression
|
|
// it defaults to line number 1
|
|
int lineNumber = 1;
|
|
Dictionary<string, int> lineNumberDictionary = this.settings.ForImplementation ? this.lineNumbersForNSesForImpl : this.lineNumbersForNSes;
|
|
|
|
int lineNumReturend;
|
|
if (lineNumberDictionary.TryGetValue(namespaceName, out lineNumReturend))
|
|
{
|
|
lineNumber = lineNumReturend;
|
|
}
|
|
|
|
return new CodeLinePragma(this.fileName, lineNumber);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
bool TryGetSymbols(Activity rootActivity, out Dictionary<object, SourceLocation> symbols, out string fileName)
|
|
{
|
|
symbols = null;
|
|
fileName = null;
|
|
Activity implementationRoot = null;
|
|
if (this.settings.ForImplementation)
|
|
{
|
|
// Regular compilation case via XamlBuildTask or for DynamicActivity
|
|
// Debugger Symbols are attached to the first implementation child of rootActivity
|
|
IEnumerable<Activity> children = WorkflowInspectionServices.GetActivities(rootActivity);
|
|
foreach (Activity child in children)
|
|
{
|
|
// Find the first implementation child of an activity
|
|
if (child.Id.Contains("."))
|
|
{
|
|
implementationRoot = child;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// XamlX case
|
|
// Debugger Symbols are attached to WorkflowService.Body which is passed in the rootActivity
|
|
implementationRoot = rootActivity;
|
|
}
|
|
|
|
if (implementationRoot == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
try
|
|
{
|
|
string symbolString = DebugSymbol.GetSymbol(implementationRoot) as string;
|
|
if (!string.IsNullOrEmpty(symbolString))
|
|
{
|
|
WorkflowSymbol wfSymbol = WorkflowSymbol.Decode(symbolString);
|
|
if (wfSymbol != null)
|
|
{
|
|
symbols = SourceLocationProvider.GetSourceLocations(rootActivity, wfSymbol);
|
|
fileName = wfSymbol.FileName;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
if (Fx.IsFatal(e))
|
|
{
|
|
throw;
|
|
}
|
|
// Ignore invalid symbols.
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
string GetActivityFullName(TextExpressionCompilerSettings settings)
|
|
{
|
|
string rootNamespacePrefix = null;
|
|
string namespacePrefix = null;
|
|
string activityFullName = "";
|
|
if (this.IsVB && !String.IsNullOrWhiteSpace(this.settings.RootNamespace))
|
|
{
|
|
rootNamespacePrefix = this.settings.RootNamespace + ".";
|
|
}
|
|
|
|
if (!String.IsNullOrWhiteSpace(this.settings.ActivityNamespace))
|
|
{
|
|
namespacePrefix = this.settings.ActivityNamespace + ".";
|
|
}
|
|
|
|
if (rootNamespacePrefix != null)
|
|
{
|
|
if (namespacePrefix != null)
|
|
{
|
|
activityFullName = rootNamespacePrefix + namespacePrefix + settings.ActivityName;
|
|
}
|
|
else
|
|
{
|
|
activityFullName = rootNamespacePrefix + settings.ActivityName;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (namespacePrefix != null)
|
|
{
|
|
activityFullName = namespacePrefix + settings.ActivityName;
|
|
}
|
|
else
|
|
{
|
|
activityFullName = settings.ActivityName;
|
|
}
|
|
}
|
|
|
|
return activityFullName;
|
|
}
|
|
|
|
class ExpressionCompilerActivityVisitor : CompiledExpressionActivityVisitor
|
|
{
|
|
TextExpressionCompiler compiler;
|
|
|
|
public ExpressionCompilerActivityVisitor(TextExpressionCompiler compiler)
|
|
{
|
|
this.compiler = compiler;
|
|
}
|
|
|
|
public int NextExpressionId
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
protected override void Visit(Activity activity, out bool exit)
|
|
{
|
|
base.Visit(activity, out exit);
|
|
}
|
|
|
|
protected override void VisitRoot(Activity activity, out bool exit)
|
|
{
|
|
this.compiler.OnRootActivity();
|
|
|
|
base.VisitRoot(activity, out exit);
|
|
|
|
this.compiler.OnAfterRootActivity();
|
|
}
|
|
|
|
protected override void VisitRootImplementationArguments(Activity activity, out bool exit)
|
|
{
|
|
base.VisitRootImplementationArguments(activity, out exit);
|
|
|
|
if (this.ForImplementation)
|
|
{
|
|
this.compiler.OnAfterRootArguments(activity);
|
|
}
|
|
}
|
|
|
|
protected override void VisitVariableScope(Activity activity, out bool exit)
|
|
{
|
|
this.compiler.OnVariableScope(activity);
|
|
|
|
base.VisitVariableScope(activity, out exit);
|
|
this.compiler.OnAfterVariableScope();
|
|
}
|
|
|
|
protected override void VisitRootImplementationScope(Activity activity, out bool exit)
|
|
{
|
|
CompiledDataContextDescriptor rootArgumentAccessorContext = null;
|
|
this.compiler.OnRootImplementationScope(activity, out rootArgumentAccessorContext);
|
|
|
|
base.VisitRootImplementationScope(activity, out exit);
|
|
|
|
this.compiler.OnAfterRootImplementationScope(activity, rootArgumentAccessorContext);
|
|
}
|
|
|
|
protected override void VisitVariableScopeArgument(RuntimeArgument runtimeArgument, out bool exit)
|
|
{
|
|
this.compiler.InVariableScopeArgument = true;
|
|
base.VisitVariableScopeArgument(runtimeArgument, out exit);
|
|
this.compiler.InVariableScopeArgument = false;
|
|
}
|
|
|
|
protected override void VisitITextExpression(Activity activity, out bool exit)
|
|
{
|
|
this.compiler.OnITextExpressionFound(activity, this);
|
|
exit = false;
|
|
}
|
|
|
|
protected override void VisitDelegate(ActivityDelegate activityDelegate, out bool exit)
|
|
{
|
|
this.compiler.OnActivityDelegateScope();
|
|
|
|
base.VisitDelegate(activityDelegate, out exit);
|
|
|
|
this.compiler.OnAfterActivityDelegateScope();
|
|
|
|
exit = false;
|
|
}
|
|
|
|
protected override void VisitDelegateArgument(RuntimeDelegateArgument delegateArgument, out bool exit)
|
|
{
|
|
this.compiler.OnDelegateArgument(delegateArgument);
|
|
|
|
base.VisitDelegateArgument(delegateArgument, out exit);
|
|
}
|
|
}
|
|
|
|
class CompiledExpressionDescriptor
|
|
{
|
|
internal bool IsValue
|
|
{
|
|
get
|
|
{
|
|
return !string.IsNullOrWhiteSpace(this.GetMethodName) &&
|
|
string.IsNullOrWhiteSpace(this.SetMethodName) &&
|
|
string.IsNullOrWhiteSpace(this.StatementMethodName);
|
|
}
|
|
}
|
|
|
|
internal bool IsReference
|
|
{
|
|
get
|
|
{
|
|
return !string.IsNullOrWhiteSpace(this.SetMethodName);
|
|
}
|
|
}
|
|
|
|
internal bool IsStatement
|
|
{
|
|
get
|
|
{
|
|
return !string.IsNullOrWhiteSpace(this.StatementMethodName);
|
|
}
|
|
}
|
|
|
|
internal string TypeName
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
internal Type ResultType
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
internal string GetMethodName
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
internal string SetMethodName
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
internal string StatementMethodName
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
internal int Id
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
internal string ExpressionText
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
internal string GetExpressionTreeMethodName
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
}
|
|
|
|
class CompiledDataContextDescriptor
|
|
{
|
|
IDictionary<string, MemberData> fields;
|
|
IDictionary<string, MemberData> properties;
|
|
ISet<string> duplicates;
|
|
Func<bool> isVb;
|
|
|
|
public CompiledDataContextDescriptor(Func<bool> isVb)
|
|
{
|
|
this.isVb = isVb;
|
|
}
|
|
|
|
public IDictionary<string, MemberData> Fields
|
|
{
|
|
get
|
|
{
|
|
if (this.fields == null)
|
|
{
|
|
if (this.isVb())
|
|
{
|
|
this.fields = new Dictionary<string, MemberData>(StringComparer.OrdinalIgnoreCase);
|
|
}
|
|
else
|
|
{
|
|
this.fields = new Dictionary<string, MemberData>();
|
|
}
|
|
}
|
|
return this.fields;
|
|
}
|
|
}
|
|
|
|
public IDictionary<string, MemberData> Properties
|
|
{
|
|
get
|
|
{
|
|
if (this.properties == null)
|
|
{
|
|
if (this.isVb())
|
|
{
|
|
this.properties = new Dictionary<string, MemberData>(StringComparer.OrdinalIgnoreCase);
|
|
}
|
|
else
|
|
{
|
|
this.properties = new Dictionary<string, MemberData>();
|
|
}
|
|
}
|
|
return this.properties;
|
|
}
|
|
}
|
|
|
|
public ISet<string> Duplicates
|
|
{
|
|
get
|
|
{
|
|
if (this.duplicates == null)
|
|
{
|
|
if (this.isVb())
|
|
{
|
|
this.duplicates = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
|
}
|
|
else
|
|
{
|
|
this.duplicates = new HashSet<string>();
|
|
}
|
|
}
|
|
return this.duplicates;
|
|
}
|
|
}
|
|
|
|
public CodeTypeDeclaration CodeTypeDeclaration
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
public CodeTypeDeclaration CodeTypeDeclarationForReadOnly
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
public int NextMemberIndex
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
}
|
|
|
|
struct MemberData
|
|
{
|
|
public int Index;
|
|
public string Name;
|
|
public Type Type;
|
|
}
|
|
}
|
|
}
|