Exemplo n.º 1
0
        /* Function: HasAnyTag
         * Whether the passed block of text contains any Javadoc tags at all.
         */
        protected bool HasAnyTag(TokenIterator start, TokenIterator end)
        {
            string text     = start.Tokenizer.RawText;
            int    endIndex = end.RawTextIndex;

            int textIndex = text.IndexOf('@', start.RawTextIndex, endIndex - start.RawTextIndex);

            while (textIndex != -1)
            {
                start.NextByCharacters(textIndex - start.RawTextIndex);
                start.Next();

                if (textIndex > 0 && text[textIndex - 1] == '{')
                {
                    if (InlineTags.Contains(start.String))
                    {
                        return(true);
                    }
                }
                else
                {
                    if (BlockTags.Contains(start.String))
                    {
                        return(true);
                    }
                }

                textIndex = text.IndexOf('@', textIndex + 1, endIndex - (textIndex + 1));
            }

            return(false);
        }
Exemplo n.º 2
0
        /* Function: TryToSkipBlockComment
         * If the iterator is on the opening symbol of a block comment, skips over it and returns true.  Otherwise leaves the iterator
         * alone and returns false.
         */
        protected bool TryToSkipBlockComment(ref TokenIterator iterator, string openingSymbol, string closingSymbol)
        {
            if (iterator.MatchesAcrossTokens(openingSymbol))
            {
                iterator.NextByCharacters(openingSymbol.Length);

                while (iterator.IsInBounds && !iterator.MatchesAcrossTokens(closingSymbol))
                {
                    iterator.Next();
                }

                if (iterator.IsInBounds)
                {
                    iterator.NextByCharacters(closingSymbol.Length);
                }

                return(true);
            }
            else
            {
                return(false);
            }
        }
Exemplo n.º 3
0
        /* Function: TryToGetLineComment
         *
         * If the iterator is on a line that starts with a line comment symbol, this function moves the iterator past the entire
         * comment and returns true.  If the comment is a candidate for documentation it will also return it as a
         * <PossibleDocumentationComment> and mark the symbols as <CommentParsingType.CommentSymbol>.  If the
         * line does not start with a line comment symbol it will return false and leave the iterator where it is.
         *
         * This function takes a separate comment symbol for the first line and all remaining lines, allowing you to detect
         * Javadoc line comments that start with ## and the remaining lines use #.  Both symbols can be the same if this isn't
         * required.
         *
         * If openingMustBeAlone is set, no symbol can appear immediately after the first line symbol.  If it does the function
         * will return false and not move past the comment.  This allows you to specifically detect something like ## without
         * also matching #######.
         */
        protected bool TryToGetLineComment(ref LineIterator lineIterator,
                                           string firstSymbol, string remainderSymbol, bool openingMustBeAlone,
                                           out PossibleDocumentationComment comment)
        {
            TokenIterator firstToken = lineIterator.FirstToken(LineBoundsMode.ExcludeWhitespace);

            if (firstToken.MatchesAcrossTokens(firstSymbol) == false)
            {
                comment = null;
                return(false);
            }

            if (openingMustBeAlone)
            {
                TokenIterator nextToken = firstToken;
                nextToken.NextByCharacters(firstSymbol.Length);

                if (nextToken.FundamentalType == FundamentalType.Symbol)
                {
                    comment = null;
                    return(false);
                }
            }

            comment       = new PossibleDocumentationComment();
            comment.Start = lineIterator;
            lineIterator.Next();

            // Since we're definitely returning a comment we can mark the comment symbols as we go rather than waiting until
            // the end.
            firstToken.SetCommentParsingTypeByCharacters(CommentParsingType.CommentSymbol, firstSymbol.Length);

            while (lineIterator.IsInBounds)
            {
                firstToken = lineIterator.FirstToken(LineBoundsMode.ExcludeWhitespace);

                if (firstToken.MatchesAcrossTokens(remainderSymbol) == false)
                {
                    break;
                }

                firstToken.SetCommentParsingTypeByCharacters(CommentParsingType.CommentSymbol, remainderSymbol.Length);
                lineIterator.Next();
            }

            comment.End = lineIterator;
            return(true);
        }
