예제 #1
0
        /* Function: Load
         * Loads <Style.txt> and returns it as a <Styles.Advanced> object.  If there are any errors found in <Style.txt> they will be added
         * to the list and the function will return null.
         */
        public Styles.Advanced Load(Path path, Errors.ErrorList errors)
        {
            Styles.Advanced style = new Styles.Advanced(path);

            using (ConfigFile file = new ConfigFile())
            {
                if (!file.Open(path,
                               Config.PropertySource.StyleConfigurationFile,
                               ConfigFile.FileFormatFlags.MakeIdentifiersLowercase |
                               ConfigFile.FileFormatFlags.CondenseIdentifierWhitespace, errors))
                {
                    return(null);
                }

                int    errorCount = errors.Count;
                string lcIdentifier, value;
                System.Text.RegularExpressions.Match match;

                while (file.Get(out lcIdentifier, out value))
                {
                    // Inherit

                    if (inheritRegex.IsMatch(lcIdentifier))
                    {
                        style.AddInheritedStyle(value, file.PropertyLocation, null);
                        continue;
                    }


                    // Link

                    match = linkRegex.Match(lcIdentifier);
                    if (match.Success)
                    {
                        PageType pageType = PageType.All;
                        if (match.Groups[1].Success)
                        {
                            PageType?pageTypeTemp = PageTypes.FromName(match.Groups[1].ToString());

                            if (pageTypeTemp == null)
                            {
                                file.AddError(Locale.Get("NaturalDocs.Engine", "ConfigFile.NotAValidIdentifier(identifier)", lcIdentifier));
                            }
                            else
                            {
                                pageType = pageTypeTemp.Value;
                            }
                        }

                        Path linkedFile = value;

                        if (!Styles.Manager.LinkableFileExtensions.Contains(linkedFile.Extension))
                        {
                            file.AddError(Locale.Get("NaturalDocs.Engine", "Style.txt.CantLinkFileWithExtension(extension)",
                                                     linkedFile.Extension));
                        }
                        else if (linkedFile.Extension.ToLower() == "css" && pageType != PageType.All)
                        {
                            file.AddError(Locale.Get("NaturalDocs.Engine", "Style.txt.CantLinkCSSFileToSpecificPageTypes(pageType)",
                                                     PageTypes.NameOf(pageType)));
                        }
                        else
                        {
                            if (linkedFile.IsRelative)
                            {
                                linkedFile = style.Folder + "/" + linkedFile;
                            }

                            if (!System.IO.File.Exists(linkedFile))
                            {
                                file.AddError(Locale.Get("NaturalDocs.Engine", "Style.txt.CantFindLinkedFile(name)", linkedFile));
                            }
                            else if (!style.Folder.Contains(linkedFile))
                            {
                                file.AddError(Locale.Get("NaturalDocs.Engine", "Style.txt.LinkedFileMustBeInStyleFolder(name, folder)", linkedFile, style.Folder));
                            }
                            else
                            {
                                style.AddLinkedFile(linkedFile, file.PropertyLocation, pageType);
                            }
                        }

                        continue;
                    }


                    // OnLoad

                    match = onLoadRegex.Match(lcIdentifier);
                    if (match.Success)
                    {
                        PageType pageType = PageType.All;
                        if (match.Groups[1].Success)
                        {
                            PageType?pageTypeTemp = PageTypes.FromName(match.Groups[1].ToString());

                            if (pageTypeTemp == null)
                            {
                                file.AddError(Locale.Get("NaturalDocs.Engine", "ConfigFile.NotAValidIdentifier(identifier)", lcIdentifier));
                            }
                            else
                            {
                                pageType = pageTypeTemp.Value;
                            }
                        }

                        style.AddOnLoad(value, file.PropertyLocation, pageType);
                        continue;
                    }


                    // Home Page

                    if (homePageRegex.IsMatch(lcIdentifier))
                    {
                        Path   homePageFile = value;
                        string lcExtension  = homePageFile.Extension.ToLower();

                        if (lcExtension != "html" && lcExtension != "htm")
                        {
                            file.AddError(Locale.Get("NaturalDocs.Engine", "Style.txt.HomePageMustHaveHTMLExtension(extension)",
                                                     homePageFile.Extension));
                        }
                        else
                        {
                            if (homePageFile.IsRelative)
                            {
                                homePageFile = style.Folder + "/" + homePageFile;
                            }

                            if (!System.IO.File.Exists(homePageFile))
                            {
                                file.AddError(Locale.Get("NaturalDocs.Engine", "Style.txt.CantFindHomePageFile(name)", homePageFile));
                            }
                            else if (!style.Folder.Contains(homePageFile))
                            {
                                file.AddError(Locale.Get("NaturalDocs.Engine", "Style.txt.HomePageFileMustBeInStyleFolder(name, folder)", homePageFile, style.Folder));
                            }
                            else
                            {
                                style.SetHomePage(homePageFile, file.PropertyLocation);
                            }
                        }

                        continue;
                    }


                    file.AddError(Locale.Get("NaturalDocs.Engine", "ConfigFile.NotAValidIdentifier(identifier)", lcIdentifier));
                }


                // Check for files or JavaScript linked to custom home pages since they wouldn't apply.

                if (style.HomePage != null)
                {
                    if (style.Links != null)
                    {
                        foreach (var link in style.Links)
                        {
                            if (link.Type == PageType.Home)
                            {
                                errors.Add(Locale.Get("NaturalDocs.Engine", "Style.txt.CantUseHomeLinksWithCustomHomePage"), link.PropertyLocation);
                            }
                        }
                    }

                    if (style.OnLoad != null)
                    {
                        foreach (var onLoad in style.OnLoad)
                        {
                            if (onLoad.Type == PageType.Home)
                            {
                                errors.Add(Locale.Get("NaturalDocs.Engine", "Style.txt.CantUseHomeOnLoadWithCustomHomePage"), onLoad.PropertyLocation);
                            }
                        }
                    }
                }


                if (errorCount == errors.Count)
                {
                    return(style);
                }
                else
                {
                    return(null);
                }
            }
        }
