// Copyright (c) AlphaSierraPapa for the SharpDevelop Team // // Permission is hereby granted, free of charge, to any person obtaining a copy of this // software and associated documentation files (the "Software"), to deal in the Software // without restriction, including without limitation the rights to use, copy, modify, merge, // publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons // to whom the Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all copies or // substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE // FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Text; using ICSharpCode.NRefactory.PatternMatching; using ICSharpCode.NRefactory.TypeSystem; namespace ICSharpCode.NRefactory.CSharp { /// /// Outputs the AST. /// public class OutputVisitor : IAstVisitor, IPatternAstVisitor { readonly IOutputFormatter formatter; readonly CSharpFormattingOptions policy; readonly Stack containerStack = new Stack (); readonly Stack positionStack = new Stack (); /// /// Used to insert the minimal amount of spaces so that the lexer recognizes the tokens that were written. /// LastWritten lastWritten; enum LastWritten { Whitespace, Other, KeywordOrIdentifier, Plus, Minus, Ampersand, QuestionMark, Division } public OutputVisitor (TextWriter textWriter, CSharpFormattingOptions formattingPolicy) { if (textWriter == null) throw new ArgumentNullException ("textWriter"); if (formattingPolicy == null) throw new ArgumentNullException ("formattingPolicy"); this.formatter = new TextWriterOutputFormatter (textWriter); this.policy = formattingPolicy; } public OutputVisitor (IOutputFormatter formatter, CSharpFormattingOptions formattingPolicy) { if (formatter == null) throw new ArgumentNullException ("formatter"); if (formattingPolicy == null) throw new ArgumentNullException ("formattingPolicy"); this.formatter = formatter; this.policy = formattingPolicy; } #region StartNode/EndNode public event EventHandler OutputStarted; protected virtual void OnOutputStarted (AstNodeEventArgs e) { EventHandler handler = this.OutputStarted; if (handler != null) handler (this, e); } public event EventHandler OutputFinished; protected virtual void OnOutputFinished (AstNodeEventArgs e) { EventHandler handler = this.OutputFinished; if (handler != null) handler (this, e); } [Serializable] public sealed class AstNodeEventArgs : EventArgs { public AstNode AstNode { get; private set; } public AstNodeEventArgs (AstNode node) { this.AstNode = node; } } void StartNode (AstNode node) { // Ensure that nodes are visited in the proper nested order. // Jumps to different subtrees are allowed only for the child of a placeholder node. Debug.Assert (containerStack.Count == 0 || node.Parent == containerStack.Peek () || containerStack.Peek ().NodeType == NodeType.Pattern); if (positionStack.Count > 0) WriteSpecialsUpToNode (node); containerStack.Push (node); positionStack.Push (node.FirstChild); OnOutputStarted (new AstNodeEventArgs (node)); formatter.StartNode (node); } object EndNode (AstNode node) { Debug.Assert (node == containerStack.Peek ()); AstNode pos = positionStack.Pop (); Debug.Assert (pos == null || pos.Parent == node); WriteSpecials (pos, null); containerStack.Pop (); OnOutputFinished (new AstNodeEventArgs (node)); formatter.EndNode (node); return null; } #endregion #region WriteSpecials /// /// Writes all specials from start to end (exclusive). Does not touch the positionStack. /// void WriteSpecials (AstNode start, AstNode end) { for (AstNode pos = start; pos != end; pos = pos.NextSibling) { if (pos.Role == AstNode.Roles.Comment) { pos.AcceptVisitor (this, null); } } } /// /// Writes all specials between the current position (in the positionStack) and the next /// node with the specified role. Advances the current position. /// void WriteSpecialsUpToRole (Role role) { for (AstNode pos = positionStack.Peek(); pos != null; pos = pos.NextSibling) { if (pos.Role == role) { WriteSpecials (positionStack.Pop (), pos); positionStack.Push (pos); break; } } } /// /// Writes all specials between the current position (in the positionStack) and the specified node. /// Advances the current position. /// void WriteSpecialsUpToNode (AstNode node) { for (AstNode pos = positionStack.Peek(); pos != null; pos = pos.NextSibling) { if (pos == node) { WriteSpecials (positionStack.Pop (), pos); positionStack.Push (pos); break; } } } void WriteSpecialsUpToRole (Role role, AstNode nextNode) { // Look for the role between the current position and the nextNode. for (AstNode pos = positionStack.Peek(); pos != null && pos != nextNode; pos = pos.NextSibling) { if (pos.Role == AstNode.Roles.Comma) { WriteSpecials (positionStack.Pop (), pos); positionStack.Push (pos); break; } } } #endregion #region Comma /// /// Writes a comma. /// /// The next node after the comma. /// When set prevents printing a space after comma. void Comma (AstNode nextNode, bool noSpaceAfterComma = false) { WriteSpecialsUpToRole (AstNode.Roles.Comma, nextNode); Space (policy.SpaceBeforeBracketComma); // TODO: Comma policy has changed. formatter.WriteToken (","); lastWritten = LastWritten.Other; Space (!noSpaceAfterComma && policy.SpaceAfterBracketComma); // TODO: Comma policy has changed. } void WriteCommaSeparatedList (IEnumerable list) { bool isFirst = true; foreach (AstNode node in list) { if (isFirst) { isFirst = false; } else { Comma (node); } node.AcceptVisitor (this, null); } } void WriteCommaSeparatedListInParenthesis (IEnumerable list, bool spaceWithin) { LPar (); if (list.Any ()) { Space (spaceWithin); WriteCommaSeparatedList (list); Space (spaceWithin); } RPar (); } #if DOTNET35 void WriteCommaSeparatedList(IEnumerable list) { WriteCommaSeparatedList(list.SafeCast()); } void WriteCommaSeparatedList(IEnumerable list) { WriteCommaSeparatedList(list.SafeCast()); } void WriteCommaSeparatedListInParenthesis(IEnumerable list, bool spaceWithin) { WriteCommaSeparatedListInParenthesis(list.SafeCast(), spaceWithin); } void WriteCommaSeparatedListInParenthesis(IEnumerable list, bool spaceWithin) { WriteCommaSeparatedListInParenthesis(list.SafeCast(), spaceWithin); } #endif void WriteCommaSeparatedListInBrackets (IEnumerable list, bool spaceWithin) { WriteToken ("[", AstNode.Roles.LBracket); if (list.Any ()) { Space (spaceWithin); WriteCommaSeparatedList (list.SafeCast ()); Space (spaceWithin); } WriteToken ("]", AstNode.Roles.RBracket); } void WriteCommaSeparatedListInBrackets (IEnumerable list) { WriteToken ("[", AstNode.Roles.LBracket); if (list.Any ()) { Space (policy.SpacesWithinBrackets); WriteCommaSeparatedList (list.SafeCast ()); Space (policy.SpacesWithinBrackets); } WriteToken ("]", AstNode.Roles.RBracket); } #endregion #region Write tokens /// /// Writes a keyword, and all specials up to /// void WriteKeyword (string keyword, Role tokenRole = null) { WriteSpecialsUpToRole (tokenRole ?? AstNode.Roles.Keyword); if (lastWritten == LastWritten.KeywordOrIdentifier) formatter.Space (); formatter.WriteKeyword (keyword); lastWritten = LastWritten.KeywordOrIdentifier; } void WriteIdentifier (string identifier, Role identifierRole = null) { WriteSpecialsUpToRole (identifierRole ?? AstNode.Roles.Identifier); if (IsKeyword (identifier, containerStack.Peek ())) { if (lastWritten == LastWritten.KeywordOrIdentifier) Space (); // this space is not strictly required, so we call Space() formatter.WriteToken ("@"); } else if (lastWritten == LastWritten.KeywordOrIdentifier) { formatter.Space (); // this space is strictly required, so we directly call the formatter } formatter.WriteIdentifier (identifier); lastWritten = LastWritten.KeywordOrIdentifier; } void WriteToken (string token, Role tokenRole) { WriteSpecialsUpToRole (tokenRole); // Avoid that two +, - or ? tokens are combined into a ++, -- or ?? token. // Note that we don't need to handle tokens like = because there's no valid // C# program that contains the single token twice in a row. // (for +, - and &, this can happen with unary operators; // for ?, this can happen in "a is int? ? b : c" or "a as int? ?? 0"; // and for /, this can happen with "1/ *ptr" or "1/ //comment".) if (lastWritten == LastWritten.Plus && token [0] == '+' || lastWritten == LastWritten.Minus && token [0] == '-' || lastWritten == LastWritten.Ampersand && token [0] == '&' || lastWritten == LastWritten.QuestionMark && token [0] == '?' || lastWritten == LastWritten.Division && token [0] == '*') { formatter.Space (); } formatter.WriteToken (token); if (token == "+") lastWritten = LastWritten.Plus; else if (token == "-") lastWritten = LastWritten.Minus; else if (token == "&") lastWritten = LastWritten.Ampersand; else if (token == "?") lastWritten = LastWritten.QuestionMark; else if (token == "/") lastWritten = LastWritten.Division; else lastWritten = LastWritten.Other; } void LPar () { WriteToken ("(", AstNode.Roles.LPar); } void RPar () { WriteToken (")", AstNode.Roles.LPar); } /// /// Marks the end of a statement /// void Semicolon () { Role role = containerStack.Peek ().Role; // get the role of the current node if (!(role == ForStatement.InitializerRole || role == ForStatement.IteratorRole || role == UsingStatement.ResourceAcquisitionRole)) { WriteToken (";", AstNode.Roles.Semicolon); NewLine (); } } /// /// Writes a space depending on policy. /// void Space (bool addSpace = true) { if (addSpace) { formatter.Space (); lastWritten = LastWritten.Whitespace; } } void NewLine () { formatter.NewLine (); lastWritten = LastWritten.Whitespace; } void OpenBrace (BraceStyle style) { WriteSpecialsUpToRole (AstNode.Roles.LBrace); formatter.OpenBrace (style); lastWritten = LastWritten.Other; } void CloseBrace (BraceStyle style) { WriteSpecialsUpToRole (AstNode.Roles.RBrace); formatter.CloseBrace (style); lastWritten = LastWritten.Other; } #endregion #region IsKeyword Test static readonly HashSet unconditionalKeywords = new HashSet { "abstract", "as", "base", "bool", "break", "byte", "case", "catch", "char", "checked", "class", "const", "continue", "decimal", "default", "delegate", "do", "double", "else", "enum", "event", "explicit", "extern", "false", "finally", "fixed", "float", "for", "foreach", "goto", "if", "implicit", "in", "int", "interface", "internal", "is", "lock", "long", "namespace", "new", "null", "object", "operator", "out", "override", "params", "private", "protected", "public", "readonly", "ref", "return", "sbyte", "sealed", "short", "sizeof", "stackalloc", "static", "string", "struct", "switch", "this", "throw", "true", "try", "typeof", "uint", "ulong", "unchecked", "unsafe", "ushort", "using", "virtual", "void", "volatile", "while" }; static readonly HashSet queryKeywords = new HashSet { "from", "where", "join", "on", "equals", "into", "let", "orderby", "ascending", "descending", "select", "group", "by" }; /// /// Determines whether the specified identifier is a keyword in the given context. /// public static bool IsKeyword (string identifier, AstNode context) { if (unconditionalKeywords.Contains (identifier)) return true; if (context.Ancestors.Any (a => a is QueryExpression)) { if (queryKeywords.Contains (identifier)) return true; } return false; } #endregion #region Write constructs void WriteTypeArguments (IEnumerable typeArguments) { if (typeArguments.Any ()) { WriteToken ("<", AstNode.Roles.LChevron); WriteCommaSeparatedList (typeArguments); WriteToken (">", AstNode.Roles.RChevron); } } void WriteTypeParameters (IEnumerable typeParameters) { if (typeParameters.Any ()) { WriteToken ("<", AstNode.Roles.LChevron); WriteCommaSeparatedList (typeParameters.SafeCast ()); WriteToken (">", AstNode.Roles.RChevron); } } void WriteModifiers (IEnumerable modifierTokens) { foreach (CSharpModifierToken modifier in modifierTokens) { modifier.AcceptVisitor (this, null); } } void WriteQualifiedIdentifier (IEnumerable identifiers) { bool first = true; foreach (Identifier ident in identifiers) { if (first) { first = false; if (lastWritten == LastWritten.KeywordOrIdentifier) formatter.Space (); } else { WriteSpecialsUpToRole (AstNode.Roles.Dot, ident); formatter.WriteToken ("."); lastWritten = LastWritten.Other; } WriteSpecialsUpToNode (ident); formatter.WriteIdentifier (ident.Name); lastWritten = LastWritten.KeywordOrIdentifier; } } void WriteEmbeddedStatement (Statement embeddedStatement) { if (embeddedStatement.IsNull) return; BlockStatement block = embeddedStatement as BlockStatement; if (block != null) VisitBlockStatement (block, null); else { NewLine (); formatter.Indent (); embeddedStatement.AcceptVisitor (this, null); formatter.Unindent (); } } void WriteMethodBody (BlockStatement body) { if (body.IsNull) Semicolon (); else VisitBlockStatement (body, null); } void WriteAttributes (IEnumerable attributes) { foreach (AttributeSection attr in attributes) { attr.AcceptVisitor (this, null); } } void WritePrivateImplementationType (AstType privateImplementationType) { if (!privateImplementationType.IsNull) { privateImplementationType.AcceptVisitor (this, null); WriteToken (".", AstNode.Roles.Dot); } } #endregion #region Expressions public object VisitAnonymousMethodExpression (AnonymousMethodExpression anonymousMethodExpression, object data) { StartNode (anonymousMethodExpression); WriteKeyword ("delegate"); if (anonymousMethodExpression.HasParameterList) { Space (policy.SpaceBeforeMethodDeclarationParentheses); WriteCommaSeparatedListInParenthesis (anonymousMethodExpression.Parameters, policy.SpaceWithinMethodDeclarationParentheses); } anonymousMethodExpression.Body.AcceptVisitor (this, data); return EndNode (anonymousMethodExpression); } public object VisitUndocumentedExpression (UndocumentedExpression undocumentedExpression, object data) { StartNode (undocumentedExpression); switch (undocumentedExpression.UndocumentedExpressionType) { case UndocumentedExpressionType.ArgList: case UndocumentedExpressionType.ArgListAccess: WriteKeyword ("__arglist"); break; case UndocumentedExpressionType.MakeRef: WriteKeyword ("__makeref"); break; case UndocumentedExpressionType.RefType: WriteKeyword ("__reftype"); break; case UndocumentedExpressionType.RefValue: WriteKeyword ("__refvalue"); break; } if (undocumentedExpression.Arguments.Count > 0) { Space (policy.SpaceBeforeMethodCallParentheses); WriteCommaSeparatedListInParenthesis (undocumentedExpression.Arguments, policy.SpaceWithinMethodCallParentheses); } return EndNode (undocumentedExpression); } public object VisitArrayCreateExpression (ArrayCreateExpression arrayCreateExpression, object data) { StartNode (arrayCreateExpression); WriteKeyword ("new"); arrayCreateExpression.Type.AcceptVisitor (this, data); WriteCommaSeparatedListInBrackets (arrayCreateExpression.Arguments); foreach (var specifier in arrayCreateExpression.AdditionalArraySpecifiers) specifier.AcceptVisitor (this, data); arrayCreateExpression.Initializer.AcceptVisitor (this, data); return EndNode (arrayCreateExpression); } public object VisitArrayInitializerExpression (ArrayInitializerExpression arrayInitializerExpression, object data) { StartNode (arrayInitializerExpression); BraceStyle style; if (policy.PlaceArrayInitializersOnNewLine == ArrayInitializerPlacement.AlwaysNewLine) style = BraceStyle.NextLine; else style = BraceStyle.EndOfLine; OpenBrace (style); bool isFirst = true; foreach (AstNode node in arrayInitializerExpression.Elements) { if (isFirst) { isFirst = false; } else { Comma (node); NewLine (); } node.AcceptVisitor (this, null); } NewLine (); CloseBrace (style); return EndNode (arrayInitializerExpression); } public object VisitAsExpression (AsExpression asExpression, object data) { StartNode (asExpression); asExpression.Expression.AcceptVisitor (this, data); Space (); WriteKeyword ("as"); Space (); asExpression.Type.AcceptVisitor (this, data); return EndNode (asExpression); } public object VisitAssignmentExpression (AssignmentExpression assignmentExpression, object data) { StartNode (assignmentExpression); assignmentExpression.Left.AcceptVisitor (this, data); Space (policy.SpaceAroundAssignment); WriteToken (AssignmentExpression.GetOperatorSymbol (assignmentExpression.Operator), AssignmentExpression.OperatorRole); Space (policy.SpaceAroundAssignment); assignmentExpression.Right.AcceptVisitor (this, data); return EndNode (assignmentExpression); } public object VisitBaseReferenceExpression (BaseReferenceExpression baseReferenceExpression, object data) { StartNode (baseReferenceExpression); WriteKeyword ("base"); return EndNode (baseReferenceExpression); } public object VisitBinaryOperatorExpression (BinaryOperatorExpression binaryOperatorExpression, object data) { StartNode (binaryOperatorExpression); binaryOperatorExpression.Left.AcceptVisitor (this, data); bool spacePolicy; switch (binaryOperatorExpression.Operator) { case BinaryOperatorType.BitwiseAnd: case BinaryOperatorType.BitwiseOr: case BinaryOperatorType.ExclusiveOr: spacePolicy = policy.SpaceAroundBitwiseOperator; break; case BinaryOperatorType.ConditionalAnd: case BinaryOperatorType.ConditionalOr: spacePolicy = policy.SpaceAroundLogicalOperator; break; case BinaryOperatorType.GreaterThan: case BinaryOperatorType.GreaterThanOrEqual: case BinaryOperatorType.LessThanOrEqual: case BinaryOperatorType.LessThan: spacePolicy = policy.SpaceAroundRelationalOperator; break; case BinaryOperatorType.Equality: case BinaryOperatorType.InEquality: spacePolicy = policy.SpaceAroundEqualityOperator; break; case BinaryOperatorType.Add: case BinaryOperatorType.Subtract: spacePolicy = policy.SpaceAroundAdditiveOperator; break; case BinaryOperatorType.Multiply: case BinaryOperatorType.Divide: case BinaryOperatorType.Modulus: spacePolicy = policy.SpaceAroundMultiplicativeOperator; break; case BinaryOperatorType.ShiftLeft: case BinaryOperatorType.ShiftRight: spacePolicy = policy.SpaceAroundShiftOperator; break; case BinaryOperatorType.NullCoalescing: spacePolicy = true; break; default: throw new NotSupportedException ("Invalid value for BinaryOperatorType"); } Space (spacePolicy); WriteToken (BinaryOperatorExpression.GetOperatorSymbol (binaryOperatorExpression.Operator), BinaryOperatorExpression.OperatorRole); Space (spacePolicy); binaryOperatorExpression.Right.AcceptVisitor (this, data); return EndNode (binaryOperatorExpression); } public object VisitCastExpression (CastExpression castExpression, object data) { StartNode (castExpression); LPar (); Space (policy.SpacesWithinCastParentheses); castExpression.Type.AcceptVisitor (this, data); Space (policy.SpacesWithinCastParentheses); RPar (); Space (policy.SpaceAfterTypecast); castExpression.Expression.AcceptVisitor (this, data); return EndNode (castExpression); } public object VisitCheckedExpression (CheckedExpression checkedExpression, object data) { StartNode (checkedExpression); WriteKeyword ("checked"); LPar (); Space (policy.SpacesWithinCheckedExpressionParantheses); checkedExpression.Expression.AcceptVisitor (this, data); Space (policy.SpacesWithinCheckedExpressionParantheses); RPar (); return EndNode (checkedExpression); } public object VisitConditionalExpression (ConditionalExpression conditionalExpression, object data) { StartNode (conditionalExpression); conditionalExpression.Condition.AcceptVisitor (this, data); Space (policy.SpaceBeforeConditionalOperatorCondition); WriteToken ("?", ConditionalExpression.QuestionMarkRole); Space (policy.SpaceAfterConditionalOperatorCondition); conditionalExpression.TrueExpression.AcceptVisitor (this, data); Space (policy.SpaceBeforeConditionalOperatorSeparator); WriteToken (":", ConditionalExpression.ColonRole); Space (policy.SpaceAfterConditionalOperatorSeparator); conditionalExpression.FalseExpression.AcceptVisitor (this, data); return EndNode (conditionalExpression); } public object VisitDefaultValueExpression (DefaultValueExpression defaultValueExpression, object data) { StartNode (defaultValueExpression); WriteKeyword ("default"); LPar (); Space (policy.SpacesWithinTypeOfParentheses); defaultValueExpression.Type.AcceptVisitor (this, data); Space (policy.SpacesWithinTypeOfParentheses); RPar (); return EndNode (defaultValueExpression); } public object VisitDirectionExpression (DirectionExpression directionExpression, object data) { StartNode (directionExpression); switch (directionExpression.FieldDirection) { case FieldDirection.Out: WriteKeyword ("out"); break; case FieldDirection.Ref: WriteKeyword ("ref"); break; default: throw new NotSupportedException ("Invalid value for FieldDirection"); } Space (); directionExpression.Expression.AcceptVisitor (this, data); return EndNode (directionExpression); } public object VisitIdentifierExpression (IdentifierExpression identifierExpression, object data) { StartNode (identifierExpression); WriteIdentifier (identifierExpression.Identifier); WriteTypeArguments (identifierExpression.TypeArguments); return EndNode (identifierExpression); } public object VisitIndexerExpression (IndexerExpression indexerExpression, object data) { StartNode (indexerExpression); indexerExpression.Target.AcceptVisitor (this, data); Space (policy.SpaceBeforeMethodCallParentheses); WriteCommaSeparatedListInBrackets (indexerExpression.Arguments); return EndNode (indexerExpression); } public object VisitInvocationExpression (InvocationExpression invocationExpression, object data) { StartNode (invocationExpression); invocationExpression.Target.AcceptVisitor (this, data); Space (policy.SpaceBeforeMethodCallParentheses); WriteCommaSeparatedListInParenthesis (invocationExpression.Arguments, policy.SpaceWithinMethodCallParentheses); return EndNode (invocationExpression); } public object VisitIsExpression (IsExpression isExpression, object data) { StartNode (isExpression); isExpression.Expression.AcceptVisitor (this, data); Space (); WriteKeyword ("is"); isExpression.Type.AcceptVisitor (this, data); return EndNode (isExpression); } public object VisitLambdaExpression (LambdaExpression lambdaExpression, object data) { StartNode (lambdaExpression); if (LambdaNeedsParenthesis (lambdaExpression)) { WriteCommaSeparatedListInParenthesis (lambdaExpression.Parameters, policy.SpaceWithinMethodDeclarationParentheses); } else { lambdaExpression.Parameters.Single ().AcceptVisitor (this, data); } Space (); WriteToken ("=>", LambdaExpression.ArrowRole); Space (); lambdaExpression.Body.AcceptVisitor (this, data); return EndNode (lambdaExpression); } bool LambdaNeedsParenthesis (LambdaExpression lambdaExpression) { if (lambdaExpression.Parameters.Count != 1) return true; var p = lambdaExpression.Parameters.Single (); return !(p.Type.IsNull && p.ParameterModifier == ParameterModifier.None); } public object VisitMemberReferenceExpression (MemberReferenceExpression memberReferenceExpression, object data) { StartNode (memberReferenceExpression); memberReferenceExpression.Target.AcceptVisitor (this, data); WriteToken (".", MemberReferenceExpression.Roles.Dot); WriteIdentifier (memberReferenceExpression.MemberName); WriteTypeArguments (memberReferenceExpression.TypeArguments); return EndNode (memberReferenceExpression); } public object VisitNamedArgumentExpression (NamedArgumentExpression namedArgumentExpression, object data) { StartNode (namedArgumentExpression); WriteIdentifier (namedArgumentExpression.Identifier); if (namedArgumentExpression.Parent is ArrayInitializerExpression) { Space(); WriteToken("=", NamedArgumentExpression.Roles.Assign); } else { WriteToken(":", NamedArgumentExpression.Roles.Colon); } Space (); namedArgumentExpression.Expression.AcceptVisitor (this, data); return EndNode (namedArgumentExpression); } public object VisitNullReferenceExpression (NullReferenceExpression nullReferenceExpression, object data) { StartNode (nullReferenceExpression); WriteKeyword ("null"); return EndNode (nullReferenceExpression); } public object VisitObjectCreateExpression (ObjectCreateExpression objectCreateExpression, object data) { StartNode (objectCreateExpression); WriteKeyword ("new"); objectCreateExpression.Type.AcceptVisitor (this, data); bool useParenthesis = objectCreateExpression.Arguments.Any() || objectCreateExpression.Initializer.IsNull; // also use parenthesis if there is an '(' token and this isn't an anonymous type if (!objectCreateExpression.LParToken.IsNull && !objectCreateExpression.Type.IsNull) useParenthesis = true; if (useParenthesis) { Space (policy.SpaceBeforeMethodCallParentheses); WriteCommaSeparatedListInParenthesis (objectCreateExpression.Arguments, policy.SpaceWithinMethodCallParentheses); } objectCreateExpression.Initializer.AcceptVisitor (this, data); return EndNode (objectCreateExpression); } public object VisitAnonymousTypeCreateExpression (AnonymousTypeCreateExpression anonymousTypeCreateExpression, object data) { StartNode (anonymousTypeCreateExpression); WriteKeyword ("new"); Space (); LPar (); RPar (); Space (); OpenBrace (policy.AnonymousMethodBraceStyle); foreach (AstNode node in anonymousTypeCreateExpression.Initializer) { node.AcceptVisitor (this, null); if (node.NextSibling != null) Comma (node); NewLine (); } CloseBrace (policy.AnonymousMethodBraceStyle); return EndNode (anonymousTypeCreateExpression); } public object VisitParenthesizedExpression (ParenthesizedExpression parenthesizedExpression, object data) { StartNode (parenthesizedExpression); LPar (); Space (policy.SpacesWithinParentheses); parenthesizedExpression.Expression.AcceptVisitor (this, data); Space (policy.SpacesWithinParentheses); RPar (); return EndNode (parenthesizedExpression); } public object VisitPointerReferenceExpression (PointerReferenceExpression pointerReferenceExpression, object data) { StartNode (pointerReferenceExpression); pointerReferenceExpression.Target.AcceptVisitor (this, data); WriteToken ("->", PointerReferenceExpression.ArrowRole); WriteIdentifier (pointerReferenceExpression.MemberName); WriteTypeArguments (pointerReferenceExpression.TypeArguments); return EndNode (pointerReferenceExpression); } public object VisitEmptyExpression (EmptyExpression emptyExpression, object data) { StartNode (emptyExpression); return EndNode (emptyExpression); } #region VisitPrimitiveExpression public object VisitPrimitiveExpression (PrimitiveExpression primitiveExpression, object data) { StartNode (primitiveExpression); if (!string.IsNullOrEmpty (primitiveExpression.LiteralValue)) { formatter.WriteToken (primitiveExpression.LiteralValue); } else { WritePrimitiveValue (primitiveExpression.Value); } return EndNode (primitiveExpression); } void WritePrimitiveValue (object val) { if (val == null) { // usually NullReferenceExpression should be used for this, but we'll handle it anyways WriteKeyword ("null"); return; } if (val is bool) { if ((bool)val) { WriteKeyword ("true"); } else { WriteKeyword ("false"); } return; } if (val is string) { formatter.WriteToken ("\"" + ConvertString (val.ToString ()) + "\""); lastWritten = LastWritten.Other; } else if (val is char) { formatter.WriteToken ("'" + ConvertCharLiteral ((char)val) + "'"); lastWritten = LastWritten.Other; } else if (val is decimal) { formatter.WriteToken (((decimal)val).ToString (NumberFormatInfo.InvariantInfo) + "m"); lastWritten = LastWritten.Other; } else if (val is float) { float f = (float)val; if (float.IsInfinity (f) || float.IsNaN (f)) { // Strictly speaking, these aren't PrimitiveExpressions; // but we still support writing these to make life easier for code generators. WriteKeyword ("float"); WriteToken (".", AstNode.Roles.Dot); if (float.IsPositiveInfinity (f)) WriteIdentifier ("PositiveInfinity"); else if (float.IsNegativeInfinity (f)) WriteIdentifier ("NegativeInfinity"); else WriteIdentifier ("NaN"); return; } formatter.WriteToken (f.ToString ("R", NumberFormatInfo.InvariantInfo) + "f"); lastWritten = LastWritten.Other; } else if (val is double) { double f = (double)val; if (double.IsInfinity (f) || double.IsNaN (f)) { // Strictly speaking, these aren't PrimitiveExpressions; // but we still support writing these to make life easier for code generators. WriteKeyword ("double"); WriteToken (".", AstNode.Roles.Dot); if (double.IsPositiveInfinity (f)) WriteIdentifier ("PositiveInfinity"); else if (double.IsNegativeInfinity (f)) WriteIdentifier ("NegativeInfinity"); else WriteIdentifier ("NaN"); return; } string number = f.ToString ("R", NumberFormatInfo.InvariantInfo); if (number.IndexOf ('.') < 0 && number.IndexOf ('E') < 0) number += ".0"; formatter.WriteToken (number); // needs space if identifier follows number; this avoids mistaking the following identifier as type suffix lastWritten = LastWritten.KeywordOrIdentifier; } else if (val is IFormattable) { StringBuilder b = new StringBuilder (); // if (primitiveExpression.LiteralFormat == LiteralFormat.HexadecimalNumber) { // b.Append("0x"); // b.Append(((IFormattable)val).ToString("x", NumberFormatInfo.InvariantInfo)); // } else { b.Append (((IFormattable)val).ToString (null, NumberFormatInfo.InvariantInfo)); // } if (val is uint || val is ulong) { b.Append ("u"); } if (val is long || val is ulong) { b.Append ("L"); } formatter.WriteToken (b.ToString ()); // needs space if identifier follows number; this avoids mistaking the following identifier as type suffix lastWritten = LastWritten.KeywordOrIdentifier; } else { formatter.WriteToken (val.ToString ()); lastWritten = LastWritten.Other; } } static string ConvertCharLiteral (char ch) { if (ch == '\'') return "\\'"; return ConvertChar (ch); } /// /// Gets the escape sequence for the specified character. /// /// This method does not convert ' or ". public static string ConvertChar(char ch) { switch (ch) { case '\\': return "\\\\"; case '\0': return "\\0"; case '\a': return "\\a"; case '\b': return "\\b"; case '\f': return "\\f"; case '\n': return "\\n"; case '\r': return "\\r"; case '\t': return "\\t"; case '\v': return "\\v"; default: if (char.IsControl(ch) || char.IsSurrogate(ch) || // print all uncommon white spaces as numbers (char.IsWhiteSpace(ch) && ch != ' ')) { return "\\u" + ((int)ch).ToString ("x4"); } else { return ch.ToString (); } } } /// /// Converts special characters to escape sequences within the given string. /// public static string ConvertString(string str) { StringBuilder sb = new StringBuilder (); foreach (char ch in str) { if (ch == '"') sb.Append ("\\\""); else sb.Append (ConvertChar (ch)); } return sb.ToString (); } #endregion public object VisitSizeOfExpression (SizeOfExpression sizeOfExpression, object data) { StartNode (sizeOfExpression); WriteKeyword ("sizeof"); LPar (); Space (policy.SpacesWithinSizeOfParentheses); sizeOfExpression.Type.AcceptVisitor (this, data); Space (policy.SpacesWithinSizeOfParentheses); RPar (); return EndNode (sizeOfExpression); } public object VisitStackAllocExpression (StackAllocExpression stackAllocExpression, object data) { StartNode (stackAllocExpression); WriteKeyword ("stackalloc"); stackAllocExpression.Type.AcceptVisitor (this, data); WriteCommaSeparatedListInBrackets (new[] { stackAllocExpression.CountExpression }); return EndNode (stackAllocExpression); } public object VisitThisReferenceExpression (ThisReferenceExpression thisReferenceExpression, object data) { StartNode (thisReferenceExpression); WriteKeyword ("this"); return EndNode (thisReferenceExpression); } public object VisitTypeOfExpression (TypeOfExpression typeOfExpression, object data) { StartNode (typeOfExpression); WriteKeyword ("typeof"); LPar (); Space (policy.SpacesWithinTypeOfParentheses); typeOfExpression.Type.AcceptVisitor (this, data); Space (policy.SpacesWithinTypeOfParentheses); RPar (); return EndNode (typeOfExpression); } public object VisitTypeReferenceExpression (TypeReferenceExpression typeReferenceExpression, object data) { StartNode (typeReferenceExpression); typeReferenceExpression.Type.AcceptVisitor (this, data); return EndNode (typeReferenceExpression); } public object VisitUnaryOperatorExpression (UnaryOperatorExpression unaryOperatorExpression, object data) { StartNode (unaryOperatorExpression); UnaryOperatorType opType = unaryOperatorExpression.Operator; string opSymbol = UnaryOperatorExpression.GetOperatorSymbol (opType); if (!(opType == UnaryOperatorType.PostIncrement || opType == UnaryOperatorType.PostDecrement)) WriteToken (opSymbol, UnaryOperatorExpression.OperatorRole); unaryOperatorExpression.Expression.AcceptVisitor (this, data); if (opType == UnaryOperatorType.PostIncrement || opType == UnaryOperatorType.PostDecrement) WriteToken (opSymbol, UnaryOperatorExpression.OperatorRole); return EndNode (unaryOperatorExpression); } public object VisitUncheckedExpression (UncheckedExpression uncheckedExpression, object data) { StartNode (uncheckedExpression); WriteKeyword ("unchecked"); LPar (); Space (policy.SpacesWithinCheckedExpressionParantheses); uncheckedExpression.Expression.AcceptVisitor (this, data); Space (policy.SpacesWithinCheckedExpressionParantheses); RPar (); return EndNode (uncheckedExpression); } #endregion #region Query Expressions public object VisitQueryExpression (QueryExpression queryExpression, object data) { StartNode (queryExpression); bool indent = !(queryExpression.Parent is QueryContinuationClause); if (indent) { formatter.Indent(); NewLine(); } bool first = true; foreach (var clause in queryExpression.Clauses) { if (first) { first = false; } else { if (!(clause is QueryContinuationClause)) NewLine (); } clause.AcceptVisitor (this, data); } if (indent) formatter.Unindent(); return EndNode (queryExpression); } public object VisitQueryContinuationClause (QueryContinuationClause queryContinuationClause, object data) { StartNode (queryContinuationClause); queryContinuationClause.PrecedingQuery.AcceptVisitor (this, data); Space (); WriteKeyword ("into", QueryContinuationClause.IntoKeywordRole); Space (); WriteIdentifier (queryContinuationClause.Identifier); return EndNode (queryContinuationClause); } public object VisitQueryFromClause (QueryFromClause queryFromClause, object data) { StartNode (queryFromClause); WriteKeyword ("from", QueryFromClause.FromKeywordRole); queryFromClause.Type.AcceptVisitor (this, data); Space (); WriteIdentifier (queryFromClause.Identifier); Space (); WriteKeyword ("in", QueryFromClause.InKeywordRole); Space (); queryFromClause.Expression.AcceptVisitor (this, data); return EndNode (queryFromClause); } public object VisitQueryLetClause (QueryLetClause queryLetClause, object data) { StartNode (queryLetClause); WriteKeyword ("let"); Space (); WriteIdentifier (queryLetClause.Identifier); Space (policy.SpaceAroundAssignment); WriteToken ("=", QueryLetClause.Roles.Assign); Space (policy.SpaceAroundAssignment); queryLetClause.Expression.AcceptVisitor (this, data); return EndNode (queryLetClause); } public object VisitQueryWhereClause (QueryWhereClause queryWhereClause, object data) { StartNode (queryWhereClause); WriteKeyword ("where"); Space (); queryWhereClause.Condition.AcceptVisitor (this, data); return EndNode (queryWhereClause); } public object VisitQueryJoinClause (QueryJoinClause queryJoinClause, object data) { StartNode (queryJoinClause); WriteKeyword ("join", QueryJoinClause.JoinKeywordRole); queryJoinClause.Type.AcceptVisitor (this, data); Space (); WriteIdentifier (queryJoinClause.JoinIdentifier, QueryJoinClause.JoinIdentifierRole); Space (); WriteKeyword ("in", QueryJoinClause.InKeywordRole); Space (); queryJoinClause.InExpression.AcceptVisitor (this, data); Space (); WriteKeyword ("on", QueryJoinClause.OnKeywordRole); Space (); queryJoinClause.OnExpression.AcceptVisitor (this, data); Space (); WriteKeyword ("equals", QueryJoinClause.EqualsKeywordRole); Space (); queryJoinClause.EqualsExpression.AcceptVisitor (this, data); if (queryJoinClause.IsGroupJoin) { Space (); WriteKeyword ("into", QueryJoinClause.IntoKeywordRole); WriteIdentifier (queryJoinClause.IntoIdentifier, QueryJoinClause.IntoIdentifierRole); } return EndNode (queryJoinClause); } public object VisitQueryOrderClause (QueryOrderClause queryOrderClause, object data) { StartNode (queryOrderClause); WriteKeyword ("orderby"); Space (); WriteCommaSeparatedList (queryOrderClause.Orderings.SafeCast ()); return EndNode (queryOrderClause); } public object VisitQueryOrdering (QueryOrdering queryOrdering, object data) { StartNode (queryOrdering); queryOrdering.Expression.AcceptVisitor (this, data); switch (queryOrdering.Direction) { case QueryOrderingDirection.Ascending: Space (); WriteKeyword ("ascending"); break; case QueryOrderingDirection.Descending: Space (); WriteKeyword ("descending"); break; } return EndNode (queryOrdering); } public object VisitQuerySelectClause (QuerySelectClause querySelectClause, object data) { StartNode (querySelectClause); WriteKeyword ("select"); Space (); querySelectClause.Expression.AcceptVisitor (this, data); return EndNode (querySelectClause); } public object VisitQueryGroupClause (QueryGroupClause queryGroupClause, object data) { StartNode (queryGroupClause); WriteKeyword ("group", QueryGroupClause.GroupKeywordRole); Space (); queryGroupClause.Projection.AcceptVisitor (this, data); Space (); WriteKeyword ("by", QueryGroupClause.ByKeywordRole); Space (); queryGroupClause.Key.AcceptVisitor (this, data); return EndNode (queryGroupClause); } #endregion #region GeneralScope public object VisitAttribute (Attribute attribute, object data) { StartNode (attribute); attribute.Type.AcceptVisitor (this, data); Space (policy.SpaceBeforeMethodCallParentheses); if (attribute.Arguments.Count != 0 || !attribute.GetChildByRole (AstNode.Roles.LPar).IsNull) WriteCommaSeparatedListInParenthesis (attribute.Arguments, policy.SpaceWithinMethodCallParentheses); return EndNode (attribute); } public object VisitAttributeSection (AttributeSection attributeSection, object data) { StartNode (attributeSection); WriteToken ("[", AstNode.Roles.LBracket); if (!string.IsNullOrEmpty (attributeSection.AttributeTarget)) { WriteToken (attributeSection.AttributeTarget, AttributeSection.TargetRole); WriteToken (":", AttributeSection.Roles.Colon); Space (); } WriteCommaSeparatedList (attributeSection.Attributes.SafeCast ()); WriteToken ("]", AstNode.Roles.RBracket); if (attributeSection.Parent is ParameterDeclaration || attributeSection.Parent is TypeParameterDeclaration) Space (); else NewLine (); return EndNode (attributeSection); } public object VisitDelegateDeclaration (DelegateDeclaration delegateDeclaration, object data) { StartNode (delegateDeclaration); WriteAttributes (delegateDeclaration.Attributes); WriteModifiers (delegateDeclaration.ModifierTokens); WriteKeyword ("delegate"); delegateDeclaration.ReturnType.AcceptVisitor (this, data); Space (); WriteIdentifier (delegateDeclaration.Name); WriteTypeParameters (delegateDeclaration.TypeParameters); Space (policy.SpaceBeforeDelegateDeclarationParentheses); WriteCommaSeparatedListInParenthesis (delegateDeclaration.Parameters, policy.SpaceWithinMethodDeclarationParentheses); foreach (Constraint constraint in delegateDeclaration.Constraints) { constraint.AcceptVisitor (this, data); } Semicolon (); return EndNode (delegateDeclaration); } public object VisitNamespaceDeclaration (NamespaceDeclaration namespaceDeclaration, object data) { StartNode (namespaceDeclaration); WriteKeyword ("namespace"); WriteQualifiedIdentifier (namespaceDeclaration.Identifiers); OpenBrace (policy.NamespaceBraceStyle); foreach (var member in namespaceDeclaration.Members) member.AcceptVisitor (this, data); CloseBrace (policy.NamespaceBraceStyle); NewLine (); return EndNode (namespaceDeclaration); } public object VisitTypeDeclaration (TypeDeclaration typeDeclaration, object data) { StartNode (typeDeclaration); WriteAttributes (typeDeclaration.Attributes); WriteModifiers (typeDeclaration.ModifierTokens); BraceStyle braceStyle; switch (typeDeclaration.ClassType) { case ClassType.Enum: WriteKeyword ("enum"); braceStyle = policy.EnumBraceStyle; break; case ClassType.Interface: WriteKeyword ("interface"); braceStyle = policy.InterfaceBraceStyle; break; case ClassType.Struct: WriteKeyword ("struct"); braceStyle = policy.StructBraceStyle; break; default: WriteKeyword ("class"); braceStyle = policy.ClassBraceStyle; break; } WriteIdentifier (typeDeclaration.Name); WriteTypeParameters (typeDeclaration.TypeParameters); if (typeDeclaration.BaseTypes.Any ()) { Space (); WriteToken (":", TypeDeclaration.ColonRole); Space (); WriteCommaSeparatedList (typeDeclaration.BaseTypes); } foreach (Constraint constraint in typeDeclaration.Constraints) { constraint.AcceptVisitor (this, data); } OpenBrace (braceStyle); if (typeDeclaration.ClassType == ClassType.Enum) { bool first = true; foreach (var member in typeDeclaration.Members) { if (first) { first = false; } else { Comma (member, noSpaceAfterComma: true); NewLine (); } member.AcceptVisitor (this, data); } NewLine (); } else { foreach (var member in typeDeclaration.Members) { member.AcceptVisitor (this, data); } } CloseBrace (braceStyle); NewLine (); return EndNode (typeDeclaration); } public object VisitUsingAliasDeclaration (UsingAliasDeclaration usingAliasDeclaration, object data) { StartNode (usingAliasDeclaration); WriteKeyword ("using"); WriteIdentifier (usingAliasDeclaration.Alias, UsingAliasDeclaration.AliasRole); Space (policy.SpaceAroundEqualityOperator); WriteToken ("=", AstNode.Roles.Assign); Space (policy.SpaceAroundEqualityOperator); usingAliasDeclaration.Import.AcceptVisitor (this, data); Semicolon (); return EndNode (usingAliasDeclaration); } public object VisitUsingDeclaration (UsingDeclaration usingDeclaration, object data) { StartNode (usingDeclaration); WriteKeyword ("using"); usingDeclaration.Import.AcceptVisitor (this, data); Semicolon (); return EndNode (usingDeclaration); } public object VisitExternAliasDeclaration (ExternAliasDeclaration externAliasDeclaration, object data) { StartNode (externAliasDeclaration); WriteKeyword ("extern"); Space (); WriteKeyword ("alias"); Space (); externAliasDeclaration.NameToken.AcceptVisitor (this, data); Semicolon (); return EndNode (externAliasDeclaration); } #endregion #region Statements public object VisitBlockStatement (BlockStatement blockStatement, object data) { StartNode (blockStatement); BraceStyle style; if (blockStatement.Parent is AnonymousMethodExpression || blockStatement.Parent is LambdaExpression) { style = policy.AnonymousMethodBraceStyle; } else if (blockStatement.Parent is ConstructorDeclaration) { style = policy.ConstructorBraceStyle; } else if (blockStatement.Parent is DestructorDeclaration) { style = policy.DestructorBraceStyle; } else if (blockStatement.Parent is MethodDeclaration) { style = policy.MethodBraceStyle; } else if (blockStatement.Parent is Accessor) { if (blockStatement.Parent.Role == PropertyDeclaration.GetterRole) style = policy.PropertyGetBraceStyle; else if (blockStatement.Parent.Role == PropertyDeclaration.SetterRole) style = policy.PropertySetBraceStyle; else if (blockStatement.Parent.Role == CustomEventDeclaration.AddAccessorRole) style = policy.EventAddBraceStyle; else if (blockStatement.Parent.Role == CustomEventDeclaration.RemoveAccessorRole) style = policy.EventRemoveBraceStyle; else throw new NotSupportedException ("Unknown type of accessor"); } else { style = policy.StatementBraceStyle; } OpenBrace (style); foreach (var node in blockStatement.Statements) { node.AcceptVisitor (this, data); } CloseBrace (style); NewLine (); return EndNode (blockStatement); } public object VisitBreakStatement (BreakStatement breakStatement, object data) { StartNode (breakStatement); WriteKeyword ("break"); Semicolon (); return EndNode (breakStatement); } public object VisitCheckedStatement (CheckedStatement checkedStatement, object data) { StartNode (checkedStatement); WriteKeyword ("checked"); checkedStatement.Body.AcceptVisitor (this, data); return EndNode (checkedStatement); } public object VisitContinueStatement (ContinueStatement continueStatement, object data) { StartNode (continueStatement); WriteKeyword ("continue"); Semicolon (); return EndNode (continueStatement); } public object VisitDoWhileStatement (DoWhileStatement doWhileStatement, object data) { StartNode (doWhileStatement); WriteKeyword ("do", DoWhileStatement.DoKeywordRole); WriteEmbeddedStatement (doWhileStatement.EmbeddedStatement); WriteKeyword ("while", DoWhileStatement.WhileKeywordRole); Space (policy.SpaceBeforeWhileParentheses); LPar (); Space (policy.SpacesWithinWhileParentheses); doWhileStatement.Condition.AcceptVisitor (this, data); Space (policy.SpacesWithinWhileParentheses); RPar (); Semicolon (); return EndNode (doWhileStatement); } public object VisitEmptyStatement (EmptyStatement emptyStatement, object data) { StartNode (emptyStatement); Semicolon (); return EndNode (emptyStatement); } public object VisitExpressionStatement (ExpressionStatement expressionStatement, object data) { StartNode (expressionStatement); expressionStatement.Expression.AcceptVisitor (this, data); Semicolon (); return EndNode (expressionStatement); } public object VisitFixedStatement (FixedStatement fixedStatement, object data) { StartNode (fixedStatement); WriteKeyword ("fixed"); Space (policy.SpaceBeforeUsingParentheses); LPar (); Space (policy.SpacesWithinUsingParentheses); fixedStatement.Type.AcceptVisitor (this, data); Space (); WriteCommaSeparatedList (fixedStatement.Variables); Space (policy.SpacesWithinUsingParentheses); RPar (); WriteEmbeddedStatement (fixedStatement.EmbeddedStatement); return EndNode (fixedStatement); } public object VisitForeachStatement (ForeachStatement foreachStatement, object data) { StartNode (foreachStatement); WriteKeyword ("foreach"); Space (policy.SpaceBeforeForeachParentheses); LPar (); Space (policy.SpacesWithinForeachParentheses); foreachStatement.VariableType.AcceptVisitor (this, data); Space (); WriteIdentifier (foreachStatement.VariableName); WriteKeyword ("in", ForeachStatement.Roles.InKeyword); Space (); foreachStatement.InExpression.AcceptVisitor (this, data); Space (policy.SpacesWithinForeachParentheses); RPar (); WriteEmbeddedStatement (foreachStatement.EmbeddedStatement); return EndNode (foreachStatement); } public object VisitForStatement (ForStatement forStatement, object data) { StartNode (forStatement); WriteKeyword ("for"); Space (policy.SpaceBeforeForParentheses); LPar (); Space (policy.SpacesWithinForParentheses); WriteCommaSeparatedList (forStatement.Initializers.SafeCast ()); Space (policy.SpaceBeforeForSemicolon); WriteToken (";", AstNode.Roles.Semicolon); Space (policy.SpaceAfterForSemicolon); forStatement.Condition.AcceptVisitor (this, data); Space (policy.SpaceBeforeForSemicolon); WriteToken (";", AstNode.Roles.Semicolon); Space (policy.SpaceAfterForSemicolon); WriteCommaSeparatedList (forStatement.Iterators.SafeCast ()); Space (policy.SpacesWithinForParentheses); RPar (); WriteEmbeddedStatement (forStatement.EmbeddedStatement); return EndNode (forStatement); } public object VisitGotoCaseStatement (GotoCaseStatement gotoCaseStatement, object data) { StartNode (gotoCaseStatement); WriteKeyword ("goto"); WriteKeyword ("case", GotoCaseStatement.CaseKeywordRole); Space (); gotoCaseStatement.LabelExpression.AcceptVisitor (this, data); Semicolon (); return EndNode (gotoCaseStatement); } public object VisitGotoDefaultStatement (GotoDefaultStatement gotoDefaultStatement, object data) { StartNode (gotoDefaultStatement); WriteKeyword ("goto"); WriteKeyword ("default", GotoDefaultStatement.DefaultKeywordRole); Semicolon (); return EndNode (gotoDefaultStatement); } public object VisitGotoStatement (GotoStatement gotoStatement, object data) { StartNode (gotoStatement); WriteKeyword ("goto"); WriteIdentifier (gotoStatement.Label); Semicolon (); return EndNode (gotoStatement); } public object VisitIfElseStatement (IfElseStatement ifElseStatement, object data) { StartNode (ifElseStatement); WriteKeyword ("if", IfElseStatement.IfKeywordRole); Space (policy.SpaceBeforeIfParentheses); LPar (); Space (policy.SpacesWithinIfParentheses); ifElseStatement.Condition.AcceptVisitor (this, data); Space (policy.SpacesWithinIfParentheses); RPar (); WriteEmbeddedStatement (ifElseStatement.TrueStatement); if (!ifElseStatement.FalseStatement.IsNull) { WriteKeyword ("else", IfElseStatement.ElseKeywordRole); WriteEmbeddedStatement (ifElseStatement.FalseStatement); } return EndNode (ifElseStatement); } public object VisitLabelStatement (LabelStatement labelStatement, object data) { StartNode (labelStatement); WriteIdentifier (labelStatement.Label); WriteToken (":", LabelStatement.Roles.Colon); bool foundLabelledStatement = false; for (AstNode tmp = labelStatement.NextSibling; tmp != null; tmp = tmp.NextSibling) { if (tmp.Role == labelStatement.Role) { foundLabelledStatement = true; } } if (!foundLabelledStatement) { // introduce an EmptyStatement so that the output becomes syntactically valid WriteToken(";", LabelStatement.Roles.Semicolon); } NewLine (); return EndNode (labelStatement); } public object VisitLockStatement (LockStatement lockStatement, object data) { StartNode (lockStatement); WriteKeyword ("lock"); Space (policy.SpaceBeforeLockParentheses); LPar (); Space (policy.SpacesWithinLockParentheses); lockStatement.Expression.AcceptVisitor (this, data); Space (policy.SpacesWithinLockParentheses); RPar (); WriteEmbeddedStatement (lockStatement.EmbeddedStatement); return EndNode (lockStatement); } public object VisitReturnStatement (ReturnStatement returnStatement, object data) { StartNode (returnStatement); WriteKeyword ("return"); if (!returnStatement.Expression.IsNull) { Space (); returnStatement.Expression.AcceptVisitor (this, data); } Semicolon (); return EndNode (returnStatement); } public object VisitSwitchStatement (SwitchStatement switchStatement, object data) { StartNode (switchStatement); WriteKeyword ("switch"); Space (policy.SpaceBeforeSwitchParentheses); LPar (); Space (policy.SpacesWithinSwitchParentheses); switchStatement.Expression.AcceptVisitor (this, data); Space (policy.SpacesWithinSwitchParentheses); RPar (); OpenBrace (policy.StatementBraceStyle); if (!policy.IndentSwitchBody) formatter.Unindent (); foreach (var section in switchStatement.SwitchSections) section.AcceptVisitor (this, data); if (!policy.IndentSwitchBody) formatter.Indent (); CloseBrace (policy.StatementBraceStyle); NewLine (); return EndNode (switchStatement); } public object VisitSwitchSection (SwitchSection switchSection, object data) { StartNode (switchSection); bool first = true; foreach (var label in switchSection.CaseLabels) { if (!first) NewLine (); label.AcceptVisitor (this, data); first = false; } if (policy.IndentCaseBody) formatter.Indent (); foreach (var statement in switchSection.Statements) { NewLine (); statement.AcceptVisitor (this, data); } if (policy.IndentCaseBody) formatter.Unindent (); return EndNode (switchSection); } public object VisitCaseLabel (CaseLabel caseLabel, object data) { StartNode (caseLabel); if (caseLabel.Expression.IsNull) { WriteKeyword ("default"); } else { WriteKeyword ("case"); Space (); caseLabel.Expression.AcceptVisitor (this, data); } WriteToken (":", CaseLabel.Roles.Colon); return EndNode (caseLabel); } public object VisitThrowStatement (ThrowStatement throwStatement, object data) { StartNode (throwStatement); WriteKeyword ("throw"); if (!throwStatement.Expression.IsNull) { Space (); throwStatement.Expression.AcceptVisitor (this, data); } Semicolon (); return EndNode (throwStatement); } public object VisitTryCatchStatement (TryCatchStatement tryCatchStatement, object data) { StartNode (tryCatchStatement); WriteKeyword ("try", TryCatchStatement.TryKeywordRole); tryCatchStatement.TryBlock.AcceptVisitor (this, data); foreach (var catchClause in tryCatchStatement.CatchClauses) catchClause.AcceptVisitor (this, data); if (!tryCatchStatement.FinallyBlock.IsNull) { WriteKeyword ("finally", TryCatchStatement.FinallyKeywordRole); tryCatchStatement.FinallyBlock.AcceptVisitor (this, data); } return EndNode (tryCatchStatement); } public object VisitCatchClause (CatchClause catchClause, object data) { StartNode (catchClause); WriteKeyword ("catch"); if (!catchClause.Type.IsNull) { Space (policy.SpaceBeforeCatchParentheses); LPar (); Space (policy.SpacesWithinCatchParentheses); catchClause.Type.AcceptVisitor (this, data); if (!string.IsNullOrEmpty(catchClause.VariableName)) { Space (); WriteIdentifier (catchClause.VariableName); } Space (policy.SpacesWithinCatchParentheses); RPar (); } catchClause.Body.AcceptVisitor (this, data); return EndNode (catchClause); } public object VisitUncheckedStatement (UncheckedStatement uncheckedStatement, object data) { StartNode (uncheckedStatement); WriteKeyword ("unchecked"); uncheckedStatement.Body.AcceptVisitor (this, data); return EndNode (uncheckedStatement); } public object VisitUnsafeStatement (UnsafeStatement unsafeStatement, object data) { StartNode (unsafeStatement); WriteKeyword ("unsafe"); unsafeStatement.Body.AcceptVisitor (this, data); return EndNode (unsafeStatement); } public object VisitUsingStatement (UsingStatement usingStatement, object data) { StartNode (usingStatement); WriteKeyword ("using"); Space (policy.SpaceBeforeUsingParentheses); LPar (); Space (policy.SpacesWithinUsingParentheses); usingStatement.ResourceAcquisition.AcceptVisitor (this, data); Space (policy.SpacesWithinUsingParentheses); RPar (); WriteEmbeddedStatement (usingStatement.EmbeddedStatement); return EndNode (usingStatement); } public object VisitVariableDeclarationStatement (VariableDeclarationStatement variableDeclarationStatement, object data) { StartNode (variableDeclarationStatement); variableDeclarationStatement.Type.AcceptVisitor (this, data); Space (); WriteCommaSeparatedList (variableDeclarationStatement.Variables); Semicolon (); return EndNode (variableDeclarationStatement); } public object VisitWhileStatement (WhileStatement whileStatement, object data) { StartNode (whileStatement); WriteKeyword ("while", WhileStatement.WhileKeywordRole); Space (policy.SpaceBeforeWhileParentheses); LPar (); Space (policy.SpacesWithinWhileParentheses); whileStatement.Condition.AcceptVisitor (this, data); Space (policy.SpacesWithinWhileParentheses); RPar (); WriteEmbeddedStatement (whileStatement.EmbeddedStatement); return EndNode (whileStatement); } public object VisitYieldBreakStatement (YieldBreakStatement yieldBreakStatement, object data) { StartNode (yieldBreakStatement); WriteKeyword ("yield", YieldBreakStatement.YieldKeywordRole); WriteKeyword ("break", YieldBreakStatement.BreakKeywordRole); Semicolon (); return EndNode (yieldBreakStatement); } public object VisitYieldStatement (YieldStatement yieldStatement, object data) { StartNode (yieldStatement); WriteKeyword ("yield", YieldStatement.YieldKeywordRole); WriteKeyword ("return", YieldStatement.ReturnKeywordRole); Space (); yieldStatement.Expression.AcceptVisitor (this, data); Semicolon (); return EndNode (yieldStatement); } #endregion #region TypeMembers public object VisitAccessor (Accessor accessor, object data) { StartNode (accessor); WriteAttributes (accessor.Attributes); WriteModifiers (accessor.ModifierTokens); if (accessor.Role == PropertyDeclaration.GetterRole) { WriteKeyword ("get"); } else if (accessor.Role == PropertyDeclaration.SetterRole) { WriteKeyword ("set"); } else if (accessor.Role == CustomEventDeclaration.AddAccessorRole) { WriteKeyword ("add"); } else if (accessor.Role == CustomEventDeclaration.RemoveAccessorRole) { WriteKeyword ("remove"); } WriteMethodBody (accessor.Body); return EndNode (accessor); } public object VisitConstructorDeclaration (ConstructorDeclaration constructorDeclaration, object data) { StartNode (constructorDeclaration); WriteAttributes (constructorDeclaration.Attributes); WriteModifiers (constructorDeclaration.ModifierTokens); TypeDeclaration type = constructorDeclaration.Parent as TypeDeclaration; WriteIdentifier (type != null ? type.Name : constructorDeclaration.Name); Space (policy.SpaceBeforeConstructorDeclarationParentheses); WriteCommaSeparatedListInParenthesis (constructorDeclaration.Parameters, policy.SpaceWithinMethodDeclarationParentheses); if (!constructorDeclaration.Initializer.IsNull) { Space (); constructorDeclaration.Initializer.AcceptVisitor (this, data); } WriteMethodBody (constructorDeclaration.Body); return EndNode (constructorDeclaration); } public object VisitConstructorInitializer (ConstructorInitializer constructorInitializer, object data) { StartNode (constructorInitializer); WriteToken (":", ConstructorInitializer.Roles.Colon); Space (); if (constructorInitializer.ConstructorInitializerType == ConstructorInitializerType.This) { WriteKeyword ("this"); } else { WriteKeyword ("base"); } Space (policy.SpaceBeforeMethodCallParentheses); WriteCommaSeparatedListInParenthesis (constructorInitializer.Arguments, policy.SpaceWithinMethodCallParentheses); return EndNode (constructorInitializer); } public object VisitDestructorDeclaration (DestructorDeclaration destructorDeclaration, object data) { StartNode (destructorDeclaration); WriteAttributes (destructorDeclaration.Attributes); WriteModifiers (destructorDeclaration.ModifierTokens); WriteToken ("~", DestructorDeclaration.TildeRole); TypeDeclaration type = destructorDeclaration.Parent as TypeDeclaration; WriteIdentifier (type != null ? type.Name : destructorDeclaration.Name); Space (policy.SpaceBeforeConstructorDeclarationParentheses); LPar (); RPar (); WriteMethodBody (destructorDeclaration.Body); return EndNode (destructorDeclaration); } public object VisitEnumMemberDeclaration (EnumMemberDeclaration enumMemberDeclaration, object data) { StartNode (enumMemberDeclaration); WriteAttributes (enumMemberDeclaration.Attributes); WriteModifiers (enumMemberDeclaration.ModifierTokens); WriteIdentifier (enumMemberDeclaration.Name); if (!enumMemberDeclaration.Initializer.IsNull) { Space (policy.SpaceAroundAssignment); WriteToken ("=", EnumMemberDeclaration.Roles.Assign); Space (policy.SpaceAroundAssignment); enumMemberDeclaration.Initializer.AcceptVisitor (this, data); } return EndNode (enumMemberDeclaration); } public object VisitEventDeclaration (EventDeclaration eventDeclaration, object data) { StartNode (eventDeclaration); WriteAttributes (eventDeclaration.Attributes); WriteModifiers (eventDeclaration.ModifierTokens); WriteKeyword ("event"); eventDeclaration.ReturnType.AcceptVisitor (this, data); Space (); WriteCommaSeparatedList (eventDeclaration.Variables); Semicolon (); return EndNode (eventDeclaration); } public object VisitCustomEventDeclaration (CustomEventDeclaration customEventDeclaration, object data) { StartNode (customEventDeclaration); WriteAttributes (customEventDeclaration.Attributes); WriteModifiers (customEventDeclaration.ModifierTokens); WriteKeyword ("event"); customEventDeclaration.ReturnType.AcceptVisitor (this, data); Space (); WritePrivateImplementationType (customEventDeclaration.PrivateImplementationType); WriteIdentifier (customEventDeclaration.Name); OpenBrace (policy.EventBraceStyle); // output add/remove in their original order foreach (AstNode node in customEventDeclaration.Children) { if (node.Role == CustomEventDeclaration.AddAccessorRole || node.Role == CustomEventDeclaration.RemoveAccessorRole) { node.AcceptVisitor (this, data); } } CloseBrace (policy.EventBraceStyle); NewLine (); return EndNode (customEventDeclaration); } public object VisitFieldDeclaration (FieldDeclaration fieldDeclaration, object data) { StartNode (fieldDeclaration); WriteAttributes (fieldDeclaration.Attributes); WriteModifiers (fieldDeclaration.ModifierTokens); fieldDeclaration.ReturnType.AcceptVisitor (this, data); Space (); WriteCommaSeparatedList (fieldDeclaration.Variables); Semicolon (); return EndNode (fieldDeclaration); } public object VisitFixedFieldDeclaration (FixedFieldDeclaration fixedFieldDeclaration, object data) { StartNode (fixedFieldDeclaration); WriteAttributes (fixedFieldDeclaration.Attributes); WriteModifiers (fixedFieldDeclaration.ModifierTokens); WriteKeyword ("fixed"); Space (); fixedFieldDeclaration.ReturnType.AcceptVisitor (this, data); Space (); WriteCommaSeparatedList (fixedFieldDeclaration.Variables); Semicolon (); return EndNode (fixedFieldDeclaration); } public object VisitFixedVariableInitializer (FixedVariableInitializer fixedVariableInitializer, object data) { StartNode (fixedVariableInitializer); WriteIdentifier (fixedVariableInitializer.Name); if (!fixedVariableInitializer.CountExpression.IsNull) { WriteToken ("[", AstNode.Roles.LBracket); Space (policy.SpacesWithinBrackets); fixedVariableInitializer.CountExpression.AcceptVisitor (this, data); Space (policy.SpacesWithinBrackets); WriteToken ("]", AstNode.Roles.RBracket); } return EndNode (fixedVariableInitializer); } public object VisitIndexerDeclaration (IndexerDeclaration indexerDeclaration, object data) { StartNode (indexerDeclaration); WriteAttributes (indexerDeclaration.Attributes); WriteModifiers (indexerDeclaration.ModifierTokens); indexerDeclaration.ReturnType.AcceptVisitor (this, data); WritePrivateImplementationType (indexerDeclaration.PrivateImplementationType); WriteKeyword ("this"); Space (policy.SpaceBeforeMethodDeclarationParentheses); WriteCommaSeparatedListInBrackets (indexerDeclaration.Parameters, policy.SpaceWithinMethodDeclarationParentheses); OpenBrace (policy.PropertyBraceStyle); // output get/set in their original order foreach (AstNode node in indexerDeclaration.Children) { if (node.Role == IndexerDeclaration.GetterRole || node.Role == IndexerDeclaration.SetterRole) { node.AcceptVisitor (this, data); } } CloseBrace (policy.PropertyBraceStyle); NewLine (); return EndNode (indexerDeclaration); } public object VisitMethodDeclaration (MethodDeclaration methodDeclaration, object data) { StartNode (methodDeclaration); WriteAttributes (methodDeclaration.Attributes); WriteModifiers (methodDeclaration.ModifierTokens); methodDeclaration.ReturnType.AcceptVisitor (this, data); Space (); WritePrivateImplementationType (methodDeclaration.PrivateImplementationType); WriteIdentifier (methodDeclaration.Name); WriteTypeParameters (methodDeclaration.TypeParameters); Space (policy.SpaceBeforeMethodDeclarationParentheses); WriteCommaSeparatedListInParenthesis (methodDeclaration.Parameters, policy.SpaceWithinMethodDeclarationParentheses); foreach (Constraint constraint in methodDeclaration.Constraints) { constraint.AcceptVisitor (this, data); } WriteMethodBody (methodDeclaration.Body); return EndNode (methodDeclaration); } public object VisitOperatorDeclaration (OperatorDeclaration operatorDeclaration, object data) { StartNode (operatorDeclaration); WriteAttributes (operatorDeclaration.Attributes); WriteModifiers (operatorDeclaration.ModifierTokens); if (operatorDeclaration.OperatorType == OperatorType.Explicit) { WriteKeyword ("explicit", OperatorDeclaration.OperatorTypeRole); } else if (operatorDeclaration.OperatorType == OperatorType.Implicit) { WriteKeyword ("implicit", OperatorDeclaration.OperatorTypeRole); } else { operatorDeclaration.ReturnType.AcceptVisitor (this, data); } WriteKeyword ("operator", OperatorDeclaration.OperatorKeywordRole); Space (); if (operatorDeclaration.OperatorType == OperatorType.Explicit || operatorDeclaration.OperatorType == OperatorType.Implicit) { operatorDeclaration.ReturnType.AcceptVisitor (this, data); } else { WriteToken (OperatorDeclaration.GetToken (operatorDeclaration.OperatorType), OperatorDeclaration.OperatorTypeRole); } Space (policy.SpaceBeforeMethodDeclarationParentheses); WriteCommaSeparatedListInParenthesis (operatorDeclaration.Parameters, policy.SpaceWithinMethodDeclarationParentheses); WriteMethodBody (operatorDeclaration.Body); return EndNode (operatorDeclaration); } public object VisitParameterDeclaration (ParameterDeclaration parameterDeclaration, object data) { StartNode (parameterDeclaration); WriteAttributes (parameterDeclaration.Attributes); switch (parameterDeclaration.ParameterModifier) { case ParameterModifier.Ref: WriteKeyword ("ref", ParameterDeclaration.ModifierRole); break; case ParameterModifier.Out: WriteKeyword ("out", ParameterDeclaration.ModifierRole); break; case ParameterModifier.Params: WriteKeyword ("params", ParameterDeclaration.ModifierRole); break; case ParameterModifier.This: WriteKeyword ("this", ParameterDeclaration.ModifierRole); break; } parameterDeclaration.Type.AcceptVisitor (this, data); if (!parameterDeclaration.Type.IsNull && !string.IsNullOrEmpty (parameterDeclaration.Name)) Space (); if (!string.IsNullOrEmpty (parameterDeclaration.Name)) WriteIdentifier (parameterDeclaration.Name); if (!parameterDeclaration.DefaultExpression.IsNull) { Space (policy.SpaceAroundAssignment); WriteToken ("=", ParameterDeclaration.Roles.Assign); Space (policy.SpaceAroundAssignment); parameterDeclaration.DefaultExpression.AcceptVisitor (this, data); } return EndNode (parameterDeclaration); } public object VisitPropertyDeclaration (PropertyDeclaration propertyDeclaration, object data) { StartNode (propertyDeclaration); WriteAttributes (propertyDeclaration.Attributes); WriteModifiers (propertyDeclaration.ModifierTokens); propertyDeclaration.ReturnType.AcceptVisitor (this, data); Space (); WritePrivateImplementationType (propertyDeclaration.PrivateImplementationType); WriteIdentifier (propertyDeclaration.Name); OpenBrace (policy.PropertyBraceStyle); // output get/set in their original order foreach (AstNode node in propertyDeclaration.Children) { if (node.Role == IndexerDeclaration.GetterRole || node.Role == IndexerDeclaration.SetterRole) { node.AcceptVisitor (this, data); } } CloseBrace (policy.PropertyBraceStyle); NewLine (); return EndNode (propertyDeclaration); } #endregion #region Other nodes public object VisitVariableInitializer (VariableInitializer variableInitializer, object data) { StartNode (variableInitializer); WriteIdentifier (variableInitializer.Name); if (!variableInitializer.Initializer.IsNull) { Space (policy.SpaceAroundAssignment); WriteToken ("=", VariableInitializer.Roles.Assign); Space (policy.SpaceAroundAssignment); variableInitializer.Initializer.AcceptVisitor (this, data); } return EndNode (variableInitializer); } public object VisitCompilationUnit (CompilationUnit compilationUnit, object data) { // don't do node tracking as we visit all children directly foreach (AstNode node in compilationUnit.Children) node.AcceptVisitor (this, data); return null; } public object VisitSimpleType (SimpleType simpleType, object data) { StartNode (simpleType); WriteIdentifier (simpleType.Identifier); WriteTypeArguments (simpleType.TypeArguments); return EndNode (simpleType); } public object VisitMemberType (MemberType memberType, object data) { StartNode (memberType); memberType.Target.AcceptVisitor (this, data); if (memberType.IsDoubleColon) WriteToken ("::", MemberType.Roles.Dot); else WriteToken (".", MemberType.Roles.Dot); WriteIdentifier (memberType.MemberName); WriteTypeArguments (memberType.TypeArguments); return EndNode (memberType); } public object VisitComposedType (ComposedType composedType, object data) { StartNode (composedType); composedType.BaseType.AcceptVisitor (this, data); if (composedType.HasNullableSpecifier) WriteToken ("?", ComposedType.NullableRole); for (int i = 0; i < composedType.PointerRank; i++) WriteToken ("*", ComposedType.PointerRole); foreach (var node in composedType.ArraySpecifiers) node.AcceptVisitor (this, data); return EndNode (composedType); } public object VisitArraySpecifier (ArraySpecifier arraySpecifier, object data) { StartNode (arraySpecifier); WriteToken ("[", ArraySpecifier.Roles.LBracket); foreach (var comma in arraySpecifier.GetChildrenByRole(ArraySpecifier.Roles.Comma)) { WriteSpecialsUpToNode (comma); formatter.WriteToken (","); lastWritten = LastWritten.Other; } WriteToken ("]", ArraySpecifier.Roles.RBracket); return EndNode (arraySpecifier); } public object VisitPrimitiveType (PrimitiveType primitiveType, object data) { StartNode (primitiveType); WriteKeyword (primitiveType.Keyword); if (primitiveType.Keyword == "new") { // new() constraint LPar (); RPar (); } return EndNode (primitiveType); } public object VisitComment (Comment comment, object data) { if (lastWritten == LastWritten.Division) { // When there's a comment starting after a division operator // "1.0 / /*comment*/a", then we need to insert a space in front of the comment. formatter.Space (); } formatter.StartNode(comment); formatter.WriteComment (comment.CommentType, comment.Content); formatter.EndNode(comment); lastWritten = LastWritten.Whitespace; return null; } public object VisitTypeParameterDeclaration (TypeParameterDeclaration typeParameterDeclaration, object data) { StartNode (typeParameterDeclaration); WriteAttributes (typeParameterDeclaration.Attributes); switch (typeParameterDeclaration.Variance) { case VarianceModifier.Invariant: break; case VarianceModifier.Covariant: WriteKeyword ("out"); break; case VarianceModifier.Contravariant: WriteKeyword ("in"); break; default: throw new NotSupportedException ("Invalid value for VarianceModifier"); } WriteIdentifier (typeParameterDeclaration.Name); return EndNode (typeParameterDeclaration); } public object VisitConstraint (Constraint constraint, object data) { StartNode (constraint); Space (); WriteKeyword ("where"); WriteIdentifier (constraint.TypeParameter); Space (); WriteToken (":", Constraint.ColonRole); Space (); WriteCommaSeparatedList (constraint.BaseTypes); return EndNode (constraint); } public object VisitCSharpTokenNode (CSharpTokenNode cSharpTokenNode, object data) { CSharpModifierToken mod = cSharpTokenNode as CSharpModifierToken; if (mod != null) { StartNode (mod); WriteKeyword (CSharpModifierToken.GetModifierName (mod.Modifier)); return EndNode (mod); } else { throw new NotSupportedException ("Should never visit individual tokens"); } } public object VisitIdentifier (Identifier identifier, object data) { StartNode (identifier); WriteIdentifier (identifier.Name); return EndNode (identifier); } #endregion #region Pattern Nodes public object VisitPatternPlaceholder (AstNode placeholder, PatternMatching.Pattern pattern, object data) { StartNode (placeholder); pattern.AcceptVisitor (this, data); return EndNode (placeholder); } object IPatternAstVisitor.VisitAnyNode (AnyNode anyNode, object data) { if (!string.IsNullOrEmpty (anyNode.GroupName)) { WriteIdentifier (anyNode.GroupName); WriteToken (":", AstNode.Roles.Colon); } WriteKeyword ("anyNode"); return null; } object IPatternAstVisitor.VisitBackreference (Backreference backreference, object data) { WriteKeyword ("backreference"); LPar (); WriteIdentifier (backreference.ReferencedGroupName); RPar (); return null; } object IPatternAstVisitor.VisitIdentifierExpressionBackreference (IdentifierExpressionBackreference identifierExpressionBackreference, object data) { WriteKeyword ("identifierBackreference"); LPar (); WriteIdentifier (identifierExpressionBackreference.ReferencedGroupName); RPar (); return null; } object IPatternAstVisitor.VisitChoice (Choice choice, object data) { WriteKeyword ("choice"); Space (); LPar (); NewLine (); formatter.Indent (); foreach (INode alternative in choice) { VisitNodeInPattern (alternative, data); if (alternative != choice.Last ()) WriteToken (",", AstNode.Roles.Comma); NewLine (); } formatter.Unindent (); RPar (); return null; } object IPatternAstVisitor.VisitNamedNode (NamedNode namedNode, object data) { if (!string.IsNullOrEmpty (namedNode.GroupName)) { WriteIdentifier (namedNode.GroupName); WriteToken (":", AstNode.Roles.Colon); } VisitNodeInPattern (namedNode.ChildNode, data); return null; } object IPatternAstVisitor.VisitRepeat (Repeat repeat, object data) { WriteKeyword ("repeat"); LPar (); if (repeat.MinCount != 0 || repeat.MaxCount != int.MaxValue) { WriteIdentifier (repeat.MinCount.ToString ()); WriteToken (",", AstNode.Roles.Comma); WriteIdentifier (repeat.MaxCount.ToString ()); WriteToken (",", AstNode.Roles.Comma); } VisitNodeInPattern (repeat.ChildNode, data); RPar (); return null; } object IPatternAstVisitor.VisitOptionalNode (OptionalNode optionalNode, object data) { WriteKeyword ("optional"); LPar (); VisitNodeInPattern (optionalNode.ChildNode, data); RPar (); return null; } void VisitNodeInPattern (INode childNode, object data) { AstNode astNode = childNode as AstNode; if (astNode != null) { astNode.AcceptVisitor (this, data); } else { Pattern pattern = childNode as Pattern; if (pattern != null) { pattern.AcceptVisitor (this, data); } else { throw new InvalidOperationException ("Unknown node type in pattern"); } } } #endregion } }