.NET Decompiler with support for PDB generation, ReadyToRun, Metadata (&more) - cross-platform!
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

2637 lines
83 KiB

// 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 System.Threading.Tasks;
using ICSharpCode.NRefactory.PatternMatching;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp
{
/// <summary>
/// Outputs the AST.
/// </summary>
public class CSharpOutputVisitor : IAstVisitor
{
readonly IOutputFormatter formatter;
readonly CSharpFormattingOptions policy;
readonly Stack<AstNode> containerStack = new Stack<AstNode> ();
readonly Stack<AstNode> positionStack = new Stack<AstNode> ();
/// <summary>
/// Used to insert the minimal amount of spaces so that the lexer recognizes the tokens that were written.
/// </summary>
LastWritten lastWritten;
enum LastWritten
{
Whitespace,
Other,
KeywordOrIdentifier,
Plus,
Minus,
Ampersand,
QuestionMark,
Division
}
public CSharpOutputVisitor (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 CSharpOutputVisitor (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
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);
formatter.StartNode(node);
}
void EndNode(AstNode node)
{
Debug.Assert(node == containerStack.Peek());
AstNode pos = positionStack.Pop();
Debug.Assert(pos == null || pos.Parent == node);
WriteSpecials(pos, null);
containerStack.Pop();
formatter.EndNode(node);
}
#endregion
#region WriteSpecials
/// <summary>
/// Writes all specials from start to end (exclusive). Does not touch the positionStack.
/// </summary>
void WriteSpecials(AstNode start, AstNode end)
{
for (AstNode pos = start; pos != end; pos = pos.NextSibling) {
if (pos.Role == Roles.Comment || pos.Role == Roles.NewLine || pos.Role == Roles.PreProcessorDirective) {
pos.AcceptVisitor(this);
}
}
}
/// <summary>
/// Writes all specials between the current position (in the positionStack) and the next
/// node with the specified role. Advances the current position.
/// </summary>
void WriteSpecialsUpToRole(Role role)
{
WriteSpecialsUpToRole(role, null);
}
void WriteSpecialsUpToRole(Role role, AstNode nextNode)
{
if (positionStack.Count == 0) {
return;
}
// 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 == role) {
WriteSpecials(positionStack.Pop(), pos);
// Push the next sibling because the node matching the role is not a special,
// and should be considered to be already handled.
positionStack.Push(pos.NextSibling);
// This is necessary for OptionalComma() to work correctly.
break;
}
}
}
/// <summary>
/// Writes all specials between the current position (in the positionStack) and the specified node.
/// Advances the current position.
/// </summary>
void WriteSpecialsUpToNode(AstNode node)
{
if (positionStack.Count == 0) {
return;
}
for (AstNode pos = positionStack.Peek(); pos != null; pos = pos.NextSibling) {
if (pos == node) {
WriteSpecials(positionStack.Pop(), pos);
// Push the next sibling because the node itself is not a special,
// and should be considered to be already handled.
positionStack.Push(pos.NextSibling);
// This is necessary for OptionalComma() to work correctly.
break;
}
}
}
#endregion
#region Comma
/// <summary>
/// Writes a comma.
/// </summary>
/// <param name="nextNode">The next node after the comma.</param>
/// <param name="noSpaceAfterComma">When set prevents printing a space after comma.</param>
void Comma(AstNode nextNode, bool noSpaceAfterComma = false)
{
WriteSpecialsUpToRole(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.
}
/// <summary>
/// Writes an optional comma, e.g. at the end of an enum declaration or in an array initializer
/// </summary>
void OptionalComma()
{
// Look if there's a comma after the current node, and insert it if it exists.
AstNode pos = positionStack.Peek();
while (pos != null && pos.NodeType == NodeType.Whitespace) {
pos = pos.NextSibling;
}
if (pos != null && pos.Role == Roles.Comma) {
Comma(null, noSpaceAfterComma: true);
}
}
/// <summary>
/// Writes an optional semicolon, e.g. at the end of a type or namespace declaration.
/// </summary>
void OptionalSemicolon()
{
// Look if there's a semicolon after the current node, and insert it if it exists.
AstNode pos = positionStack.Peek();
while (pos != null && pos.NodeType == NodeType.Whitespace) {
pos = pos.NextSibling;
}
if (pos != null && pos.Role == Roles.Semicolon) {
Semicolon();
}
}
void WriteCommaSeparatedList(IEnumerable<AstNode> list)
{
bool isFirst = true;
foreach (AstNode node in list) {
if (isFirst) {
isFirst = false;
} else {
Comma(node);
}
node.AcceptVisitor(this);
}
}
void WriteCommaSeparatedListInParenthesis(IEnumerable<AstNode> list, bool spaceWithin)
{
LPar();
if (list.Any()) {
Space(spaceWithin);
WriteCommaSeparatedList(list);
Space(spaceWithin);
}
RPar();
}
#if DOTNET35
void WriteCommaSeparatedList(IEnumerable<VariableInitializer> list)
{
WriteCommaSeparatedList(list.SafeCast<VariableInitializer, AstNode>());
}
void WriteCommaSeparatedList(IEnumerable<AstType> list)
{
WriteCommaSeparatedList(list.SafeCast<AstType, AstNode>());
}
void WriteCommaSeparatedListInParenthesis(IEnumerable<Expression> list, bool spaceWithin)
{
WriteCommaSeparatedListInParenthesis(list.SafeCast<Expression, AstNode>(), spaceWithin);
}
void WriteCommaSeparatedListInParenthesis(IEnumerable<ParameterDeclaration> list, bool spaceWithin)
{
WriteCommaSeparatedListInParenthesis(list.SafeCast<ParameterDeclaration, AstNode>(), spaceWithin);
}
#endif
void WriteCommaSeparatedListInBrackets(IEnumerable<ParameterDeclaration> list, bool spaceWithin)
{
WriteToken(Roles.LBracket);
if (list.Any()) {
Space(spaceWithin);
WriteCommaSeparatedList(list);
Space(spaceWithin);
}
WriteToken(Roles.RBracket);
}
void WriteCommaSeparatedListInBrackets(IEnumerable<Expression> list)
{
WriteToken(Roles.LBracket);
if (list.Any()) {
Space(policy.SpacesWithinBrackets);
WriteCommaSeparatedList(list);
Space(policy.SpacesWithinBrackets);
}
WriteToken(Roles.RBracket);
}
#endregion
#region Write tokens
/// <summary>
/// Writes a keyword, and all specials up to
/// </summary>
void WriteKeyword(TokenRole tokenRole)
{
WriteKeyword(tokenRole.Token, tokenRole);
}
void WriteKeyword(string token, Role tokenRole = null)
{
if (tokenRole != null) {
WriteSpecialsUpToRole(tokenRole);
}
if (lastWritten == LastWritten.KeywordOrIdentifier) {
formatter.Space();
}
formatter.WriteKeyword(token);
lastWritten = LastWritten.KeywordOrIdentifier;
}
/* void WriteKeyword (string keyword, Role tokenRole)
{
WriteSpecialsUpToRole (tokenRole);
if (lastWritten == LastWritten.KeywordOrIdentifier)
formatter.Space ();
formatter.WriteKeyword (keyword);
lastWritten = LastWritten.KeywordOrIdentifier;
}*/
void WriteIdentifier(string identifier, Role<Identifier> identifierRole = null)
{
WriteSpecialsUpToRole(identifierRole ?? 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(TokenRole tokenRole)
{
WriteToken(tokenRole.Token, tokenRole);
}
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(Roles.LPar);
}
void RPar()
{
WriteToken(Roles.RPar);
}
/// <summary>
/// Marks the end of a statement
/// </summary>
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(Roles.Semicolon);
NewLine();
}
}
/// <summary>
/// Writes a space depending on policy.
/// </summary>
void Space(bool addSpace = true)
{
if (addSpace) {
formatter.Space();
lastWritten = LastWritten.Whitespace;
}
}
void NewLine()
{
formatter.NewLine();
lastWritten = LastWritten.Whitespace;
}
void OpenBrace(BraceStyle style)
{
WriteSpecialsUpToRole(Roles.LBrace);
formatter.OpenBrace(style);
lastWritten = LastWritten.Other;
}
void CloseBrace(BraceStyle style)
{
WriteSpecialsUpToRole(Roles.RBrace);
formatter.CloseBrace(style);
lastWritten = LastWritten.Other;
}
#endregion
#region IsKeyword Test
static readonly HashSet<string> unconditionalKeywords = new HashSet<string> {
"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<string> queryKeywords = new HashSet<string> {
"from", "where", "join", "on", "equals", "into", "let", "orderby",
"ascending", "descending", "select", "group", "by"
};
/// <summary>
/// Determines whether the specified identifier is a keyword in the given context.
/// </summary>
public static bool IsKeyword(string identifier, AstNode context)
{
if (unconditionalKeywords.Contains(identifier)) {
return true;
}
foreach (AstNode ancestor in context.Ancestors) {
if (ancestor is QueryExpression && queryKeywords.Contains(identifier)) {
return true;
}
if (identifier == "await") {
// with lambdas/anonymous methods,
if (ancestor is LambdaExpression) {
return ((LambdaExpression)ancestor).IsAsync;
}
if (ancestor is AnonymousMethodExpression) {
return ((AnonymousMethodExpression)ancestor).IsAsync;
}
if (ancestor is EntityDeclaration) {
return (((EntityDeclaration)ancestor).Modifiers & Modifiers.Async) == Modifiers.Async;
}
}
}
return false;
}
#endregion
#region Write constructs
void WriteTypeArguments(IEnumerable<AstType> typeArguments)
{
if (typeArguments.Any()) {
WriteToken(Roles.LChevron);
WriteCommaSeparatedList(typeArguments);
WriteToken(Roles.RChevron);
}
}
public void WriteTypeParameters(IEnumerable<TypeParameterDeclaration> typeParameters)
{
if (typeParameters.Any()) {
WriteToken(Roles.LChevron);
WriteCommaSeparatedList(typeParameters);
WriteToken(Roles.RChevron);
}
}
void WriteModifiers(IEnumerable<CSharpModifierToken> modifierTokens)
{
foreach (CSharpModifierToken modifier in modifierTokens) {
modifier.AcceptVisitor(this);
}
}
void WriteQualifiedIdentifier(IEnumerable<Identifier> identifiers)
{
bool first = true;
foreach (Identifier ident in identifiers) {
if (first) {
first = false;
if (lastWritten == LastWritten.KeywordOrIdentifier) {
formatter.Space();
}
} else {
WriteSpecialsUpToRole(Roles.Dot, ident);
formatter.WriteToken(".");
lastWritten = LastWritten.Other;
}
WriteSpecialsUpToNode(ident);
formatter.WriteIdentifier(ident.Name);
lastWritten = LastWritten.KeywordOrIdentifier;
}
}
void WriteEmbeddedStatement(Statement embeddedStatement)
{
if (embeddedStatement.IsNull) {
NewLine();
return;
}
BlockStatement block = embeddedStatement as BlockStatement;
if (block != null) {
VisitBlockStatement(block);
} else {
NewLine();
formatter.Indent();
embeddedStatement.AcceptVisitor(this);
formatter.Unindent();
}
}
void WriteMethodBody(BlockStatement body)
{
if (body.IsNull) {
Semicolon();
} else {
VisitBlockStatement(body);
}
}
void WriteAttributes(IEnumerable<AttributeSection> attributes)
{
foreach (AttributeSection attr in attributes) {
attr.AcceptVisitor(this);
}
}
void WritePrivateImplementationType(AstType privateImplementationType)
{
if (!privateImplementationType.IsNull) {
privateImplementationType.AcceptVisitor(this);
WriteToken(Roles.Dot);
}
}
#endregion
#region Expressions
public void VisitAnonymousMethodExpression(AnonymousMethodExpression anonymousMethodExpression)
{
StartNode(anonymousMethodExpression);
if (anonymousMethodExpression.IsAsync) {
WriteKeyword(AnonymousMethodExpression.AsyncModifierRole);
Space();
}
WriteKeyword(AnonymousMethodExpression.DelegateKeywordRole);
if (anonymousMethodExpression.HasParameterList) {
Space(policy.SpaceBeforeMethodDeclarationParentheses);
WriteCommaSeparatedListInParenthesis(anonymousMethodExpression.Parameters, policy.SpaceWithinMethodDeclarationParentheses);
}
anonymousMethodExpression.Body.AcceptVisitor(this);
EndNode(anonymousMethodExpression);
}
public void VisitUndocumentedExpression(UndocumentedExpression undocumentedExpression)
{
StartNode(undocumentedExpression);
switch (undocumentedExpression.UndocumentedExpressionType) {
case UndocumentedExpressionType.ArgList:
case UndocumentedExpressionType.ArgListAccess:
WriteKeyword(UndocumentedExpression.ArglistKeywordRole);
break;
case UndocumentedExpressionType.MakeRef:
WriteKeyword(UndocumentedExpression.MakerefKeywordRole);
break;
case UndocumentedExpressionType.RefType:
WriteKeyword(UndocumentedExpression.ReftypeKeywordRole);
break;
case UndocumentedExpressionType.RefValue:
WriteKeyword(UndocumentedExpression.RefvalueKeywordRole);
break;
}
if (undocumentedExpression.Arguments.Count > 0) {
Space(policy.SpaceBeforeMethodCallParentheses);
WriteCommaSeparatedListInParenthesis(undocumentedExpression.Arguments, policy.SpaceWithinMethodCallParentheses);
}
EndNode(undocumentedExpression);
}
public void VisitArrayCreateExpression(ArrayCreateExpression arrayCreateExpression)
{
StartNode(arrayCreateExpression);
WriteKeyword(ArrayCreateExpression.NewKeywordRole);
arrayCreateExpression.Type.AcceptVisitor(this);
if (arrayCreateExpression.Arguments.Count > 0) {
WriteCommaSeparatedListInBrackets(arrayCreateExpression.Arguments);
}
foreach (var specifier in arrayCreateExpression.AdditionalArraySpecifiers) {
specifier.AcceptVisitor(this);
}
arrayCreateExpression.Initializer.AcceptVisitor(this);
EndNode(arrayCreateExpression);
}
public void VisitArrayInitializerExpression(ArrayInitializerExpression arrayInitializerExpression)
{
StartNode(arrayInitializerExpression);
// "new List<int> { { 1 } }" and "new List<int> { 1 }" are the same semantically.
// We also use the same AST for both: we always use two nested ArrayInitializerExpressions
// for collection initializers, even if the user did not write nested brackets.
// The output visitor will output nested braces only if they are necessary,
// or if the braces tokens exist in the AST.
bool bracesAreOptional = arrayInitializerExpression.Elements.Count == 1
&& IsObjectOrCollectionInitializer(arrayInitializerExpression.Parent)
&& !CanBeConfusedWithObjectInitializer(arrayInitializerExpression.Elements.Single());
if (bracesAreOptional && arrayInitializerExpression.LBraceToken.IsNull) {
arrayInitializerExpression.Elements.Single().AcceptVisitor(this);
} else {
PrintInitializerElements(arrayInitializerExpression.Elements);
}
EndNode(arrayInitializerExpression);
}
bool CanBeConfusedWithObjectInitializer(Expression expr)
{
// "int a; new List<int> { a = 1 };" is an object initalizers and invalid, but
// "int a; new List<int> { { a = 1 } };" is a valid collection initializer.
AssignmentExpression ae = expr as AssignmentExpression;
return ae != null && ae.Operator == AssignmentOperatorType.Assign;
}
bool IsObjectOrCollectionInitializer(AstNode node)
{
if (!(node is ArrayInitializerExpression)) {
return false;
}
if (node.Parent is ObjectCreateExpression) {
return node.Role == ObjectCreateExpression.InitializerRole;
}
if (node.Parent is NamedExpression) {
return node.Role == Roles.Expression;
}
return false;
}
void PrintInitializerElements(AstNodeCollection<Expression> elements)
{
BraceStyle style;
if (policy.ArrayInitializerWrapping == Wrapping.WrapAlways) {
style = BraceStyle.NextLine;
} else {
style = BraceStyle.EndOfLine;
}
OpenBrace(style);
bool isFirst = true;
foreach (AstNode node in elements) {
if (isFirst) {
isFirst = false;
} else {
Comma(node, noSpaceAfterComma: true);
NewLine();
}
node.AcceptVisitor(this);
}
OptionalComma();
NewLine();
CloseBrace(style);
}
public void VisitAsExpression(AsExpression asExpression)
{
StartNode(asExpression);
asExpression.Expression.AcceptVisitor(this);
Space();
WriteKeyword(AsExpression.AsKeywordRole);
Space();
asExpression.Type.AcceptVisitor(this);
EndNode(asExpression);
}
public void VisitAssignmentExpression(AssignmentExpression assignmentExpression)
{
StartNode(assignmentExpression);
assignmentExpression.Left.AcceptVisitor(this);
Space(policy.SpaceAroundAssignment);
WriteToken(AssignmentExpression.GetOperatorRole(assignmentExpression.Operator));
Space(policy.SpaceAroundAssignment);
assignmentExpression.Right.AcceptVisitor(this);
EndNode(assignmentExpression);
}
public void VisitBaseReferenceExpression(BaseReferenceExpression baseReferenceExpression)
{
StartNode(baseReferenceExpression);
WriteKeyword("base", baseReferenceExpression.Role);
EndNode(baseReferenceExpression);
}
public void VisitBinaryOperatorExpression(BinaryOperatorExpression binaryOperatorExpression)
{
StartNode(binaryOperatorExpression);
binaryOperatorExpression.Left.AcceptVisitor(this);
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.GetOperatorRole(binaryOperatorExpression.Operator));
Space(spacePolicy);
binaryOperatorExpression.Right.AcceptVisitor(this);
EndNode(binaryOperatorExpression);
}
public void VisitCastExpression(CastExpression castExpression)
{
StartNode(castExpression);
LPar();
Space(policy.SpacesWithinCastParentheses);
castExpression.Type.AcceptVisitor(this);
Space(policy.SpacesWithinCastParentheses);
RPar();
Space(policy.SpaceAfterTypecast);
castExpression.Expression.AcceptVisitor(this);
EndNode(castExpression);
}
public void VisitCheckedExpression(CheckedExpression checkedExpression)
{
StartNode(checkedExpression);
WriteKeyword(CheckedExpression.CheckedKeywordRole);
LPar();
Space(policy.SpacesWithinCheckedExpressionParantheses);
checkedExpression.Expression.AcceptVisitor(this);
Space(policy.SpacesWithinCheckedExpressionParantheses);
RPar();
EndNode(checkedExpression);
}
public void VisitConditionalExpression(ConditionalExpression conditionalExpression)
{
StartNode(conditionalExpression);
conditionalExpression.Condition.AcceptVisitor(this);
Space(policy.SpaceBeforeConditionalOperatorCondition);
WriteToken(ConditionalExpression.QuestionMarkRole);
Space(policy.SpaceAfterConditionalOperatorCondition);
conditionalExpression.TrueExpression.AcceptVisitor(this);
Space(policy.SpaceBeforeConditionalOperatorSeparator);
WriteToken(ConditionalExpression.ColonRole);
Space(policy.SpaceAfterConditionalOperatorSeparator);
conditionalExpression.FalseExpression.AcceptVisitor(this);
EndNode(conditionalExpression);
}
public void VisitDefaultValueExpression(DefaultValueExpression defaultValueExpression)
{
StartNode(defaultValueExpression);
WriteKeyword(DefaultValueExpression.DefaultKeywordRole);
LPar();
Space(policy.SpacesWithinTypeOfParentheses);
defaultValueExpression.Type.AcceptVisitor(this);
Space(policy.SpacesWithinTypeOfParentheses);
RPar();
EndNode(defaultValueExpression);
}
public void VisitDirectionExpression(DirectionExpression directionExpression)
{
StartNode(directionExpression);
switch (directionExpression.FieldDirection) {
case FieldDirection.Out:
WriteKeyword(DirectionExpression.OutKeywordRole);
break;
case FieldDirection.Ref:
WriteKeyword(DirectionExpression.RefKeywordRole);
break;
default:
throw new NotSupportedException ("Invalid value for FieldDirection");
}
Space();
directionExpression.Expression.AcceptVisitor(this);
EndNode(directionExpression);
}
public void VisitIdentifierExpression(IdentifierExpression identifierExpression)
{
StartNode(identifierExpression);
WriteIdentifier(identifierExpression.Identifier);
WriteTypeArguments(identifierExpression.TypeArguments);
EndNode(identifierExpression);
}
public void VisitIndexerExpression(IndexerExpression indexerExpression)
{
StartNode(indexerExpression);
indexerExpression.Target.AcceptVisitor(this);
Space(policy.SpaceBeforeMethodCallParentheses);
WriteCommaSeparatedListInBrackets(indexerExpression.Arguments);
EndNode(indexerExpression);
}
public void VisitInvocationExpression(InvocationExpression invocationExpression)
{
StartNode(invocationExpression);
invocationExpression.Target.AcceptVisitor(this);
Space(policy.SpaceBeforeMethodCallParentheses);
WriteCommaSeparatedListInParenthesis(invocationExpression.Arguments, policy.SpaceWithinMethodCallParentheses);
EndNode(invocationExpression);
}
public void VisitIsExpression(IsExpression isExpression)
{
StartNode(isExpression);
isExpression.Expression.AcceptVisitor(this);
Space();
WriteKeyword(IsExpression.IsKeywordRole);
isExpression.Type.AcceptVisitor(this);
EndNode(isExpression);
}
public void VisitLambdaExpression(LambdaExpression lambdaExpression)
{
StartNode(lambdaExpression);
if (lambdaExpression.IsAsync) {
WriteKeyword(LambdaExpression.AsyncModifierRole);
Space();
}
if (LambdaNeedsParenthesis(lambdaExpression)) {
WriteCommaSeparatedListInParenthesis(lambdaExpression.Parameters, policy.SpaceWithinMethodDeclarationParentheses);
} else {
lambdaExpression.Parameters.Single().AcceptVisitor(this);
}
Space();
WriteToken(LambdaExpression.ArrowRole);
Space();
lambdaExpression.Body.AcceptVisitor(this);
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 void VisitMemberReferenceExpression(MemberReferenceExpression memberReferenceExpression)
{
StartNode(memberReferenceExpression);
memberReferenceExpression.Target.AcceptVisitor(this);
WriteToken(Roles.Dot);
WriteIdentifier(memberReferenceExpression.MemberName);
WriteTypeArguments(memberReferenceExpression.TypeArguments);
EndNode(memberReferenceExpression);
}
public void VisitNamedArgumentExpression(NamedArgumentExpression namedArgumentExpression)
{
StartNode(namedArgumentExpression);
namedArgumentExpression.NameToken.AcceptVisitor(this);
WriteToken(Roles.Colon);
Space();
namedArgumentExpression.Expression.AcceptVisitor(this);
EndNode(namedArgumentExpression);
}
public void VisitNamedExpression(NamedExpression namedExpression)
{
StartNode(namedExpression);
namedExpression.NameToken.AcceptVisitor(this);
Space();
WriteToken(Roles.Assign);
Space();
namedExpression.Expression.AcceptVisitor(this);
EndNode(namedExpression);
}
public void VisitNullReferenceExpression(NullReferenceExpression nullReferenceExpression)
{
StartNode(nullReferenceExpression);
WriteKeyword("null", nullReferenceExpression.Role);
EndNode(nullReferenceExpression);
}
public void VisitObjectCreateExpression(ObjectCreateExpression objectCreateExpression)
{
StartNode(objectCreateExpression);
WriteKeyword(ObjectCreateExpression.NewKeywordRole);
objectCreateExpression.Type.AcceptVisitor(this);
bool useParenthesis = objectCreateExpression.Arguments.Any() || objectCreateExpression.Initializer.IsNull;
// also use parenthesis if there is an '(' token
if (!objectCreateExpression.LParToken.IsNull) {
useParenthesis = true;
}
if (useParenthesis) {
Space(policy.SpaceBeforeMethodCallParentheses);
WriteCommaSeparatedListInParenthesis(objectCreateExpression.Arguments, policy.SpaceWithinMethodCallParentheses);
}
objectCreateExpression.Initializer.AcceptVisitor(this);
EndNode(objectCreateExpression);
}
public void VisitAnonymousTypeCreateExpression(AnonymousTypeCreateExpression anonymousTypeCreateExpression)
{
StartNode(anonymousTypeCreateExpression);
WriteKeyword(AnonymousTypeCreateExpression.NewKeywordRole);
PrintInitializerElements(anonymousTypeCreateExpression.Initializers);
EndNode(anonymousTypeCreateExpression);
}
public void VisitParenthesizedExpression(ParenthesizedExpression parenthesizedExpression)
{
StartNode(parenthesizedExpression);
LPar();
Space(policy.SpacesWithinParentheses);
parenthesizedExpression.Expression.AcceptVisitor(this);
Space(policy.SpacesWithinParentheses);
RPar();
EndNode(parenthesizedExpression);
}
public void VisitPointerReferenceExpression(PointerReferenceExpression pointerReferenceExpression)
{
StartNode(pointerReferenceExpression);
pointerReferenceExpression.Target.AcceptVisitor(this);
WriteToken(PointerReferenceExpression.ArrowRole);
WriteIdentifier(pointerReferenceExpression.MemberName);
WriteTypeArguments(pointerReferenceExpression.TypeArguments);
EndNode(pointerReferenceExpression);
}
public void VisitEmptyExpression(EmptyExpression emptyExpression)
{
StartNode(emptyExpression);
EndNode(emptyExpression);
}
#region VisitPrimitiveExpression
public void VisitPrimitiveExpression(PrimitiveExpression primitiveExpression)
{
StartNode(primitiveExpression);
if (!string.IsNullOrEmpty(primitiveExpression.LiteralValue)) {
formatter.WriteToken(primitiveExpression.LiteralValue);
} else {
WritePrimitiveValue(primitiveExpression.Value);
}
EndNode(primitiveExpression);
}
public static string PrintPrimitiveValue(object val)
{
StringWriter writer = new StringWriter();
CSharpOutputVisitor visitor = new CSharpOutputVisitor(writer, new CSharpFormattingOptions());
visitor.WritePrimitiveValue(val);
return writer.ToString();
}
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(Roles.Dot);
if (float.IsPositiveInfinity(f)) {
WriteIdentifier("PositiveInfinity");
} else if (float.IsNegativeInfinity(f)) {
WriteIdentifier("NegativeInfinity");
} else {
WriteIdentifier("NaN");
}
return;
}
if (f == 0 && 1 / f == double.NegativeInfinity) {
// negative zero is a special case
// (again, not a primitive expression, but it's better to handle
// the special case here than to do it in all code generators)
formatter.WriteToken("-");
}
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(Roles.Dot);
if (double.IsPositiveInfinity(f)) {
WriteIdentifier("PositiveInfinity");
} else if (double.IsNegativeInfinity(f)) {
WriteIdentifier("NegativeInfinity");
} else {
WriteIdentifier("NaN");
}
return;
}
if (f == 0 && 1 / f == double.NegativeInfinity) {
// negative zero is a special case
// (again, not a primitive expression, but it's better to handle
// the special case here than to do it in all code generators)
formatter.WriteToken("-");
}
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);
}
/// <summary>
/// Gets the escape sequence for the specified character.
/// </summary>
/// <remarks>This method does not convert ' or ".</remarks>
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();
}
}
}
/// <summary>
/// Converts special characters to escape sequences within the given string.
/// </summary>
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 void VisitSizeOfExpression(SizeOfExpression sizeOfExpression)
{
StartNode(sizeOfExpression);
WriteKeyword(SizeOfExpression.SizeofKeywordRole);
LPar();
Space(policy.SpacesWithinSizeOfParentheses);
sizeOfExpression.Type.AcceptVisitor(this);
Space(policy.SpacesWithinSizeOfParentheses);
RPar();
EndNode(sizeOfExpression);
}
public void VisitStackAllocExpression(StackAllocExpression stackAllocExpression)
{
StartNode(stackAllocExpression);
WriteKeyword(StackAllocExpression.StackallocKeywordRole);
stackAllocExpression.Type.AcceptVisitor(this);
WriteCommaSeparatedListInBrackets(new[] { stackAllocExpression.CountExpression });
EndNode(stackAllocExpression);
}
public void VisitThisReferenceExpression(ThisReferenceExpression thisReferenceExpression)
{
StartNode(thisReferenceExpression);
WriteKeyword("this", thisReferenceExpression.Role);
EndNode(thisReferenceExpression);
}
public void VisitTypeOfExpression(TypeOfExpression typeOfExpression)
{
StartNode(typeOfExpression);
WriteKeyword(TypeOfExpression.TypeofKeywordRole);
LPar();
Space(policy.SpacesWithinTypeOfParentheses);
typeOfExpression.Type.AcceptVisitor(this);
Space(policy.SpacesWithinTypeOfParentheses);
RPar();
EndNode(typeOfExpression);
}
public void VisitTypeReferenceExpression(TypeReferenceExpression typeReferenceExpression)
{
StartNode(typeReferenceExpression);
typeReferenceExpression.Type.AcceptVisitor(this);
EndNode(typeReferenceExpression);
}
public void VisitUnaryOperatorExpression(UnaryOperatorExpression unaryOperatorExpression)
{
StartNode(unaryOperatorExpression);
UnaryOperatorType opType = unaryOperatorExpression.Operator;
var opSymbol = UnaryOperatorExpression.GetOperatorRole(opType);
if (opType == UnaryOperatorType.Await) {
WriteKeyword(opSymbol);
} else if (!(opType == UnaryOperatorType.PostIncrement || opType == UnaryOperatorType.PostDecrement)) {
WriteToken(opSymbol);
}
unaryOperatorExpression.Expression.AcceptVisitor(this);
if (opType == UnaryOperatorType.PostIncrement || opType == UnaryOperatorType.PostDecrement) {
WriteToken(opSymbol);
}
EndNode(unaryOperatorExpression);
}
public void VisitUncheckedExpression(UncheckedExpression uncheckedExpression)
{
StartNode(uncheckedExpression);
WriteKeyword(UncheckedExpression.UncheckedKeywordRole);
LPar();
Space(policy.SpacesWithinCheckedExpressionParantheses);
uncheckedExpression.Expression.AcceptVisitor(this);
Space(policy.SpacesWithinCheckedExpressionParantheses);
RPar();
EndNode(uncheckedExpression);
}
#endregion
#region Query Expressions
public void VisitQueryExpression(QueryExpression queryExpression)
{
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);
}
if (indent) {
formatter.Unindent();
}
EndNode(queryExpression);
}
public void VisitQueryContinuationClause(QueryContinuationClause queryContinuationClause)
{
StartNode(queryContinuationClause);
queryContinuationClause.PrecedingQuery.AcceptVisitor(this);
Space();
WriteKeyword(QueryContinuationClause.IntoKeywordRole);
Space();
queryContinuationClause.IdentifierToken.AcceptVisitor(this);
EndNode(queryContinuationClause);
}
public void VisitQueryFromClause(QueryFromClause queryFromClause)
{
StartNode(queryFromClause);
WriteKeyword(QueryFromClause.FromKeywordRole);
queryFromClause.Type.AcceptVisitor(this);
Space();
queryFromClause.IdentifierToken.AcceptVisitor(this);
Space();
WriteKeyword(QueryFromClause.InKeywordRole);
Space();
queryFromClause.Expression.AcceptVisitor(this);
EndNode(queryFromClause);
}
public void VisitQueryLetClause(QueryLetClause queryLetClause)
{
StartNode(queryLetClause);
WriteKeyword(QueryLetClause.LetKeywordRole);
Space();
queryLetClause.IdentifierToken.AcceptVisitor(this);
Space(policy.SpaceAroundAssignment);
WriteToken(Roles.Assign);
Space(policy.SpaceAroundAssignment);
queryLetClause.Expression.AcceptVisitor(this);
EndNode(queryLetClause);
}
public void VisitQueryWhereClause(QueryWhereClause queryWhereClause)
{
StartNode(queryWhereClause);
WriteKeyword(QueryWhereClause.WhereKeywordRole);
Space();
queryWhereClause.Condition.AcceptVisitor(this);
EndNode(queryWhereClause);
}
public void VisitQueryJoinClause(QueryJoinClause queryJoinClause)
{
StartNode(queryJoinClause);
WriteKeyword(QueryJoinClause.JoinKeywordRole);
queryJoinClause.Type.AcceptVisitor(this);
Space();
WriteIdentifier(queryJoinClause.JoinIdentifier, QueryJoinClause.JoinIdentifierRole);
Space();
WriteKeyword(QueryJoinClause.InKeywordRole);
Space();
queryJoinClause.InExpression.AcceptVisitor(this);
Space();
WriteKeyword(QueryJoinClause.OnKeywordRole);
Space();
queryJoinClause.OnExpression.AcceptVisitor(this);
Space();
WriteKeyword(QueryJoinClause.EqualsKeywordRole);
Space();
queryJoinClause.EqualsExpression.AcceptVisitor(this);
if (queryJoinClause.IsGroupJoin) {
Space();
WriteKeyword(QueryJoinClause.IntoKeywordRole);
WriteIdentifier(queryJoinClause.IntoIdentifier, QueryJoinClause.IntoIdentifierRole);
}
EndNode(queryJoinClause);
}
public void VisitQueryOrderClause(QueryOrderClause queryOrderClause)
{
StartNode(queryOrderClause);
WriteKeyword(QueryOrderClause.OrderbyKeywordRole);
Space();
WriteCommaSeparatedList(queryOrderClause.Orderings);
EndNode(queryOrderClause);
}
public void VisitQueryOrdering(QueryOrdering queryOrdering)
{
StartNode(queryOrdering);
queryOrdering.Expression.AcceptVisitor(this);
switch (queryOrdering.Direction) {
case QueryOrderingDirection.Ascending:
Space();
WriteKeyword(QueryOrdering.AscendingKeywordRole);
break;
case QueryOrderingDirection.Descending:
Space();
WriteKeyword(QueryOrdering.DescendingKeywordRole);
break;
}
EndNode(queryOrdering);
}
public void VisitQuerySelectClause(QuerySelectClause querySelectClause)
{
StartNode(querySelectClause);
WriteKeyword(QuerySelectClause.SelectKeywordRole);
Space();
querySelectClause.Expression.AcceptVisitor(this);
EndNode(querySelectClause);
}
public void VisitQueryGroupClause(QueryGroupClause queryGroupClause)
{
StartNode(queryGroupClause);
WriteKeyword(QueryGroupClause.GroupKeywordRole);
Space();
queryGroupClause.Projection.AcceptVisitor(this);
Space();
WriteKeyword(QueryGroupClause.ByKeywordRole);
Space();
queryGroupClause.Key.AcceptVisitor(this);
EndNode(queryGroupClause);
}
#endregion
#region GeneralScope
public void VisitAttribute(Attribute attribute)
{
StartNode(attribute);
attribute.Type.AcceptVisitor(this);
if (attribute.Arguments.Count != 0 || !attribute.GetChildByRole(Roles.LPar).IsNull) {
Space(policy.SpaceBeforeMethodCallParentheses);
WriteCommaSeparatedListInParenthesis(attribute.Arguments, policy.SpaceWithinMethodCallParentheses);
}
EndNode(attribute);
}
public void VisitAttributeSection(AttributeSection attributeSection)
{
StartNode(attributeSection);
WriteToken(Roles.LBracket);
if (!string.IsNullOrEmpty(attributeSection.AttributeTarget)) {
WriteToken(attributeSection.AttributeTarget, Roles.AttributeTargetRole);
WriteToken(Roles.Colon);
Space();
}
WriteCommaSeparatedList(attributeSection.Attributes);
WriteToken(Roles.RBracket);
if (attributeSection.Parent is ParameterDeclaration || attributeSection.Parent is TypeParameterDeclaration) {
Space();
} else {
NewLine();
}
EndNode(attributeSection);
}
public void VisitDelegateDeclaration(DelegateDeclaration delegateDeclaration)
{
StartNode(delegateDeclaration);
WriteAttributes(delegateDeclaration.Attributes);
WriteModifiers(delegateDeclaration.ModifierTokens);
WriteKeyword(Roles.DelegateKeyword);
delegateDeclaration.ReturnType.AcceptVisitor(this);
Space();
delegateDeclaration.NameToken.AcceptVisitor(this);
WriteTypeParameters(delegateDeclaration.TypeParameters);
Space(policy.SpaceBeforeDelegateDeclarationParentheses);
WriteCommaSeparatedListInParenthesis(delegateDeclaration.Parameters, policy.SpaceWithinMethodDeclarationParentheses);
foreach (Constraint constraint in delegateDeclaration.Constraints) {
constraint.AcceptVisitor(this);
}
Semicolon();
EndNode(delegateDeclaration);
}
public void VisitNamespaceDeclaration(NamespaceDeclaration namespaceDeclaration)
{
StartNode(namespaceDeclaration);
WriteKeyword(Roles.NamespaceKeyword);
WriteQualifiedIdentifier(namespaceDeclaration.Identifiers);
OpenBrace(policy.NamespaceBraceStyle);
foreach (var member in namespaceDeclaration.Members) {
member.AcceptVisitor(this);
}
CloseBrace(policy.NamespaceBraceStyle);
OptionalSemicolon();
NewLine();
EndNode(namespaceDeclaration);
}
public void VisitTypeDeclaration(TypeDeclaration typeDeclaration)
{
StartNode(typeDeclaration);
WriteAttributes(typeDeclaration.Attributes);
WriteModifiers(typeDeclaration.ModifierTokens);
BraceStyle braceStyle;
switch (typeDeclaration.ClassType) {
case ClassType.Enum:
WriteKeyword(Roles.EnumKeyword);
braceStyle = policy.EnumBraceStyle;
break;
case ClassType.Interface:
WriteKeyword(Roles.InterfaceKeyword);
braceStyle = policy.InterfaceBraceStyle;
break;
case ClassType.Struct:
WriteKeyword(Roles.StructKeyword);
braceStyle = policy.StructBraceStyle;
break;
default:
WriteKeyword(Roles.ClassKeyword);
braceStyle = policy.ClassBraceStyle;
break;
}
typeDeclaration.NameToken.AcceptVisitor(this);
WriteTypeParameters(typeDeclaration.TypeParameters);
if (typeDeclaration.BaseTypes.Any()) {
Space();
WriteToken(Roles.Colon);
Space();
WriteCommaSeparatedList(typeDeclaration.BaseTypes);
}
foreach (Constraint constraint in typeDeclaration.Constraints) {
constraint.AcceptVisitor(this);
}
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);
}
OptionalComma();
NewLine();
} else {
foreach (var member in typeDeclaration.Members) {
member.AcceptVisitor(this);
}
}
CloseBrace(braceStyle);
OptionalSemicolon();
NewLine();
EndNode(typeDeclaration);
}
public void VisitUsingAliasDeclaration(UsingAliasDeclaration usingAliasDeclaration)
{
StartNode(usingAliasDeclaration);
WriteKeyword(UsingAliasDeclaration.UsingKeywordRole);
WriteIdentifier(usingAliasDeclaration.Alias, UsingAliasDeclaration.AliasRole);
Space(policy.SpaceAroundEqualityOperator);
WriteToken(Roles.Assign);
Space(policy.SpaceAroundEqualityOperator);
usingAliasDeclaration.Import.AcceptVisitor(this);
Semicolon();
EndNode(usingAliasDeclaration);
}
public void VisitUsingDeclaration(UsingDeclaration usingDeclaration)
{
StartNode(usingDeclaration);
WriteKeyword(UsingDeclaration.UsingKeywordRole);
usingDeclaration.Import.AcceptVisitor(this);
Semicolon();
EndNode(usingDeclaration);
}
public void VisitExternAliasDeclaration(ExternAliasDeclaration externAliasDeclaration)
{
StartNode(externAliasDeclaration);
WriteKeyword(Roles.ExternKeyword);
Space();
WriteKeyword(Roles.AliasKeyword);
Space();
externAliasDeclaration.NameToken.AcceptVisitor(this);
Semicolon();
EndNode(externAliasDeclaration);
}
#endregion
#region Statements
public void VisitBlockStatement(BlockStatement blockStatement)
{
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 {
style = policy.StatementBraceStyle;
}
} else {
style = policy.StatementBraceStyle;
}
OpenBrace(style);
foreach (var node in blockStatement.Statements) {
node.AcceptVisitor(this);
}
CloseBrace(style);
if (!(blockStatement.Parent is Expression))
NewLine();
EndNode(blockStatement);
}
public void VisitBreakStatement(BreakStatement breakStatement)
{
StartNode(breakStatement);
WriteKeyword("break");
Semicolon();
EndNode(breakStatement);
}
public void VisitCheckedStatement(CheckedStatement checkedStatement)
{
StartNode(checkedStatement);
WriteKeyword(CheckedStatement.CheckedKeywordRole);
checkedStatement.Body.AcceptVisitor(this);
EndNode(checkedStatement);
}
public void VisitContinueStatement(ContinueStatement continueStatement)
{
StartNode(continueStatement);
WriteKeyword("continue");
Semicolon();
EndNode(continueStatement);
}
public void VisitDoWhileStatement(DoWhileStatement doWhileStatement)
{
StartNode(doWhileStatement);
WriteKeyword(DoWhileStatement.DoKeywordRole);
WriteEmbeddedStatement(doWhileStatement.EmbeddedStatement);
WriteKeyword(DoWhileStatement.WhileKeywordRole);
Space(policy.SpaceBeforeWhileParentheses);
LPar();
Space(policy.SpacesWithinWhileParentheses);
doWhileStatement.Condition.AcceptVisitor(this);
Space(policy.SpacesWithinWhileParentheses);
RPar();
Semicolon();
EndNode(doWhileStatement);
}
public void VisitEmptyStatement(EmptyStatement emptyStatement)
{
StartNode(emptyStatement);
Semicolon();
EndNode(emptyStatement);
}
public void VisitExpressionStatement(ExpressionStatement expressionStatement)
{
StartNode(expressionStatement);
expressionStatement.Expression.AcceptVisitor(this);
Semicolon();
EndNode(expressionStatement);
}
public void VisitFixedStatement(FixedStatement fixedStatement)
{
StartNode(fixedStatement);
WriteKeyword(FixedStatement.FixedKeywordRole);
Space(policy.SpaceBeforeUsingParentheses);
LPar();
Space(policy.SpacesWithinUsingParentheses);
fixedStatement.Type.AcceptVisitor(this);
Space();
WriteCommaSeparatedList(fixedStatement.Variables);
Space(policy.SpacesWithinUsingParentheses);
RPar();
WriteEmbeddedStatement(fixedStatement.EmbeddedStatement);
EndNode(fixedStatement);
}
public void VisitForeachStatement(ForeachStatement foreachStatement)
{
StartNode(foreachStatement);
WriteKeyword(ForeachStatement.ForeachKeywordRole);
Space(policy.SpaceBeforeForeachParentheses);
LPar();
Space(policy.SpacesWithinForeachParentheses);
foreachStatement.VariableType.AcceptVisitor(this);
Space();
foreachStatement.VariableNameToken.AcceptVisitor(this);
WriteKeyword(ForeachStatement.InKeywordRole);
Space();
foreachStatement.InExpression.AcceptVisitor(this);
Space(policy.SpacesWithinForeachParentheses);
RPar();
WriteEmbeddedStatement(foreachStatement.EmbeddedStatement);
EndNode(foreachStatement);
}
public void VisitForStatement(ForStatement forStatement)
{
StartNode(forStatement);
WriteKeyword(ForStatement.ForKeywordRole);
Space(policy.SpaceBeforeForParentheses);
LPar();
Space(policy.SpacesWithinForParentheses);
WriteCommaSeparatedList(forStatement.Initializers);
Space(policy.SpaceBeforeForSemicolon);
WriteToken(Roles.Semicolon);
Space(policy.SpaceAfterForSemicolon);
forStatement.Condition.AcceptVisitor(this);
Space(policy.SpaceBeforeForSemicolon);
WriteToken(Roles.Semicolon);
if (forStatement.Iterators.Any()) {
Space(policy.SpaceAfterForSemicolon);
WriteCommaSeparatedList(forStatement.Iterators);
}
Space(policy.SpacesWithinForParentheses);
RPar();
WriteEmbeddedStatement(forStatement.EmbeddedStatement);
EndNode(forStatement);
}
public void VisitGotoCaseStatement(GotoCaseStatement gotoCaseStatement)
{
StartNode(gotoCaseStatement);
WriteKeyword(GotoCaseStatement.GotoKeywordRole);
WriteKeyword(GotoCaseStatement.CaseKeywordRole);
Space();
gotoCaseStatement.LabelExpression.AcceptVisitor(this);
Semicolon();
EndNode(gotoCaseStatement);
}
public void VisitGotoDefaultStatement(GotoDefaultStatement gotoDefaultStatement)
{
StartNode(gotoDefaultStatement);
WriteKeyword(GotoDefaultStatement.GotoKeywordRole);
WriteKeyword(GotoDefaultStatement.DefaultKeywordRole);
Semicolon();
EndNode(gotoDefaultStatement);
}
public void VisitGotoStatement(GotoStatement gotoStatement)
{
StartNode(gotoStatement);
WriteKeyword(GotoStatement.GotoKeywordRole);
WriteIdentifier(gotoStatement.Label);
Semicolon();
EndNode(gotoStatement);
}
public void VisitIfElseStatement(IfElseStatement ifElseStatement)
{
StartNode(ifElseStatement);
WriteKeyword(IfElseStatement.IfKeywordRole);
Space(policy.SpaceBeforeIfParentheses);
LPar();
Space(policy.SpacesWithinIfParentheses);
ifElseStatement.Condition.AcceptVisitor(this);
Space(policy.SpacesWithinIfParentheses);
RPar();
WriteEmbeddedStatement(ifElseStatement.TrueStatement);
if (!ifElseStatement.FalseStatement.IsNull) {
WriteKeyword(IfElseStatement.ElseKeywordRole);
WriteEmbeddedStatement(ifElseStatement.FalseStatement);
}
EndNode(ifElseStatement);
}
public void VisitLabelStatement(LabelStatement labelStatement)
{
StartNode(labelStatement);
WriteIdentifier(labelStatement.Label);
WriteToken(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(Roles.Semicolon);
}
NewLine();
EndNode(labelStatement);
}
public void VisitLockStatement(LockStatement lockStatement)
{
StartNode(lockStatement);
WriteKeyword(LockStatement.LockKeywordRole);
Space(policy.SpaceBeforeLockParentheses);
LPar();
Space(policy.SpacesWithinLockParentheses);
lockStatement.Expression.AcceptVisitor(this);
Space(policy.SpacesWithinLockParentheses);
RPar();
WriteEmbeddedStatement(lockStatement.EmbeddedStatement);
EndNode(lockStatement);
}
public void VisitReturnStatement(ReturnStatement returnStatement)
{
StartNode(returnStatement);
WriteKeyword(ReturnStatement.ReturnKeywordRole);
if (!returnStatement.Expression.IsNull) {
Space();
returnStatement.Expression.AcceptVisitor(this);
}
Semicolon();
EndNode(returnStatement);
}
public void VisitSwitchStatement(SwitchStatement switchStatement)
{
StartNode(switchStatement);
WriteKeyword(SwitchStatement.SwitchKeywordRole);
Space(policy.SpaceBeforeSwitchParentheses);
LPar();
Space(policy.SpacesWithinSwitchParentheses);
switchStatement.Expression.AcceptVisitor(this);
Space(policy.SpacesWithinSwitchParentheses);
RPar();
OpenBrace(policy.StatementBraceStyle);
if (!policy.IndentSwitchBody) {
formatter.Unindent();
}
foreach (var section in switchStatement.SwitchSections) {
section.AcceptVisitor(this);
}
if (!policy.IndentSwitchBody) {
formatter.Indent();
}
CloseBrace(policy.StatementBraceStyle);
NewLine();
EndNode(switchStatement);
}
public void VisitSwitchSection(SwitchSection switchSection)
{
StartNode(switchSection);
bool first = true;
foreach (var label in switchSection.CaseLabels) {
if (!first) {
NewLine();
}
label.AcceptVisitor(this);
first = false;
}
bool isBlock = switchSection.Statements.Count == 1 && switchSection.Statements.Single() is BlockStatement;
if (policy.IndentCaseBody && !isBlock) {
formatter.Indent();
}
if (!isBlock)
NewLine();
foreach (var statement in switchSection.Statements) {
statement.AcceptVisitor(this);
}
if (policy.IndentCaseBody && !isBlock) {
formatter.Unindent();
}
EndNode(switchSection);
}
public void VisitCaseLabel(CaseLabel caseLabel)
{
StartNode(caseLabel);
if (caseLabel.Expression.IsNull) {
WriteKeyword(CaseLabel.DefaultKeywordRole);
} else {
WriteKeyword(CaseLabel.CaseKeywordRole);
Space();
caseLabel.Expression.AcceptVisitor(this);
}
WriteToken(Roles.Colon);
EndNode(caseLabel);
}
public void VisitThrowStatement(ThrowStatement throwStatement)
{
StartNode(throwStatement);
WriteKeyword(ThrowStatement.ThrowKeywordRole);
if (!throwStatement.Expression.IsNull) {
Space();
throwStatement.Expression.AcceptVisitor(this);
}
Semicolon();
EndNode(throwStatement);
}
public void VisitTryCatchStatement(TryCatchStatement tryCatchStatement)
{
StartNode(tryCatchStatement);
WriteKeyword(TryCatchStatement.TryKeywordRole);
tryCatchStatement.TryBlock.AcceptVisitor(this);
foreach (var catchClause in tryCatchStatement.CatchClauses) {
catchClause.AcceptVisitor(this);
}
if (!tryCatchStatement.FinallyBlock.IsNull) {
WriteKeyword(TryCatchStatement.FinallyKeywordRole);
tryCatchStatement.FinallyBlock.AcceptVisitor(this);
}
EndNode(tryCatchStatement);
}
public void VisitCatchClause(CatchClause catchClause)
{
StartNode(catchClause);
WriteKeyword(CatchClause.CatchKeywordRole);
if (!catchClause.Type.IsNull) {
Space(policy.SpaceBeforeCatchParentheses);
LPar();
Space(policy.SpacesWithinCatchParentheses);
catchClause.Type.AcceptVisitor(this);
if (!string.IsNullOrEmpty(catchClause.VariableName)) {
Space();
catchClause.VariableNameToken.AcceptVisitor(this);
}
Space(policy.SpacesWithinCatchParentheses);
RPar();
}
catchClause.Body.AcceptVisitor(this);
EndNode(catchClause);
}
public void VisitUncheckedStatement(UncheckedStatement uncheckedStatement)
{
StartNode(uncheckedStatement);
WriteKeyword(UncheckedStatement.UncheckedKeywordRole);
uncheckedStatement.Body.AcceptVisitor(this);
EndNode(uncheckedStatement);
}
public void VisitUnsafeStatement(UnsafeStatement unsafeStatement)
{
StartNode(unsafeStatement);
WriteKeyword(UnsafeStatement.UnsafeKeywordRole);
unsafeStatement.Body.AcceptVisitor(this);
EndNode(unsafeStatement);
}
public void VisitUsingStatement(UsingStatement usingStatement)
{
StartNode(usingStatement);
WriteKeyword(UsingStatement.UsingKeywordRole);
Space(policy.SpaceBeforeUsingParentheses);
LPar();
Space(policy.SpacesWithinUsingParentheses);
usingStatement.ResourceAcquisition.AcceptVisitor(this);
Space(policy.SpacesWithinUsingParentheses);
RPar();
WriteEmbeddedStatement(usingStatement.EmbeddedStatement);
EndNode(usingStatement);
}
public void VisitVariableDeclarationStatement(VariableDeclarationStatement variableDeclarationStatement)
{
StartNode(variableDeclarationStatement);
WriteModifiers(variableDeclarationStatement.GetChildrenByRole(VariableDeclarationStatement.ModifierRole));
variableDeclarationStatement.Type.AcceptVisitor(this);
Space();
WriteCommaSeparatedList(variableDeclarationStatement.Variables);
Semicolon();
EndNode(variableDeclarationStatement);
}
public void VisitWhileStatement(WhileStatement whileStatement)
{
StartNode(whileStatement);
WriteKeyword(WhileStatement.WhileKeywordRole);
Space(policy.SpaceBeforeWhileParentheses);
LPar();
Space(policy.SpacesWithinWhileParentheses);
whileStatement.Condition.AcceptVisitor(this);
Space(policy.SpacesWithinWhileParentheses);
RPar();
WriteEmbeddedStatement(whileStatement.EmbeddedStatement);
EndNode(whileStatement);
}
public void VisitYieldBreakStatement(YieldBreakStatement yieldBreakStatement)
{
StartNode(yieldBreakStatement);
WriteKeyword(YieldBreakStatement.YieldKeywordRole);
WriteKeyword(YieldBreakStatement.BreakKeywordRole);
Semicolon();
EndNode(yieldBreakStatement);
}
public void VisitYieldReturnStatement(YieldReturnStatement yieldReturnStatement)
{
StartNode(yieldReturnStatement);
WriteKeyword(YieldReturnStatement.YieldKeywordRole);
WriteKeyword(YieldReturnStatement.ReturnKeywordRole);
Space();
yieldReturnStatement.Expression.AcceptVisitor(this);
Semicolon();
EndNode(yieldReturnStatement);
}
#endregion
#region TypeMembers
public void VisitAccessor(Accessor accessor)
{
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);
EndNode(accessor);
}
public void VisitConstructorDeclaration(ConstructorDeclaration constructorDeclaration)
{
StartNode(constructorDeclaration);
WriteAttributes(constructorDeclaration.Attributes);
WriteModifiers(constructorDeclaration.ModifierTokens);
TypeDeclaration type = constructorDeclaration.Parent as TypeDeclaration;
StartNode(constructorDeclaration.NameToken);
WriteIdentifier(type != null ? type.Name : constructorDeclaration.Name);
EndNode(constructorDeclaration.NameToken);
Space(policy.SpaceBeforeConstructorDeclarationParentheses);
WriteCommaSeparatedListInParenthesis(constructorDeclaration.Parameters, policy.SpaceWithinMethodDeclarationParentheses);
if (!constructorDeclaration.Initializer.IsNull) {
Space();
constructorDeclaration.Initializer.AcceptVisitor(this);
}
WriteMethodBody(constructorDeclaration.Body);
EndNode(constructorDeclaration);
}
public void VisitConstructorInitializer(ConstructorInitializer constructorInitializer)
{
StartNode(constructorInitializer);
WriteToken(Roles.Colon);
Space();
if (constructorInitializer.ConstructorInitializerType == ConstructorInitializerType.This) {
WriteKeyword(ConstructorInitializer.ThisKeywordRole);
} else {
WriteKeyword(ConstructorInitializer.BaseKeywordRole);
}
Space(policy.SpaceBeforeMethodCallParentheses);
WriteCommaSeparatedListInParenthesis(constructorInitializer.Arguments, policy.SpaceWithinMethodCallParentheses);
EndNode(constructorInitializer);
}
public void VisitDestructorDeclaration(DestructorDeclaration destructorDeclaration)
{
StartNode(destructorDeclaration);
WriteAttributes(destructorDeclaration.Attributes);
WriteModifiers(destructorDeclaration.ModifierTokens);
WriteToken(DestructorDeclaration.TildeRole);
TypeDeclaration type = destructorDeclaration.Parent as TypeDeclaration;
StartNode(destructorDeclaration.NameToken);
WriteIdentifier(type != null ? type.Name : destructorDeclaration.Name);
EndNode(destructorDeclaration.NameToken);
Space(policy.SpaceBeforeConstructorDeclarationParentheses);
LPar();
RPar();
WriteMethodBody(destructorDeclaration.Body);
EndNode(destructorDeclaration);
}
public void VisitEnumMemberDeclaration(EnumMemberDeclaration enumMemberDeclaration)
{
StartNode(enumMemberDeclaration);
WriteAttributes(enumMemberDeclaration.Attributes);
WriteModifiers(enumMemberDeclaration.ModifierTokens);
enumMemberDeclaration.NameToken.AcceptVisitor(this);
if (!enumMemberDeclaration.Initializer.IsNull) {
Space(policy.SpaceAroundAssignment);
WriteToken(Roles.Assign);
Space(policy.SpaceAroundAssignment);
enumMemberDeclaration.Initializer.AcceptVisitor(this);
}
EndNode(enumMemberDeclaration);
}
public void VisitEventDeclaration(EventDeclaration eventDeclaration)
{
StartNode(eventDeclaration);
WriteAttributes(eventDeclaration.Attributes);
WriteModifiers(eventDeclaration.ModifierTokens);
WriteKeyword(EventDeclaration.EventKeywordRole);
eventDeclaration.ReturnType.AcceptVisitor(this);
Space();
WriteCommaSeparatedList(eventDeclaration.Variables);
Semicolon();
EndNode(eventDeclaration);
}
public void VisitCustomEventDeclaration(CustomEventDeclaration customEventDeclaration)
{
StartNode(customEventDeclaration);
WriteAttributes(customEventDeclaration.Attributes);
WriteModifiers(customEventDeclaration.ModifierTokens);
WriteKeyword(CustomEventDeclaration.EventKeywordRole);
customEventDeclaration.ReturnType.AcceptVisitor(this);
Space();
WritePrivateImplementationType(customEventDeclaration.PrivateImplementationType);
customEventDeclaration.NameToken.AcceptVisitor(this);
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);
}
}
CloseBrace(policy.EventBraceStyle);
NewLine();
EndNode(customEventDeclaration);
}
public void VisitFieldDeclaration(FieldDeclaration fieldDeclaration)
{
StartNode(fieldDeclaration);
WriteAttributes(fieldDeclaration.Attributes);
WriteModifiers(fieldDeclaration.ModifierTokens);
fieldDeclaration.ReturnType.AcceptVisitor(this);
Space();
WriteCommaSeparatedList(fieldDeclaration.Variables);
Semicolon();
EndNode(fieldDeclaration);
}
public void VisitFixedFieldDeclaration(FixedFieldDeclaration fixedFieldDeclaration)
{
StartNode(fixedFieldDeclaration);
WriteAttributes(fixedFieldDeclaration.Attributes);
WriteModifiers(fixedFieldDeclaration.ModifierTokens);
WriteKeyword(FixedFieldDeclaration.FixedKeywordRole);
Space();
fixedFieldDeclaration.ReturnType.AcceptVisitor(this);
Space();
WriteCommaSeparatedList(fixedFieldDeclaration.Variables);
Semicolon();
EndNode(fixedFieldDeclaration);
}
public void VisitFixedVariableInitializer(FixedVariableInitializer fixedVariableInitializer)
{
StartNode(fixedVariableInitializer);
fixedVariableInitializer.NameToken.AcceptVisitor(this);
if (!fixedVariableInitializer.CountExpression.IsNull) {
WriteToken(Roles.LBracket);
Space(policy.SpacesWithinBrackets);
fixedVariableInitializer.CountExpression.AcceptVisitor(this);
Space(policy.SpacesWithinBrackets);
WriteToken(Roles.RBracket);
}
EndNode(fixedVariableInitializer);
}
public void VisitIndexerDeclaration(IndexerDeclaration indexerDeclaration)
{
StartNode(indexerDeclaration);
WriteAttributes(indexerDeclaration.Attributes);
WriteModifiers(indexerDeclaration.ModifierTokens);
indexerDeclaration.ReturnType.AcceptVisitor(this);
Space();
WritePrivateImplementationType(indexerDeclaration.PrivateImplementationType);
WriteKeyword(IndexerDeclaration.ThisKeywordRole);
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);
}
}
CloseBrace(policy.PropertyBraceStyle);
NewLine();
EndNode(indexerDeclaration);
}
public void VisitMethodDeclaration(MethodDeclaration methodDeclaration)
{
StartNode(methodDeclaration);
WriteAttributes(methodDeclaration.Attributes);
WriteModifiers(methodDeclaration.ModifierTokens);
methodDeclaration.ReturnType.AcceptVisitor(this);
Space();
WritePrivateImplementationType(methodDeclaration.PrivateImplementationType);
methodDeclaration.NameToken.AcceptVisitor(this);
WriteTypeParameters(methodDeclaration.TypeParameters);
Space(policy.SpaceBeforeMethodDeclarationParentheses);
WriteCommaSeparatedListInParenthesis(methodDeclaration.Parameters, policy.SpaceWithinMethodDeclarationParentheses);
foreach (Constraint constraint in methodDeclaration.Constraints) {
constraint.AcceptVisitor(this);
}
WriteMethodBody(methodDeclaration.Body);
EndNode(methodDeclaration);
}
public void VisitOperatorDeclaration(OperatorDeclaration operatorDeclaration)
{
StartNode(operatorDeclaration);
WriteAttributes(operatorDeclaration.Attributes);
WriteModifiers(operatorDeclaration.ModifierTokens);
if (operatorDeclaration.OperatorType == OperatorType.Explicit) {
WriteKeyword(OperatorDeclaration.ExplicitRole);
} else if (operatorDeclaration.OperatorType == OperatorType.Implicit) {
WriteKeyword(OperatorDeclaration.ImplicitRole);
} else {
operatorDeclaration.ReturnType.AcceptVisitor(this);
}
WriteKeyword(OperatorDeclaration.OperatorKeywordRole);
Space();
if (operatorDeclaration.OperatorType == OperatorType.Explicit
|| operatorDeclaration.OperatorType == OperatorType.Implicit) {
operatorDeclaration.ReturnType.AcceptVisitor(this);
} else {
WriteToken(OperatorDeclaration.GetToken(operatorDeclaration.OperatorType), OperatorDeclaration.GetRole(operatorDeclaration.OperatorType));
}
Space(policy.SpaceBeforeMethodDeclarationParentheses);
WriteCommaSeparatedListInParenthesis(operatorDeclaration.Parameters, policy.SpaceWithinMethodDeclarationParentheses);
WriteMethodBody(operatorDeclaration.Body);
EndNode(operatorDeclaration);
}
public void VisitParameterDeclaration(ParameterDeclaration parameterDeclaration)
{
StartNode(parameterDeclaration);
WriteAttributes(parameterDeclaration.Attributes);
switch (parameterDeclaration.ParameterModifier) {
case ParameterModifier.Ref:
WriteKeyword(ParameterDeclaration.RefModifierRole);
break;
case ParameterModifier.Out:
WriteKeyword(ParameterDeclaration.OutModifierRole);
break;
case ParameterModifier.Params:
WriteKeyword(ParameterDeclaration.ParamsModifierRole);
break;
case ParameterModifier.This:
WriteKeyword(ParameterDeclaration.ThisModifierRole);
break;
}
parameterDeclaration.Type.AcceptVisitor(this);
if (!parameterDeclaration.Type.IsNull && !string.IsNullOrEmpty(parameterDeclaration.Name)) {
Space();
}
if (!string.IsNullOrEmpty(parameterDeclaration.Name)) {
parameterDeclaration.NameToken.AcceptVisitor(this);
}
if (!parameterDeclaration.DefaultExpression.IsNull) {
Space(policy.SpaceAroundAssignment);
WriteToken(Roles.Assign);
Space(policy.SpaceAroundAssignment);
parameterDeclaration.DefaultExpression.AcceptVisitor(this);
}
EndNode(parameterDeclaration);
}
public void VisitPropertyDeclaration(PropertyDeclaration propertyDeclaration)
{
StartNode(propertyDeclaration);
WriteAttributes(propertyDeclaration.Attributes);
WriteModifiers(propertyDeclaration.ModifierTokens);
propertyDeclaration.ReturnType.AcceptVisitor(this);
Space();
WritePrivateImplementationType(propertyDeclaration.PrivateImplementationType);
propertyDeclaration.NameToken.AcceptVisitor(this);
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);
}
}
CloseBrace(policy.PropertyBraceStyle);
NewLine();
EndNode(propertyDeclaration);
}
#endregion
#region Other nodes
public void VisitVariableInitializer(VariableInitializer variableInitializer)
{
StartNode(variableInitializer);
variableInitializer.NameToken.AcceptVisitor(this);
if (!variableInitializer.Initializer.IsNull) {
Space(policy.SpaceAroundAssignment);
WriteToken(Roles.Assign);
Space(policy.SpaceAroundAssignment);
variableInitializer.Initializer.AcceptVisitor(this);
}
EndNode(variableInitializer);
}
public void VisitSyntaxTree(SyntaxTree syntaxTree)
{
// don't do node tracking as we visit all children directly
foreach (AstNode node in syntaxTree.Children) {
node.AcceptVisitor(this);
}
}
public void VisitSimpleType(SimpleType simpleType)
{
StartNode(simpleType);
WriteIdentifier(simpleType.Identifier);
WriteTypeArguments(simpleType.TypeArguments);
EndNode(simpleType);
}
public void VisitMemberType(MemberType memberType)
{
StartNode(memberType);
memberType.Target.AcceptVisitor(this);
if (memberType.IsDoubleColon) {
WriteToken(Roles.DoubleColon);
} else {
WriteToken(Roles.Dot);
}
WriteIdentifier(memberType.MemberName);
WriteTypeArguments(memberType.TypeArguments);
EndNode(memberType);
}
public void VisitComposedType(ComposedType composedType)
{
StartNode(composedType);
composedType.BaseType.AcceptVisitor(this);
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);
}
EndNode(composedType);
}
public void VisitArraySpecifier(ArraySpecifier arraySpecifier)
{
StartNode(arraySpecifier);
WriteToken(Roles.LBracket);
foreach (var comma in arraySpecifier.GetChildrenByRole(Roles.Comma)) {
WriteSpecialsUpToNode(comma);
formatter.WriteToken(",");
lastWritten = LastWritten.Other;
}
WriteToken(Roles.RBracket);
EndNode(arraySpecifier);
}
public void VisitPrimitiveType(PrimitiveType primitiveType)
{
StartNode(primitiveType);
WriteKeyword(primitiveType.Keyword);
if (primitiveType.Keyword == "new") {
// new() constraint
LPar();
RPar();
}
EndNode(primitiveType);
}
public void VisitComment(Comment comment)
{
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;
}
public void VisitNewLine(NewLineNode newLineNode)
{
formatter.StartNode(newLineNode);
formatter.NewLine();
formatter.EndNode(newLineNode);
}
public void VisitWhitespace(WhitespaceNode whitespaceNode)
{
// unused
}
public void VisitText(TextNode textNode)
{
// unused
}
public void VisitPreProcessorDirective(PreProcessorDirective preProcessorDirective)
{
formatter.StartNode(preProcessorDirective);
formatter.WritePreProcessorDirective(preProcessorDirective.Type, preProcessorDirective.Argument);
formatter.EndNode(preProcessorDirective);
lastWritten = LastWritten.Whitespace;
}
public void VisitTypeParameterDeclaration(TypeParameterDeclaration typeParameterDeclaration)
{
StartNode(typeParameterDeclaration);
WriteAttributes(typeParameterDeclaration.Attributes);
switch (typeParameterDeclaration.Variance) {
case VarianceModifier.Invariant:
break;
case VarianceModifier.Covariant:
WriteKeyword(TypeParameterDeclaration.OutVarianceKeywordRole);
break;
case VarianceModifier.Contravariant:
WriteKeyword(TypeParameterDeclaration.InVarianceKeywordRole);
break;
default:
throw new NotSupportedException ("Invalid value for VarianceModifier");
}
typeParameterDeclaration.NameToken.AcceptVisitor(this);
EndNode(typeParameterDeclaration);
}
public void VisitConstraint(Constraint constraint)
{
StartNode(constraint);
Space();
WriteKeyword(Roles.WhereKeyword);
WriteIdentifier(constraint.TypeParameter.Identifier);
Space();
WriteToken(Roles.Colon);
Space();
WriteCommaSeparatedList(constraint.BaseTypes);
EndNode(constraint);
}
public void VisitCSharpTokenNode(CSharpTokenNode cSharpTokenNode)
{
CSharpModifierToken mod = cSharpTokenNode as CSharpModifierToken;
if (mod != null) {
StartNode(mod);
WriteKeyword(CSharpModifierToken.GetModifierName(mod.Modifier));
EndNode(mod);
} else {
throw new NotSupportedException ("Should never visit individual tokens");
}
}
public void VisitIdentifier(Identifier identifier)
{
StartNode(identifier);
WriteIdentifier(identifier.Name);
EndNode(identifier);
}
#endregion
#region Pattern Nodes
public void VisitPatternPlaceholder(AstNode placeholder, PatternMatching.Pattern pattern)
{
StartNode(placeholder);
VisitNodeInPattern(pattern);
EndNode(placeholder);
}
void VisitAnyNode(AnyNode anyNode)
{
if (!string.IsNullOrEmpty(anyNode.GroupName)) {
WriteIdentifier(anyNode.GroupName);
WriteToken(Roles.Colon);
}
}
void VisitBackreference(Backreference backreference)
{
WriteKeyword("backreference");
LPar();
WriteIdentifier(backreference.ReferencedGroupName);
RPar();
}
void VisitIdentifierExpressionBackreference(IdentifierExpressionBackreference identifierExpressionBackreference)
{
WriteKeyword("identifierBackreference");
LPar();
WriteIdentifier(identifierExpressionBackreference.ReferencedGroupName);
RPar();
}
void VisitChoice(Choice choice)
{
WriteKeyword("choice");
Space();
LPar();
NewLine();
formatter.Indent();
foreach (INode alternative in choice) {
VisitNodeInPattern(alternative);
if (alternative != choice.Last()) {
WriteToken(Roles.Comma);
}
NewLine();
}
formatter.Unindent();
RPar();
}
void VisitNamedNode(NamedNode namedNode)
{
if (!string.IsNullOrEmpty(namedNode.GroupName)) {
WriteIdentifier(namedNode.GroupName);
WriteToken(Roles.Colon);
}
VisitNodeInPattern(namedNode.ChildNode);
}
void VisitRepeat(Repeat repeat)
{
WriteKeyword("repeat");
LPar();
if (repeat.MinCount != 0 || repeat.MaxCount != int.MaxValue) {
WriteIdentifier(repeat.MinCount.ToString());
WriteToken(Roles.Comma);
WriteIdentifier(repeat.MaxCount.ToString());
WriteToken(Roles.Comma);
}
VisitNodeInPattern(repeat.ChildNode);
RPar();
}
void VisitOptionalNode(OptionalNode optionalNode)
{
WriteKeyword("optional");
LPar();
VisitNodeInPattern(optionalNode.ChildNode);
RPar();
}
void VisitNodeInPattern(INode childNode)
{
if (childNode is AstNode) {
((AstNode)childNode).AcceptVisitor(this);
} else if (childNode is IdentifierExpressionBackreference) {
VisitIdentifierExpressionBackreference((IdentifierExpressionBackreference)childNode);
} else if (childNode is Choice) {
VisitChoice((Choice)childNode);
} else if (childNode is AnyNode) {
VisitAnyNode((AnyNode)childNode);
} else if (childNode is Backreference) {
VisitBackreference((Backreference)childNode);
} else if (childNode is NamedNode) {
VisitNamedNode((NamedNode)childNode);
} else if (childNode is OptionalNode) {
VisitOptionalNode((OptionalNode)childNode);
} else if (childNode is Repeat) {
VisitRepeat((Repeat)childNode);
} else {
WritePrimitiveValue(childNode);
}
}
#endregion
#region Documentation Reference
public void VisitDocumentationReference(DocumentationReference documentationReference)
{
StartNode(documentationReference);
if (!documentationReference.DeclaringType.IsNull) {
documentationReference.DeclaringType.AcceptVisitor(this);
if (documentationReference.EntityType != EntityType.TypeDefinition) {
WriteToken(Roles.Dot);
}
}
switch (documentationReference.EntityType) {
case EntityType.TypeDefinition:
// we already printed the DeclaringType
break;
case EntityType.Indexer:
WriteKeyword(IndexerDeclaration.ThisKeywordRole);
break;
case EntityType.Operator:
var opType = documentationReference.OperatorType;
if (opType == OperatorType.Explicit) {
WriteKeyword(OperatorDeclaration.ExplicitRole);
} else if (opType == OperatorType.Implicit) {
WriteKeyword(OperatorDeclaration.ImplicitRole);
}
WriteKeyword(OperatorDeclaration.OperatorKeywordRole);
Space();
if (opType == OperatorType.Explicit || opType == OperatorType.Implicit) {
documentationReference.ConversionOperatorReturnType.AcceptVisitor(this);
} else {
WriteToken(OperatorDeclaration.GetToken(opType), OperatorDeclaration.GetRole(opType));
}
break;
default:
WriteIdentifier(documentationReference.MemberName);
break;
}
WriteTypeArguments(documentationReference.TypeArguments);
if (documentationReference.HasParameterList) {
Space(policy.SpaceBeforeMethodDeclarationParentheses);
if (documentationReference.EntityType == EntityType.Indexer) {
WriteCommaSeparatedListInBrackets(documentationReference.Parameters, policy.SpaceWithinMethodDeclarationParentheses);
} else {
WriteCommaSeparatedListInParenthesis(documentationReference.Parameters, policy.SpaceWithinMethodDeclarationParentheses);
}
}
EndNode(documentationReference);
}
#endregion
}
}