Exemplo n.º 4
0
        /* Function: TryToSkipLocaleSubstitutionIdentifier
         * If the iterator is on a valid locale substitution identifier, advances it past it, returns it, and returns true.
         * Otherwise the iterator will be left alone and it will return false.
         */
        protected bool TryToSkipLocaleSubstitutionIdentifier(ref TokenIterator iterator, out string identifier, out string localeIdentifier)
        {
            if (iterator.Character != '$' && iterator.Character != '@')
            {
                identifier       = null;
                localeIdentifier = null;
                return(false);
            }

            TokenIterator lookahead = iterator;

            lookahead.Next();

            if (lookahead.MatchesAcrossTokens("Locale{") == false)
            {
                identifier       = null;
                localeIdentifier = null;
                return(false);
            }

            lookahead.NextByCharacters(7);
            TokenIterator startOfLocaleIdentifier = lookahead;

            while (lookahead.IsInBounds && lookahead.Character != '}')
            {
                lookahead.Next();
            }

            if (lookahead.Character != '}')
            {
                identifier       = null;
                localeIdentifier = null;
                return(false);
            }

            localeIdentifier = startOfLocaleIdentifier.TextBetween(lookahead);
            lookahead.Next();

            identifier = iterator.TextBetween(lookahead);

            iterator = lookahead;
            return(true);
        }
Exemplo n.º 5
0
        /* Function: TryToSkipLineComment
         * If the iterator is on the opening symbol of a line comment, skips over it and returns true.  Otherwise leaves the iterator
         * alone and returns false.
         */
        protected bool TryToSkipLineComment(ref TokenIterator iterator, string symbol)
        {
            if (iterator.MatchesAcrossTokens(symbol))
            {
                iterator.NextByCharacters(symbol.Length);

                while (iterator.IsInBounds && iterator.FundamentalType != FundamentalType.LineBreak)
                {
                    iterator.Next();
                }

                if (iterator.FundamentalType == FundamentalType.LineBreak)
                {
                    iterator.Next();
                }

                return(true);
            }
            else
            {
                return(false);
            }
        }
Exemplo n.º 6
0
        /* Function: TryToGetBlockSymbol
         * If the iterator is on the symbol part of a block tag that has one, such as "@param symbol description", extracts the symbol,
         * moves the iterator past it, and returns true.
         */
        protected bool TryToGetBlockSymbol(ref TokenIterator iterator, TokenIterator limit, out string entryText)
        {
            TokenIterator lookahead = iterator;

            // Javadoc recommends documenting template parameters as "@param <T> ...".
            if (lookahead.Character == '<')
            {
                lookahead.Next();

                for (;;)
                {
                    if (lookahead >= limit)
                    {
                        entryText = null;
                        return(false);
                    }
                    else if (lookahead.Character == '>')
                    {
                        lookahead.Next();
                        break;
                    }
                    else
                    {
                        lookahead.Next();
                    }
                }
            }

            else             // not '<'
            {
                for (;;)
                {
                    if (lookahead >= limit)
                    {
                        entryText = null;
                        return(false);
                    }
                    else if (lookahead.FundamentalType == FundamentalType.Text ||
                             lookahead.Character == '_' ||
                             lookahead.Character == '.')
                    {
                        lookahead.Next();
                    }
                    else if (lookahead.MatchesAcrossTokens("::") ||
                             lookahead.MatchesAcrossTokens("->"))
                    {
                        lookahead.NextByCharacters(2);
                    }
                    else
                    {
                        break;
                    }
                }
            }

            if (lookahead >= limit || lookahead.FundamentalType != FundamentalType.Whitespace)
            {
                entryText = null;
                return(false);
            }

            entryText = iterator.TextBetween(lookahead);
            iterator  = lookahead;
            return(true);
        }