예제 #2
0
        // Group: Loading Functions
        // __________________________________________________________________________


        /* Function: Load
         *
         * Loads the configuration file and parses it.  Redundant information will be simplified out, such as an Alter
         * Language section that applies to a language defined in the same file.
         *
         * Parameters:
         *
         *		filename - The <Path> where the file is located.
         *		fileLanguages - Returns a list of <ConfigFileLanguages> in no particular order.
         *		fileIgnoredExtensions - Returns any ignored extensions as a string array.
         *		errorList - If it couldn't successfully parse the file it will add error messages to this list.
         *
         * Returns:
         *
         *		Whether it was able to successfully load and parse the file without any errors.
         */
        public bool Load(Path filename, out List <ConfigFileLanguage> fileLanguages,
                         out List <string> fileIgnoredExtensions, Errors.ErrorList errorList)
        {
            fileLanguages         = new List <ConfigFileLanguage>();
            fileIgnoredExtensions = new List <string>();
            StringTable <ConfigFileLanguage> fileLanguageNames =
                new StringTable <ConfigFileLanguage>(Engine.Languages.Manager.KeySettingsForLanguageName);

            int previousErrorCount = errorList.Count;

            using (ConfigFile file = new ConfigFile())
            {
                // Can't make identifiers lowercase here or we'd lose the case of the comment type in prototype ender lines.
                bool openResult = file.Open(filename,
                                            ConfigFile.FileFormatFlags.CondenseIdentifierWhitespace |
                                            ConfigFile.FileFormatFlags.CondenseValueWhitespace,
                                            errorList);

                if (openResult == false)
                {
                    return(false);
                }

                string             identifier, lcIdentifier, value;
                ConfigFileLanguage currentLanguage = null;

                // We need this in addition to ConfigFileLanguage.AlterLanguage because an entry altering a type defined in the
                // same file would be combined into the original, yet we still need to know if that entry is Alter to properly
                // detect whether we need to use Add/Replace with certain properties.
                bool alterCurrentLanguage = false;

                char[] space = { ' ' };

                System.Text.RegularExpressions.Match match;


                while (file.Get(out identifier, out value))
                {
                    lcIdentifier = identifier.ToLower();

                    //
                    // Ignore Extensions
                    //

                    if (ignoreExtensionsRegex.IsMatch(lcIdentifier))
                    {
                        currentLanguage = null;

                        string[] ignoredExtensionsArray = value.Split(space);
                        fileIgnoredExtensions.AddRange(ignoredExtensionsArray);
                    }


                    //
                    // Language
                    //

                    else if (lcIdentifier == "language")
                    {
                        if (fileLanguageNames.ContainsKey(value))
                        {
                            file.AddError(
                                Locale.Get("NaturalDocs.Engine", "Languages.txt.LanguageAlreadyExists(name)", value)
                                );

                            // Continue parsing.  We'll throw this into the existing language even though it shouldn't be overwriting
                            // its values because we want to find any other errors there are in the file.
                            currentLanguage      = fileLanguageNames[value];
                            alterCurrentLanguage = false;
                        }

                        else
                        {
                            currentLanguage      = new ConfigFileLanguage(value, false, file.LineNumber);
                            alterCurrentLanguage = false;
                            fileLanguages.Add(currentLanguage);
                            fileLanguageNames.Add(value, currentLanguage);
                        }
                    }



                    //
                    // Alter Language
                    //

                    else if (alterLanguageRegex.IsMatch(lcIdentifier))
                    {
                        // If this language already exists, collapse it into the current definition.
                        if (fileLanguageNames.ContainsKey(value))
                        {
                            currentLanguage      = fileLanguageNames[value];
                            alterCurrentLanguage = true;
                        }

                        // If it doesn't exist, create the new language anyway with the alter flag set because it may exist in another
                        // file.
                        else
                        {
                            currentLanguage      = new ConfigFileLanguage(value, true, file.LineNumber);
                            alterCurrentLanguage = true;
                            fileLanguages.Add(currentLanguage);
                            fileLanguageNames.Add(value, currentLanguage);
                        }
                    }


                    //
                    // Aliases
                    //

                    else if (aliasesRegex.IsMatch(lcIdentifier))
                    {
                        if (currentLanguage == null)
                        {
                            NeedsLanguageError(file, identifier);
                        }
                        else if (alterCurrentLanguage == true)
                        {
                            file.AddError(
                                Locale.Get("NaturalDocs.Engine", "Languages.txt.NeedAddReplaceWhenAlteringLanguage(keyword)", "Aliases")
                                );
                        }
                        else
                        {
                            currentLanguage.Aliases    = value.Split(space);
                            currentLanguage.AddAliases = false;
                        }
                    }


                    //
                    // Add/Replace Aliases
                    //

                    else if ((match = addReplaceAliasesRegex.Match(lcIdentifier)) != null && match.Success)
                    {
                        if (currentLanguage == null)
                        {
                            NeedsLanguageError(file, identifier);
                        }

                        else if (alterCurrentLanguage == true && match.Groups[1].Value == "add" &&
                                 currentLanguage.Aliases != null)
                        {
                            string[] addAliases = value.Split(space);
                            string[] newAliases = new string[addAliases.Length + currentLanguage.Aliases.Length];

                            currentLanguage.Aliases.CopyTo(newAliases, 0);
                            addAliases.CopyTo(newAliases, currentLanguage.Aliases.Length);

                            currentLanguage.Aliases    = newAliases;
                            currentLanguage.AddAliases = true;
                        }

                        // Covers "replace" when altering a language, "add" and "replace" when not altering a language (no point
                        // in adding an error when we can just tolerate it, and "replace" when altering a language that doesn't have
                        // anything defined.
                        else
                        {
                            currentLanguage.Aliases    = value.Split(space);
                            currentLanguage.AddAliases = (match.Groups[1].Value == "add");
                        }
                    }



                    //
                    // Extensions
                    //

                    else if (extensionsRegex.IsMatch(lcIdentifier))
                    {
                        if (currentLanguage == null)
                        {
                            NeedsLanguageError(file, identifier);
                        }
                        else if (alterCurrentLanguage == true)
                        {
                            file.AddError(
                                Locale.Get("NaturalDocs.Engine", "Languages.txt.NeedAddReplaceWhenAlteringLanguage(keyword)", "Extensions")
                                );
                        }
                        else
                        {
                            currentLanguage.Extensions    = value.Split(space);
                            currentLanguage.AddExtensions = false;
                        }
                    }


                    //
                    // Add/Replace Extensions
                    //

                    else if ((match = addReplaceExtensionsRegex.Match(lcIdentifier)) != null && match.Success)
                    {
                        if (currentLanguage == null)
                        {
                            NeedsLanguageError(file, identifier);
                        }

                        else if (alterCurrentLanguage == true && match.Groups[1].Value == "add" &&
                                 currentLanguage.Extensions != null)
                        {
                            string[] addExtensions = value.Split(space);
                            string[] newExtensions = new string[addExtensions.Length + currentLanguage.Extensions.Length];

                            currentLanguage.Extensions.CopyTo(newExtensions, 0);
                            addExtensions.CopyTo(newExtensions, currentLanguage.Extensions.Length);

                            currentLanguage.Extensions    = newExtensions;
                            currentLanguage.AddExtensions = true;
                        }

                        // Covers "replace" when altering a language, "add" and "replace" when not altering a language (no point
                        // in adding an error when we can just tolerate it, and "replace" when altering a language that doesn't have
                        // anything defined.
                        else
                        {
                            currentLanguage.Extensions    = value.Split(space);
                            currentLanguage.AddExtensions = (match.Groups[1].Value == "add");
                        }
                    }



                    //
                    // Shebang Strings
                    //

                    else if (shebangStringsRegex.IsMatch(lcIdentifier))
                    {
                        if (currentLanguage == null)
                        {
                            NeedsLanguageError(file, identifier);
                        }
                        else if (alterCurrentLanguage == true)
                        {
                            file.AddError(
                                Locale.Get("NaturalDocs.Engine", "Languages.txt.NeedAddReplaceWhenAlteringLanguage(keyword)", "Shebang Strings")
                                );
                        }
                        else
                        {
                            currentLanguage.ShebangStrings    = value.Split(space);
                            currentLanguage.AddShebangStrings = false;
                        }
                    }


                    //
                    // Add/Replace Shebang Strings
                    //

                    else if ((match = addReplaceShebangStringsRegex.Match(lcIdentifier)) != null && match.Success)
                    {
                        if (currentLanguage == null)
                        {
                            NeedsLanguageError(file, identifier);
                        }

                        else if (alterCurrentLanguage == true && match.Groups[1].Value == "add" &&
                                 currentLanguage.ShebangStrings != null)
                        {
                            string[] addShebangStrings = value.Split(space);
                            string[] newShebangStrings = new string[addShebangStrings.Length +
                                                                    currentLanguage.ShebangStrings.Length];

                            currentLanguage.ShebangStrings.CopyTo(newShebangStrings, 0);
                            addShebangStrings.CopyTo(newShebangStrings, currentLanguage.ShebangStrings.Length);

                            currentLanguage.ShebangStrings    = newShebangStrings;
                            currentLanguage.AddShebangStrings = true;
                        }

                        // Covers "replace" when altering a language, "add" and "replace" when not altering a language (no point
                        // in adding an error when we can just tolerate it, and "replace" when altering a language that doesn't have
                        // anything defined.
                        else
                        {
                            currentLanguage.ShebangStrings    = value.Split(space);
                            currentLanguage.AddShebangStrings = (match.Groups[1].Value == "add");
                        }
                    }



                    //
                    // Simple Identifier
                    //

                    else if (lcIdentifier == "simple identifier")
                    {
                        if (currentLanguage == null)
                        {
                            NeedsLanguageError(file, identifier);
                        }
                        else if (nonASCIILettersRegex.IsMatch(value))
                        {
                            file.AddError(
                                Locale.Get("NaturalDocs.Engine", "Languages.txt.SimpleIdentifierMustOnlyBeASCIILetters(name)", value)
                                );
                        }
                        else
                        {
                            currentLanguage.SimpleIdentifier = value;
                        }
                    }



                    //
                    // Line Comments
                    //

                    else if (lineCommentsRegex.IsMatch(lcIdentifier))
                    {
                        if (currentLanguage == null)
                        {
                            NeedsLanguageError(file, identifier);
                        }
                        else
                        {
                            currentLanguage.LineCommentStrings = value.Split(space);
                        }
                    }



                    //
                    // Block Comments
                    //

                    else if (blockCommentsRegex.IsMatch(lcIdentifier))
                    {
                        if (currentLanguage == null)
                        {
                            NeedsLanguageError(file, identifier);
                        }
                        else
                        {
                            string[] newBlockCommentStrings = value.Split(space);

                            if (newBlockCommentStrings.Length % 2 != 0)
                            {
                                file.AddError(
                                    Locale.Get("NaturalDocs.Engine", "Languages.txt.BlockCommentsMustHaveAnEvenNumberOfSymbols")
                                    );
                            }
                            else
                            {
                                currentLanguage.BlockCommentStringPairs = newBlockCommentStrings;
                            }
                        }
                    }



                    //
                    // Member Operator
                    //

                    else if (memberOperatorRegex.IsMatch(lcIdentifier))
                    {
                        if (currentLanguage == null)
                        {
                            NeedsLanguageError(file, identifier);
                        }
                        else
                        {
                            currentLanguage.MemberOperator = value;
                        }
                    }



                    //
                    // Line Extender
                    //

                    else if (lcIdentifier == "line extender")
                    {
                        if (currentLanguage == null)
                        {
                            NeedsLanguageError(file, identifier);
                        }
                        else
                        {
                            currentLanguage.LineExtender = value;
                        }
                    }



                    //
                    // Enum Values
                    //

                    else if (enumValuesRegex.IsMatch(lcIdentifier))
                    {
                        string lcValue = value.ToLower();

                        if (currentLanguage == null)
                        {
                            NeedsLanguageError(file, identifier);
                        }
                        else if (lcValue == "global")
                        {
                            currentLanguage.EnumValue = Language.EnumValues.Global;
                        }
                        else if (lcValue == "under type")
                        {
                            currentLanguage.EnumValue = Language.EnumValues.UnderType;
                        }
                        else if (lcValue == "under parent")
                        {
                            currentLanguage.EnumValue = Language.EnumValues.UnderParent;
                        }
                        else
                        {
                            file.AddError(
                                Locale.Get("NaturalDocs.Engine", "Languages.txt.InvalidEnumValue(value)", value)
                                );
                        }
                    }


                    //
                    // Case Sensitive
                    //

                    else if (caseSensitiveRegex.IsMatch(lcIdentifier))
                    {
                        string lcValue = value.ToLower();

                        if (currentLanguage == null)
                        {
                            NeedsLanguageError(file, identifier);
                        }
                        else if (yesRegex.IsMatch(lcValue))
                        {
                            currentLanguage.CaseSensitive = true;
                        }
                        else if (noRegex.IsMatch(lcValue))
                        {
                            currentLanguage.CaseSensitive = false;
                        }
                        else
                        {
                            file.AddError(
                                Locale.Get("NaturalDocs.Engine", "Languages.txt.UnrecognizedValue(keyword, value)", "Case Sensitive", value)
                                );
                        }
                    }


                    //
                    // Prototype Enders
                    //

                    // Use identifier and not lcIdentifier to keep the case of the comment type.  The regex will compensate.
                    else if ((match = prototypeEndersRegex.Match(identifier)) != null && match.Success)
                    {
                        if (currentLanguage == null)
                        {
                            NeedsLanguageError(file, identifier);
                        }
                        else
                        {
                            string   commentType  = match.Groups[1].Value;
                            string[] enderStrings = value.Split(space);

                            currentLanguage.SetPrototypeEnderStrings(commentType, enderStrings);
                        }
                    }


                    //
                    // Deprecated keywords
                    //

                    else if (ignorePrefixesRegex.IsMatch(lcIdentifier) ||
                             lcIdentifier == "perl package" || lcIdentifier == "full language support")
                    {
                        // Ignore
                    }


                    //
                    // Unrecognized keywords
                    //

                    else
                    {
                        file.AddError(
                            Locale.Get("NaturalDocs.Engine", "Languages.txt.UnrecognizedKeyword(keyword)", identifier)
                            );
                    }
                }                          // while (file.Get)

                file.Close();
            }


            if (errorList.Count == previousErrorCount)
            {
                return(true);
            }
            else
            {
                return(false);
            }
        }
