public StrongTypeRulesBase[] CreateNewRules(Rule[] RulesToCreate) { Log.WriteDetailedDebug("{0}: Start compiling rules {1}", GetType().FullName, RulesToString(RulesToCreate)); #region Namespaces creation and import relevant namespaces CodeCompileUnit CompileUnit = new CodeCompileUnit(); CodeNamespace StrongTypedNamespace = new CodeNamespace(STRONG_TYPED_CLASSES_NAMESPACE); StrongTypedNamespace.Imports.Add(new CodeNamespaceImport("System")); // a reference to the current module is required since the compiled code inherits // from a base class which is defined in this module string BaseClassNamespace = typeof(StrongTypeRulesBase).Namespace; StrongTypedNamespace.Imports.Add(new CodeNamespaceImport(BaseClassNamespace)); CompileUnit.Namespaces.Add(StrongTypedNamespace); #endregion #region Create & Add Dom classes // Create Type names for rules string[] TypeNames = CreateTypeNames(RulesToCreate); // Create & Add Rules classes to namespace for (int i = 0; i < RulesToCreate.Length; i++) { Rule oRule = RulesToCreate[i]; string sUniqueRuleName = TypeNames[i]; CodeTypeDeclaration oRuleDomClass = CreateRuleDomClass( oRule, sUniqueRuleName); StrongTypedNamespace.Types.Add(oRuleDomClass); } #endregion #region Prepare CompilerParams CompilerParameters CompilerParams = new CompilerParameters(); // scan each meta tag in the collection foreach (VariableDeclaration oVariableDeclaration in m_GlobalVariablesSchema) { // add reference to the assembly that contains that meta tag // TODO: add only assemblies that does not occure more than once Type VariableType = oVariableDeclaration.Type; CompilerParams.ReferencedAssemblies.Add(VariableType.Module.FullyQualifiedName); } #endregion #region Convert the generated CompileUnit to source code in memory (string) VBCodeProvider VBProvider = new VBCodeProvider(); ICodeGenerator CodeGen = VBProvider.CreateGenerator(); StringBuilder ClassSourceCode = new StringBuilder(); StringWriter StringWrite = new StringWriter(ClassSourceCode); CodeGeneratorOptions CodeGenOptions = new CodeGeneratorOptions(); CodeGenOptions.BracingStyle = "C"; CodeGenOptions.ElseOnClosing = false; CodeGen.GenerateCodeFromCompileUnit(CompileUnit, StringWrite, CodeGenOptions); #endregion #region DEBUG Mode Only - Save the resulted generated source code to disk #if (DEBUG_RULE_BUILDER) try { String sourceFile = m_TestVBRulesFileFullPath; System.IO.Directory.CreateDirectory(Path.GetDirectoryName(sourceFile)); IndentedTextWriter tw = new IndentedTextWriter( new StreamWriter(sourceFile, false), " "); CodeGen.GenerateCodeFromCompileUnit(CompileUnit, tw, CodeGenOptions); tw.Close(); } catch { } #endif #endregion #region Compile the source code ICodeCompiler VBCompiler = VBProvider.CreateCompiler(); #region Set compiler references to needed modules: System32.dll, original object, base class CompilerParams.ReferencedAssemblies.Add("System.dll"); // Since the run-time compiled unit should know the the type it // was derived from, during the compilation process, an explicit reference // to the module that contains the class (which must be in memory since // the class was just sent to this function) must be add to the compilation // unit. string VariableValuesModuleName = typeof(VariableValueList).Module.FullyQualifiedName; CompilerParams.ReferencedAssemblies.Add(VariableValuesModuleName); string UserDefinedFunctionsModuleName = (m_PredefinedFunctions.GetType()).Module.FullyQualifiedName; CompilerParams.ReferencedAssemblies.Add(UserDefinedFunctionsModuleName); #endregion CompilerParams.GenerateExecutable = false; CompilerParams.GenerateInMemory = true; if (StringUtil.IsStringInitialized(m_sTempFilesPath)) { CompilerParams.TempFiles = new TempFileCollection(m_sTempFilesPath); CompilerParams.TempFiles.KeepFiles = m_bKeepTempFiles; } CompilerResults CompilerRes = VBCompiler.CompileAssemblyFromDom(CompilerParams, CompileUnit); Assembly oCompiledAssembly = null; try { // Check if we have compilation errors if (CompilerRes.Errors.Count > 0) { throw new TisException("Errors in compilation"); } if (CompilerRes.PathToAssembly != null) { // For the case that assembly not generated in memory oCompiledAssembly = Assembly.LoadFrom( CompilerRes.PathToAssembly); } else { // We can still have a problem // (Maybe there's no compilation errors because // the compiler not even started) oCompiledAssembly = CompilerRes.CompiledAssembly; } } catch (Exception oOrigExc) { Log.WriteException(oOrigExc); RuleCompilationException oExc = new RuleCompilationException( CompilerRes.Output, RulesToString(RulesToCreate)); // Add errors foreach (CompilerError oErr in CompilerRes.Errors) { oExc.AddErrorInfo( oErr.IsWarning, oErr.ErrorText, oErr.ErrorNumber, oErr.Column, oErr.FileName, oErr.Line); } Log.WriteException(oExc); throw oExc; } #endregion StrongTypeRulesBase[] RuleObjects = GetRulesFromAssembly( oCompiledAssembly, TypeNames); return(RuleObjects); }
private CodeTypeDeclaration CreateRuleDomClass( Rule oRule, string sUniqueRuleName) { CodeTypeDeclaration oDomClass = new CodeTypeDeclaration(sUniqueRuleName); oDomClass.IsClass = true; // <ClassName> : <ObjectType>,.... // Since we want to serialize the protected members as well, we need to derive // from the class we would like to serialize, to have access to the // memebers - note that private memebers can not be accessed using this // logic. oDomClass.BaseTypes.Add(typeof(StrongTypeRulesBase)); oDomClass.Attributes = MemberAttributes.Public; #region Add Ctor // Add the constructor CodeConstructor ObjectConstructor = new CodeConstructor(); ObjectConstructor.Attributes = MemberAttributes.Public; ObjectConstructor.Parameters.Add(new CodeParameterDeclarationExpression("System.Object", "UserDefinedFunctions")); CodeArgumentReferenceExpression ObjectArgument = new CodeArgumentReferenceExpression("UserDefinedFunctions"); ObjectConstructor.BaseConstructorArgs.Add(ObjectArgument); oDomClass.Members.Add(ObjectConstructor); #endregion #region Add properties defined in m_GlobalVariablesSchema and getters // scan each meta tag in the collection foreach (VariableDeclaration oVariableDeclaration in m_GlobalVariablesSchema) { // add reference to the assembly that contains that meta tag // TODO: add only assemblies that does not occure more than once Type VariableType = oVariableDeclaration.Type; string VariableName = oVariableDeclaration.Name; string VariableFieldName = "m_" + VariableName; // Add a private field named m_..... (oVariableDeclaration name) CodeMemberField VariableFields = new CodeMemberField(VariableType.ToString(), VariableFieldName); VariableFields.Attributes = MemberAttributes.Private; oDomClass.Members.Add(VariableFields); CodeMemberProperty VariableProperty = new CodeMemberProperty(); // Since we would like that the user function will access the meta tags // values by their names, we set the property name as the name of the meta tag VariableProperty.Name = VariableName; VariableProperty.Attributes = MemberAttributes.Public; VariableProperty.HasGet = true; VariableProperty.HasSet = false; VariableProperty.Type = new CodeTypeReference(VariableType); // add the getter for the specific field CodeFieldReferenceExpression oRefExpression = new CodeFieldReferenceExpression( new CodeThisReferenceExpression(), VariableFieldName); if (VariableType == typeof(string)) { CodeMethodInvokeExpression IsStringEmptyExpression = new CodeMethodInvokeExpression( oRefExpression, "Equals", new CodeExpression[] { new CodePrimitiveExpression(String.Empty) }); CodeMethodReturnStatement oReturnTrue = new CodeMethodReturnStatement(new CodePrimitiveExpression(null)); CodeMethodReturnStatement oReturnFalse = new CodeMethodReturnStatement(oRefExpression); CodeConditionStatement IfStringEmpty = new CodeConditionStatement( // The condition to test. IsStringEmptyExpression, // The statements to execute if the condition evaluates to true. new CodeStatement[] { oReturnTrue }, // The statements to execute if the condition evalues to false. new CodeStatement[] { oReturnFalse }); // add the getter for the specific field VariableProperty.GetStatements.Add(IfStringEmpty); } else { VariableProperty.GetStatements.Add(new CodeMethodReturnStatement( new CodeFieldReferenceExpression( new CodeThisReferenceExpression(), VariableFieldName))); } oDomClass.Members.Add(VariableProperty); } #endregion #region Add the specific user functions as defined in m_PredefinedFunctions MethodInfo[] PredefinedFunctions = m_FunctionsReflector.GetMethodsInfo(); foreach (MethodInfo mi in PredefinedFunctions) { CodeMemberMethod OriginInvoker = new CodeMemberMethod(); OriginInvoker.Name = mi.Name; OriginInvoker.Attributes = MemberAttributes.Private; OriginInvoker.ReturnType = new CodeTypeReference(mi.ReturnType); ParameterInfo[] Params = mi.GetParameters(); int index = 0; // Array of CodeExpression ArrayBuilder oCodeInvokeParams = new ArrayBuilder(); oCodeInvokeParams.Add(new CodePrimitiveExpression(mi.Name)); // Each functions is allowed to have maximum of one VariableValueList // parameters int nVariableValuesFunctionParameters = 0; foreach (ParameterInfo pi in Params) { Type ParameterType = pi.ParameterType; String OriginalParameterName = pi.Name; String ParameterName = pi.Name; ++index; // in the created method, ignore the VariableValueList, which is // contained as a memebr of the object if (ParameterType != typeof(VariableValueList)) { oCodeInvokeParams.Add(new CodeVariableReferenceExpression(ParameterName)); CodeParameterDeclarationExpression OriginalParameter = new CodeParameterDeclarationExpression(ParameterType.ToString(), pi.Name); OriginInvoker.Parameters.Add(OriginalParameter); } else { ++nVariableValuesFunctionParameters; } } // ... more than single VariableValueList parameter if (nVariableValuesFunctionParameters > 1) { string ExceptionMessage = "Error! StringTypedRule:StrongTypedRuleBuilder method " + "m_PredefinedFunctions:" + mi.Name + " contains more than single" + " parameter of type VariableValueList "; throw new ArgumentException(ExceptionMessage, mi.Name); } oDomClass.Members.Add(OriginInvoker); CodeMethodInvokeExpression UserDefinedInvoke = new CodeMethodInvokeExpression( new CodeThisReferenceExpression(), "InvokeUserDefinedFunction", (CodeExpression[])oCodeInvokeParams.GetArray()); // new CodeExpression[] { OriginalFunctionParametersName } ); // if the return type of the function is not void, than a "return" // clause should be added before the invocation of the function if (mi.ReturnType != typeof(void)) { // return ... CodeMethodReturnStatement ReturnStatement = new CodeMethodReturnStatement(UserDefinedInvoke); OriginInvoker.Statements.Add(ReturnStatement); } else { OriginInvoker.Statements.Add(UserDefinedInvoke); } } // end of foreach( MethodInfo mi #endregion #region Add the RuleTrue override of the virtual function that actually computes the rule CodeMemberMethod RuleTrueMethod = new CodeMemberMethod(); RuleTrueMethod.Name = "RuleTrue"; RuleTrueMethod.Attributes = MemberAttributes.Public | MemberAttributes.Override; RuleTrueMethod.ReturnType = new CodeTypeReference(typeof(System.Boolean)); // ... ( VariableValueList RUN_TRUE_METHOD_PARAMETER_NAME ) CodeParameterDeclarationExpression RuleTrueParameter = new CodeParameterDeclarationExpression(typeof(VariableValueList).ToString(), RUN_TRUE_METHOD_PARAMETER_NAME); RuleTrueMethod.Parameters.Add(RuleTrueParameter); // base.RuleTrue( RUN_TRUE_METHOD_PARAMETER_NAME ) CodeMethodInvokeExpression InvokeBaseRuleTrue = new CodeMethodInvokeExpression( new CodeBaseReferenceExpression(), // Method name and method parameter arguments "RuleTrue", new CodeExpression[] { new CodeArgumentReferenceExpression(RUN_TRUE_METHOD_PARAMETER_NAME) }); RuleTrueMethod.Statements.Add(InvokeBaseRuleTrue); // Add the IfExists check on the VariableValueList, and if exists assign it to the // relevant private meta tag // if( m_TiSVariableValues.Exists("VariableName") == true ) // m_VariableName = <VariableValueType>( m_TiSVariableValues.GetValue("VariableName") ) foreach (VariableDeclaration oVariableDeclaration in m_GlobalVariablesSchema) { string VariableName = oVariableDeclaration.Name; Type VariableType = oVariableDeclaration.Type; // m_TiSVariableValues.Contains("VariableName") CodeMethodInvokeExpression ExistVariable = new CodeMethodInvokeExpression( new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), "m_TiSVariableValues"), "Contains", new CodeExpression[] { new CodePrimitiveExpression(VariableName) }); //m_TiSVariableValues["VariableName"] CodeIndexerExpression VariableGetValue = new CodeIndexerExpression(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), "m_TiSVariableValues"), new CodePrimitiveExpression(VariableName)); // m_TiSVariableValues.GetValue("VariableName") //CodeMethodInvokeExpression VariableGetValue = new CodeMethodInvokeExpression( // new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), // "m_TiSVariableValues"), // "GetValue", // new CodeExpression[] { new CodePrimitiveExpression(VariableName) }); // <VariableValueType> CodeCastExpression VariableGetSpecificValue = new CodeCastExpression( VariableType, VariableGetValue); string PrivateFieldName = "m_" + VariableName; // m_VariableName = <Me ... CodeAssignStatement VariableAssignment = new CodeAssignStatement( new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), PrivateFieldName), VariableGetSpecificValue); // if ... CodeConditionStatement CheckVariableValueExistence = new CodeConditionStatement( // The condition to test. ExistVariable, // The statements to execute if the condition evaluates to true. new CodeStatement[] { VariableAssignment }, // The statements to execute if the condition evalues to false. new CodeStatement[] { }); RuleTrueMethod.Statements.Add(CheckVariableValueExistence); } string BracketsWrapped = "( " + oRule.Text + " ) "; CodeSnippetExpression ActualUserRule = new CodeSnippetExpression(BracketsWrapped); CodeMethodReturnStatement ReturnedRule = new CodeMethodReturnStatement(ActualUserRule); // return ( User Function ) RuleTrueMethod.Statements.Add(ReturnedRule); oDomClass.Members.Add(RuleTrueMethod); #endregion return(oDomClass); }