Exemplo n.º 7
0
        // Group: Support Functions
        // __________________________________________________________________________


        /* Function: TryToGetPDBlockComment
         *
         * If the line iterator is on the starting symbol of a block comment, return it as a <PossibleDocumentationComment>
         * and mark the symbols as <CommentParsingType.CommentSymbol>.  If the iterator is not on the opening comment
         * symbol or there is content after the closing comment symbol making it unsuitable as a documentation comment,
         * returns null.
         *
         * If openingMustBeAlone is set, that means no symbol can appear immediately after the opening symbol for this
         * function to succeed.  This allows you to specifically detect something like /** without also matching /******.
         */
        protected PossibleDocumentationComment TryToGetPDBlockComment(LineIterator lineIterator,
                                                                      string openingSymbol, string closingSymbol,
                                                                      bool openingMustBeAlone)
        {
            TokenIterator firstToken = lineIterator.FirstToken(LineBoundsMode.ExcludeWhitespace);

            if (firstToken.MatchesAcrossTokens(openingSymbol) == false)
            {
                return(null);
            }

            if (openingMustBeAlone)
            {
                TokenIterator nextToken = firstToken;
                nextToken.NextByCharacters(openingSymbol.Length);
                if (nextToken.FundamentalType == FundamentalType.Symbol)
                {
                    return(null);
                }
            }

            PossibleDocumentationComment comment = new PossibleDocumentationComment();

            comment.Start = lineIterator;

            for (;;)
            {
                if (!lineIterator.IsInBounds)
                {
                    return(null);
                }

                TokenIterator closingSymbolIterator;

                if (lineIterator.FindAcrossTokens(closingSymbol, false, LineBoundsMode.Everything, out closingSymbolIterator) == true)
                {
                    closingSymbolIterator.NextByCharacters(closingSymbol.Length);

                    closingSymbolIterator.NextPastWhitespace();

                    if (closingSymbolIterator.FundamentalType != FundamentalType.LineBreak &&
                        closingSymbolIterator.FundamentalType != FundamentalType.Null)
                    {
                        return(null);
                    }

                    lineIterator.Next();
                    comment.End = lineIterator;
                    break;
                }

                lineIterator.Next();
            }

            // Success.  Mark the symbols before returning.
            firstToken.SetCommentParsingTypeByCharacters(CommentParsingType.CommentSymbol, openingSymbol.Length);

            TokenIterator lastToken;

            lineIterator.Previous();
            lineIterator.GetBounds(LineBoundsMode.ExcludeWhitespace, out firstToken, out lastToken);
            lastToken.PreviousByCharacters(closingSymbol.Length);
            lastToken.SetCommentParsingTypeByCharacters(CommentParsingType.CommentSymbol, closingSymbol.Length);

            return(comment);
        }
Exemplo n.º 8
0
        /* Function: HasSimilarSpacing
         * Returns whether the spacing of the tokens between the two iterators matches what would have been built by this
         * class if the tokens were passed through it.
         */
        public static bool HasSimilarSpacing(TokenIterator start, TokenIterator end)
        {
            // ::Package::Name* array of const*[]
            // Single spaces only between words, and between words and prior symbols except for leading symbols and package separators

            TokenIterator iterator = start;

            bool            pastFirstText           = false;
            FundamentalType lastTokenType           = FundamentalType.Null;
            bool            dontAddSpaceAfterSymbol = false;
            bool            lastSymbolWasBlock      = false;

            while (iterator < end)
            {
                if (iterator.FundamentalType == FundamentalType.Text ||
                    iterator.Character == '_')
                {
                    if (lastTokenType == FundamentalType.Null ||
                        lastTokenType == FundamentalType.Text ||
                        (lastTokenType == FundamentalType.Symbol && (dontAddSpaceAfterSymbol || (!pastFirstText && !lastSymbolWasBlock))) ||
                        lastTokenType == FundamentalType.Whitespace)
                    {
                        pastFirstText = true;
                        lastTokenType = FundamentalType.Text;

                        if (!TryToSkipModifierBlock(ref iterator))
                        {
                            iterator.Next();
                        }
                    }
                    else
                    {
                        return(false);
                    }
                }
                else if (iterator.FundamentalType == FundamentalType.Symbol)
                {
                    if (iterator.Character == ',')
                    {
                        // Quit early on commas, since it could be x[,,] or (x, y), in which case it's not clear whether there should be
                        // a space without making this logic even more complicated.  Just fail out and build a new one.
                        return(false);
                    }

                    if (lastTokenType == FundamentalType.Null ||
                        lastTokenType == FundamentalType.Text ||
                        lastTokenType == FundamentalType.Symbol)
                    {
                        lastTokenType = FundamentalType.Symbol;

                        if (iterator.MatchesAcrossTokens("::"))
                        {
                            lastSymbolWasBlock      = false;
                            dontAddSpaceAfterSymbol = true;
                            iterator.NextByCharacters(2);
                        }
                        else if (iterator.Character == '.' || iterator.Character == '%' ||
                                 iterator.Character == '"' || iterator.Character == '\'' || iterator.Character == '@' ||
                                 iterator.Character == '(')
                        {
                            lastSymbolWasBlock      = false;
                            dontAddSpaceAfterSymbol = true;
                            iterator.Next();
                        }
                        else if (TryToSkipModifierBlock(ref iterator))
                        {
                            lastSymbolWasBlock      = true;
                            dontAddSpaceAfterSymbol = false;
                            // already moved iterator
                        }
                        else
                        {
                            lastSymbolWasBlock      = false;
                            dontAddSpaceAfterSymbol = false;
                            iterator.Next();
                        }
                    }
                    else
                    {
                        return(false);
                    }
                }
                else if (iterator.FundamentalType == FundamentalType.Whitespace &&
                         iterator.Character == ' ' && iterator.RawTextLength == 1)
                {
                    if ((lastTokenType == FundamentalType.Symbol && !dontAddSpaceAfterSymbol && (pastFirstText || lastSymbolWasBlock)) ||
                        lastTokenType == FundamentalType.Text)
                    {
                        lastTokenType = FundamentalType.Whitespace;
                        iterator.Next();
                    }
                    else
                    {
                        return(false);
                    }
                }
                else
                {
                    return(false);
                }
            }

            return(true);
        }
