Esempio n. 1
0
        // Group: Initialization Functions
        // __________________________________________________________________________


        /* Function: Start_Stage1
         *
         * Loads and combines the two versions of <Languages.txt>, returning whether it was successful.  If there were any
         * errors they will be added to errorList.
         *
         * Only the settings which don't depend on <Comments.txt> will be loaded.  Call <Start_Stage2()> after
         * <CommentTypes.Manager.Start_Stage1()> has been called to complete the process.
         *
         * Dependencies:
         *
         *		- <Config.Manager> must be started before this class can start.
         */
        public bool Start_Stage1(Errors.ErrorList errorList)
        {
            StartupIssues newStartupIssues = StartupIssues.None;
            bool          success          = true;


            //
            // Languages.txt
            //

            Path systemTextConfigPath  = EngineInstance.Config.SystemConfigFolder + "/Languages.txt";
            Path projectTextConfigPath = EngineInstance.Config.ProjectConfigFolder + "/Languages.txt";

            ConfigFiles.TextFileParser textConfigFileParser = new ConfigFiles.TextFileParser();

            // Load the system Languages.txt.
            if (!textConfigFileParser.Load(systemTextConfigPath, PropertySource.SystemLanguagesFile, errorList, out systemTextConfig))
            {
                success = false;
            }

            // Load the project Languages.txt.  We want to do this even if the system Languages.txt failed so we get the error messages
            // from both.
            if (System.IO.File.Exists(projectTextConfigPath))
            {
                if (!textConfigFileParser.Load(projectTextConfigPath, PropertySource.ProjectLanguagesFile, errorList, out projectTextConfig))
                {
                    success = false;
                }
            }
            // If it doesn't exist it's not an error.  Just create a blank config.
            else
            {
                projectTextConfig = new ConfigFiles.TextFile();
            }

            if (!success)
            {
                return(false);
            }

            if (!ValidateLanguages(systemTextConfig, errorList))
            {
                success = false;
            }
            if (!ValidateLanguages(projectTextConfig, errorList))
            {
                success = false;
            }

            if (!success)
            {
                return(false);
            }

            // Merge them into one combined config.  Note that this doesn't do file extensions, aliases, or shebang strings.  Only the
            // languages and their other properties will exist in the merged config.
            if (!MergeLanguages(systemTextConfig, projectTextConfig, out mergedTextConfig, errorList))
            {
                return(false);
            }
            if (!ValidateLanguages(mergedTextConfig, errorList))
            {
                return(false);
            }


            //
            // Languages.nd
            //

            Path lastRunConfigPath = EngineInstance.Config.WorkingDataFolder + "/Languages.nd";

            ConfigFiles.BinaryFileParser binaryConfigFileParser = new ConfigFiles.BinaryFileParser();

            // If we need to start fresh anyway we can skip loading the file and create a blank config
            if (EngineInstance.HasIssues(StartupIssues.NeedToStartFresh |
                                         StartupIssues.CommentIDsInvalidated |
                                         StartupIssues.CodeIDsInvalidated) ||

                // though if that wasn't the case but we failed at loading the file, the result is the same
                !binaryConfigFileParser.Load(lastRunConfigPath, out lastRunConfig))
            {
                lastRunConfig = new Config();

                newStartupIssues |= StartupIssues.NeedToReparseAllFiles |
                                    StartupIssues.CodeIDsInvalidated;
            }


            //
            // Create the final config
            //

            config = new Config();


            // We go through the languages present in the merged text config files and convert them into the final config.  We
            // need the contents of Comments.nd so we can keep the language IDs consistent from one run to the next if possible.

            IDObjects.NumberSet usedLanguageIDs        = new IDObjects.NumberSet();
            IDObjects.NumberSet lastRunUsedLanguageIDs = lastRunConfig.UsedLanguageIDs();

            if (mergedTextConfig.HasLanguages)
            {
                foreach (var textLanguage in mergedTextConfig.Languages)
                {
                    // First we need our base language object.  If there's a predefined language matching the name we'll use that so
                    // we get its settings and parser.  If not we'll create a new object.  We shouldn't have to worry about more than one
                    // language using the same predefined language object because validation should have taken care of that.
                    var finalLanguage = FindPredefinedLanguage(textLanguage.Name);

                    if (finalLanguage == null)
                    {
                        finalLanguage = new Language(textLanguage.Name);
                    }

                    // Apply the properties.  Keep going if there are errors since we want to find them all.
                    if (!FinalizeLanguage(ref finalLanguage, textLanguage, errorList))
                    {
                        success = false;
                    }

                    // We still need to set the ID.  See if a language of the same name existed in the previous run.
                    var lastRunLanguage = lastRunConfig.LanguageFromName(textLanguage.Name);

                    // If there wasn't one we can assign a new ID, but pick one that isn't used in this run or the last run so there's no
                    // conflicts.
                    if (lastRunLanguage == null)
                    {
                        int id = lastRunUsedLanguageIDs.LowestAvailable;

                        if (usedLanguageIDs.Contains(id))
                        {
                            id = Math.Max(usedLanguageIDs.Highest + 1, lastRunUsedLanguageIDs.Highest + 1);
                        }

                        finalLanguage.ID = id;
                        config.AddLanguage(finalLanguage);

                        usedLanguageIDs.Add(finalLanguage.ID);
                        lastRunUsedLanguageIDs.Add(finalLanguage.ID);
                    }
                    // If the language did exist but we haven't used its ID yet, we can keep it.
                    else if (!usedLanguageIDs.Contains(lastRunLanguage.ID))
                    {
                        finalLanguage.ID = lastRunLanguage.ID;
                        config.AddLanguage(finalLanguage);

                        usedLanguageIDs.Add(finalLanguage.ID);
                    }
                    // However, if the language did exist and we assigned that ID already, then we have a conflict and have to tell the
                    // engine that the IDs from the last run were invalidated.  We can just assign anything unused at this point since it
                    // no longer matters.
                    else
                    {
                        finalLanguage.ID = usedLanguageIDs.LowestAvailable;
                        config.AddLanguage(finalLanguage);

                        usedLanguageIDs.Add(finalLanguage.ID);
                        newStartupIssues |= StartupIssues.CodeIDsInvalidated;
                    }

                    // Now that we have a final ID, set the simple identifier for any type that still needs it.  Some types may have it null if
                    // it wasn't manually defined and the name didn't contain A-Z characters.
                    if (finalLanguage.SimpleIdentifier == null)
                    {
                        finalLanguage.SimpleIdentifier = "LanguageID" + finalLanguage.ID;
                    }

                    // Also create a generic parser object if one wasn't inherited from a predefined language.
                    if (!finalLanguage.HasParser)
                    {
                        finalLanguage.Parser = new Parser(EngineInstance, finalLanguage);
                    }
                }
            }

            if (!success)
            {
                return(false);
            }


            // Apply file extensions, aliases, and shebang strings now.

            MergeLanguageIdentifiersInto(ref config, systemTextConfig, projectTextConfig);


            // That's it for stage one.  Everything else is in stage 2.

            if (newStartupIssues != StartupIssues.None)
            {
                EngineInstance.AddStartupIssues(newStartupIssues);
            }

            return(true);
        }
