static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");

            var unit   = new CodeCompilationUnit();
            var ns     = unit.AddNamespace("Meziantou.CodeDom");
            var c      = ns.AddType(new CodeClassDeclaration("Sample"));
            var method = c.AddMember(new CodeMethodDeclaration("Factorial"));

            method.ReturnType = typeof(int);
            var n = method.AddArgument("n", typeof(int));

            method.Modifiers = Modifiers.Public | Modifiers.Static;

            method.Statements = new CodeConditionStatement()
            {
                Condition       = new CodeBinaryExpression(BinaryOperator.LessThanOrEqual, 1, n),
                TrueStatements  = new CodeReturnStatement(1),
                FalseStatements = new CodeReturnStatement(new CodeBinaryExpression(
                                                              BinaryOperator.Multiply,
                                                              n,
                                                              new CodeMethodInvokeExpression(method, new CodeBinaryExpression(BinaryOperator.Substract, n, 1))))
            };

            var generator = new CSharpCodeGenerator();

            Console.WriteLine(generator.Write(unit));
        }
        public void RebuildLibraryAndAPI()
        {
            UpdateMsBuildPath();
            CheckIspcBinary();

            ProjectConfigKind configKind = ProjectConfigKind;
            SimpleVcxProjGen  gen        = new SimpleVcxProjGen();
            //set some proprties

            //eg. IspcFilename=> simple.ispc

            string onlyProjectName = Path.GetFileNameWithoutExtension(IspcFilename);

            gen.ProjectName = onlyProjectName; //project name and output

            string current_dir = Directory.GetCurrentDirectory();
            string tmp_dir     = current_dir + "/temp";

            gen.FullProjSrcPath   = current_dir;
            gen.FullProjBuildPath = tmp_dir;
            string finalProductName = gen.GetFinalProductName(configKind);

            //-----
            CreateDirIfNotExists(tmp_dir);
            //

            string ispc_src       = IspcFilename;
            string ispc_obj       = tmp_dir + "/" + onlyProjectName + ".obj";
            string ispc_llvm_text = tmp_dir + "/" + onlyProjectName + "_ispc.llvm.txt";
            string ispc_cpp       = tmp_dir + "/" + onlyProjectName + "_ispc.cpp";
            string ispc_header    = tmp_dir + "/" + onlyProjectName + "_ispc.h";


            //generate header and object file in temp dir
            var procStartInfo = new System.Diagnostics.ProcessStartInfo(s_ispc,
                                                                        $"{ispc_src} -O2 -o {ispc_obj} -h {ispc_header}");

            //$"{ispc_src} --emit-c++ -o {ispc_cpp}");
            //$"{ispc_src} --emit-llvm-text -o {ispc_llvm_text} -h {ispc_header}");

            procStartInfo.UseShellExecute        = false;
            procStartInfo.RedirectStandardOutput = true;
            procStartInfo.RedirectStandardError  = true;

            System.Diagnostics.Process proc = System.Diagnostics.Process.Start(procStartInfo);


            StreamReader errReader = proc.StandardError;
            {
                string line = errReader.ReadLine();
                while (line != null)
                {
                    System.Diagnostics.Debug.WriteLine(line);
                    line = errReader.ReadLine();
                }
            }
            StreamReader outputStrmReader = proc.StandardOutput;

            {
                string line = outputStrmReader.ReadLine();
                while (line != null)
                {
                    System.Diagnostics.Debug.WriteLine(line);
                    line = outputStrmReader.ReadLine();
                }
            }

            proc.WaitForExit();

            int exit_code2 = proc.ExitCode;

            if (exit_code2 != 0)
            {
                throw new NotSupportedException();
            }
            //----------
            //now read auto-gen header

            string c_interface_filename = gen.FullProjSrcPath + "/" + onlyProjectName + ".cpp";

            CodeCompilationUnit cu = ParseAutoGenHeaderFromFile(ispc_header);

            GenerateCBinder(cu, ispc_header, c_interface_filename);

            string cs_method_invoke_filename = onlyProjectName + ".cs"; //save to

            GenerateCsBinder(cu, ispc_header, cs_method_invoke_filename, Path.GetFileName(finalProductName));

            //move cs code to src folder
            if (AutoCsTargetFile != null)
            {
                MoveFileOrReplaceIfExists(cs_method_invoke_filename, AutoCsTargetFile);
            }

            //
            //at this step we have object file and header
            //build a cpp dll with msbuild
            gen.AddObjectFile(ispc_obj);
            gen.AddIncludeFile(ispc_header);
            //add our c-interface
            gen.AddCompileFile(c_interface_filename);

            if (AdditionalInputItems != null)
            {
                foreach (string s in AdditionalInputItems)
                {
                    switch (Path.GetExtension(s))
                    {
                    default: throw new NotSupportedException();

                    case ".c":
                    case ".cpp":
                        gen.AddCompileFile(s);
                        break;

                    case ".h":
                    case ".hpp":
                        gen.AddIncludeFile(s);
                        break;

                    case ".obj":
                        gen.AddObjectFile(s);
                        break;
                    }
                }
            }


            VcxProject project = gen.CreateVcxTemplate();

            XmlOutputGen xmlOutput = new XmlOutputGen();

            project.GenerateOutput(xmlOutput);

            string vxs_projOutputFilename = "ispc_autogen.xml.vcxproj";

            File.WriteAllText(vxs_projOutputFilename, xmlOutput.Output.ToString());

            //debug build or release build

            string p_config = "";

            switch (configKind)
            {
            default: throw new NotSupportedException();

            case ProjectConfigKind.Debug:
                p_config = " /p:configuration=debug";
                break;

            case ProjectConfigKind.Release:
                p_config = " /p:configuration=release";
                break;
            }

            System.Diagnostics.Process proc1 = System.Diagnostics.Process.Start(s_MsBuildPath, vxs_projOutputFilename + p_config);
            proc1.WaitForExit();
            int exit_code1 = proc1.ExitCode;

            if (exit_code1 != 0)
            {
                throw new NotSupportedException();
            }

            //build pass, then copy the result dll back
            MoveFileOrReplaceIfExists(finalProductName, Path.GetFileName(finalProductName));
        }
        /// <summary>
        /// generate C binder
        /// </summary>
        /// <param name="ispc_headerFilename"></param>
        /// <param name="outputC_filename"></param>
        void GenerateCBinder(CodeCompilationUnit cu, string ispc_headerFilename, string outputC_filename)
        {
            //from cu=> we generate interface c
            CodeStringBuilder sb = new CodeStringBuilder();

            sb.AppendLine("//AUTOGEN," + DateTime.Now.ToString("s"));
            sb.AppendLine("//Tools: ispc and BridgeBuilder");
            sb.AppendLine("//Src: " + ispc_headerFilename);

            sb.AppendLine("#include <stdio.h>");
            sb.AppendLine("#include <stdlib.h>");
            sb.AppendLine("//Include the header file that the ispc compiler generates");
            sb.AppendLine($"#include \"{ Path.GetFileName(ispc_headerFilename) }\"");

            sb.AppendLine(@"#ifdef _WIN32 
#define MY_DLL_EXPORT __declspec(dllexport)
#else 
#define MY_DLL_EXPORT
#endif
 ");

            sb.AppendLine("using namespace ispc;");
            //c_inf.AppendLine("using namespace ispc;");
            sb.AppendLine("extern \"C\"{");

            foreach (CodeMemberDeclaration mb in cu.GlobalTypeDecl.GetMemberIter())
            {
                if (mb is CodeTypeDeclaration namespaceDecl &&
                    namespaceDecl.Kind == TypeKind.Namespace)
                {
                    //ispc output

                    //iterate member inside the current namespace
                    foreach (CodeMemberDeclaration nsMember in namespaceDecl.GetMemberIter())
                    {
                        if (nsMember is CodeMethodDeclaration met)
                        {
                            sb.AppendLine("MY_DLL_EXPORT "); //WINDOWS

                            sb.Append(met.ToString(IspcBridgeFunctionNamePrefix));

                            sb.AppendLine("{");
                            string ret = met.ReturnType.ToString();
                            if (ret != "void")
                            {
                                sb.Append("return ");
                            }
                            sb.Append("ispc::" + met.Name + "(");

                            int par_i = 0;
                            foreach (CodeMethodParameter par in met.Parameters)
                            {
                                if (par_i > 0)
                                {
                                    sb.Append(",");
                                }
                                sb.Append(par.ParameterName);
                                par_i++;
                            }
                            sb.AppendLine(");");
                            sb.AppendLine("}");
                        }
                        else if (nsMember is CodeTypeDeclaration other && other.Kind == TypeKind.Struct)
                        {
                            //skip C struct  regen
                        }