Exemplo n.º 9
0
        /* Function: HasSimilarSpacing
         * Returns whether the spacing of the tokens between the two iterators matches what would have been built by this
         * class if the tokens were passed through it.
         */
        public static bool HasSimilarSpacing(TokenIterator start, TokenIterator end)
        {
            // ::Package::Name* array of const*[]
            // Single spaces only between words, and between words and prior symbols except for leading symbols and package separators

            TokenIterator iterator = start;

            bool            pastFirstText           = false;
            FundamentalType lastTokenType           = FundamentalType.Null;
            bool            dontAddSpaceAfterSymbol = false;
            bool            lastSymbolWasBlock      = false;

            while (iterator < end)
            {
                if (iterator.FundamentalType == FundamentalType.Text ||
                    iterator.Character == '_')
                {
                    if (lastTokenType == FundamentalType.Null ||
                        lastTokenType == FundamentalType.Text ||
                        (lastTokenType == FundamentalType.Symbol && (dontAddSpaceAfterSymbol || (!pastFirstText && !lastSymbolWasBlock))) ||
                        lastTokenType == FundamentalType.Whitespace)
                    {
                        pastFirstText = true;
                        lastTokenType = FundamentalType.Text;

                        if (!TryToSkipModifierBlock(ref iterator))
                        {
                            iterator.Next();
                        }
                    }
                    else
                    {
                        return(false);
                    }
                }
                else if (iterator.FundamentalType == FundamentalType.Symbol)
                {
                    if (lastTokenType == FundamentalType.Null ||
                        lastTokenType == FundamentalType.Text ||
                        lastTokenType == FundamentalType.Symbol)
                    {
                        lastTokenType = FundamentalType.Symbol;

                        if (iterator.MatchesAcrossTokens("::"))
                        {
                            lastSymbolWasBlock      = false;
                            dontAddSpaceAfterSymbol = true;
                            iterator.NextByCharacters(2);
                        }
                        else if (iterator.Character == '.' || iterator.Character == '%')
                        {
                            lastSymbolWasBlock      = false;
                            dontAddSpaceAfterSymbol = true;
                            iterator.Next();
                        }
                        else if (TryToSkipModifierBlock(ref iterator))
                        {
                            lastSymbolWasBlock      = true;
                            dontAddSpaceAfterSymbol = false;
                            // already moved iterator
                        }
                        else
                        {
                            lastSymbolWasBlock      = false;
                            dontAddSpaceAfterSymbol = false;
                            iterator.Next();
                        }
                    }
                    else
                    {
                        return(false);
                    }
                }
                else if (iterator.FundamentalType == FundamentalType.Whitespace &&
                         iterator.Character == ' ' && iterator.RawTextLength == 1)
                {
                    if ((lastTokenType == FundamentalType.Symbol && !dontAddSpaceAfterSymbol && (pastFirstText || lastSymbolWasBlock)) ||
                        lastTokenType == FundamentalType.Text)
                    {
                        lastTokenType = FundamentalType.Whitespace;
                        iterator.Next();
                    }
                    else
                    {
                        return(false);
                    }
                }
                else
                {
                    return(false);
                }
            }

            return(true);
        }