Esempio n. 2
0
        /* Function: Start_Stage2
         *
         * Finishes loading and and combing the two versions of <Languages.txt>, returning whether it was successful.  If there
         * were any errors they will be added to errorList.
         *
         * This must be called after <Start_Stage1()> has been called, and also <CommentTypes.Manager.Start_Stage1()>.  This
         * finalizes any settings which also depend on <Comments.txt>.
         *
         * Dependencies:
         *
         *		- <Config.Manager> must be started before this class can start.
         *		- <Start_Stage1()> must be called and return true before this function can be called.
         *		- <CommentTypes.Manager.Start_Stage1()> must be called and return true before this function can be called.
         */
        public bool Start_Stage2(Errors.ErrorList errorList)
        {
            bool success = true;


            // Go through the lists and apply prototype enders, since CommentTypes.Manager should have all their names now.

            if (!MergePrototypeEndersInto_Stage2(ref config, systemTextConfig, errorList))
            {
                success = false;
            }
            if (!MergePrototypeEndersInto_Stage2(ref config, projectTextConfig, errorList))
            {
                success = false;
            }

            if (!success)
            {
                return(false);
            }


            // Now we have our final configuration and everything is okay.  Save the text files again to reformat them.

            TouchUp_Stage2(ref systemTextConfig, config);
            TouchUp_Stage2(ref projectTextConfig, config);

            Path systemTextConfigPath  = EngineInstance.Config.SystemConfigFolder + "/Languages.txt";
            Path projectTextConfigPath = EngineInstance.Config.ProjectConfigFolder + "/Languages.txt";

            ConfigFiles.TextFileParser textConfigFileParser = new ConfigFiles.TextFileParser();

            // If the project Languages.txt didn't exist, saving the blank structure that was created will create a default one.
            if (!textConfigFileParser.Save(projectTextConfigPath, PropertySource.ProjectLanguagesFile, projectTextConfig, errorList))
            {
                return(false);
            }
            ;

            // We don't care if we're not able to resave the system Languages.txt since it may be in a protected location.
            textConfigFileParser.Save(systemTextConfigPath, PropertySource.SystemLanguagesFile, systemTextConfig, errorList: null);


            // Save Languages.nd as well.

            Path lastRunConfigPath = EngineInstance.Config.WorkingDataFolder + "/Languages.nd";

            ConfigFiles.BinaryFileParser binaryConfigFileParser = new ConfigFiles.BinaryFileParser();

            binaryConfigFileParser.Save(lastRunConfigPath, config);


            // Compare the config against the previous one and reparse everything if there are changes.  Changes that would invalidate
            // IDs have already been handled.

            if (config != lastRunConfig)
            {
                EngineInstance.AddStartupIssues(StartupIssues.NeedToReparseAllFiles);
            }


            // We're done with these variables which were only needed between start stages 1 and 2.

            systemTextConfig  = null;
            projectTextConfig = null;
            mergedTextConfig  = null;
            lastRunConfig     = null;

            started = true;
            return(true);
        }