예제 #3
0
 /* Function: NeedsLanguageError
  * A shortcut function only used by <Load()> which adds an error stating that the passed keyword needs to appear
  * in a language section.
  */
 private void NeedsLanguageError(ConfigFile file, string identifier)
 {
     file.AddError(
         Locale.Get("NaturalDocs.Engine", "Languages.txt.KeywordMustBeInLanguage(keyword)", identifier)
         );
 }
예제 #4
0
        /* Function: LoadStyle
         * Converts a style path to a <HTMLStyle> object, loading its <Style.txt> if appropriate.  If there are any errors found
         * in <Style.txt> they will be added to the list and the function will return null.
         */
        public static HTMLStyle LoadStyle(Path stylePath, Errors.ErrorList errors)
        {
            HTMLStyle style = new HTMLStyle(stylePath);

            if (style.IsCSSOnly)
            {
                return(style);
            }

            using (ConfigFile file = new ConfigFile())
            {
                if (!file.Open(stylePath, ConfigFile.FileFormatFlags.MakeIdentifiersLowercase |
                               ConfigFile.FileFormatFlags.CondenseIdentifierWhitespace, errors))
                {
                    return(null);
                }

                int    errorCount = errors.Count;
                string lcIdentifier, value;
                System.Text.RegularExpressions.Match match;

                Regex.Styles.HTML.Inherit inheritRegex = new Regex.Styles.HTML.Inherit();
                Regex.Styles.HTML.Link    linkRegex = new Regex.Styles.HTML.Link();
                Regex.Styles.HTML.OnLoad  onLoadRegex = new Regex.Styles.HTML.OnLoad();
                Regex.Styles.HTML.LinkableFileExtensions linkableFileExtensionsRegex = new Regex.Styles.HTML.LinkableFileExtensions();

                while (file.Get(out lcIdentifier, out value))
                {
                    if (inheritRegex.IsMatch(lcIdentifier))
                    {
                        style.AddInheritedStyle(value);
                        continue;
                    }

                    match = linkRegex.Match(lcIdentifier);
                    if (match.Success)
                    {
                        PageType pageType = PageType.All;
                        if (match.Groups[1].Success)
                        {
                            PageType?pageTypeTemp = PageTypeOf(match.Groups[1].ToString());

                            if (pageTypeTemp == null)
                            {
                                file.AddError(Locale.Get("NaturalDocs.Engine", "ConfigFile.NotAValidIdentifier(identifier)", lcIdentifier));
                            }
                            else
                            {
                                pageType = pageTypeTemp.Value;
                            }
                        }

                        Path linkedFile = value;

                        if (linkableFileExtensionsRegex.IsMatch(linkedFile.Extension))
                        {
                            Path fullLinkedFile = style.Folder + "/" + linkedFile;

                            if (System.IO.File.Exists(fullLinkedFile))
                            {
                                style.AddLinkedFile(linkedFile, pageType);
                            }
                            else
                            {
                                file.AddError(Locale.Get("NaturalDocs.Engine", "HTML.Style.txt.CantFindLinkedFile(name)", fullLinkedFile));
                            }
                        }
                        else
                        {
                            file.AddError(Locale.Get("NaturalDocs.Engine", "HTML.Style.txt.CantLinkFileWithExtension(extension)",
                                                     linkedFile.Extension));
                        }

                        continue;
                    }

                    match = onLoadRegex.Match(lcIdentifier);
                    if (match.Success)
                    {
                        PageType pageType = PageType.All;
                        if (match.Groups[1].Success)
                        {
                            PageType?pageTypeTemp = PageTypeOf(match.Groups[1].ToString());

                            if (pageTypeTemp == null)
                            {
                                file.AddError(Locale.Get("NaturalDocs.Engine", "ConfigFile.NotAValidIdentifier(identifier)", lcIdentifier));
                            }
                            else
                            {
                                pageType = pageTypeTemp.Value;
                            }
                        }

                        style.AddOnLoad(value, pageType);
                        continue;
                    }

                    file.AddError(Locale.Get("NaturalDocs.Engine", "ConfigFile.NotAValidIdentifier(identifier)", lcIdentifier));
                }

                if (errorCount == errors.Count)
                {
                    return(style);
                }
                else
                {
                    return(null);
                }
            }
        }
