Ejemplo n.º 1
0
        /// <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;
        }
Ejemplo n.º 2
0
        /// <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);
        }
Ejemplo n.º 3
0
        /// <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()
Ejemplo n.º 4
0
        /// <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()
Ejemplo n.º 5
0
 /// <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);
 }
Ejemplo n.º 6
0
        /// <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()