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); }
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); }
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 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 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); } }
CompiledDataContextDescriptor PushDataContextDescriptor() { CompiledDataContextDescriptor contextDescriptor = new CompiledDataContextDescriptor(() => this.IsVB) { CodeTypeDeclaration = GenerateCompiledDataContext(false), CodeTypeDeclarationForReadOnly = GenerateCompiledDataContext(true), NextMemberIndex = GetStartMemberIndex() }; this.compiledDataContexts.Push(contextDescriptor); this.nextContextId++; return contextDescriptor; }
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; }
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); } }
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; }