/// <summary> /// Should generate the code according to the specification of the algebra. /// </summary> /// <param name="S">The specification of the algebra. The specification also lists the names of the files /// to be generated, or at least the base path.</param> /// <param name="plugins">The plugins which Gaigen found that support the same language as this code generator.</param> /// <returns>a list of filenames; the names of the files that were generated. This may be used /// for post processing.</returns> public List<string> GenerateCode(Specification S, List<CodeGeneratorPlugin> plugins) { // disable all inlining since the Java language does not support this: S.SetInlineNone(); CreatePackageDirectory(S); CoGsharp.CoG cog = InitCog(S); CG.Shared.CGdata cgd = new G25.CG.Shared.CGdata(plugins, cog); cgd.SetDependencyPrefix("missing_function_"); // this makes sure that the user sees the function call is a missing dependency G25.CG.Shared.FunctionGeneratorInfo FGI = (S.m_generateTestSuite) ? new G25.CG.Shared.FunctionGeneratorInfo() : null; // the fields in this variable are set by Functions.WriteFunctions() and reused by TestSuite.GenerateCode() { // pregenerated code that will go into main source // generate code for parts of the geometric product, dual, etc (works in parallel internally) try { bool declOnly = false; G25.CG.Shared.PartsCode.GeneratePartsCode(S, cgd, declOnly); } catch (G25.UserException E) { cgd.AddError(E); } // write function (works in parallel internally) G25.CG.Shared.Functions.WriteFunctions(S, cgd, FGI, Functions.GetFunctionGeneratorPlugins(cgd)); } List<string> generatedFiles = new List<string>(); // generate Doxyfile generatedFiles.Add(G25.CG.Shared.Util.GenerateDoxyfile(S, cgd)); // generate source files / classes for all GMV, SMV, GOM, SOM types generatedFiles.AddRange(GenerateClasses(S, cgd)); // generate source generatedFiles.AddRange(Source.GenerateCode(S, cgd)); // generate smv type enum generatedFiles.AddRange(SmvType.GenerateCode(S, cgd)); // generate GroupBitmap class generatedFiles.AddRange(GroupBitmap.GenerateCode(S, cgd)); // generate multivector interfaces generatedFiles.AddRange(MvInterface.GenerateCode(S, cgd)); // generate parser generatedFiles.AddRange(Parser.GenerateCode(S, cgd)); // generate report usage code generatedFiles.AddRange(ReportUsage.GenerateCode(S, cgd)); // report errors and missing deps to user cgd.PrintErrors(S); cgd.PrintMissingDependencies(S); if ((cgd.GetNbErrors() == 0) && (cgd.GetNbMissingDependencies() == 0) && S.m_generateTestSuite) { // generate test suite generatedFiles.AddRange(TestSuite.GenerateCode(S, cgd, FGI)); } return generatedFiles; }
/// <summary> /// Generate all code according to the specification of the algebra. /// </summary> /// <param name="S">The specification of the algebra. The specification also lists the names of the files /// to be generated, or at least the base path.</param> /// <param name="plugins">The plugins which Gaigen found that support the same language as this code generator.</param> /// <returns>a list of filenames; the names of the files that were generated. This may be used /// for post processing.</returns> public List <string> GenerateCode(Specification S, List <CodeGeneratorPlugin> plugins) { // disable all inlining since the C language does not support this: S.SetInlineNone(); CoGsharp.CoG cog = InitCog(S); CG.Shared.CGdata cgd = new G25.CG.Shared.CGdata(plugins, cog); cgd.SetDependencyPrefix("missing_function_"); // this makes sure that the user sees the function call is a missing dependency G25.CG.Shared.FunctionGeneratorInfo FGI = (S.m_generateTestSuite) ? new G25.CG.Shared.FunctionGeneratorInfo() : null; // the fields in this variable are set by Functions.WriteFunctions() and reused by TestSuite.GenerateCode() { // pregenerated code that will go into header, source // generate code for parts of the geometric product, dual, etc (works in parallel internally) try { bool declOnly = false; G25.CG.Shared.PartsCode.GeneratePartsCode(S, cgd, declOnly); } catch (G25.UserException E) { cgd.AddError(E); } // write set zero, set, copy, copy between float types, extract coordinate, largest coordinate, etc (works in parallel internally) try { GenerateSetFunctions(S, plugins, cgd); } catch (G25.UserException E) { cgd.AddError(E); } // write function (works in parallel internally) G25.CG.Shared.Functions.WriteFunctions(S, cgd, FGI, Functions.GetFunctionGeneratorPlugins(cgd)); } List <string> generatedFiles = new List <string>(); // generate Doxyfile generatedFiles.Add(G25.CG.Shared.Util.GenerateDoxyfile(S, cgd)); // generate header generatedFiles.AddRange(Header.GenerateCode(S, cgd)); // generate source generatedFiles.AddRange(Source.GenerateCode(S, cgd)); // generate parser generatedFiles.AddRange(Parser.GenerateCode(S, cgd)); // report errors and missing deps to user cgd.PrintErrors(S); cgd.PrintMissingDependencies(S); if ((cgd.GetNbErrors() == 0) && (cgd.GetNbMissingDependencies() == 0) && S.m_generateTestSuite) { // if no errors, then generate testing code TestSuite.GenerateCode(S, cgd, FGI); } // Generate random number generator source code (Mersenne Twister). // This must be done last since the testing code may require it! if (cgd.GetFeedback(G25.CG.C.MainGenerator.MERSENNE_TWISTER) == "true") { generatedFiles.AddRange(RandomMT.GenerateCode(S, cgd)); } 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 = 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(); // output license, copyright G25.CG.Shared.Util.WriteCopyright(SB, S); G25.CG.Shared.Util.WriteLicense(SB, S); // using ... Util.WriteGenericUsing(SB, S); G25.CG.Shared.Util.WriteOpenNamespace(SB, S); G25.CG.Shared.Util.WriteOpenClass(SB, S, G25.CG.Shared.AccessModifier.AM_public, "TestSuite", new string[] { S.m_namespace }, null); // 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); } // 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 (todo: in parallel (is easy because they all have their own CGdata, just see in Functions.WriteFunctions() how it's done) // NOTE THAT m_errors and m_missingDependencies of each function cgd are shared with main cgd! for (int i = 0; i < FGI.m_functionFGS.Count; i++) { if (FGI.m_functionGenerators[i] != null) { FGI.m_functionGenerators[i].CheckTestingDepenciesEntryPoint(); } } // 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) { 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); Dictionary <String, String> gpGmvFuncName = new Dictionary <string, string>(); // geometric product of all metrics and float types: { foreach (FloatType FT in S.m_floatTypes) { 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 definitions:"); SB.Append(cgd.m_defSB); cgd.ResetSB(); List <string> testFunctionNames = new List <string>(); // list of names of bool functionName(void) goes here // metric, parser test { // write all 'other' test code (metric, parsing) // metric testFunctionNames.AddRange(WriteMetricTests(S, cgd, gpGmvFuncName)); // converters // toString & parser (if available) if (S.m_parserType != PARSER.NONE) { testFunctionNames.Add(WriteParserTest(S, cgd, randomNumberGenerators[0], randomVersorFuncName, subtractGmvFuncName)); } } { // write all test functions { 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()); // close class G25.CG.Shared.Util.WriteCloseClass(SB, S, "TestSuite"); // close namespace G25.CG.Shared.Util.WriteCloseNamespace(SB, S); // write all to file G25.CG.Shared.Util.WriteFile(sourceFilename, SB.ToString()); return(generatedFiles); } // end of GenerateCode()
/// <summary> /// Writes code for all functions to <c>cgd.m_defSB</c>, <c>cgd.m_inlineDefSB and</c> <c>cgd.m_declSB</c>. /// /// Takes an explicit list of functions (used by <c>TestSuite.GenerateCode()</c>). /// </summary> /// <param name="S"></param> /// <param name="cgd">Generated code goes here</param> /// <param name="FGI">Info about what plugin should implement what function /// The member variables are initialized by this function. <c>FGI</c> can be null when /// no testing code is generated. This allows the memory of the FunctionGenerators to be released /// earlier on.</param> /// <param name="plugins">The available function generators.</param> /// <param name="functions">List of <c>G25.fgs</c> to implement.</param> public static void WriteFunctions( Specification S, G25.CG.Shared.CGdata cgd, G25.CG.Shared.FunctionGeneratorInfo FGI, List <G25.CG.Shared.BaseFunctionGenerator> plugins, List <G25.fgs> functions) { // first split functions into converters and regular functions List <G25.fgs> converterFGS = new List <fgs>(); List <G25.fgs> functionFGS = new List <fgs>(); foreach (G25.fgs F in functions) { if (F.IsConverter(S)) // is 'F' a converter (underscore constructor)? { converterFGS.Add(F); } else { functionFGS.Add(F); } } // store converterFGS and functionFGS in FGI, for later use by TestSuite.GenerateCode() if (FGI != null) { FGI.m_converterFGS = converterFGS; FGI.m_functionFGS = functionFGS; } // start threads to generate code for all converters Thread[] converterThreads = new Thread[converterFGS.Count]; Converter[] converters = new Converter[converterFGS.Count]; for (int f = 0; f < converterFGS.Count; f++) { G25.fgs F = converterFGS[f]; converters[f] = new Converter(S, cgd, F); converterThreads[f] = new Thread(converters[f].WriteConverter); } G25.CG.Shared.Threads.StartThreadArray(converterThreads); // find out which plugin can implement which FGS Thread[] functionThreads = new Thread[functionFGS.Count]; G25.CG.Shared.BaseFunctionGenerator[] functionGenerators = new G25.CG.Shared.BaseFunctionGenerator[functionFGS.Count]; G25.CG.Shared.CGdata[] functionCgd = new G25.CG.Shared.CGdata[functionFGS.Count]; for (int f = 0; f < functionFGS.Count; f++) { G25.fgs F = functionFGS[f]; foreach (G25.CG.Shared.BaseFunctionGenerator P in plugins) // check all C plugins { if (P.CanImplement(S, F)) // ask them if they can handle 'F' { // get a clean instance of the code generator and initialize it functionGenerators[f] = System.Activator.CreateInstance(P.GetType()) as BaseFunctionGenerator; functionCgd[f] = new G25.CG.Shared.CGdata(cgd); // m_errors and m_missingDependencies will be shared with main cgd! functionGenerators[f].Init(S, F, functionCgd[f]); F.SetSupportedByPlugin(); break; } } if (!F.GetSupportedByPlugin()) {// no plugin could do 'F': complain about it System.Console.WriteLine("Warning no suitable plugin for function " + F.Name + "; XML specification: "); System.Console.WriteLine(" " + XML.FunctionToXmlString(S, F)); } } // store functionGenerators in FGI, for later use by TestSuite.GenerateCode() if (FGI != null) { FGI.m_functionGenerators = functionGenerators; FGI.m_functionCgd = functionCgd; } // run threads for fill-in of functions for (int f = 0; f < functionFGS.Count; f++) { if (functionGenerators[f] == null) { continue; } functionThreads[f] = new Thread(functionGenerators[f].CompleteFGSentryPoint); } G25.CG.Shared.Threads.StartThreadArray(functionThreads); G25.CG.Shared.Threads.JoinThreadArray(functionThreads); //G25.CG.Shared.Threads.RunThreadArraySerially(functionThreads); // runs thread for dependency check of functions for (int f = 0; f < functionFGS.Count; f++) { if (functionGenerators[f] == null) { continue; } functionThreads[f] = new Thread(functionGenerators[f].CheckDepenciesEntryPoint); } G25.CG.Shared.Threads.StartThreadArray(functionThreads); G25.CG.Shared.Threads.JoinThreadArray(functionThreads); //G25.CG.Shared.Threads.RunThreadArraySerially(functionThreads); // runs thread for actual code generation of functions for (int f = 0; f < functionFGS.Count; f++) { if (functionGenerators[f] == null) { continue; } functionThreads[f] = new Thread(functionGenerators[f].WriteFunctionEntryPoint); } G25.CG.Shared.Threads.StartThreadArray(functionThreads); //G25.CG.Shared.Threads.RunThreadArraySerially(functionThreads); // join all the converter threads: G25.CG.Shared.Threads.JoinThreadArray(converterThreads); // join all function generation threads G25.CG.Shared.Threads.JoinThreadArray(functionThreads); // collect all the results from the threads: for (int f = 0; f < converters.Length; f++) { cgd.m_declSB.Append(converters[f].m_declSB); cgd.m_defSB.Append(converters[f].m_defSB); cgd.m_inlineDefSB.Append(converters[f].m_inlineDefSB); cgd.MergeErrors(converters[f].m_cgd); } // collect all the results from the threads: for (int f = 0; f < functionCgd.Length; f++) { if (functionGenerators[f] == null) { continue; } cgd.m_declSB.Append(functionCgd[f].m_declSB); cgd.m_defSB.Append(functionCgd[f].m_defSB); cgd.m_inlineDefSB.Append(functionCgd[f].m_inlineDefSB); } } // end of WriteFunctions()
/// <summary> /// Writes code for all functions to <c>cgd.m_defSB</c>, <c>cgd.m_inlineDefSB and</c> <c>cgd.m_declSB</c>. /// /// This is the regular entrypoint. The other <c>WriteFunctions()</c> takes an explicit list /// of functions and is used by <c>TestSuite.GenerateCode()</c>. /// </summary> /// <param name="S"></param> /// <param name="cgd">Generated code goes here</param> /// <param name="FGI">Info about what plugin should implement what function /// The member variables are initialized by this function. <c>FGI</c> can be null when /// no testing code is generated. This allows the memory of the FunctionGenerators to be released /// earlier on.</param> /// <param name="plugins">The available function generators.</param> public static void WriteFunctions(Specification S, G25.CG.Shared.CGdata cgd, G25.CG.Shared.FunctionGeneratorInfo FGI, List <G25.CG.Shared.BaseFunctionGenerator> plugins) { WriteFunctions(S, cgd, FGI, plugins, S.m_functions); }
/// <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); } // end of GenerateCode()