NArrange.VisualBasic.VBParser.ParseElements C# (CSharp) Method

ParseElements() private method

Parses elements from the current point in the stream.
private ParseElements ( ICodeElement parentElement ) : List
parentElement ICodeElement Parent element
return List
        private List<ICodeElement> ParseElements(ICodeElement parentElement)
        {
            List<ICodeElement> codeElements = new List<ICodeElement>();
            List<ICodeElement> siblingElements = new List<ICodeElement>();
            List<ICommentElement> comments = new List<ICommentElement>();
            List<AttributeElement> attributes = new List<AttributeElement>();
            Stack<ICodeElement> enclosingElementStack = new Stack<ICodeElement>();

            StringBuilder elementBuilder = new StringBuilder(DefaultBlockLength);

            char nextChar;
            bool end = false;
            bool lineContinuation = false;

            while (TryReadChar() && !end)
            {
                switch (CurrentChar)
                {
                    //
                    // Comments
                    //
                    case VBSymbol.BeginComment:
                        CommentElement commentLine = ParseCommentLine();
                        string commentDirectiveRegionName =
                            GetCommentDirectiveText(commentLine, Configuration.Formatting.Regions.CommentDirectiveBeginPattern, "Name");

                        if (commentDirectiveRegionName != null)
                        {
                            PushComments(codeElements, comments);

                            RegionElement regionElement = new RegionElement();
                            regionElement.Name = commentDirectiveRegionName;
                            enclosingElementStack.Push(regionElement);
                        }
                        else
                        {
                            commentDirectiveRegionName = GetCommentDirectiveText(commentLine,
                                Configuration.Formatting.Regions.CommentDirectiveEndPattern, "Name");
                            if (commentDirectiveRegionName != null)
                            {
                                if (enclosingElementStack.Count == 0 ||
                                    enclosingElementStack.Peek().ElementType != ElementType.Region)
                                {
                                    this.OnParseError("Unmatched end region directive");
                                }

                                ICodeElement enclosingElement = enclosingElementStack.Pop();

                                //
                                // Add any processed comments to the region or condition directive.
                                //
                                if (comments.Count > 0)
                                {
                                    foreach (ICommentElement commentElement in comments)
                                    {
                                        enclosingElement.AddChild(commentElement);
                                    }
                                    comments.Clear();
                                }

                                //
                                // Are we processing a nested region or condition directive?
                                //
                                if (enclosingElementStack.Count > 0)
                                {
                                    enclosingElementStack.Peek().AddChild(enclosingElement);
                                }
                                else
                                {
                                    codeElements.Add(enclosingElement);
                                }
                            }
                            else
                            {
                                comments.Add(commentLine);
                            }
                        }
                        break;

                    //
                    // Preprocessor
                    //
                    case VBSymbol.Preprocessor:
                        //
                        // TODO: Parse additional preprocessor directives.
                        //
                        string line = ReadLine().Trim();
                        string[] words = line.Split(WhiteSpaceCharacters, StringSplitOptions.RemoveEmptyEntries);
                        if (words.Length > 0 && VBKeyword.Normalize(words[0]) == VBKeyword.Region)
                        {
                            PushComments(codeElements, comments);

                            RegionElement regionElement = ParseRegion(line);
                            enclosingElementStack.Push(regionElement);
                        }
                        else if (words.Length > 0 &&
                                 (VBKeyword.Normalize(words[0]) == VBKeyword.If ||
                                  VBKeyword.Normalize(words[0]) == VBKeyword.Else ||
                                  VBKeyword.Normalize(words[0]) == VBKeyword.ElseIf))
                        {
                            bool isIf;
                            ConditionDirectiveElement conditionDirective = ParseConditionDirective(line.Trim(), out isIf);

                            if (isIf)
                            {
                                enclosingElementStack.Push(conditionDirective);
                            }
                            else
                            {
                                if (enclosingElementStack.Count == 0 ||
                                    enclosingElementStack.Peek().ElementType != ElementType.ConditionDirective)
                                {
                                    this.OnParseError("Expected 'If' preprocessor directive.");
                                }
                                else
                                {
                                    ConditionDirectiveElement previousCondition =
                                        enclosingElementStack.Peek() as ConditionDirectiveElement;
                                    while (previousCondition.ElseCondition != null)
                                    {
                                        previousCondition = previousCondition.ElseCondition;
                                    }

                                    // Add the condition to the end of the condition linked list
                                    previousCondition.ElseCondition = conditionDirective;
                                }
                            }
                        }
                        else if (words.Length > 1 &&
                                 VBKeyword.Normalize(words[0]) == VBKeyword.End &&
                                 (VBKeyword.Normalize(words[1]) == VBKeyword.Region ||
                                  VBKeyword.Normalize(words[1]) == VBKeyword.If))
                        {
                            ICodeElement enclosingElement = null;

                            if (VBKeyword.Normalize(words[1]) == VBKeyword.Region)
                            {
                                if (enclosingElementStack.Count == 0 ||
                                    enclosingElementStack.Peek().ElementType != ElementType.Region)
                                {
                                    this.OnParseError("Unmatched end region directive");
                                }
                            }
                            else if (enclosingElementStack.Count == 0 ||
                                     enclosingElementStack.Peek().ElementType != ElementType.ConditionDirective)
                            {
                                this.OnParseError("Unmatched #End If");
                            }

                            enclosingElement = enclosingElementStack.Pop();

                            //
                            // If there are any attributes not associated with an element (e.g.
                            // a condition directive containing only an attribute, then
                            // throw an error as this is currently not supported.
                            //
                            if (enclosingElement.ElementType == ElementType.ConditionDirective &&
                                attributes.Count > 0)
                            {
                                this.OnParseError(
                                    "Cannot arrange files with preprocessor directives containing attributes unassociated to an element");
                            }

                            if (comments.Count > 0)
                            {
                                foreach (ICommentElement commentElement in comments)
                                {
                                    enclosingElement.AddChild(commentElement);
                                }
                                comments.Clear();
                            }

                            if (enclosingElementStack.Count > 0)
                            {
                                enclosingElementStack.Peek().AddChild(enclosingElement);
                            }
                            else
                            {
                                codeElements.Add(enclosingElement);
                            }
                        }
                        else
                        {
                            this.OnParseError(
                                "Cannot arrange files with preprocessor directives " +
                                "other than #Region, #End Region and conditional compilation directives");
                        }
                        break;

                    //
                    // Attribute
                    //
                    case VBSymbol.BeginAttribute:
                        nextChar = NextChar;

                        //
                        // Parse attribute
                        //
                        AttributeElement attributeElement = ParseAttribute(comments.AsReadOnly());

                        attributes.Add(attributeElement);
                        codeElements.Add(attributeElement);
                        comments.Clear();
                        break;

                    case VBSymbol.LineContinuation:
                        if (IsWhiteSpace(PreviousChar) && IsWhiteSpace(NextChar))
                        {
                            lineContinuation = true;
                        }
                        else
                        {
                            elementBuilder.Append(CurrentChar);
                        }
                        break;

                    // Eat any unneeded whitespace
                    case ' ':
                    case '\n':
                    case '\r':
                    case '\t':
                    case ':':
                        if (elementBuilder.Length > 0)
                        {
                            string processedText = elementBuilder.ToString().Trim();
                            if (CurrentChar == '\n')
                            {
                                if (!lineContinuation)
                                {
                                    this.OnParseError(
                                        string.Format(
                                            Thread.CurrentThread.CurrentCulture,
                                            "Unhandled element text '{0}'",
                                            processedText));
                                }
                                else
                                {
                                    lineContinuation = false;
                                }
                            }

                            if (elementBuilder[elementBuilder.Length - 1] != ' ')
                            {
                                elementBuilder.Append(' ');
                            }
                        }
                        break;

                    default:
                        elementBuilder.Append(CurrentChar);

                        string upperElementText = elementBuilder.ToString().ToUpperInvariant();
                        nextChar = NextChar;

                        if (upperElementText == VBKeyword.End.ToUpperInvariant())
                        {
                            end = true;
                            elementBuilder = new StringBuilder(DefaultBlockLength);
                        }
                        else if (upperElementText == VBKeyword.Rem.ToUpperInvariant() &&
                                 nextChar == ' ')
                        {
                            CommentElement remCommentLine = ParseCommentLine();
                            comments.Add(remCommentLine);
                            elementBuilder = new StringBuilder(DefaultBlockLength);
                        }
                        else if (upperElementText == VBKeyword.Option.ToUpperInvariant() &&
                                 IsWhiteSpace(nextChar))
                        {
                            ICodeElement optionElement = ParseOption(comments.AsReadOnly());
                            comments.Clear();
                            codeElements.Add(optionElement);
                            elementBuilder = new StringBuilder(DefaultBlockLength);
                        }
                        else
                        {
                            if (char.IsWhiteSpace(nextChar) || VBSymbol.IsVBSymbol(CurrentChar))
                            {
                                string elementText = VBKeyword.Normalize(elementBuilder.ToString());
                                bool isImplements = elementText.StartsWith(
                                    VBKeyword.Implements, StringComparison.OrdinalIgnoreCase);
                                bool isInherits = !isImplements && elementText.StartsWith(
                                    VBKeyword.Inherits, StringComparison.OrdinalIgnoreCase);
                                TypeElement typeElement = parentElement as TypeElement;
                                if ((isImplements || isInherits) && typeElement != null)
                                {
                                    InterfaceReferenceType referenceType = InterfaceReferenceType.None;
                                    if (isInherits)
                                    {
                                        referenceType = InterfaceReferenceType.Class;
                                    }
                                    else if (isImplements)
                                    {
                                        referenceType = InterfaceReferenceType.Interface;
                                    }

                                    do
                                    {
                                        EatWhiteSpace(WhiteSpaceTypes.SpaceAndTab);
                                        if (NextChar == VBSymbol.AliasSeparator)
                                        {
                                            EatChar(VBSymbol.AliasSeparator);
                                        }

                                        string typeName = CaptureTypeName();
                                        InterfaceReference interfaceReference =
                                            new InterfaceReference(typeName, referenceType);
                                        typeElement.AddInterface(interfaceReference);
                                        EatWhiteSpace(WhiteSpaceTypes.SpaceAndTab);
                                    } while (NextChar == VBSymbol.AliasSeparator);

                                    elementBuilder = new StringBuilder(DefaultBlockLength);
                                }
                                else
                                {
                                    //
                                    // Try to parse a code element
                                    //
                                    ICodeElement element = TryParseElement(parentElement,
                                        elementBuilder, comments.AsReadOnly(), attributes.AsReadOnly());
                                    if (element != null)
                                    {
                                        // Since more than one field can be declared per line, we need special
                                        // handling here.
                                        FieldElement fieldElement = element as FieldElement;
                                        if (fieldElement != null)
                                        {
                                            if (elementBuilder[0] == VBSymbol.AliasSeparator
                                                && codeElements[codeElements.Count - 1] is FieldElement)
                                            {
                                                FieldElement previousFieldElement = codeElements[codeElements.Count - 1] as FieldElement;
                                                FieldElement currentField = element as FieldElement;

                                                if (currentField.Access == CodeAccess.None)
                                                {
                                                    currentField.Access = previousFieldElement.Access;
                                                }
                                            }
                                            else if (fieldElement.Name.Contains(VBSymbol.AliasSeparator.ToString()))
                                            {
                                                string[] fieldNames = fieldElement.Name.Split(
                                                    new char[] {VBSymbol.AliasSeparator}, StringSplitOptions.RemoveEmptyEntries);
                                                for (int fieldIndex = 0; fieldIndex < fieldNames.Length; fieldIndex++)
                                                {
                                                    if (fieldIndex == 0)
                                                    {
                                                        fieldElement.Name = fieldNames[0];
                                                    }
                                                    else
                                                    {
                                                        FieldElement siblingFieldElement = fieldElement.Clone() as FieldElement;
                                                        siblingFieldElement.Name = fieldNames[fieldIndex].Trim();
                                                        siblingElements.Add(siblingFieldElement);
                                                    }
                                                }
                                            }
                                        }

                                        if (element is CommentedElement)
                                        {
                                            UsingElement usingElement = element as UsingElement;

                                            //
                                            // If this is the first using statement, then don't attach
                                            // header comments to the element.
                                            //
                                            if (usingElement != null && parentElement == null && codeElements.Count == 0)
                                            {
                                                foreach (ICommentElement commentElement in usingElement.HeaderComments)
                                                {
                                                    if (enclosingElementStack.Count > 0)
                                                    {
                                                        enclosingElementStack.Peek().AddChild(commentElement);
                                                    }
                                                    else
                                                    {
                                                        codeElements.Add(commentElement);
                                                    }
                                                }
                                                usingElement.ClearHeaderCommentLines();
                                            }
                                            comments.Clear();
                                        }

                                        if (enclosingElementStack.Count > 0)
                                        {
                                            ICodeElement enclosingElement = enclosingElementStack.Peek();

                                            if (enclosingElement.ElementType == ElementType.ConditionDirective)
                                            {
                                                ConditionDirectiveElement conditionDirective = enclosingElement as ConditionDirectiveElement;
                                                while (conditionDirective.ElseCondition != null)
                                                {
                                                    conditionDirective = conditionDirective.ElseCondition;
                                                }

                                                enclosingElement = conditionDirective;
                                            }

                                            enclosingElement.AddChild(element);
                                            foreach (ICodeElement additionalElement in siblingElements)
                                            {
                                                enclosingElement.AddChild(additionalElement);
                                            }
                                        }
                                        else
                                        {
                                            codeElements.Add(element);
                                            foreach (ICodeElement additionalElement in siblingElements)
                                            {
                                                codeElements.Add(additionalElement);
                                            }
                                        }
                                        siblingElements.Clear();

                                        elementBuilder = new StringBuilder(DefaultBlockLength);

                                        if (element is IAttributedElement)
                                        {
                                            foreach (AttributeElement attribute in attributes)
                                            {
                                                codeElements.Remove(attribute);
                                            }

                                            attributes = new List<AttributeElement>();
                                        }
                                    }
                                }
                            }
                        }

                        break;
                }

                char nextCh = NextChar;
            }

            if (comments.Count > 0)
            {
                for (int commentIndex = 0; commentIndex < comments.Count; commentIndex++)
                {
                    ICommentElement comment = comments[commentIndex];
                    codeElements.Insert(commentIndex, comment);
                }
            }

            //
            // Make sure that all region elements have been closed
            //
            if (enclosingElementStack.Count > 0)
            {
                if (enclosingElementStack.Peek().ElementType == ElementType.Region)
                {
                    this.OnParseError(
                        string.Format(
                            CultureInfo.InvariantCulture,
                            "Missing end region directive for '{0}'",
                            enclosingElementStack.Peek().Name));
                }
                else
                {
                    this.OnParseError("Expected #End If");
                }
            }

            if (elementBuilder.Length > 0)
            {
                this.OnParseError(
                    string.Format(
                        Thread.CurrentThread.CurrentCulture,
                        "Unhandled element text '{0}'",
                        elementBuilder));
            }

            return codeElements;
        }