Exemplo n.º 10
0
        // Group: Private Functions
        // __________________________________________________________________________


        /* Function: DetermineElement
         * Determines which <JavadocElementType> the iterator is currently on, setting <type> and <length>.
         */
        private void DetermineElement()
        {
            bool found = false;

            if (tokenIterator == null || !IsInBounds)
            {
                type   = JavadocElementType.OutOfBounds;
                length = 0;
                found  = true;
            }
            // If we're on a new line and either whitespace or a comment token...
            else if ((RawTextIndex == 0 ||
                      Tokenizer.FundamentalTypeOf(RawText[RawTextIndex - 1]) == FundamentalType.LineBreak)
                     &&
                     (tokenIterator.FundamentalType == FundamentalType.Whitespace ||
                      tokenIterator.CommentParsingType == CommentParsingType.CommentSymbol ||
                      tokenIterator.CommentParsingType == CommentParsingType.CommentDecoration))
            {
                type   = JavadocElementType.Indent;
                length = 0;

                TokenIterator lookahead = tokenIterator;

                do
                {
                    length += lookahead.RawTextLength;
                    lookahead.Next();
                }while (lookahead.RawTextIndex < endingRawTextIndex &&
                        (lookahead.FundamentalType == FundamentalType.Whitespace ||
                         lookahead.CommentParsingType == CommentParsingType.CommentSymbol ||
                         lookahead.CommentParsingType == CommentParsingType.CommentDecoration));

                found = true;
            }
            else if (tokenIterator.FundamentalType == FundamentalType.LineBreak)
            {
                type   = JavadocElementType.LineBreak;
                length = tokenIterator.RawTextLength;
                found  = true;
            }
            else if (tokenIterator.MatchesAcrossTokens("<!--"))
            {
                type = JavadocElementType.HTMLComment;

                int endingCommentIndex = RawText.IndexOf("-->", RawTextIndex + 4, endingRawTextIndex - (RawTextIndex + 4));

                if (endingCommentIndex == -1)
                {
                    length = endingRawTextIndex - RawTextIndex;
                }
                else
                {
                    length = (endingCommentIndex + 3) - RawTextIndex;
                }

                found = true;
            }
            else if (tokenIterator.Character == '<')
            {
                int nextBracketIndex = RawText.IndexOfAny(AngleBrackets, RawTextIndex + 1);

                if (nextBracketIndex != -1 && nextBracketIndex < endingRawTextIndex && RawText[nextBracketIndex] == '>')
                {
                    type   = JavadocElementType.HTMLTag;
                    length = nextBracketIndex + 1 - RawTextIndex;

                    Match tagMatch = HTMLTagRegex.Match(RawText, RawTextIndex, length);

                    if (tagMatch.Success)
                    {
                        found   = true;
                        tagType = tagMatch.Groups[1].ToString().ToLower();
                    }
                }
            }
            else if (tokenIterator.MatchesAcrossTokens("{@"))
            {
                int closingBrace = RawText.IndexOf('}', RawTextIndex + 2);

                TokenIterator lookahead = tokenIterator;
                lookahead.NextByCharacters(2);

                if (closingBrace != -1 && closingBrace < endingRawTextIndex &&
                    lookahead.FundamentalType == FundamentalType.Text &&
                    Parsers.Javadoc.InlineTags.Contains(lookahead.String))
                {
                    found   = true;
                    type    = JavadocElementType.JavadocTag;
                    tagType = lookahead.String;
                    length  = (closingBrace + 1) - RawTextIndex;
                }
            }
            else if (tokenIterator.Character == '@')
            {
                TokenIterator lookahead = tokenIterator;
                lookahead.Next();

                if (lookahead.FundamentalType == FundamentalType.Text &&
                    Parsers.Javadoc.BlockTags.Contains(lookahead.String))
                {
                    found   = true;
                    type    = JavadocElementType.JavadocTag;
                    tagType = lookahead.String;
                    length  = tagType.Length + 1;
                }
            }
            else if (tokenIterator.Character == '&')
            {
                int semicolonIndex = RawText.IndexOf(';', RawTextIndex + 1);

                if (semicolonIndex != -1 && semicolonIndex < endingRawTextIndex &&
                    HTMLEntityChars.IsEntityChar(RawText, RawTextIndex, semicolonIndex + 1 - RawTextIndex))
                {
                    type   = JavadocElementType.EntityChar;
                    length = semicolonIndex + 1 - RawTextIndex;
                    found  = true;
                }
            }

            if (!found)
            {
                type = JavadocElementType.Text;

                int nextElementIndex = RawText.IndexOfAny(StartOfElement, RawTextIndex + 1);

                if (nextElementIndex == -1)
                {
                    length = endingRawTextIndex - RawTextIndex;
                }
                else
                {
                    length = nextElementIndex - RawTextIndex;
                }
            }
        }