Exemplo n.º 1
0
        /* Function: ApplySubstitutions
         * Finds all substitutions in the source that match those in the table and replaces them with their values.  Will also comment
         * out any substitution definitions found.
         */
        protected Tokenizer ApplySubstitutions(Tokenizer source, StringToStringTable substitutions, bool applyNestedSubstitutions = true)
        {
            TokenIterator iterator = source.FirstToken;


            // Find the first valid substitution identifier or definition.  If there aren't any we don't want to \do unnecessary memory
            // allocation and processing.

            bool   foundSubstitution = false;
            string identifier = null;
            string localeIdentifier, value, declaration;

            while (iterator.IsInBounds)
            {
                if (TryToSkipSubstitutionIdentifier(ref iterator, out identifier) ||
                    TryToSkipLocaleSubstitutionIdentifier(ref iterator, out identifier, out localeIdentifier))
                {
                    foundSubstitution = true;
                    break;
                }
                // else if (TryToSkipSubstitutionDefinition())
                // {
                // Unnecessary because definitions will start with identifiers so it will get picked up by that
                // }
                else
                {
                    GenericSkip(ref iterator);
                }
            }

            if (!foundSubstitution)
            {
                return(source);
            }


            // Now that we know we have one, we can back up the iterator and build new output

            iterator.PreviousByCharacters(identifier.Length);

            StringBuilder output = new StringBuilder(source.RawText.Length);

            output.Append(source.RawText, 0, iterator.RawTextIndex);

            while (iterator.IsInBounds)
            {
                TokenIterator previousIterator = iterator;

                if (TryToSkipSubstitutionDefinition(ref iterator, out identifier, out value, out declaration))
                {
                    if (this.blockCommentStringPairs != null)
                    {
                        output.Append(this.blockCommentStringPairs[0] + ' ' + declaration + ' ' + this.blockCommentStringPairs[1]);
                    }
                }
                else if (TryToSkipSubstitutionIdentifier(ref iterator, out identifier))
                {
                    string substitution = substitutions[identifier];

                    if (substitution == null)
                    {
                        output.Append(identifier);
                    }
                    else
                    {
                        if (applyNestedSubstitutions)
                        {
                            substitution = ApplyNestedSubstitutions(substitution, substitutions);
                        }

                        output.Append(substitution);
                    }
                }
                else if (TryToSkipLocaleSubstitutionIdentifier(ref iterator, out identifier, out localeIdentifier))
                {
                    string substitution = Engine.Locale.SafeGet("NaturalDocs.Engine", localeIdentifier, null);

                    if (substitution == null)
                    {
                        output.Append(identifier);
                    }
                    else
                    {
                        output.Append('"' + substitution.StringEscape() + '"');
                    }
                }
                else
                {
                    GenericSkip(ref iterator);
                    source.AppendTextBetweenTo(previousIterator, iterator, output);
                }
            }

            return(new Tokenizer(output.ToString()));
        }
Exemplo n.º 2
0
        /* Function: TryToGetBlockComment
         *
         * If the iterator is on a line that starts with the opening symbol of a block comment, 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 an opening comment symbol it will return false and leave the iterator where it is.
         */
        protected bool TryToGetBlockComment(ref LineIterator lineIterator, out PossibleDocumentationComment comment)
        {
            TokenIterator firstToken, endOfLine;

            lineIterator.GetBounds(LineBoundsMode.ExcludeWhitespace, out firstToken, out endOfLine);


            // Are we on a block comment?

            TokenIterator lookahead = firstToken;
            string        closingSymbol;

            if (TryToSkipOpeningBlockCommentSymbol(ref lookahead, out closingSymbol) == false)
            {
                comment = null;
                return(false);
            }


            // We are.  Create a possible documentation comment.

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


            // Check if we're on a Javadoc comment, which will be an extra [.

            if (lookahead.Character == '[')
            {
                lookahead.Next();

                if (lookahead.FundamentalType != FundamentalType.Symbol)
                {
                    comment.Javadoc = true;
                }
            }


            // Find the end of the comment, which could be on the same line as the start.

            var  tokenizer         = lineIterator.Tokenizer;
            var  lineLookahead     = lineIterator;
            bool hadTrailingDashes = false;

            for (;;)
            {
                TokenIterator closingSymbolIterator;

                if (tokenizer.FindTokensBetween(closingSymbol, false, firstToken, endOfLine, out closingSymbolIterator) == true)
                {
                    // Move past the end of the comment regardless of whether it's acceptable for documentation or not
                    lineLookahead.Next();

                    // Make sure nothing appears after the closing symbol on the line
                    closingSymbolIterator.NextByCharacters(closingSymbol.Length);

                    // We'll allow -- though since some people use --[[ and ]]-- for balance even though the latter is actually the
                    // closing comment symbol followed by a line comment.
                    if (closingSymbolIterator.MatchesAcrossTokens("--"))
                    {
                        hadTrailingDashes = true;
                        closingSymbolIterator.Next(2);
                    }

                    closingSymbolIterator.NextPastWhitespace();

                    if (closingSymbolIterator.FundamentalType != FundamentalType.LineBreak &&
                        closingSymbolIterator.FundamentalType != FundamentalType.Null)
                    {
                        comment = null;
                    }
                    else
                    {
                        comment.End = lineLookahead;
                    }

                    break;
                }

                lineLookahead.Next();

                // If we're not in bounds that means there was an unclosed comment at the end of the file.  Skip it but don't treat
                // it as a documentation candidate.
                if (!lookahead.IsInBounds)
                {
                    comment = null;
                    break;
                }

                lineLookahead.GetBounds(LineBoundsMode.ExcludeWhitespace, out firstToken, out endOfLine);
            }


            if (comment != null)
            {
                // Mark the symbols before returning

                firstToken = comment.Start.FirstToken(LineBoundsMode.ExcludeWhitespace);
                lookahead  = firstToken;
                TryToSkipOpeningBlockCommentSymbol(ref lookahead, out closingSymbol);

                if (comment.Javadoc)
                {
                    lookahead.Next();
                }

                firstToken.SetCommentParsingTypeBetween(lookahead, CommentParsingType.CommentSymbol);

                LineIterator lastLine = comment.End;
                lastLine.Previous();
                lastLine.GetBounds(LineBoundsMode.ExcludeWhitespace, out firstToken, out endOfLine);

                lookahead = endOfLine;

                if (hadTrailingDashes)
                {
                    lookahead.Previous(2);
                }

                lookahead.PreviousByCharacters(closingSymbol.Length);

                lookahead.SetCommentParsingTypeBetween(endOfLine, CommentParsingType.CommentSymbol);
            }

            // If we made it this far that means we found a comment and can move the line iterator and return true.  Whether
            // that comment was suitable for documentation will be determined by the comment variable, but we are moving the
            // iterator and returning true either way.
            lineIterator = lineLookahead;
            return(true);
        }