예제 #5
0
        // Group: Loading Functions
        // __________________________________________________________________________


        /* Function: Load
         *
         * Loads the contents of a <Languages.txt> file into a <ConfigFiles.Textfile>, returning whether it was successful.  If it
         * was unsuccessful config will be null and it will place errors on the errorList.
         *
         * Parameters:
         *
         *		filename - The <Path> where the file is located.
         *		propertySource - The <Engine.Config.PropertySource> associated with the file.
         *		errorList - If it couldn't successfully parse the file it will add error messages to this list.
         *		config - The contents of the file as a <ConfigFiles.TextFile>.
         */
        public bool Load(Path filename, Engine.Config.PropertySource propertySource, Errors.ErrorList errorList,
                         out ConfigFiles.TextFile config)
        {
            int previousErrorCount = errorList.Count;

            using (ConfigFile file = new ConfigFile())
            {
                bool openResult = file.Open(filename,
                                            propertySource,
                                            ConfigFile.FileFormatFlags.CondenseIdentifierWhitespace |
                                            ConfigFile.FileFormatFlags.CondenseValueWhitespace |
                                            ConfigFile.FileFormatFlags.MakeIdentifiersLowercase,
                                            errorList);

                if (openResult == false)
                {
                    config = null;
                    return(false);
                }

                config = new ConfigFiles.TextFile();

                TextFileLanguage currentLanguage = null;
                char[]           space           = { ' ' };
                System.Text.RegularExpressions.Match match;


                while (file.Get(out string identifier, out string value))
                {
                    //
                    // Ignore Extensions
                    //

                    if (ignoreExtensionsRegex.IsMatch(identifier))
                    {
                        currentLanguage = null;

                        var ignoredExtensions = value.Split(space);
                        NormalizeFileExtensions(ignoredExtensions);

                        config.AddIgnoredFileExtensions(ignoredExtensions, file.PropertyLocation);
                    }


                    //
                    // Language
                    //

                    else if (identifier == "language")
                    {
                        var existingLanguage = config.FindLanguage(value);

                        if (existingLanguage != null)
                        {
                            file.AddError(
                                Locale.Get("NaturalDocs.Engine", "Languages.txt.LanguageAlreadyExists(name)", value)
                                );

                            // Continue parsing.  We'll throw this into the existing language even though it shouldn't be overwriting
                            // its values because we want to find any other errors there are in the file.
                            currentLanguage = existingLanguage;
                        }

                        else
                        {
                            currentLanguage = new TextFileLanguage(value, file.PropertyLocation);
                            config.AddLanguage(currentLanguage);
                        }
                    }


                    //
                    // Alter Language
                    //

                    else if (alterLanguageRegex.IsMatch(identifier))
                    {
                        // We don't check if the name exists because it may exist in a different file.  We also don't check if it exists
                        // in the current file because using Alter is valid (if unnecessary) in that case and we don't want to combine
                        // their definitions.  Why?  Consider this:
                        //
                        // Language: Language A
                        //    Extensions: langA
                        //
                        // Language: Language B
                        //    Extensions: langB
                        //
                        // Alter Language: Language A
                        //    Add Extensions: langB
                        //
                        // Extension langB should be part of Language A.  However, if we merged the definitions it would appear
                        // first and be overridden by Language B.  So we just create two language entries for A instead.

                        currentLanguage = new TextFileLanguage(value, file.PropertyLocation, alterLanguage: true);
                        config.AddLanguage(currentLanguage);
                    }


                    //
                    // Aliases
                    //

                    else if (aliasesRegex.IsMatch(identifier))
                    {
                        if (currentLanguage == null)
                        {
                            AddNeedsLanguageError(file, identifier);
                        }
                        else if (currentLanguage.AlterLanguage)
                        {
                            file.AddError(
                                Locale.Get("NaturalDocs.Engine", "Languages.txt.NeedAddReplaceWhenAlteringLanguage(keyword)", "Aliases")
                                );
                        }
                        else
                        {
                            var aliases = value.Split(space);
                            currentLanguage.SetAliases(aliases, file.PropertyLocation);
                        }
                    }


                    //
                    // Add/Replace Aliases
                    //

                    else if ((match = addReplaceAliasesRegex.Match(identifier)) != null && match.Success)
                    {
                        if (currentLanguage == null)
                        {
                            AddNeedsLanguageError(file, identifier);
                        }
                        else
                        {
                            TextFileLanguage.PropertyChange propertyChange;

                            if (match.Groups[1].Value == "add")
                            {
                                propertyChange = TextFileLanguage.PropertyChange.Add;
                            }
                            else if (match.Groups[1].Value == "replace")
                            {
                                propertyChange = TextFileLanguage.PropertyChange.Replace;
                            }
                            else
                            {
                                throw new NotImplementedException();
                            }

                            // If we're adding to a language that already has them, we need to combine the properties.
                            if (propertyChange == TextFileLanguage.PropertyChange.Add &&
                                currentLanguage.HasAliases)
                            {
                                var oldAliases = currentLanguage.Aliases;
                                var newAliases = value.Split(space);

                                List <string> combinedAliases = new List <string>(oldAliases.Count + newAliases.Length);
                                combinedAliases.AddRange(oldAliases);
                                combinedAliases.AddRange(newAliases);

                                currentLanguage.SetAliases(combinedAliases, file.PropertyLocation, propertyChange);
                            }

                            // Otherwise we can just add them as is.
                            else
                            {
                                var aliases = value.Split(space);
                                currentLanguage.SetAliases(aliases, file.PropertyLocation, propertyChange);
                            }
                        }
                    }



                    //
                    // File Extensions
                    //

                    else if (fileExtensionsRegex.IsMatch(identifier))
                    {
                        if (currentLanguage == null)
                        {
                            AddNeedsLanguageError(file, identifier);
                        }
                        else if (currentLanguage.AlterLanguage)
                        {
                            file.AddError(
                                Locale.Get("NaturalDocs.Engine", "Languages.txt.NeedAddReplaceWhenAlteringLanguage(keyword)", "Extensions")
                                );
                        }
                        else
                        {
                            var extensions = value.Split(space);
                            NormalizeFileExtensions(extensions);

                            currentLanguage.SetFileExtensions(extensions, file.PropertyLocation);
                        }
                    }


                    //
                    // Add/Replace File Extensions
                    //

                    else if ((match = addReplaceExtensionsRegex.Match(identifier)) != null && match.Success)
                    {
                        if (currentLanguage == null)
                        {
                            AddNeedsLanguageError(file, identifier);
                        }
                        else
                        {
                            TextFileLanguage.PropertyChange propertyChange;

                            if (match.Groups[1].Value == "add")
                            {
                                propertyChange = TextFileLanguage.PropertyChange.Add;
                            }
                            else if (match.Groups[1].Value == "replace")
                            {
                                propertyChange = TextFileLanguage.PropertyChange.Replace;
                            }
                            else
                            {
                                throw new NotImplementedException();
                            }

                            // If we're adding to a language that already has them, we need to combine the properties.
                            if (propertyChange == TextFileLanguage.PropertyChange.Add &&
                                currentLanguage.HasFileExtensions)
                            {
                                var oldExtensions = currentLanguage.FileExtensions;
                                var newExtensions = value.Split(space);
                                NormalizeFileExtensions(newExtensions);

                                List <string> combinedExtensions = new List <string>(oldExtensions.Count + newExtensions.Length);
                                combinedExtensions.AddRange(oldExtensions);
                                combinedExtensions.AddRange(newExtensions);

                                currentLanguage.SetFileExtensions(combinedExtensions, file.PropertyLocation, propertyChange);
                            }

                            // Otherwise we can just add them as is.
                            else
                            {
                                var extensions = value.Split(space);
                                NormalizeFileExtensions(extensions);

                                currentLanguage.SetFileExtensions(extensions, file.PropertyLocation, propertyChange);
                            }
                        }
                    }



                    //
                    // Shebang Strings
                    //

                    else if (shebangStringsRegex.IsMatch(identifier))
                    {
                        if (currentLanguage == null)
                        {
                            AddNeedsLanguageError(file, identifier);
                        }
                        else if (currentLanguage.AlterLanguage)
                        {
                            file.AddError(
                                Locale.Get("NaturalDocs.Engine", "Languages.txt.NeedAddReplaceWhenAlteringLanguage(keyword)", "Shebang Strings")
                                );
                        }
                        else
                        {
                            var shebangStrings = value.Split(space);
                            currentLanguage.SetShebangStrings(shebangStrings, file.PropertyLocation);
                        }
                    }


                    //
                    // Add/Replace Shebang Strings
                    //

                    else if ((match = addReplaceShebangStringsRegex.Match(identifier)) != null && match.Success)
                    {
                        if (currentLanguage == null)
                        {
                            AddNeedsLanguageError(file, identifier);
                        }
                        else
                        {
                            TextFileLanguage.PropertyChange propertyChange;

                            if (match.Groups[1].Value == "add")
                            {
                                propertyChange = TextFileLanguage.PropertyChange.Add;
                            }
                            else if (match.Groups[1].Value == "replace")
                            {
                                propertyChange = TextFileLanguage.PropertyChange.Replace;
                            }
                            else
                            {
                                throw new NotImplementedException();
                            }

                            // If we're adding to a language that already has them, we need to combine the properties.
                            if (propertyChange == TextFileLanguage.PropertyChange.Add &&
                                currentLanguage.HasShebangStrings)
                            {
                                var oldShebangStrings = currentLanguage.ShebangStrings;
                                var newShebangStrings = value.Split(space);

                                List <string> combinedShebangStrings = new List <string>(oldShebangStrings.Count + newShebangStrings.Length);
                                combinedShebangStrings.AddRange(oldShebangStrings);
                                combinedShebangStrings.AddRange(newShebangStrings);

                                currentLanguage.SetShebangStrings(combinedShebangStrings, file.PropertyLocation, propertyChange);
                            }

                            // Otherwise we can just add them as is.
                            else
                            {
                                var shebangStrings = value.Split(space);
                                currentLanguage.SetShebangStrings(shebangStrings, file.PropertyLocation, propertyChange);
                            }
                        }
                    }



                    //
                    // Simple Identifier
                    //

                    else if (identifier == "simple identifier")
                    {
                        if (currentLanguage == null)
                        {
                            AddNeedsLanguageError(file, identifier);
                        }
                        else if (nonASCIILettersRegex.IsMatch(value))
                        {
                            file.AddError(
                                Locale.Get("NaturalDocs.Engine", "Languages.txt.SimpleIdentifierMustOnlyBeASCIILetters(name)", value)
                                );
                        }
                        else
                        {
                            currentLanguage.SetSimpleIdentifier(value, file.PropertyLocation);
                        }
                    }



                    //
                    // Line Comments
                    //

                    else if (lineCommentsRegex.IsMatch(identifier))
                    {
                        if (currentLanguage == null)
                        {
                            AddNeedsLanguageError(file, identifier);
                        }
                        else
                        {
                            var lineCommentSymbols = value.Split(space);
                            currentLanguage.SetLineCommentSymbols(lineCommentSymbols, file.PropertyLocation);
                        }
                    }



                    //
                    // Block Comments
                    //

                    else if (blockCommentsRegex.IsMatch(identifier))
                    {
                        if (currentLanguage == null)
                        {
                            AddNeedsLanguageError(file, identifier);
                        }
                        else
                        {
                            var blockCommentStrings = value.Split(space);

                            if (blockCommentStrings.Length % 2 != 0)
                            {
                                file.AddError(
                                    Locale.Get("NaturalDocs.Engine", "Languages.txt.BlockCommentsMustHaveAnEvenNumberOfSymbols")
                                    );
                            }
                            else
                            {
                                List <BlockCommentSymbols> blockCommentSymbols =
                                    new List <BlockCommentSymbols>(blockCommentStrings.Length / 2);

                                for (int i = 0; i < blockCommentStrings.Length; i += 2)
                                {
                                    blockCommentSymbols.Add(
                                        new BlockCommentSymbols(blockCommentStrings[i], blockCommentStrings[i + 1])
                                        );
                                }

                                currentLanguage.SetBlockCommentSymbols(blockCommentSymbols, file.PropertyLocation);
                            }
                        }
                    }



                    //
                    // Member Operator
                    //

                    else if (memberOperatorRegex.IsMatch(identifier))
                    {
                        if (currentLanguage == null)
                        {
                            AddNeedsLanguageError(file, identifier);
                        }
                        else
                        {
                            currentLanguage.SetMemberOperator(value, file.PropertyLocation);
                        }
                    }



                    //
                    // Line Extender
                    //

                    else if (identifier == "line extender")
                    {
                        if (currentLanguage == null)
                        {
                            AddNeedsLanguageError(file, identifier);
                        }
                        else
                        {
                            currentLanguage.SetLineExtender(value, file.PropertyLocation);
                        }
                    }



                    //
                    // Enum Values
                    //

                    else if (enumValuesRegex.IsMatch(identifier))
                    {
                        if (currentLanguage == null)
                        {
                            AddNeedsLanguageError(file, identifier);
                        }
                        else
                        {
                            string lcValue = value.ToLower();

                            if (lcValue == "global")
                            {
                                currentLanguage.SetEnumValues(Language.EnumValues.Global, file.PropertyLocation);
                            }
                            else if (lcValue == "under type")
                            {
                                currentLanguage.SetEnumValues(Language.EnumValues.UnderType, file.PropertyLocation);
                            }
                            else if (lcValue == "under parent")
                            {
                                currentLanguage.SetEnumValues(Language.EnumValues.UnderParent, file.PropertyLocation);
                            }
                            else
                            {
                                file.AddError(
                                    Locale.Get("NaturalDocs.Engine", "Languages.txt.InvalidEnumValue(value)", value)
                                    );
                            }
                        }
                    }


                    //
                    // Case Sensitive
                    //

                    else if (caseSensitiveRegex.IsMatch(identifier))
                    {
                        if (currentLanguage == null)
                        {
                            AddNeedsLanguageError(file, identifier);
                        }
                        else
                        {
                            string lcValue = value.ToLower();

                            if (yesRegex.IsMatch(lcValue))
                            {
                                currentLanguage.SetCaseSensitive(true, file.PropertyLocation);
                            }
                            else if (noRegex.IsMatch(lcValue))
                            {
                                currentLanguage.SetCaseSensitive(false, file.PropertyLocation);
                            }
                            else
                            {
                                file.AddError(
                                    Locale.Get("NaturalDocs.Engine", "Languages.txt.UnrecognizedValue(keyword, value)", "Case Sensitive", value)
                                    );
                            }
                        }
                    }


                    //
                    // Prototype Enders
                    //

                    // Use identifier and not lcIdentifier to keep the case of the comment type.  The regex will compensate.
                    else if ((match = prototypeEndersRegex.Match(identifier)) != null && match.Success)
                    {
                        if (currentLanguage == null)
                        {
                            AddNeedsLanguageError(file, identifier);
                        }
                        else
                        {
                            string   commentType  = match.Groups[1].Value;
                            string[] enderStrings = value.Split(space);

                            var enders = new TextFilePrototypeEnders(commentType, file.PropertyLocation);
                            enders.AddEnderStrings(enderStrings);

                            currentLanguage.AddPrototypeEnders(enders);
                        }
                    }


                    //
                    // Deprecated keywords
                    //

                    else if (ignorePrefixesRegex.IsMatch(identifier) ||
                             identifier == "perl package" ||
                             identifier == "full language support")
                    {
                        // Ignore
                    }


                    //
                    // Unrecognized keywords
                    //

                    else
                    {
                        file.AddError(
                            Locale.Get("NaturalDocs.Engine", "Languages.txt.UnrecognizedKeyword(keyword)", identifier)
                            );
                    }
                }                          // while (file.Get)

                file.Close();
            }


            if (errorList.Count == previousErrorCount)
            {
                return(true);
            }
            else
            {
                return(false);
            }
        }
