/// <summary>
 /// Write an identifier, prefixing with '@' if it happens to be a keyword.
 /// </summary>
 public void WriteIdentifier(string text, CodeObject.RenderFlags flags)
 {
     // Delimit the identifier if we're not in a doc comment and it's the same as a C# keyword
     if (!flags.HasFlag(CodeObject.RenderFlags.InDocComment) && Keywords.Contains(text))
     {
         Write("@");
     }
     Write(text);
 }
        /// <summary>
        /// Write a pending EOL comment, to be flushed later once it's known if anything follows it on the same line.
        /// </summary>
        public void WritePendingEOLComment(Comment comment, CodeObject.RenderFlags flags)
        {
            // If the EOL comment is on a new line (postfix comment), flush any existing pending EOL comments first
            if (comment.IsFirstOnLine && _pendingEOLComments.Count > 0)
            {
                FlushPendingEOLComments(true);
            }

            // Save the comment until the next write, so we can determine if it's the last thing on the line.
            // Also save the indentation of the parent, in case it's actually a postfix comment on a new line (for
            // an Expression).  Use the max of any ParentOffset or the current IndentOffset.
            // Also save the rendering flags, to preserve flags such as UpdateLineCol for later rendering.
            int parentOffset = _indentStateStack.Peek().ParentOffset;

            _pendingEOLComments.Add(new EOLComment(comment, Math.Max(parentOffset, IndentOffset), flags & CodeObject.RenderFlags.PassMask));
        }
 /// <summary>
 /// Render a name, hiding any 'Attribute' suffix if it's an attribute name.
 /// </summary>
 public void WriteName(string name, CodeObject.RenderFlags flags, bool possibleKeyword)
 {
     // Hide any "Attribute" suffix for attribute constructor names
     if (flags.HasFlag(CodeObject.RenderFlags.Attribute) && name.EndsWith(Attribute.NameSuffix))
     {
         name            = name.Substring(0, name.Length - Attribute.NameSuffix.Length);
         possibleKeyword = false;
     }
     if (possibleKeyword)
     {
         WriteIdentifier(name, flags);
     }
     else
     {
         Write(name);
     }
 }
 /// <summary>
 /// Create an <see cref="EOLComment"/>.
 /// </summary>
 public EOLComment(Comment comment, int indentation, CodeObject.RenderFlags flags)
 {
     Comment     = comment;
     Indentation = indentation;
     RenderFlags = flags;
 }
 /// <summary>
 /// Write a list of CodeObjects.
 /// </summary>
 public void WriteList <T>(IEnumerable <T> enumerable, CodeObject.RenderFlags flags, CodeObject parent) where T : CodeObject
 {
     WriteList(enumerable, flags, parent, null);
 }
        /// <summary>
        /// Write a list of CodeObjects.
        /// </summary>
        public void WriteList <T>(IEnumerable <T> enumerable, CodeObject.RenderFlags flags, CodeObject parent, int[] columnWidths) where T : CodeObject
        {
            if (enumerable == null)
            {
                return;
            }

            // Increase the indent level for any newlines that occur within the child list unless specifically told not to
            bool increaseIndent = !flags.HasFlag(CodeObject.RenderFlags.NoIncreaseIndent);

            if (increaseIndent)
            {
                BeginIndentOnNewLine(parent);
            }

            // Render the items in the list
            bool            isSingleLine = true;
            bool            isFirst      = true;
            int             column       = 0;
            IEnumerator <T> enumerator   = enumerable.GetEnumerator();
            bool            hasMore      = enumerator.MoveNext();

            while (hasMore)
            {
                CodeObject codeObject = enumerator.Current;
                hasMore = enumerator.MoveNext();
                if (codeObject != null)
                {
                    if (codeObject.IsFirstOnLine)
                    {
                        isSingleLine = false;
                        column       = 0;
                    }

                    // Render any newlines here, so that the indentation will be correct if the object has any post annotations
                    // (which are rendered separately below, so that any commas can be rendered properly).
                    if (!flags.HasFlag(CodeObject.RenderFlags.IsPrefix) && !flags.HasFlag(CodeObject.RenderFlags.SuppressNewLine) && codeObject.NewLines > 0)
                    {
                        WriteLines(codeObject.NewLines);
                        // Set the parent offset for any post annotations
                        SetParentOffset();
                    }

                    // Render the code object, omitting any EOL comments and post annotations (so they can be rendered later after
                    // any comma), and prefixing a space if it's not the first item.
                    CodeObject.RenderFlags passFlags = flags | CodeObject.RenderFlags.NoEOLComments | CodeObject.RenderFlags.NoPostAnnotations | CodeObject.RenderFlags.SuppressNewLine
                                                       | (isSingleLine ? (isFirst ? 0 : CodeObject.RenderFlags.PrefixSpace) : (codeObject.IsFirstOnLine ? 0 : CodeObject.RenderFlags.PrefixSpace));
                    codeObject.AsText(this, passFlags);
                    flags &= ~(CodeObject.RenderFlags.SuppressNewLine | CodeObject.RenderFlags.NoPreAnnotations);

                    if (hasMore)
                    {
                        // Render the trailing comma, with any EOL comments before or after it, depending on whether or not it's the last thing on the line
                        CodeObject nextObject   = enumerator.Current;
                        bool       isLastOnLine = (nextObject != null && nextObject.IsFirstOnLine);
                        if (!isLastOnLine)
                        {
                            codeObject.AsTextEOLComments(this, flags);
                        }
                        if (!flags.HasFlag(CodeObject.RenderFlags.NoItemSeparators))
                        {
                            Write(Expression.ParseTokenSeparator);
                        }
                        if (!isLastOnLine || codeObject.HasEOLComments)
                        {
                            WritePadding(codeObject, columnWidths, column);
                        }
                        if (isLastOnLine)
                        {
                            codeObject.AsTextEOLComments(this, flags);
                        }
                    }
                    else
                    {
                        if (flags.HasFlag(CodeObject.RenderFlags.HasTerminator) && !flags.HasFlag(CodeObject.RenderFlags.Description) && parent != null)
                        {
                            ((Statement)parent).AsTextTerminator(this, flags);
                        }
                        bool hasCloseBraceOnSameLine = (parent is Initializer && !((Initializer)parent).IsEndFirstOnLine);
                        if (codeObject.HasEOLComments || hasCloseBraceOnSameLine)
                        {
                            WritePadding(codeObject, columnWidths, column);

                            // If we're aligning columns and it's a multi-line list, add an extra space to line up the EOL comment
                            // or close brace since there's no trailing comma.
                            if (columnWidths != null && !isSingleLine)
                            {
                                if (_textWriter != null)
                                {
                                    _textWriter.Write(' ');
                                }
                                ++_columnNumber;
                            }
                        }
                        codeObject.AsTextEOLComments(this, flags);
                    }
                    codeObject.AsTextAnnotations(this, AnnotationFlags.IsPostfix, flags);
                }
                else if (hasMore)
                {
                    Write(Expression.ParseTokenSeparator);
                }

                isFirst = false;
                ++column;
            }

            // Reset the indent level
            if (increaseIndent)
            {
                EndIndentation(parent);
            }
        }
 /// <summary>
 /// Render a name, hiding any 'Attribute' suffix if it's an attribute name.
 /// </summary>
 public void WriteName(string name, CodeObject.RenderFlags flags)
 {
     WriteName(name, flags, false);
 }