public static List<string> GenerateCode(Specification S, G25.CG.Shared.CGdata cgd) { // get filename, list of generated filenames List<string> generatedFiles = new List<string>(); string sourceFilename = S.GetOutputPath(G25.CG.C.Source.GetRawSourceFilename(S)); generatedFiles.Add(sourceFilename); // get StringBuilder where all generated code goes StringBuilder SB = new StringBuilder(); // output license, copyright G25.CG.Shared.Util.WriteCopyright(SB, S); G25.CG.Shared.Util.WriteLicense(SB, S); { // #includes SB.AppendLine("#include <stdio.h>"); if (cgd.GetFeedback(G25.CG.Shared.Main.NEED_TIME) == "true") SB.AppendLine("#include <time.h> /* used to seed random generator */"); SB.AppendLine("#include \"" + S.GetOutputFilename(G25.CG.C.Header.GetRawHeaderFilename(S)) + "\""); } GenerateTables(S, cgd, SB); // the list of names of smv types G25.CG.C.SMV.WriteSMVtypenames(SB, S, cgd); // write constant definitions G25.CG.C.Constants.WriteDefinitions(SB, S, cgd); // set to zero / copy floats cgd.m_cog.EmitTemplate(SB, "float_zero_copy_def", "S=", S, "MAX_N=", G25.CG.Shared.Main.MAX_EXPLICIT_ZERO); if (S.m_gmvCodeGeneration == GMV_CODE.RUNTIME) { cgd.m_cog.EmitTemplate(SB, "runtimeGpTablesDefs", "S=", S); cgd.m_cog.EmitTemplate(SB, "bitmapGp", "S=", S); cgd.m_cog.EmitTemplate(SB, "runtimeGpTable", "S=", S); foreach (G25.FloatType FT in S.m_floatTypes) { cgd.m_cog.EmitTemplate(SB, "runtimeComputeGp", "S=", S, "FT=", FT); } cgd.m_cog.EmitTemplate(SB, "runtimeGpInitTables", "S=", S); cgd.m_cog.EmitTemplate(SB, "runtimeGpFreeTables", "S=", S); } // write compress source code WriteCompressSource(SB, S, cgd); cgd.m_cog.EmitTemplate(SB, "swapPointer"); { // write toString bool def = true; G25.CG.C.ToString.WriteToString(SB, S, cgd, def); } //SB.AppendLine("/* def SB: */"); SB.Append(cgd.m_defSB); // write all to file G25.CG.Shared.Util.WriteFile(sourceFilename, SB.ToString()); return generatedFiles; }
/// <summary> /// Generates a header file named S.m_namespace.h. /// </summary> /// <param name="S">Specification of algebra.</param> /// <param name="cgd">Intermediate data for code generation. Also contains plugins and cog.</param> /// <returns>a list of filenames which were generated (full path).</returns> public static List<string> GenerateCode(Specification S, G25.CG.Shared.CGdata cgd) { // get filename, list of generated filenames List<string> generatedFiles = new List<string>(); string headerFilename = S.GetOutputPath(G25.CG.C.Header.GetRawHeaderFilename(S)); generatedFiles.Add(headerFilename); // get StringBuilder where all generated code goes StringBuilder SB = new StringBuilder(); // output license, copyright G25.CG.Shared.Util.WriteCopyright(SB, S); G25.CG.Shared.Util.WriteLicense(SB, S); // write main documentation WriteDoxyMainPage(SB, S, cgd); // open include guard G25.CG.Shared.Util.WriteOpenIncludeGuard(SB, GetRawHeaderFilename(S)); { // #includes SB.AppendLine(""); SB.AppendLine("#include <stdio.h>"); SB.AppendLine("#include <stdlib.h>"); SB.AppendLine("#include <string.h>"); SB.AppendLine("#include <math.h>"); if (cgd.GetFeedback(G25.CG.C.MainGenerator.MERSENNE_TWISTER) == "true") SB.AppendLine("#include \"" + S.m_namespace + "_mt.h\""); } { // basic info { // #define GROUP_ and GRADE_ SB.AppendLine(""); // group int[] gradeBitmap = new int[S.m_dimension + 1]; for (int i = 0; i < S.m_GMV.NbGroups; i++) { gradeBitmap[S.m_GMV.Group(i)[0].Grade()] |= 1 << i; SB.Append("/* group: "); for (int j = 0; j < S.m_GMV.Group(i).Length; j++) { if (j > 0) SB.Append(", "); SB.Append(S.m_GMV.Group(i)[j].ToString(S.m_basisVectorNames)); } SB.AppendLine("*/"); SB.AppendLine("#define GROUP_" + i + " " + (1 << i)); } // grade for (int i = 0; i <= S.m_dimension; i++) SB.AppendLine("#define GRADE_" + i + " " + gradeBitmap[i]); } cgd.m_cog.EmitTemplate(SB, "basicInfo", "S=", S); if (S.m_gmvCodeGeneration == GMV_CODE.RUNTIME) cgd.m_cog.EmitTemplate(SB, "runtimeGpTablesHeader", "S=", S); } // #define for all specialized MV types if (S.m_reportUsage) G25.CG.C.SMV.WriteSMVtypeConstants(SB, S, cgd); // write structs for all GMV (all float types) G25.CG.C.GMV.WriteGMVstructs(SB, S, cgd); // write structs for all SMVs (all float types) G25.CG.C.SMV.WriteSMVstructs(SB, S, cgd); // write structs for all GOM (all float types) if (S.m_GOM != null) G25.CG.C.GOM.WriteGOMstructs(SB, S, cgd); // write structs for all SOMs (all float types) G25.CG.C.SOM.WriteSOMstructs(SB, S, cgd); { // write toString bool def = false; G25.CG.C.ToString.WriteToString(SB, S, cgd, def); } // write constant declarations G25.CG.C.Constants.WriteDeclarations(SB, S, cgd); // set to zero / copy floats cgd.m_cog.EmitTemplate(SB, "float_zero_copy_decl", "S=", S, "MAX_N=", G25.CG.Shared.Main.MAX_EXPLICIT_ZERO); //SB.AppendLine("/* decl SB: */"); SB.Append(cgd.m_declSB); //SB.AppendLine("/* inline def SB: */"); SB.Append(cgd.m_inlineDefSB); // parser declarations: if (S.m_parserType == PARSER.ANTLR) cgd.m_cog.EmitTemplate(SB, "ANTLRparserHeader", "S=", S, "FT=", S.m_floatTypes[0]); else if (S.m_parserType == PARSER.BUILTIN) cgd.m_cog.EmitTemplate(SB, "CustomParserHeader", "S=", S, "FT=", S.m_floatTypes[0]); // close include guard G25.CG.Shared.Util.WriteCloseIncludeGuard(SB, GetRawHeaderFilename(S)); // write all to file G25.CG.Shared.Util.WriteFile(headerFilename, SB.ToString()); return generatedFiles; }
/// <summary> /// Generates a header file named S.m_namespace.h. /// </summary> /// <param name="S">Specification of algebra.</param> /// <param name="cgd">Intermediate data for code generation. Also contains plugins and cog.</param> /// <returns>a list of filenames which were generated (full path).</returns> public static List<string> GenerateCode(Specification S, G25.CG.Shared.CGdata cgd) { // get filename, list of generated filenames List<string> generatedFiles = new List<string>(); string headerFilename = S.GetOutputPath(GetRawHeaderFilename(S)); generatedFiles.Add(headerFilename); // get StringBuilder where all generated code goes StringBuilder SB = new StringBuilder(); // output license, copyright G25.CG.Shared.Util.WriteCopyright(SB, S); G25.CG.Shared.Util.WriteLicense(SB, S); // write main documentation WriteDoxyMainPage(SB, S, cgd); // open include guard G25.CG.Shared.Util.WriteOpenIncludeGuard(SB, GetRawHeaderFilename(S)); { // #includes SB.AppendLine(""); SB.AppendLine("#include <stdio.h>"); SB.AppendLine("#include <stdlib.h>"); SB.AppendLine("#include <string.h>"); SB.AppendLine("#include <math.h>"); SB.AppendLine("#include <string>"); if (cgd.GetFeedback(G25.CG.Shared.Main.NEED_TIME) == "true") SB.AppendLine("#include <time.h> /* used to seed random generator */"); if (cgd.GetFeedback(G25.CG.Shared.Main.MERSENNE_TWISTER) == "true") SB.AppendLine("#include \"" + S.m_namespace + "_mt.h\""); if (S.m_reportUsage) { SB.AppendLine("#include <map>"); } } G25.CG.Shared.Util.WriteOpenNamespace(SB, S); { // basic info { // #define GROUP_ and GRADE_ SB.AppendLine(""); // group int[] gradeBitmap = new int[S.m_dimension + 1]; for (int i = 0; i < S.m_GMV.NbGroups; i++) { gradeBitmap[S.m_GMV.Group(i)[0].Grade()] |= 1 << i; SB.Append("// group: "); for (int j = 0; j < S.m_GMV.Group(i).Length; j++) { if (j > 0) SB.Append(", "); SB.Append(S.m_GMV.Group(i)[j].ToString(S.m_basisVectorNames)); } SB.AppendLine(""); SB.AppendLine("#define GROUP_" + i + " " + (1 << i)); } // grade for (int i = 0; i <= S.m_dimension; i++) SB.AppendLine("#define GRADE_" + i + " " + gradeBitmap[i]); } cgd.m_cog.EmitTemplate(SB, "basicInfo", "S=", S); if (S.m_gmvCodeGeneration == GMV_CODE.RUNTIME) { G25.CG.Shared.Util.WriteOpenNamespace(SB, S, G25.CG.Shared.Main.RUNTIME_NAMESPACE); cgd.m_cog.EmitTemplate(SB, "runtimeGpTablesHeader", "S=", S); G25.CG.Shared.Util.WriteCloseNamespace(SB, S, G25.CG.Shared.Main.RUNTIME_NAMESPACE); } } // #define for all specialized MV types if (S.m_reportUsage) G25.CG.CPP.SMV.WriteSMVtypeConstants(SB, S, cgd); { // write all class types // write types for all GMV (all float types) G25.CG.CPP.GMV.WriteGMVtypes(SB, S, cgd); // write types for all SMVs (all float types) G25.CG.CPP.SMV.WriteSMVtypes(SB, S, cgd); // write types for all GOM (all float types) if (S.m_GOM != null) G25.CG.CPP.GOM.WriteGOMtypes(SB, S, cgd); // write types for all SOMs (all float types) G25.CG.CPP.SOM.WriteSOMtypes(SB, S, cgd); } { // write toString bool def = false; G25.CG.CPP.ToString.WriteToString(SB, S, cgd, def); } // write classes for all GMV (all float types) G25.CG.CPP.GMV.WriteGMVclasses(SB, S, cgd); // write classes for all SMVs (all float types) G25.CG.CPP.SMV.WriteSMVclasses(SB, S, cgd); // write classes for all GOM (all float types) if (S.m_GOM != null) G25.CG.CPP.GOM.WriteGOMclasses(SB, S, cgd); // write classes for all SOMs (all float types) G25.CG.CPP.SOM.WriteSOMclasses(SB, S, cgd); // write constant declarations G25.CG.CPP.Constants.WriteDeclarations(SB, S, cgd); // write report usage cgd.m_cog.EmitTemplate(SB, (S.m_reportUsage) ? "ReportUsageHeader" : "NoReportUsageHeader"); // set to zero / copy floats bool hasDouble = false; foreach (FloatType FT in S.m_floatTypes) { if (FT.type == "double") hasDouble = true; cgd.m_cog.EmitTemplate(SB, "float_zero_copy_decl", "S=", S, "FT=", FT, "MAX_N=", G25.CG.Shared.Main.MAX_EXPLICIT_ZERO); } if (S.m_parserType == PARSER.ANTLR && (!hasDouble)) cgd.m_cog.EmitTemplate(SB, "float_zero_copy_decl", "S=", S, "FT=", new G25.FloatType("double", "", ""), "MAX_N=", G25.CG.Shared.Main.MAX_EXPLICIT_ZERO); SB.AppendLine("// decl SB:"); SB.Append(cgd.m_declSB); // write operators if (S.m_inlineOperators) Operators.WriteOperatorDefinitions(SB, S, cgd); else Operators.WriteOperatorDeclarations(SB, S, cgd); // set to zero / copy floats foreach (FloatType FT in S.m_floatTypes) { cgd.m_cog.EmitTemplate(SB, "float_zero_copy_def", "S=", S, "FT=", FT, "MAX_N=", G25.CG.Shared.Main.MAX_EXPLICIT_ZERO); } if (S.m_parserType == PARSER.ANTLR && (!hasDouble)) cgd.m_cog.EmitTemplate(SB, "float_zero_copy_def", "S=", S, "FT=", new G25.FloatType("double", "", ""), "MAX_N=", G25.CG.Shared.Main.MAX_EXPLICIT_ZERO); SB.AppendLine("// inline def SB:"); SB.Append(cgd.m_inlineDefSB); // parser declarations: if (S.m_parserType == PARSER.ANTLR) cgd.m_cog.EmitTemplate(SB, "ANTLRparserHeader", "S=", S, "FT=", S.m_floatTypes[0]); else if (S.m_parserType == PARSER.BUILTIN) cgd.m_cog.EmitTemplate(SB, "CustomParserHeader", "S=", S, "FT=", S.m_floatTypes[0]); // close namespace G25.CG.Shared.Util.WriteCloseNamespace(SB, S); // All this thank to Jim Lazy^H^H^H^HIdle who's too lazy to write a true C++ target for ANTLR. Thanks Jim. if (S.m_parserType == PARSER.ANTLR) { FloatType FT = Parser.GetANTLRfloatType(S); cgd.m_cog.EmitTemplate(SB, "ANTLRparserHeader_outsideNamespace", "S=", S, "FT=", FT); } // close include guard G25.CG.Shared.Util.WriteCloseIncludeGuard(SB, GetRawHeaderFilename(S)); // write all to file G25.CG.Shared.Util.WriteFile(headerFilename, SB.ToString()); return generatedFiles; }
public static List<string> GenerateCode(Specification S, G25.CG.Shared.CGdata cgd) { // get filename, list of generated filenames List<string> generatedFiles = new List<string>(); string sourceFilename = S.GetOutputPath(GetRawSourceFilename(S)); generatedFiles.Add(sourceFilename); // get StringBuilder where all generated code goes StringBuilder SB = new StringBuilder(); // output license, copyright G25.CG.Shared.Util.WriteCopyright(SB, S); G25.CG.Shared.Util.WriteLicense(SB, S); { // #includes SB.AppendLine("#include <stdio.h>"); SB.AppendLine("#include <utility> // for std::swap"); if (cgd.GetFeedback(G25.CG.Shared.Main.NEED_TIME) == "true") SB.AppendLine("#include <time.h> /* used to seed random generator */"); SB.AppendLine("#include \"" + S.GetOutputFilename(G25.CG.CPP.Header.GetRawHeaderFilename(S)) + "\""); } G25.CG.Shared.Util.WriteOpenNamespace(SB, S); GenerateTables(S, cgd, SB); // the list of names of smv types G25.CG.CPP.SMV.WriteSMVtypenames(SB, S, cgd); // write constant definitions G25.CG.CPP.Constants.WriteDefinitions(SB, S, cgd); // write report usage cgd.m_cog.EmitTemplate(SB, (S.m_reportUsage) ? "ReportUsageSource" : "NoReportUsageSource"); if (S.m_gmvCodeGeneration == GMV_CODE.RUNTIME) { G25.CG.Shared.Util.WriteOpenNamespace(SB, S, G25.CG.Shared.Main.RUNTIME_NAMESPACE); cgd.m_cog.EmitTemplate(SB, "runtimeGpTablesDefs", "S=", S); cgd.m_cog.EmitTemplate(SB, "bitmapGp", "S=", S); cgd.m_cog.EmitTemplate(SB, "runtimeGpTable", "S=", S); foreach (G25.FloatType FT in S.m_floatTypes) { cgd.m_cog.EmitTemplate(SB, "runtimeComputeGp", "S=", S, "FT=", FT); } cgd.m_cog.EmitTemplate(SB, "runtimeGpInitTables", "S=", S); cgd.m_cog.EmitTemplate(SB, "runtimeGpFreeTables", "S=", S); G25.CG.Shared.Util.WriteCloseNamespace(SB, S, G25.CG.Shared.Main.RUNTIME_NAMESPACE); } { // write toString bool def = true; G25.CG.CPP.ToString.WriteToString(SB, S, cgd, def); } // write operators if (!S.m_inlineOperators) Operators.WriteOperatorDefinitions(SB, S, cgd); SB.AppendLine("// def SB:"); SB.Append(cgd.m_defSB); // close namespace G25.CG.Shared.Util.WriteCloseNamespace(SB, S); // write all to file G25.CG.Shared.Util.WriteFile(sourceFilename, SB.ToString()); return generatedFiles; }
/// <summary> /// Generates a complete testing suite, including a main function. /// /// The testing suite should test every function implemented, but depends /// on the code generator plugins to actually generate those tests. /// </summary> /// <param name="S">Specification of algebra.</param> /// <param name="cgd">Used to pass all kinds of info around.</param> /// <param name="FGI">Info about what FunctionGenerator to use for each FGS. Recycled from /// Function.WriteFunctions() for efficiency.</param> /// <returns></returns> public static List<string> GenerateCode(Specification S, G25.CG.Shared.CGdata cgd, G25.CG.Shared.FunctionGeneratorInfo FGI) { System.Console.WriteLine("Generating test suite . . .\n"); cgd.SetDependencyPrefix(""); // we want missing dependencies to actually compile, and not generate an error based on function name // get list of generated filenames List<string> generatedFiles = new List<string>(); string sourceFilename = S.GetOutputPath(G25.CG.C.TestSuite.GetRawTestSuiteFilename(S)); generatedFiles.Add(sourceFilename); // reset code in cgd (get rid of all the code that was generated for the regular non-testsuite output) cgd.ResetSB(); // get StringBuilder where all generated code goes StringBuilder SB = new StringBuilder(); // #include all relevant headers SB.AppendLine("#include <time.h> /* used to seed random generator */"); SB.AppendLine("#include \"" + S.GetOutputFilename(G25.CG.C.Header.GetRawHeaderFilename(S)) + "\""); if (S.m_parserType != PARSER.NONE) { // SB.AppendLine("#include \"" + S.GetOutputFilename(G25.CG.C.Parser.GetRawParserSourceFilename(S)) + "\""); if (S.m_parserType == PARSER.ANTLR) { SB.AppendLine("#include \"" + S.GetOutputFilename(G25.CG.C.Parser.GetANTLRlexerHeaderFilename(S)) + "\""); SB.AppendLine("#include \"" + S.GetOutputFilename(G25.CG.C.Parser.GetANTLRparserHeaderFilename(S)) + "\""); } } if (cgd.GetFeedback(G25.CG.C.MainGenerator.MERSENNE_TWISTER) == "true") SB.AppendLine("#include \"" + S.GetOutputFilename(G25.CG.C.RandomMT.GetRawMtHeaderFilename(S)) + "\""); // generate declarations for parts of the geometric product, dual, etc (works in parallel internally) try { bool declOnly = true; G25.CG.Shared.PartsCode.GeneratePartsCode(S, cgd, declOnly); } catch (G25.UserException E) { cgd.AddError(E); } // generate extra declarations foreach (FloatType FT in S.m_floatTypes) { // output internal compress function for all float types cgd.m_cog.EmitTemplate(cgd.m_defSB, "compress_decl", "S=", S, "FT=", FT, "gmv=", S.m_GMV); } cgd.m_cog.EmitTemplate(cgd.m_defSB, "swapPointerDecl"); // reset generated code (StringBuilders) of all CGDs for (int i = 0; i < FGI.m_functionFGS.Count; i++) if (FGI.m_functionGenerators[i] != null) FGI.m_functionGenerators[i].ResetCGdata(); // figure out all dependencies // Note that m_errors and m_missingDependencies of each function cgd are shared with main cgd, but a mutex is used to avoid racing { // serial: for (int i = 0; i < FGI.m_functionFGS.Count; i++) { if (FGI.m_functionGenerators[i] != null) { FGI.m_functionGenerators[i].CheckTestingDepenciesEntryPoint(); } }/* // in parallel: Thread[] depFunctionThreads = new Thread[FGI.m_functionFGS.Count]; for (int i = 0; i < FGI.m_functionFGS.Count; i++) { if (FGI.m_functionGenerators[i] != null) { depFunctionThreads[i] = new Thread(FGI.m_functionGenerators[i].CheckTestingDepenciesEntryPoint); } } G25.CG.Shared.Threads.StartThreadArray(depFunctionThreads); G25.CG.Shared.Threads.JoinThreadArray(depFunctionThreads);*/ } // get random number generator FGS for each float type List<string> randomNumberGenerators = new List<string>(); List<string> randomNumberTimeSeedFuncs = new List<string>(); foreach (FloatType FT in S.m_floatTypes) { //bool returnTrueName = true; string funcName = G25.CG.Shared.Dependencies.GetDependency(S, cgd, "random_" + FT.type, new String[0], FT, null); randomNumberGenerators.Add(funcName); randomNumberTimeSeedFuncs.Add(funcName + "_timeSeed"); } // for parsing test, subtract is required (first float type): string subtractGmvFuncName = G25.CG.Shared.Dependencies.GetDependency(S, cgd, "subtract", new String[] { S.m_GMV.Name, S.m_GMV.Name }, S.m_GMV.Name, S.m_floatTypes[0], null); string randomVersorFuncName = G25.CG.Shared.Dependencies.GetDependency(S, cgd, "random_versor", new String[0], S.m_GMV.Name, S.m_floatTypes[0], null); // for metric / getter setter: Dictionary<string, string> randomVersorFuncNames = new Dictionary<string, string>(); Dictionary<string, string> gpGmvFuncName = new Dictionary<string, string>(); // geometric product of all metrics and float types: { foreach (FloatType FT in S.m_floatTypes) { randomVersorFuncNames[FT.type] = G25.CG.Shared.Dependencies.GetDependency(S, cgd, "random_versor", new String[0], S.m_GMV.Name, FT, null); foreach (Metric M in S.m_metric) gpGmvFuncName[FT.type + "_" + M.m_name] = G25.CG.Shared.Dependencies.GetDependency(S, cgd, "gp", new String[] { S.m_GMV.Name, S.m_GMV.Name }, S.m_GMV.Name, FT, M.m_name); } } { // iteratively get all dependencies and generate their code int count = 0; List<fgs> missingFunctions = null, alreadyGeneratedMissingFunctions = new List<fgs>(); do { count = cgd.m_missingDependencies.Count; // we loop until the number of dependencies doesn't grow anymore missingFunctions = cgd.GetMissingDependenciesList(alreadyGeneratedMissingFunctions); G25.CG.Shared.Functions.WriteFunctions(S, cgd, null, Functions.GetFunctionGeneratorPlugins(cgd), missingFunctions); alreadyGeneratedMissingFunctions.AddRange(missingFunctions); } while (count < cgd.m_missingDependencies.Count); } // write code for all dependencies to output SB.AppendLine("// Missing dependencies declarations:"); SB.Append(cgd.m_declSB); SB.AppendLine("// Missing dependencies inline definitions:"); SB.Append(cgd.m_inlineDefSB); SB.AppendLine("// Missing dependencies definitions:"); SB.Append(cgd.m_defSB); cgd.ResetSB(); List<string> testFunctionNames = new List<string>(); // list of names of bool functionName(void) goes here { // write all 'other' test code // metric testFunctionNames.AddRange(WriteMetricTests(S, cgd, gpGmvFuncName)); // converters // todo . . . // get / set coordinates testFunctionNames.AddRange(WriteGetterSetterTests(S, cgd, randomNumberGenerators, randomVersorFuncNames)); // toString & parser (if available) if (S.m_parserType != PARSER.NONE) testFunctionNames.Add(WriteParserTest(S, cgd, randomNumberGenerators[0], randomVersorFuncName, subtractGmvFuncName)); } { // write all test functions // old, serial code: /*for (int i = 0; i < FGI.m_functionFGS.Count; i++) { if (FGI.m_functionGenerators[i] != null) { FGI.m_functionGenerators[i].WriteTestFunctionEntryPoint(); } }*/ { // in parallel: Thread[] testFunctionThreads = new Thread[FGI.m_functionFGS.Count]; for (int i = 0; i < FGI.m_functionFGS.Count; i++) { if (FGI.m_functionGenerators[i] != null) { testFunctionThreads[i] = new Thread(FGI.m_functionGenerators[i].WriteTestFunctionEntryPoint); } } G25.CG.Shared.Threads.StartThreadArray(testFunctionThreads); G25.CG.Shared.Threads.JoinThreadArray(testFunctionThreads); } // collect all the results from the threads: for (int f = 0; f < FGI.m_functionFGS.Count; f++) { if (FGI.m_functionGenerators[f] != null) { if (FGI.m_functionCgd[f].m_generatedTestFunctions != null) testFunctionNames.AddRange(FGI.m_functionCgd[f].m_generatedTestFunctions); cgd.m_declSB.Append(FGI.m_functionCgd[f].m_declSB); cgd.m_defSB.Append(FGI.m_functionCgd[f].m_defSB); cgd.m_inlineDefSB.Append(FGI.m_functionCgd[f].m_inlineDefSB); } } } // write code for all testing code to output SB.AppendLine("// Testing code declarations:"); SB.Append(cgd.m_declSB); SB.AppendLine("// Testing code inline definitions:"); SB.Append(cgd.m_inlineDefSB); SB.AppendLine("// Testing code definitions:"); SB.Append(cgd.m_defSB); // write main function cgd.m_cog.EmitTemplate(SB, "testSuiteMain", "S=", S, "testFunctionNames=", testFunctionNames.ToArray(), "randomNumberSeedFunctionNames=", randomNumberTimeSeedFuncs.ToArray()); // write all to file G25.CG.Shared.Util.WriteFile(sourceFilename, SB.ToString()); return generatedFiles; }