예제 #6
0
        // Group: Loading Functions
        // __________________________________________________________________________


        /* Function: Load
         *
         * Loads the contents of a <Comments.txt> file into a <ConfigFiles.TextFile>, returning whether it was successful.  If it
         * was unsuccessful config will be null and it will place errors on the errorList.
         *
         * Parameters:
         *
         *		filename - The <Path> where the file is located.
         *		propertySource - The <Engine.Config.PropertySource> associated with the file.
         *		errorList - If it couldn't successfully parse the file it will add error messages to this list.
         *		config - The contents of the file as a <ConfigFiles.TextFile>.
         */
        public bool Load(Path filename, Engine.Config.PropertySource propertySource, Errors.ErrorList errorList,
                         out ConfigFiles.TextFile config)
        {
            int previousErrorCount = errorList.Count;

            using (ConfigFile file = new ConfigFile())
            {
                bool openResult = file.Open(filename,
                                            propertySource,
                                            ConfigFile.FileFormatFlags.CondenseIdentifierWhitespace |
                                            ConfigFile.FileFormatFlags.CondenseValueWhitespace |
                                            ConfigFile.FileFormatFlags.SupportsNullValueLines |
                                            ConfigFile.FileFormatFlags.SupportsRawValueLines |
                                            ConfigFile.FileFormatFlags.MakeIdentifiersLowercase,
                                            errorList);

                if (openResult == false)
                {
                    config = null;
                    return(false);
                }

                config = new ConfigFiles.TextFile();

                TextFileCommentType  currentCommentType  = null;
                TextFileKeywordGroup currentKeywordGroup = null;
                bool inKeywords = false;
                bool inTags     = false;

                while (file.Get(out string identifier, out string value))
                {
                    //
                    // Identifierless lines
                    //

                    if (identifier == null)
                    {
                        // Keywords

                        if (inKeywords)
                        {
                            // Separate keywords

                            string keyword, pluralKeyword;
                            int    commaIndex = value.IndexOf(',');

                            if (commaIndex == -1)
                            {
                                keyword       = value;
                                pluralKeyword = null;
                            }
                            else
                            {
                                keyword       = value.Substring(0, commaIndex).TrimEnd();
                                pluralKeyword = value.Substring(commaIndex + 1).TrimStart();

                                if (pluralKeyword.IndexOf(',') != -1)
                                {
                                    file.AddError(
                                        Locale.Get("NaturalDocs.Engine", "Comments.txt.NoMoreThanTwoKeywordsOnALine")
                                        );
                                }
                            }


                            // Check for banned characters

                            int  bannedCharIndex = keyword.IndexOfAny(BannedKeywordChars);
                            char bannedChar      = '\0';

                            if (bannedCharIndex != -1)
                            {
                                bannedChar = keyword[bannedCharIndex];
                            }
                            else if (pluralKeyword != null)
                            {
                                bannedCharIndex = pluralKeyword.IndexOfAny(BannedKeywordChars);

                                if (bannedCharIndex != -1)
                                {
                                    bannedChar = pluralKeyword[bannedCharIndex];
                                }
                            }

                            if (bannedChar != '\0')
                            {
                                file.AddError(
                                    Locale.Get("NaturalDocs.Engine", "Comments.txt.KeywordsCannotContain(char)", bannedChar)
                                    );
                                // Continue parsing
                            }


                            // Add to config

                            currentKeywordGroup.Add(keyword, pluralKeyword);
                        }


                        // Tags, only a single value allowed

                        else if (inTags)
                        {
                            if (value.IndexOf(',') != -1)
                            {
                                file.AddError(
                                    Locale.Get("NaturalDocs.Engine", "Comments.txt.NoMoreThanOneTagOnALine")
                                    );
                            }

                            int bannedChar = value.IndexOfAny(BannedKeywordChars);
                            if (bannedChar != -1)
                            {
                                file.AddError(
                                    Locale.Get("NaturalDocs.Engine", "Comments.txt.TagsCannotContain(char)", value[bannedChar])
                                    );
                                // Continue parsing
                            }

                            config.AddTag(value, file.PropertyLocation);
                        }


                        // Raw line

                        else
                        {
                            file.AddError(
                                Locale.Get("NaturalDocs.Engine", "ConfigFile.LineNotInIdentifierValueFormat")
                                );
                        }

                        // Continue so we don't need to put all the identifier handling code in an else.
                        continue;
                    }


                    // If we're here the line has an identifier
                    currentKeywordGroup = null;
                    inKeywords          = false;
                    inTags = false;


                    //
                    // Ignore Keywords
                    //

                    if (ignoreKeywordsRegex.IsMatch(identifier))
                    {
                        currentCommentType = null;

                        currentKeywordGroup = new TextFileKeywordGroup(file.PropertyLocation);
                        config.AddIgnoredKeywordGroup(currentKeywordGroup);
                        inKeywords = true;

                        if (!string.IsNullOrEmpty(value))
                        {
                            string[] ignoredKeywordsArray = commaSeparatorRegex.Split(value);

                            foreach (string ignoredKeyword in ignoredKeywordsArray)
                            {
                                int bannedChar = ignoredKeyword.IndexOfAny(BannedKeywordChars);
                                if (bannedChar != -1)
                                {
                                    file.AddError(
                                        Locale.Get("NaturalDocs.Engine", "Comments.txt.KeywordsCannotContain(char)", ignoredKeyword[bannedChar])
                                        );
                                    // Continue parsing
                                }

                                currentKeywordGroup.Add(ignoredKeyword);
                            }
                        }
                    }


                    //
                    // Tags
                    //

                    else if (tagsRegex.IsMatch(identifier))
                    {
                        currentCommentType = null;
                        inTags             = true;

                        if (!string.IsNullOrEmpty(value))
                        {
                            string[] tagsArray = commaSeparatorRegex.Split(value);

                            foreach (string tag in tagsArray)
                            {
                                int bannedChar = tag.IndexOfAny(BannedKeywordChars);
                                if (bannedChar != -1)
                                {
                                    file.AddError(
                                        Locale.Get("NaturalDocs.Engine", "Comments.txt.TagsCannotContain(char)", tag[bannedChar])
                                        );
                                    // Continue parsing
                                }

                                config.AddTag(tag, file.PropertyLocation);
                            }
                        }
                    }


                    //
                    // Comment Type
                    //

                    else if (commentTypeRegex.IsMatch(identifier))
                    {
                        var existingCommentType = config.FindCommentType(value);

                        if (existingCommentType != null)
                        {
                            file.AddError(
                                Locale.Get("NaturalDocs.Engine", "Comments.txt.CommentTypeAlreadyExists(name)", value)
                                );

                            // Continue parsing.  We'll throw this into the existing type even though it shouldn't be overwriting
                            // its values because we want to find any other errors there are in the file.
                            currentCommentType = existingCommentType;
                        }

                        else
                        {
                            // There is no 1.6, but this covers all the 2.0 prereleases.
                            if (file.Version < "1.6" && String.Compare(value, "generic", true) == 0)
                            {
                                value = "Information";
                            }

                            currentCommentType = new TextFileCommentType(value, file.PropertyLocation);
                            config.AddCommentType(currentCommentType);
                        }
                    }


                    //
                    // Alter Comment Type
                    //

                    else if (alterCommentTypeRegex.IsMatch(identifier))
                    {
                        // We don't check if the name exists because it may exist in a different file.  We also don't check if it exists
                        // in the current file because using Alter is valid (if unnecessary) in that case and we don't want to combine
                        // their definitions.  Why?  Consider this:
                        //
                        // Comment Type: Comment Type A
                        //    Keyword: Keyword A
                        //
                        // Comment Type: Comment Type B
                        //    Keyword: Keyword B
                        //
                        // Alter Comment Type: Comment Type A
                        //    Keyword: Keyword B
                        //
                        // Keyword B should be part of Comment Type A.  However, if we merged the definitions it would appear
                        // first and be overridden by Comment Type B.  So we just create two comment type entries for A instead.

                        currentCommentType = new TextFileCommentType(value, file.PropertyLocation, alterType: true);
                        config.AddCommentType(currentCommentType);
                    }


                    //
                    // (Plural) Display Name (From Locale)
                    //

                    else if (displayNameRegex.IsMatch(identifier))
                    {
                        if (currentCommentType == null)
                        {
                            AddNeedsCommentTypeError(file, identifier);
                        }
                        else if (currentCommentType.HasDisplayNameFromLocale)
                        {
                            file.AddError(
                                Locale.Get("NaturalDocs.Engine", "Comments.txt.CannotDefineXWhenYIsDefined(x,y)", "Display Name", "Display Name from Locale")
                                );
                        }
                        else
                        {
                            currentCommentType.SetDisplayName(value, file.PropertyLocation);
                        }
                    }
                    else if (pluralDisplayNameRegex.IsMatch(identifier))
                    {
                        if (currentCommentType == null)
                        {
                            AddNeedsCommentTypeError(file, identifier);
                        }
                        else if (currentCommentType.HasPluralDisplayNameFromLocale)
                        {
                            file.AddError(
                                Locale.Get("NaturalDocs.Engine", "Comments.txt.CannotDefineXWhenYIsDefined(x,y)", "Plural Display Name", "Plural Display Name from Locale")
                                );
                        }
                        else
                        {
                            currentCommentType.SetPluralDisplayName(value, file.PropertyLocation);
                        }
                    }
                    else if (displayNameFromLocaleRegex.IsMatch(identifier))
                    {
                        if (currentCommentType == null)
                        {
                            AddNeedsCommentTypeError(file, identifier);
                        }
                        else if (currentCommentType.HasDisplayName)
                        {
                            file.AddError(
                                Locale.Get("NaturalDocs.Engine", "Comments.txt.CannotDefineXWhenYIsDefined(x,y)", "Display Name from Locale", "Display Name")
                                );
                        }
                        else
                        {
                            currentCommentType.SetDisplayNameFromLocale(value, file.PropertyLocation);
                        }
                    }
                    else if (pluralDisplayNameFromLocaleRegex.IsMatch(identifier))
                    {
                        if (currentCommentType == null)
                        {
                            AddNeedsCommentTypeError(file, identifier);
                        }
                        else if (currentCommentType.HasPluralDisplayName)
                        {
                            file.AddError(
                                Locale.Get("NaturalDocs.Engine", "Comments.txt.CannotDefineXWhenYIsDefined(x,y)", "Plural Display Name from Locale", "Plural Display Name")
                                );
                        }
                        else
                        {
                            currentCommentType.SetPluralDisplayNameFromLocale(value, file.PropertyLocation);
                        }
                    }


                    //
                    // Simple Identifier
                    //

                    else if (identifier == "simple identifier")
                    {
                        if (currentCommentType == null)
                        {
                            AddNeedsCommentTypeError(file, identifier);
                        }
                        else if (nonASCIILettersRegex.IsMatch(value))
                        {
                            file.AddError(
                                Locale.Get("NaturalDocs.Engine", "Comments.txt.SimpleIdentifierMustOnlyBeASCIILetters(name)", value)
                                );
                        }
                        else
                        {
                            currentCommentType.SetSimpleIdentifier(value, file.PropertyLocation);
                        }
                    }


                    //
                    // Scope
                    //

                    else if (identifier == "scope")
                    {
                        if (currentCommentType == null)
                        {
                            AddNeedsCommentTypeError(file, identifier);
                        }
                        else
                        {
                            value = value.ToLower();

                            if (value == "normal")
                            {
                                currentCommentType.SetScope(CommentType.ScopeValue.Normal, file.PropertyLocation);
                            }
                            else if (startRegex.IsMatch(value))
                            {
                                currentCommentType.SetScope(CommentType.ScopeValue.Start, file.PropertyLocation);
                            }
                            else if (endRegex.IsMatch(value))
                            {
                                currentCommentType.SetScope(CommentType.ScopeValue.End, file.PropertyLocation);
                            }
                            else if (alwaysGlobalRegex.IsMatch(value))
                            {
                                currentCommentType.SetScope(CommentType.ScopeValue.AlwaysGlobal, file.PropertyLocation);
                            }
                            else
                            {
                                file.AddError(
                                    Locale.Get("NaturalDocs.Engine", "Comments.txt.UnrecognizedValue(keyword, value)", "Scope", value)
                                    );
                            }
                        }
                    }


                    //
                    // Flags
                    //

                    else if (flagsRegex.IsMatch(identifier))
                    {
                        if (currentCommentType == null)
                        {
                            AddNeedsCommentTypeError(file, identifier);
                        }
                        else
                        {
                            value = value.ToLower();

                            if (!string.IsNullOrEmpty(value))
                            {
                                string[] flagStrings = commaSeparatorRegex.Split(value);

                                // Merge them with the existing flags instead of overwriting them since they may also be set by the
                                // Class Hierarchy property.
                                CommentType.FlagValue flagsValue = currentCommentType.Flags ?? default;

                                foreach (string flagString in flagStrings)
                                {
                                    if (flagString == "code")
                                    {
                                        flagsValue |= CommentType.FlagValue.Code;
                                    }
                                    else if (flagString == "file")
                                    {
                                        flagsValue |= CommentType.FlagValue.File;
                                    }
                                    else if (documentationRegex.IsMatch(flagString))
                                    {
                                        flagsValue |= CommentType.FlagValue.Documentation;
                                    }
                                    else if (variableTypeRegex.IsMatch(flagString))
                                    {
                                        flagsValue |= CommentType.FlagValue.VariableType;
                                    }
                                    else if (classHierarchyRegex.IsMatch(flagString))
                                    {
                                        flagsValue |= CommentType.FlagValue.ClassHierarchy;
                                    }
                                    else if (databaseHierarchyRegex.IsMatch(flagString))
                                    {
                                        flagsValue |= CommentType.FlagValue.DatabaseHierarchy;
                                    }
                                    else if (enumRegex.IsMatch(flagString))
                                    {
                                        flagsValue |= CommentType.FlagValue.Enum;
                                    }
                                    else if (string.IsNullOrEmpty(flagString) == false)
                                    {
                                        file.AddError(
                                            Locale.Get("NaturalDocs.Engine", "Comments.txt.UnrecognizedValue(keyword, value)", "Flags", flagString)
                                            );
                                    }
                                }

                                currentCommentType.SetFlags(flagsValue, file.PropertyLocation);
                            }
                        }
                    }


                    //
                    // Class Hierarchy (deprecated, convert to flag)
                    //

                    else if (classHierarchyRegex.IsMatch(identifier))
                    {
                        if (currentCommentType == null)
                        {
                            AddNeedsCommentTypeError(file, identifier);
                        }
                        else
                        {
                            value = value.ToLower();

                            // Merge it with the existing flags since they may already be set.
                            CommentType.FlagValue flagsValue = currentCommentType.Flags ?? default;

                            if (yesRegex.IsMatch(value))
                            {
                                flagsValue |= CommentType.FlagValue.ClassHierarchy;
                            }
                            else if (noRegex.IsMatch(value))
                            {
                                flagsValue &= ~CommentType.FlagValue.ClassHierarchy;
                            }
                            else
                            {
                                file.AddError(
                                    Locale.Get("NaturalDocs.Engine", "Comments.txt.UnrecognizedValue(keyword, value)", "Class Hierarchy", value)
                                    );
                            }

                            currentCommentType.SetFlags(flagsValue, file.PropertyLocation);
                        }
                    }


                    //
                    // Keywords
                    //

                    else if (keywordsRegex.IsMatch(identifier))
                    {
                        if (currentCommentType == null)
                        {
                            AddNeedsCommentTypeError(file, identifier);
                        }
                        else
                        {
                            currentKeywordGroup = new TextFileKeywordGroup(file.PropertyLocation);
                            currentCommentType.AddKeywordGroup(currentKeywordGroup);
                            inKeywords = true;

                            if (!string.IsNullOrEmpty(value))
                            {
                                string[] keywordsArray = commaSeparatorRegex.Split(value);

                                foreach (string keyword in keywordsArray)
                                {
                                    int bannedChar = keyword.IndexOfAny(BannedKeywordChars);
                                    if (bannedChar != -1)
                                    {
                                        file.AddError(
                                            Locale.Get("NaturalDocs.Engine", "Comments.txt.KeywordsCannotContain(char)", keyword[bannedChar])
                                            );
                                        // Continue parsing
                                    }

                                    currentKeywordGroup.Add(keyword);
                                }
                            }
                        }
                    }


                    //
                    // Language-Specific Keywords
                    //

                    // This must be tested after ignored and language-general keywords so that their modifiers ("add" or "ignore") don't
                    // get mistaken for language names.
                    else if (languageSpecificKeywordsRegex.IsMatch(identifier))
                    {
                        if (currentCommentType == null)
                        {
                            AddNeedsCommentTypeError(file, identifier);
                        }
                        else
                        {
                            var match        = languageSpecificKeywordsRegex.Match(identifier);
                            var languageName = match.Groups[1].ToString();

                            currentKeywordGroup = new TextFileKeywordGroup(file.PropertyLocation, languageName);
                            currentCommentType.AddKeywordGroup(currentKeywordGroup);
                            inKeywords = true;

                            if (!string.IsNullOrEmpty(value))
                            {
                                string[] keywordsArray = commaSeparatorRegex.Split(value);

                                foreach (string keyword in keywordsArray)
                                {
                                    int bannedChar = keyword.IndexOfAny(BannedKeywordChars);
                                    if (bannedChar != -1)
                                    {
                                        file.AddError(
                                            Locale.Get("NaturalDocs.Engine", "Comments.txt.KeywordsCannotContain(char)", keyword[bannedChar])
                                            );
                                        // Continue parsing
                                    }

                                    currentKeywordGroup.Add(keyword);
                                }
                            }
                        }
                    }


                    //
                    // Deprecated keywords: Can Group With, Page Title if First
                    //

                    else if (identifier == "index" ||
                             identifier == "index with" ||
                             breakListsRegex.IsMatch(identifier) ||
                             identifier == "can group with" ||
                             identifier == "page title if first")
                    {
                        // Ignore and continue
                    }


                    //
                    // Unrecognized keywords
                    //

                    else
                    {
                        file.AddError(
                            Locale.Get("NaturalDocs.Engine", "Comments.txt.UnrecognizedKeyword(keyword)", identifier)
                            );
                    }
                }                          // while (file.Get)

                file.Close();
            }


            if (errorList.Count == previousErrorCount)
            {
                return(true);
            }
            else
            {
                config = null;
                return(false);
            }
        }
