Пример #1
0
        /// <summary>
        /// Parse tokens into Modifiers bit flags.
        /// </summary>
        public static Modifiers Parse(Parser parser, CodeObject parent)
        {
            // Search the parser's unused list for valid modifier tokens
            Modifiers           modifiers = 0;
            bool                hasSandwichedModifiers  = false;
            bool                hasConditionalModifiers = false;
            bool                needsElseCondition      = true;
            bool                elseIsNotActive         = false;
            bool                foundEndIf = false;
            List <ParsedObject> unusedList = parser.Unused;

            // First, pre-scan the unused list to check for the special case of conditional directives
            // being used on the modifiers.  Set a flag if we detect this for later processing below.
            for (int i = unusedList.Count - 1; i >= 0; --i)
            {
                ParsedObject parsedObject = unusedList[i];
                if (parsedObject is Token)
                {
                    // Abort if there's a blank line, or if we get a token that isn't a modifier
                    Token token = (Token)parsedObject;
                    if (token.NewLines > 1 || !IsModifier(token.Text))
                    {
                        break;
                    }
                    if (foundEndIf)
                    {
                        hasSandwichedModifiers = true;
                    }
                }
                else
                {
                    // Abort if we get anything other than the expected #if/#else/#endif chain, or if
                    // we have any comments before we hit the #endif (going backwards).
                    CodeObject codeObject = ((UnusedCodeObject)parsedObject).CodeObject;
                    if (codeObject is EndIfDirective)
                    {
                        if (foundEndIf || parsedObject.HasTrailingComments)
                        {
                            break;
                        }
                        foundEndIf = true;
                    }
                    else if (codeObject is ConditionalDirective)
                    {
                        if (!foundEndIf)
                        {
                            break;
                        }
                        if (codeObject is ElseDirective)
                        {
                            needsElseCondition = false;
                        }
                        else
                        {
                            if (((ConditionalDirective)codeObject).IsActive)
                            {
                                elseIsNotActive = true;
                            }
                            if (codeObject is IfDirective)
                            {
                                if (hasSandwichedModifiers)
                                {
                                    hasConditionalModifiers = true;
                                }
                                break;
                            }
                        }
                    }
                    else
                    {
                        break;
                    }
                }
            }

            // Now, reset and do the real parse scan
            bool   postDirective            = true;
            string declarationText          = null;
            string declarationModifiersText = null;
            Token  lastUnrecognizedToken    = null;
            List <ConditionalDirective> inactiveConditions = new List <ConditionalDirective>();

            for (int i = unusedList.Count - 1; i >= 0; --i)
            {
                ParsedObject parsedObject = unusedList[i];
                if (parsedObject is Token)
                {
                    // Check for modifier tokens
                    Token     token = (Token)unusedList[i];
                    Modifiers value;
                    if (_nameToModifierMap.TryGetValue(token.Text, out value))
                    {
                        modifiers |= value;
                        parent.MoveFormatting(token);
                        parent.MoveAllComments(token, true);
                        unusedList.RemoveAt(i);

                        // If we've passed the conditionals and have prefixed modifiers, add them
                        // to the skipped text of all of the inactive conditions.
                        if (!hasConditionalModifiers && inactiveConditions.Count > 0)
                        {
                            foreach (ConditionalDirective conditionalDirective in inactiveConditions)
                            {
                                conditionalDirective.SkippedText = AsString(value) + conditionalDirective.SkippedText;
                            }
                        }
                    }
                    else
                    {
                        // If the token isn't recognized, continue processing in case there are other unused tokens
                        // that we do recognize as modifiers (there might be new modifiers added in later C# versions).
                        // Also, keep track of the last unrecognized token so we can transfer any newlines to it.
                        lastUnrecognizedToken = (Token)parsedObject;
                    }
                }
                else if (hasConditionalModifiers)
                {
                    // Check for compiler directives - specifically, we handle an #endif immediately
                    // preceeding the parent declaration, allowing for a chain of conditional directives
                    // used to change the modifiers on the declaration at compile-time.  We have already
                    // verified that we have a valid sequence (above), so we process conditional directives
                    // backwards here until we get to the starting #if.
                    UnusedCodeObject unused = (UnusedCodeObject)parsedObject;
                    if (unused.CodeObject is CompilerDirective)
                    {
                        // Store any compiler directives as pre or post annotations on the parent
                        CompilerDirective compilerDirective = (CompilerDirective)unused.CodeObject;
                        if (compilerDirective is EndIfDirective)
                        {
                            declarationText          = parent.AsString();
                            declarationModifiersText = AsString(modifiers);
                        }
                        else if (compilerDirective is ConditionalDirective)
                        {
                            ConditionalDirective conditionalDirective = (ConditionalDirective)compilerDirective;

                            // Create an #else if none existed
                            if (needsElseCondition)
                            {
                                ElseDirective elseDirective = new ElseDirective();
                                if (elseIsNotActive)
                                {
                                    elseDirective.SkippedText = declarationText;
                                    inactiveConditions.Add(elseDirective);
                                }
                                else
                                {
                                    postDirective = false;
                                }
                                parent.AttachAnnotation(elseDirective, elseIsNotActive ? AnnotationFlags.IsPostfix : AnnotationFlags.None, true);
                                needsElseCondition = false;
                            }

                            // When we find the active condition, switch from post to pre
                            if (conditionalDirective.IsActive)
                            {
                                postDirective = false;
                            }
                            else
                            {
                                // Update any skipped conditions to reflect the entire declaration
                                Modifiers orderedModifiers = Parse(conditionalDirective.SkippedText + " " + declarationModifiersText);
                                conditionalDirective.SkippedText = AsString(orderedModifiers) + declarationText;
                                inactiveConditions.Add(conditionalDirective);
                            }

                            // Stop processing conditionals when we get to the #if
                            if (compilerDirective is IfDirective)
                            {
                                hasConditionalModifiers = false;
                            }
                        }
                        else
                        {
                            break;  // For now, stop if we find any other directives
                        }
                        parent.AttachAnnotation(compilerDirective, postDirective ? AnnotationFlags.IsPostfix : AnnotationFlags.None, true);
                        parent.MoveComments(unused.LastToken, true);
                        unusedList.RemoveAt(i);
                    }
                }
                else
                {
                    break;
                }
            }

            // If we had any unrecognized tokens, they'll be emitted before the parent object, so if the last one
            // doesn't have any newlines, we need to give it the parent's newlines.
            if (lastUnrecognizedToken != null)
            {
                if (lastUnrecognizedToken.NewLines == 0)
                {
                    lastUnrecognizedToken.NewLines = (ushort)parent.NewLines;
                }
                parent.NewLines = 0;
            }

            return(modifiers);
        }