예제 #7
0
 /* Function: AddNeedsCommentTypeError
  * A shortcut function only used by <Load()> which adds an error stating that the passed keyword needs to appear
  * in a comment type section.
  */
 private void AddNeedsCommentTypeError(ConfigFile file, string identifier)
 {
     file.AddError(
         Locale.Get("NaturalDocs.Engine", "Comments.txt.KeywordMustBeInCommentType(keyword)", identifier)
         );
 }
예제 #8
0
        /* Function: Load
         * Loads <Style.txt> and returns it as a <Styles.Advanced> object.  If there are any errors found in <Style.txt> they will be added
         * to the list and the function will return null.
         */
        public Styles.Advanced Load(Path path, Errors.ErrorList errors)
        {
            Styles.Advanced style = new Styles.Advanced(path);

            using (ConfigFile file = new ConfigFile())
            {
                if (!file.Open(path,
                               Config.PropertySource.StyleConfigurationFile,
                               ConfigFile.FileFormatFlags.MakeIdentifiersLowercase |
                               ConfigFile.FileFormatFlags.CondenseIdentifierWhitespace, errors))
                {
                    return(null);
                }

                int    errorCount = errors.Count;
                string lcIdentifier, value;
                System.Text.RegularExpressions.Match match;

                while (file.Get(out lcIdentifier, out value))
                {
                    // Inherit

                    if (inheritRegex.IsMatch(lcIdentifier))
                    {
                        style.AddInheritedStyle(value, file.PropertyLocation, null);
                        continue;
                    }


                    // Link

                    match = linkRegex.Match(lcIdentifier);
                    if (match.Success)
                    {
                        PageType pageType = PageType.All;
                        if (match.Groups[1].Success)
                        {
                            PageType?pageTypeTemp = PageTypes.FromName(match.Groups[1].ToString());

                            if (pageTypeTemp == null)
                            {
                                file.AddError(Locale.Get("NaturalDocs.Engine", "ConfigFile.NotAValidIdentifier(identifier)", lcIdentifier));
                            }
                            else
                            {
                                pageType = pageTypeTemp.Value;
                            }
                        }

                        Path linkedFile = value;

                        if (linkableFileExtensionsRegex.IsMatch(linkedFile.Extension))
                        {
                            Path fullLinkedFile = style.Folder + "/" + linkedFile;

                            if (System.IO.File.Exists(fullLinkedFile))
                            {
                                style.AddLinkedFile(fullLinkedFile, file.PropertyLocation, pageType);
                            }
                            else
                            {
                                file.AddError(Locale.Get("NaturalDocs.Engine", "Style.txt.CantFindLinkedFile(name)", fullLinkedFile));
                            }
                        }
                        else
                        {
                            file.AddError(Locale.Get("NaturalDocs.Engine", "Style.txt.CantLinkFileWithExtension(extension)",
                                                     linkedFile.Extension));
                        }

                        continue;
                    }


                    // OnLoad

                    match = onLoadRegex.Match(lcIdentifier);
                    if (match.Success)
                    {
                        PageType pageType = PageType.All;
                        if (match.Groups[1].Success)
                        {
                            PageType?pageTypeTemp = PageTypes.FromName(match.Groups[1].ToString());

                            if (pageTypeTemp == null)
                            {
                                file.AddError(Locale.Get("NaturalDocs.Engine", "ConfigFile.NotAValidIdentifier(identifier)", lcIdentifier));
                            }
                            else
                            {
                                pageType = pageTypeTemp.Value;
                            }
                        }

                        style.AddOnLoad(value, file.PropertyLocation, pageType);
                        continue;
                    }

                    file.AddError(Locale.Get("NaturalDocs.Engine", "ConfigFile.NotAValidIdentifier(identifier)", lcIdentifier));
                }

                if (errorCount == errors.Count)
                {
                    return(style);
                }
                else
                {
                    return(null);
                }
            }
        }