Click here to Skip to main content
15,885,309 members
Articles / Programming Languages / C#

CodeDom Assistant

Rate me:
Please Sign up or sign in to vote.
4.84/5 (26 votes)
21 Sep 20074 min read 137.6K   6.6K   82  
Generating CodeDom Code By Parsing C# or VB
// <file>
//     <copyright see="prj:///doc/copyright.txt"/>
//     <license see="prj:///doc/license.txt"/>
//     <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
//     <version>$Revision: 2522 $</version>
// </file>

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Text;

using ICSharpCode.NRefactory.Ast;
using ICSharpCode.NRefactory.Parser;
using ICSharpCode.NRefactory.Parser.CSharp;

namespace ICSharpCode.NRefactory.PrettyPrinter
{
	public sealed class CSharpOutputVisitor : IOutputAstVisitor
	{
		Errors                errors             = new Errors();
		CSharpOutputFormatter outputFormatter;
		PrettyPrintOptions    prettyPrintOptions = new PrettyPrintOptions();
		NodeTracker           nodeTracker;
		bool printFullSystemType;
		
		public string Text {
			get {
				return outputFormatter.Text;
			}
		}
		
		public Errors Errors {
			get {
				return errors;
			}
		}
		
		AbstractPrettyPrintOptions IOutputAstVisitor.Options {
			get { return prettyPrintOptions; }
		}
		
		public PrettyPrintOptions Options {
			get { return prettyPrintOptions; }
		}
		
		public IOutputFormatter OutputFormatter {
			get {
				return outputFormatter;
			}
		}
		
		public NodeTracker NodeTracker {
			get {
				return nodeTracker;
			}
		}
		
		public CSharpOutputVisitor()
		{
			outputFormatter = new CSharpOutputFormatter(prettyPrintOptions);
			nodeTracker     = new NodeTracker(this);
		}
		
		void Error(INode node, string message)
		{
			outputFormatter.PrintText(" // ERROR: " + message + Environment.NewLine);
			errors.Error(node.StartLocation.Y, node.StartLocation.X, message);
		}
		
		void NotSupported(INode node)
		{
			Error(node, "Not supported in C#: " + node.GetType().Name);
		}
		
		#region ICSharpCode.NRefactory.Parser.IASTVisitor interface implementation
		public object VisitCompilationUnit(CompilationUnit compilationUnit, object data)
		{
			nodeTracker.TrackedVisitChildren(compilationUnit, data);
			outputFormatter.EndFile();
			return null;
		}
		
		/// <summary>
		/// Converts type name to primitive type name. Returns null if typeString is not
		/// a primitive type.
		/// </summary>
		static string ConvertTypeString(string typeString)
		{
			string primitiveType;
			if (TypeReference.PrimitiveTypesCSharpReverse.TryGetValue(typeString, out primitiveType))
				return primitiveType;
			else
				return typeString;
		}
		
		void PrintTemplates(List<TemplateDefinition> templates)
		{
			if (templates.Count == 0) return;
			outputFormatter.PrintToken(Tokens.LessThan);
			for (int i = 0; i < templates.Count; i++) {
				if (i > 0) PrintFormattedComma();
				outputFormatter.PrintIdentifier(templates[i].Name);
			}
			outputFormatter.PrintToken(Tokens.GreaterThan);
		}
		
		public object VisitTypeReference(TypeReference typeReference, object data)
		{
			if (typeReference == TypeReference.ClassConstraint) {
				outputFormatter.PrintToken(Tokens.Class);
			} else if (typeReference == TypeReference.StructConstraint) {
				outputFormatter.PrintToken(Tokens.Struct);
			} else if (typeReference == TypeReference.NewConstraint) {
				outputFormatter.PrintToken(Tokens.New);
				outputFormatter.PrintToken(Tokens.OpenParenthesis);
				outputFormatter.PrintToken(Tokens.CloseParenthesis);
			} else {
				PrintTypeReferenceWithoutArray(typeReference);
				if (typeReference.IsArrayType) {
					PrintArrayRank(typeReference.RankSpecifier, 0);
				}
			}
			return null;
		}
		
		void PrintArrayRank(int[] rankSpecifier, int startRankIndex)
		{
			for (int i = startRankIndex; i < rankSpecifier.Length; ++i) {
				outputFormatter.PrintToken(Tokens.OpenSquareBracket);
				if (this.prettyPrintOptions.SpacesWithinBrackets) {
					outputFormatter.Space();
				}
				for (int j = 0; j < rankSpecifier[i]; ++j) {
					outputFormatter.PrintToken(Tokens.Comma);
				}
				if (this.prettyPrintOptions.SpacesWithinBrackets) {
					outputFormatter.Space();
				}
				outputFormatter.PrintToken(Tokens.CloseSquareBracket);
			}
		}
		
		void PrintTypeReferenceWithoutArray(TypeReference typeReference)
		{
			if (typeReference.IsGlobal) {
				outputFormatter.PrintText("global::");
			}
			if (typeReference.Type == null || typeReference.Type.Length == 0) {
				outputFormatter.PrintText("void");
			} else if (typeReference.SystemType == "System.Nullable" && typeReference.GenericTypes != null
			           && typeReference.GenericTypes.Count == 1 && !typeReference.IsGlobal)
			{
				nodeTracker.TrackedVisit(typeReference.GenericTypes[0], null);
				outputFormatter.PrintText("?");
			} else {
				if (typeReference.SystemType.Length > 0) {
					if (printFullSystemType || typeReference.IsGlobal) {
						outputFormatter.PrintIdentifier(typeReference.SystemType);
					} else {
						outputFormatter.PrintText(ConvertTypeString(typeReference.SystemType));
					}
				} else {
					outputFormatter.PrintText(typeReference.Type);
				}
				if (typeReference.GenericTypes != null && typeReference.GenericTypes.Count > 0) {
					outputFormatter.PrintToken(Tokens.LessThan);
					AppendCommaSeparatedList(typeReference.GenericTypes);
					outputFormatter.PrintToken(Tokens.GreaterThan);
				}
			}
			for (int i = 0; i < typeReference.PointerNestingLevel; ++i) {
				outputFormatter.PrintToken(Tokens.Times);
			}
		}
		
		public object VisitInnerClassTypeReference(InnerClassTypeReference innerClassTypeReference, object data)
		{
			nodeTracker.TrackedVisit(innerClassTypeReference.BaseType, data);
			outputFormatter.PrintToken(Tokens.Dot);
			return VisitTypeReference((TypeReference)innerClassTypeReference, data);
		}
		
		#region Global scope
		void VisitAttributes(ICollection attributes, object data)
		{
			if (attributes == null || attributes.Count <= 0) {
				return;
			}
			foreach (AttributeSection section in attributes) {
				nodeTracker.TrackedVisit(section, data);
			}
		}
		void PrintFormattedComma()
		{
			if (this.prettyPrintOptions.SpacesBeforeComma) {
				outputFormatter.Space();
			}
			outputFormatter.PrintToken(Tokens.Comma);
			if (this.prettyPrintOptions.SpacesAfterComma) {
				outputFormatter.Space();
			}
		}
		
		public object VisitAttributeSection(AttributeSection attributeSection, object data)
		{
			outputFormatter.Indent();
			outputFormatter.PrintToken(Tokens.OpenSquareBracket);
			if (this.prettyPrintOptions.SpacesWithinBrackets) {
				outputFormatter.Space();
			}
			if (!string.IsNullOrEmpty(attributeSection.AttributeTarget)) {
				outputFormatter.PrintText(attributeSection.AttributeTarget);
				outputFormatter.PrintToken(Tokens.Colon);
				outputFormatter.Space();
			}
			Debug.Assert(attributeSection.Attributes != null);
			for (int j = 0; j < attributeSection.Attributes.Count; ++j) {
				nodeTracker.TrackedVisit((INode)attributeSection.Attributes[j], data);
				if (j + 1 < attributeSection.Attributes.Count) {
					PrintFormattedComma();
				}
			}
			if (this.prettyPrintOptions.SpacesWithinBrackets) {
				outputFormatter.Space();
			}
			outputFormatter.PrintToken(Tokens.CloseSquareBracket);
			outputFormatter.NewLine();
			return null;
		}
		
		public object VisitAttribute(ICSharpCode.NRefactory.Ast.Attribute attribute, object data)
		{
			outputFormatter.PrintIdentifier(attribute.Name);
			outputFormatter.PrintToken(Tokens.OpenParenthesis);
			this.AppendCommaSeparatedList(attribute.PositionalArguments);
			
			if (attribute.NamedArguments != null && attribute.NamedArguments.Count > 0) {
				if (attribute.PositionalArguments.Count > 0) {
					PrintFormattedComma();
				}
				for (int i = 0; i < attribute.NamedArguments.Count; ++i) {
					nodeTracker.TrackedVisit((INode)attribute.NamedArguments[i], data);
					if (i + 1 < attribute.NamedArguments.Count) {
						PrintFormattedComma();
					}
				}
			}
			outputFormatter.PrintToken(Tokens.CloseParenthesis);
			return null;
		}
		
		public object VisitNamedArgumentExpression(NamedArgumentExpression namedArgumentExpression, object data)
		{
			outputFormatter.PrintIdentifier(namedArgumentExpression.Name);
			outputFormatter.Space();
			outputFormatter.PrintToken(Tokens.Assign);
			outputFormatter.Space();
			nodeTracker.TrackedVisit(namedArgumentExpression.Expression, data);
			return null;
		}
		
		public object VisitUsing(Using @using, object data)
		{
			outputFormatter.Indent();
			outputFormatter.PrintToken(Tokens.Using);
			outputFormatter.Space();
			
			outputFormatter.PrintIdentifier(@using.Name);
			
			if (@using.IsAlias) {
				outputFormatter.Space();
				outputFormatter.PrintToken(Tokens.Assign);
				outputFormatter.Space();
				printFullSystemType = true;
				nodeTracker.TrackedVisit(@using.Alias, data);
				printFullSystemType = false;
			}
			
			outputFormatter.PrintToken(Tokens.Semicolon);
			outputFormatter.NewLine();
			return null;
		}
		
		public object VisitUsingDeclaration(UsingDeclaration usingDeclaration, object data)
		{
			foreach (Using u in usingDeclaration.Usings) {
				nodeTracker.TrackedVisit(u, data);
			}
			return null;
		}
		
		public object VisitNamespaceDeclaration(NamespaceDeclaration namespaceDeclaration, object data)
		{
			outputFormatter.Indent();
			outputFormatter.PrintToken(Tokens.Namespace);
			outputFormatter.Space();
			outputFormatter.PrintIdentifier(namespaceDeclaration.Name);
			
			outputFormatter.BeginBrace(this.prettyPrintOptions.NamespaceBraceStyle);
			
			nodeTracker.TrackedVisitChildren(namespaceDeclaration, data);
			
			outputFormatter.EndBrace();
			
			return null;
		}
		
		
		void OutputEnumMembers(TypeDeclaration typeDeclaration, object data)
		{
			for (int i = 0; i < typeDeclaration.Children.Count; i++) {
				FieldDeclaration fieldDeclaration = (FieldDeclaration)typeDeclaration.Children[i];
				nodeTracker.BeginNode(fieldDeclaration);
				VariableDeclaration f = (VariableDeclaration)fieldDeclaration.Fields[0];
				VisitAttributes(fieldDeclaration.Attributes, data);
				outputFormatter.Indent();
				outputFormatter.PrintIdentifier(f.Name);
				if (f.Initializer != null && !f.Initializer.IsNull) {
					outputFormatter.Space();
					outputFormatter.PrintToken(Tokens.Assign);
					outputFormatter.Space();
					nodeTracker.TrackedVisit(f.Initializer, data);
				}
				if (i < typeDeclaration.Children.Count - 1) {
					outputFormatter.PrintToken(Tokens.Comma);
				}
				outputFormatter.NewLine();
				nodeTracker.EndNode(fieldDeclaration);
			}
		}
		
		TypeDeclaration currentType = null;
		
		public object VisitTypeDeclaration(TypeDeclaration typeDeclaration, object data)
		{
			VisitAttributes(typeDeclaration.Attributes, data);
			outputFormatter.Indent();
			OutputModifier(typeDeclaration.Modifier);
			switch (typeDeclaration.Type) {
				case ClassType.Enum:
					outputFormatter.PrintToken(Tokens.Enum);
					break;
				case ClassType.Interface:
					outputFormatter.PrintToken(Tokens.Interface);
					break;
				case ClassType.Struct:
					outputFormatter.PrintToken(Tokens.Struct);
					break;
				default:
					outputFormatter.PrintToken(Tokens.Class);
					break;
			}
			outputFormatter.Space();
			outputFormatter.PrintIdentifier(typeDeclaration.Name);
			
			PrintTemplates(typeDeclaration.Templates);
			
			if (typeDeclaration.BaseTypes != null && typeDeclaration.BaseTypes.Count > 0) {
				outputFormatter.Space();
				outputFormatter.PrintToken(Tokens.Colon);
				outputFormatter.Space();
				for (int i = 0; i < typeDeclaration.BaseTypes.Count; ++i) {
					if (i > 0) {
						PrintFormattedComma();
					}
					nodeTracker.TrackedVisit(typeDeclaration.BaseTypes[i], data);
				}
			}
			
			foreach (TemplateDefinition templateDefinition in typeDeclaration.Templates) {
				nodeTracker.TrackedVisit(templateDefinition, data);
			}
			
			switch (typeDeclaration.Type) {
				case ClassType.Enum:
					outputFormatter.BeginBrace(this.prettyPrintOptions.EnumBraceStyle);
					break;
				case ClassType.Interface:
					outputFormatter.BeginBrace(this.prettyPrintOptions.InterfaceBraceStyle);
					break;
				case ClassType.Struct:
					outputFormatter.BeginBrace(this.prettyPrintOptions.StructBraceStyle);
					break;
				default:
					outputFormatter.BeginBrace(this.prettyPrintOptions.ClassBraceStyle);
					break;
			}
			
			TypeDeclaration oldType = currentType;
			currentType = typeDeclaration;
			if (typeDeclaration.Type == ClassType.Enum) {
				OutputEnumMembers(typeDeclaration, data);
			} else {
				nodeTracker.TrackedVisitChildren(typeDeclaration, data);
			}
			currentType = oldType;
			outputFormatter.EndBrace();
			
			return null;
		}
		
		public object VisitTemplateDefinition(TemplateDefinition templateDefinition, object data)
		{
			if (templateDefinition.Bases.Count == 0)
				return null;
			
			outputFormatter.Space();
			outputFormatter.PrintText("where");
			outputFormatter.Space();
			outputFormatter.PrintIdentifier(templateDefinition.Name);
			outputFormatter.Space();
			outputFormatter.PrintToken(Tokens.Colon);
			outputFormatter.Space();
			
			for (int i = 0; i < templateDefinition.Bases.Count; ++i) {
				nodeTracker.TrackedVisit(templateDefinition.Bases[i], data);
				if (i + 1 < templateDefinition.Bases.Count) {
					PrintFormattedComma();
				}
			}
			return null;
		}
		
		public object VisitDelegateDeclaration(DelegateDeclaration delegateDeclaration, object data)
		{
			VisitAttributes(delegateDeclaration.Attributes, data);
			outputFormatter.Indent();
			OutputModifier(delegateDeclaration.Modifier);
			outputFormatter.PrintToken(Tokens.Delegate);
			outputFormatter.Space();
			nodeTracker.TrackedVisit(delegateDeclaration.ReturnType, data);
			outputFormatter.Space();
			outputFormatter.PrintIdentifier(delegateDeclaration.Name);
			PrintTemplates(delegateDeclaration.Templates);
			if (prettyPrintOptions.BeforeDelegateDeclarationParentheses) {
				outputFormatter.Space();
			}
			outputFormatter.PrintToken(Tokens.OpenParenthesis);
			AppendCommaSeparatedList(delegateDeclaration.Parameters);
			outputFormatter.PrintToken(Tokens.CloseParenthesis);
			foreach (TemplateDefinition templateDefinition in delegateDeclaration.Templates) {
				nodeTracker.TrackedVisit(templateDefinition, data);
			}
			outputFormatter.PrintToken(Tokens.Semicolon);
			outputFormatter.NewLine();
			return null;
		}
		
		public object VisitOptionDeclaration(OptionDeclaration optionDeclaration, object data)
		{
			NotSupported(optionDeclaration);
			return null;
		}
		#endregion
		
		#region Type level
		public object VisitFieldDeclaration(FieldDeclaration fieldDeclaration, object data)
		{
			if (!fieldDeclaration.TypeReference.IsNull) {
				VisitAttributes(fieldDeclaration.Attributes, data);
				outputFormatter.Indent();
				OutputModifier(fieldDeclaration.Modifier);
				nodeTracker.TrackedVisit(fieldDeclaration.TypeReference, data);
				outputFormatter.Space();
				AppendCommaSeparatedList(fieldDeclaration.Fields);
				outputFormatter.PrintToken(Tokens.Semicolon);
				outputFormatter.NewLine();
			} else {
				for (int i = 0; i < fieldDeclaration.Fields.Count; i++) {
					VisitAttributes(fieldDeclaration.Attributes, data);
					outputFormatter.Indent();
					OutputModifier(fieldDeclaration.Modifier);
					nodeTracker.TrackedVisit(fieldDeclaration.GetTypeForField(i), data);
					outputFormatter.Space();
					nodeTracker.TrackedVisit(fieldDeclaration.Fields[i], data);
					outputFormatter.PrintToken(Tokens.Semicolon);
					outputFormatter.NewLine();
				}
			}
			return null;
		}
		
		public object VisitVariableDeclaration(VariableDeclaration variableDeclaration, object data)
		{
			outputFormatter.PrintIdentifier(variableDeclaration.Name);
			if (!variableDeclaration.FixedArrayInitialization.IsNull) {
				outputFormatter.PrintToken(Tokens.OpenSquareBracket);
				nodeTracker.TrackedVisit(variableDeclaration.FixedArrayInitialization, data);
				outputFormatter.PrintToken(Tokens.CloseSquareBracket);
			}
			if (!variableDeclaration.Initializer.IsNull) {
				outputFormatter.Space();
				outputFormatter.PrintToken(Tokens.Assign);
				outputFormatter.Space();
				nodeTracker.TrackedVisit(variableDeclaration.Initializer, data);
			}
			return null;
		}
		
		public object VisitPropertyDeclaration(PropertyDeclaration propertyDeclaration, object data)
		{
			VisitAttributes(propertyDeclaration.Attributes, data);
			outputFormatter.Indent();
			propertyDeclaration.Modifier &= ~Modifiers.ReadOnly;
			OutputModifier(propertyDeclaration.Modifier);
			nodeTracker.TrackedVisit(propertyDeclaration.TypeReference, data);
			outputFormatter.Space();
			if (propertyDeclaration.InterfaceImplementations.Count > 0) {
				nodeTracker.TrackedVisit(propertyDeclaration.InterfaceImplementations[0].InterfaceType, data);
				outputFormatter.PrintToken(Tokens.Dot);
			}
			outputFormatter.PrintIdentifier(propertyDeclaration.Name);
			
			outputFormatter.BeginBrace(this.prettyPrintOptions.PropertyBraceStyle);
			
			nodeTracker.TrackedVisit(propertyDeclaration.GetRegion, data);
			nodeTracker.TrackedVisit(propertyDeclaration.SetRegion, data);
			
			outputFormatter.EndBrace();
			return null;
		}
		
		public object VisitPropertyGetRegion(PropertyGetRegion propertyGetRegion, object data)
		{
			this.VisitAttributes(propertyGetRegion.Attributes, data);
			outputFormatter.Indent();
			OutputModifier(propertyGetRegion.Modifier);
			outputFormatter.PrintText("get");
			OutputBlockAllowInline(propertyGetRegion.Block, prettyPrintOptions.PropertyGetBraceStyle);
			return null;
		}
		
		public object VisitPropertySetRegion(PropertySetRegion propertySetRegion, object data)
		{
			this.VisitAttributes(propertySetRegion.Attributes, data);
			outputFormatter.Indent();
			OutputModifier(propertySetRegion.Modifier);
			outputFormatter.PrintText("set");
			OutputBlockAllowInline(propertySetRegion.Block, prettyPrintOptions.PropertySetBraceStyle);
			return null;
		}
		
		public object VisitEventDeclaration(EventDeclaration eventDeclaration, object data)
		{
			VisitAttributes(eventDeclaration.Attributes, data);
			outputFormatter.Indent();
			OutputModifier(eventDeclaration.Modifier);
			outputFormatter.PrintToken(Tokens.Event);
			outputFormatter.Space();
			nodeTracker.TrackedVisit(eventDeclaration.TypeReference, data);
			outputFormatter.Space();
			
			if (eventDeclaration.InterfaceImplementations.Count > 0) {
				nodeTracker.TrackedVisit(eventDeclaration.InterfaceImplementations[0].InterfaceType, data);
				outputFormatter.PrintToken(Tokens.Dot);
			}
			
			outputFormatter.PrintIdentifier(eventDeclaration.Name);
			
			if (!eventDeclaration.Initializer.IsNull) {
				outputFormatter.Space();
				outputFormatter.PrintToken(Tokens.Assign);
				outputFormatter.Space();
				nodeTracker.TrackedVisit(eventDeclaration.Initializer, data);
			}
			
			if (eventDeclaration.AddRegion.IsNull && eventDeclaration.RemoveRegion.IsNull) {
				outputFormatter.PrintToken(Tokens.Semicolon);
				outputFormatter.NewLine();
			} else {
				outputFormatter.BeginBrace(this.prettyPrintOptions.PropertyBraceStyle);
				nodeTracker.TrackedVisit(eventDeclaration.AddRegion, data);
				nodeTracker.TrackedVisit(eventDeclaration.RemoveRegion, data);
				outputFormatter.EndBrace();
			}
			return null;
		}
		
		public object VisitEventAddRegion(EventAddRegion eventAddRegion, object data)
		{
			VisitAttributes(eventAddRegion.Attributes, data);
			outputFormatter.Indent();
			outputFormatter.PrintText("add");
			OutputBlockAllowInline(eventAddRegion.Block, prettyPrintOptions.EventAddBraceStyle);
			return null;
		}
		
		public object VisitEventRemoveRegion(EventRemoveRegion eventRemoveRegion, object data)
		{
			VisitAttributes(eventRemoveRegion.Attributes, data);
			outputFormatter.Indent();
			outputFormatter.PrintText("remove");
			OutputBlockAllowInline(eventRemoveRegion.Block, prettyPrintOptions.EventRemoveBraceStyle);
			return null;
		}
		
		public object VisitEventRaiseRegion(EventRaiseRegion eventRaiseRegion, object data)
		{
			// VB.NET only
			NotSupported(eventRaiseRegion);
			return null;
		}
		
		public object VisitParameterDeclarationExpression(ParameterDeclarationExpression parameterDeclarationExpression, object data)
		{
			VisitAttributes(parameterDeclarationExpression.Attributes, data);
			OutputModifier(parameterDeclarationExpression.ParamModifier, parameterDeclarationExpression);
			nodeTracker.TrackedVisit(parameterDeclarationExpression.TypeReference, data);
			outputFormatter.Space();
			outputFormatter.PrintIdentifier(parameterDeclarationExpression.ParameterName);
			return null;
		}
		
		public object VisitMethodDeclaration(MethodDeclaration methodDeclaration, object data)
		{
			VisitAttributes(methodDeclaration.Attributes, data);
			outputFormatter.Indent();
			OutputModifier(methodDeclaration.Modifier);
			nodeTracker.TrackedVisit(methodDeclaration.TypeReference, data);
			outputFormatter.Space();
			if (methodDeclaration.InterfaceImplementations.Count > 0) {
				nodeTracker.TrackedVisit(methodDeclaration.InterfaceImplementations[0].InterfaceType, data);
				outputFormatter.PrintToken(Tokens.Dot);
			}
			outputFormatter.PrintIdentifier(methodDeclaration.Name);
			
			PrintMethodDeclaration(methodDeclaration);
			return null;
		}
		
		void PrintMethodDeclaration(MethodDeclaration methodDeclaration)
		{
			PrintTemplates(methodDeclaration.Templates);
			if (prettyPrintOptions.BeforeMethodDeclarationParentheses) {
				outputFormatter.Space();
			}
			outputFormatter.PrintToken(Tokens.OpenParenthesis);
			AppendCommaSeparatedList(methodDeclaration.Parameters);
			outputFormatter.PrintToken(Tokens.CloseParenthesis);
			foreach (TemplateDefinition templateDefinition in methodDeclaration.Templates) {
				nodeTracker.TrackedVisit(templateDefinition, null);
			}
			OutputBlock(methodDeclaration.Body, this.prettyPrintOptions.MethodBraceStyle);
		}
		
		public object VisitOperatorDeclaration(OperatorDeclaration operatorDeclaration, object data)
		{
			VisitAttributes(operatorDeclaration.Attributes, data);
			outputFormatter.Indent();
			OutputModifier(operatorDeclaration.Modifier);
			
			if (operatorDeclaration.IsConversionOperator) {
				if (operatorDeclaration.ConversionType == ConversionType.Implicit) {
					outputFormatter.PrintToken(Tokens.Implicit);
				} else {
					outputFormatter.PrintToken(Tokens.Explicit);
				}
			} else {
				nodeTracker.TrackedVisit(operatorDeclaration.TypeReference, data);
			}
			outputFormatter.Space();
			outputFormatter.PrintToken(Tokens.Operator);
			outputFormatter.Space();
			
			if (operatorDeclaration.IsConversionOperator) {
				nodeTracker.TrackedVisit(operatorDeclaration.TypeReference, data);
			} else {
				switch (operatorDeclaration.OverloadableOperator) {
					case OverloadableOperatorType.Add:
						outputFormatter.PrintToken(Tokens.Plus);
						break;
					case OverloadableOperatorType.BitNot:
						outputFormatter.PrintToken(Tokens.BitwiseComplement);
						break;
					case OverloadableOperatorType.BitwiseAnd:
						outputFormatter.PrintToken(Tokens.BitwiseAnd);
						break;
					case OverloadableOperatorType.BitwiseOr:
						outputFormatter.PrintToken(Tokens.BitwiseOr);
						break;
					case OverloadableOperatorType.Concat:
						outputFormatter.PrintToken(Tokens.Plus);
						break;
					case OverloadableOperatorType.Decrement:
						outputFormatter.PrintToken(Tokens.Decrement);
						break;
					case OverloadableOperatorType.Divide:
					case OverloadableOperatorType.DivideInteger:
						outputFormatter.PrintToken(Tokens.Div);
						break;
					case OverloadableOperatorType.Equality:
						outputFormatter.PrintToken(Tokens.Equal);
						break;
					case OverloadableOperatorType.ExclusiveOr:
						outputFormatter.PrintToken(Tokens.Xor);
						break;
					case OverloadableOperatorType.GreaterThan:
						outputFormatter.PrintToken(Tokens.GreaterThan);
						break;
					case OverloadableOperatorType.GreaterThanOrEqual:
						outputFormatter.PrintToken(Tokens.GreaterEqual);
						break;
					case OverloadableOperatorType.Increment:
						outputFormatter.PrintToken(Tokens.Increment);
						break;
					case OverloadableOperatorType.InEquality:
						outputFormatter.PrintToken(Tokens.NotEqual);
						break;
					case OverloadableOperatorType.IsTrue:
						outputFormatter.PrintToken(Tokens.True);
						break;
					case OverloadableOperatorType.IsFalse:
						outputFormatter.PrintToken(Tokens.False);
						break;
					case OverloadableOperatorType.LessThan:
						outputFormatter.PrintToken(Tokens.LessThan);
						break;
					case OverloadableOperatorType.LessThanOrEqual:
						outputFormatter.PrintToken(Tokens.LessEqual);
						break;
					case OverloadableOperatorType.Like:
						outputFormatter.PrintText("Like");
						break;
					case OverloadableOperatorType.Modulus:
						outputFormatter.PrintToken(Tokens.Mod);
						break;
					case OverloadableOperatorType.Multiply:
						outputFormatter.PrintToken(Tokens.Times);
						break;
					case OverloadableOperatorType.Not:
						outputFormatter.PrintToken(Tokens.Not);
						break;
					case OverloadableOperatorType.Power:
						outputFormatter.PrintText("Power");
						break;
					case OverloadableOperatorType.ShiftLeft:
						outputFormatter.PrintToken(Tokens.ShiftLeft);
						break;
					case OverloadableOperatorType.ShiftRight:
						outputFormatter.PrintToken(Tokens.GreaterThan);
						outputFormatter.PrintToken(Tokens.GreaterThan);
						break;
					case OverloadableOperatorType.Subtract:
						outputFormatter.PrintToken(Tokens.Minus);
						break;
					default:
						Error(operatorDeclaration, operatorDeclaration.OverloadableOperator.ToString() + " is not supported as overloadable operator");
						break;
				}
			}
			
			PrintMethodDeclaration(operatorDeclaration);
			return null;
		}
		
		public object VisitInterfaceImplementation(InterfaceImplementation interfaceImplementation, object data)
		{
			throw new InvalidOperationException();
		}
		
		public object VisitConstructorDeclaration(ConstructorDeclaration constructorDeclaration, object data)
		{
			VisitAttributes(constructorDeclaration.Attributes, data);
			outputFormatter.Indent();
			OutputModifier(constructorDeclaration.Modifier);
			if (currentType != null) {
				outputFormatter.PrintIdentifier(currentType.Name);
			} else {
				outputFormatter.PrintIdentifier(constructorDeclaration.Name);
			}
			if (prettyPrintOptions.BeforeConstructorDeclarationParentheses) {
				outputFormatter.Space();
			}
			outputFormatter.PrintToken(Tokens.OpenParenthesis);
			AppendCommaSeparatedList(constructorDeclaration.Parameters);
			outputFormatter.PrintToken(Tokens.CloseParenthesis);
			nodeTracker.TrackedVisit(constructorDeclaration.ConstructorInitializer, data);
			OutputBlock(constructorDeclaration.Body, this.prettyPrintOptions.ConstructorBraceStyle);
			return null;
		}
		
		public object VisitConstructorInitializer(ConstructorInitializer constructorInitializer, object data)
		{
			if (constructorInitializer.IsNull) {
				return null;
			}
			outputFormatter.Space();
			outputFormatter.PrintToken(Tokens.Colon);
			outputFormatter.Space();
			if (constructorInitializer.ConstructorInitializerType == ConstructorInitializerType.Base) {
				outputFormatter.PrintToken(Tokens.Base);
			} else {
				outputFormatter.PrintToken(Tokens.This);
			}
			outputFormatter.PrintToken(Tokens.OpenParenthesis);
			AppendCommaSeparatedList(constructorInitializer.Arguments);
			outputFormatter.PrintToken(Tokens.CloseParenthesis);
			return null;
		}
		
		public object VisitIndexerDeclaration(IndexerDeclaration indexerDeclaration, object data)
		{
			VisitAttributes(indexerDeclaration.Attributes, data);
			outputFormatter.Indent();
			OutputModifier(indexerDeclaration.Modifier);
			nodeTracker.TrackedVisit(indexerDeclaration.TypeReference, data);
			outputFormatter.Space();
			if (indexerDeclaration.InterfaceImplementations.Count > 0) {
				nodeTracker.TrackedVisit(indexerDeclaration.InterfaceImplementations[0].InterfaceType, data);
				outputFormatter.PrintToken(Tokens.Dot);
			}
			outputFormatter.PrintToken(Tokens.This);
			outputFormatter.PrintToken(Tokens.OpenSquareBracket);
			if (this.prettyPrintOptions.SpacesWithinBrackets) {
				outputFormatter.Space();
			}
			AppendCommaSeparatedList(indexerDeclaration.Parameters);
			if (this.prettyPrintOptions.SpacesWithinBrackets) {
				outputFormatter.Space();
			}
			outputFormatter.PrintToken(Tokens.CloseSquareBracket);
			outputFormatter.NewLine();
			outputFormatter.Indent();
			outputFormatter.PrintToken(Tokens.OpenCurlyBrace);
			outputFormatter.NewLine();
			++outputFormatter.IndentationLevel;
			nodeTracker.TrackedVisit(indexerDeclaration.GetRegion, data);
			nodeTracker.TrackedVisit(indexerDeclaration.SetRegion, data);
			--outputFormatter.IndentationLevel;
			outputFormatter.Indent();
			outputFormatter.PrintToken(Tokens.CloseCurlyBrace);
			outputFormatter.NewLine();
			return null;
		}
		
		public object VisitDestructorDeclaration(DestructorDeclaration destructorDeclaration, object data)
		{
			VisitAttributes(destructorDeclaration.Attributes, data);
			outputFormatter.Indent();
			OutputModifier(destructorDeclaration.Modifier);
			outputFormatter.PrintToken(Tokens.BitwiseComplement);
			if (currentType != null)
				outputFormatter.PrintIdentifier(currentType.Name);
			else
				outputFormatter.PrintIdentifier(destructorDeclaration.Name);
			if (prettyPrintOptions.BeforeConstructorDeclarationParentheses) {
				outputFormatter.Space();
			}
			outputFormatter.PrintToken(Tokens.OpenParenthesis);
			outputFormatter.PrintToken(Tokens.CloseParenthesis);
			
			OutputBlock(destructorDeclaration.Body, this.prettyPrintOptions.DestructorBraceStyle);
			return null;
		}
		
		public object VisitDeclareDeclaration(DeclareDeclaration declareDeclaration, object data)
		{
			NotSupported(declareDeclaration);
			return null;
		}
		#endregion
		
		#region Statements
		
		void OutputBlock(BlockStatement blockStatement, BraceStyle braceStyle)
		{
			nodeTracker.BeginNode(blockStatement);
			if (blockStatement.IsNull) {
				outputFormatter.PrintToken(Tokens.Semicolon);
				outputFormatter.NewLine();
			} else {
				outputFormatter.BeginBrace(braceStyle);
				foreach (Statement stmt in blockStatement.Children) {
					outputFormatter.Indent();
					if (stmt is BlockStatement) {
						nodeTracker.TrackedVisit(stmt, BraceStyle.EndOfLine);
					} else {
						nodeTracker.TrackedVisit(stmt, null);
					}
					if (!outputFormatter.LastCharacterIsNewLine)
						outputFormatter.NewLine();
				}
				outputFormatter.EndBrace();
			}
			nodeTracker.EndNode(blockStatement);
		}
		
		void OutputBlockAllowInline(BlockStatement blockStatement, BraceStyle braceStyle)
		{
			OutputBlockAllowInline(blockStatement, braceStyle, true);
		}
		
		void OutputBlockAllowInline(BlockStatement blockStatement, BraceStyle braceStyle, bool useNewLine)
		{
			if (!blockStatement.IsNull
			    && (
			    	blockStatement.Children.Count == 0
			    	|| blockStatement.Children.Count == 1
			    	&& (blockStatement.Children[0] is ExpressionStatement
			    	    || blockStatement.Children[0] is ReturnStatement
			    	   )))
			{
				outputFormatter.Space();
				outputFormatter.PrintToken(Tokens.OpenCurlyBrace);
				outputFormatter.Space();
				if (blockStatement.Children.Count != 0) {
					bool doIndent  = outputFormatter.DoIndent;
					bool doNewLine = outputFormatter.DoNewLine;
					outputFormatter.DoIndent  = false;
					outputFormatter.DoNewLine = false;
					
					nodeTracker.TrackedVisit(blockStatement.Children[0], null);
					
					outputFormatter.DoIndent  = doIndent;
					outputFormatter.DoNewLine = doNewLine;
					
					outputFormatter.Space();
				}
				outputFormatter.PrintToken(Tokens.CloseCurlyBrace);
				if (useNewLine) {
					outputFormatter.NewLine();
				}
			} else {
				OutputBlock(blockStatement, braceStyle);
			}
		}
		
		public object VisitBlockStatement(BlockStatement blockStatement, object data)
		{
			if (outputFormatter.TextLength == 0) {
				// we are outputting only a code block:
				// do not output braces, just the block's contents
				foreach (Statement stmt in blockStatement.Children) {
					outputFormatter.Indent();
					nodeTracker.TrackedVisit(stmt, null);
					if (!outputFormatter.LastCharacterIsNewLine)
						outputFormatter.NewLine();
				}
				return null;
			}
			
			if (data is BraceStyle)
				OutputBlock(blockStatement, (BraceStyle)data);
			else
				OutputBlock(blockStatement, BraceStyle.NextLine);
			return null;
		}
		
		public object VisitAddHandlerStatement(AddHandlerStatement addHandlerStatement, object data)
		{
			nodeTracker.TrackedVisit(addHandlerStatement.EventExpression, data);
			outputFormatter.Space();
			outputFormatter.PrintToken(Tokens.PlusAssign);
			outputFormatter.Space();
			nodeTracker.TrackedVisit(addHandlerStatement.HandlerExpression, data);
			outputFormatter.PrintToken(Tokens.Semicolon);
			return null;
		}
		
		public object VisitRemoveHandlerStatement(RemoveHandlerStatement removeHandlerStatement, object data)
		{
			nodeTracker.TrackedVisit(removeHandlerStatement.EventExpression, data);
			outputFormatter.Space();
			outputFormatter.PrintToken(Tokens.MinusAssign);
			outputFormatter.Space();
			nodeTracker.TrackedVisit(removeHandlerStatement.HandlerExpression, data);
			outputFormatter.PrintToken(Tokens.Semicolon);
			return null;
		}
		
		public object VisitRaiseEventStatement(RaiseEventStatement raiseEventStatement, object data)
		{
			outputFormatter.PrintToken(Tokens.If);
			outputFormatter.Space();
			outputFormatter.PrintToken(Tokens.OpenParenthesis);
			outputFormatter.PrintIdentifier(raiseEventStatement.EventName);
			outputFormatter.Space();
			outputFormatter.PrintToken(Tokens.NotEqual);
			outputFormatter.Space();
			outputFormatter.PrintToken(Tokens.Null);
			outputFormatter.PrintToken(Tokens.CloseParenthesis);
			
			outputFormatter.BeginBrace(BraceStyle.EndOfLine);
			
			outputFormatter.Indent();
			outputFormatter.PrintIdentifier(raiseEventStatement.EventName);
			outputFormatter.PrintToken(Tokens.OpenParenthesis);
			this.AppendCommaSeparatedList(raiseEventStatement.Arguments);
			outputFormatter.PrintToken(Tokens.CloseParenthesis);
			outputFormatter.PrintToken(Tokens.Semicolon);
			
			outputFormatter.NewLine();
			outputFormatter.EndBrace();
			
			return null;
		}
		
		public object VisitEraseStatement(EraseStatement eraseStatement, object data)
		{
			for (int i = 0; i < eraseStatement.Expressions.Count; i++) {
				if (i > 0) {
					outputFormatter.NewLine();
					outputFormatter.Indent();
				}
				nodeTracker.TrackedVisit(eraseStatement.Expressions[i], data);
				outputFormatter.Space();
				outputFormatter.PrintToken(Tokens.Assign);
				outputFormatter.Space();
				outputFormatter.PrintToken(Tokens.Null);
				outputFormatter.PrintToken(Tokens.Semicolon);
			}
			return null;
		}
		
		public object VisitErrorStatement(ErrorStatement errorStatement, object data)
		{
			NotSupported(errorStatement);
			return null;
		}
		
		public object VisitOnErrorStatement(OnErrorStatement onErrorStatement, object data)
		{
			NotSupported(onErrorStatement);
			return null;
		}
		
		public object VisitReDimStatement(ReDimStatement reDimStatement, object data)
		{
			NotSupported(reDimStatement);
			return null;
		}
		
		public object VisitExpressionStatement(ExpressionStatement expressionStatement, object data)
		{
			nodeTracker.TrackedVisit(expressionStatement.Expression, data);
			outputFormatter.PrintToken(Tokens.Semicolon);
			return null;
		}
		
		public object VisitLocalVariableDeclaration(LocalVariableDeclaration localVariableDeclaration, object data)
		{
			for (int i = 0; i < localVariableDeclaration.Variables.Count; ++i) {
				VariableDeclaration v = (VariableDeclaration)localVariableDeclaration.Variables[i];
				if (i > 0) {
					outputFormatter.NewLine();
					outputFormatter.Indent();
				}
				OutputModifier(localVariableDeclaration.Modifier);
				nodeTracker.TrackedVisit(localVariableDeclaration.GetTypeForVariable(i) ?? new TypeReference("object"), data);
				outputFormatter.Space();
				nodeTracker.TrackedVisit(v, data);
				outputFormatter.PrintToken(Tokens.Semicolon);
			}
			return null;
		}
		
		public object VisitEmptyStatement(EmptyStatement emptyStatement, object data)
		{
			outputFormatter.PrintToken(Tokens.Semicolon);
			return null;
		}
		
		public object VisitYieldStatement(YieldStatement yieldStatement, object data)
		{
			Debug.Assert(yieldStatement != null);
			Debug.Assert(yieldStatement.Statement != null);
			outputFormatter.PrintText("yield");
			outputFormatter.Space();
			nodeTracker.TrackedVisit(yieldStatement.Statement, data);
			return null;
		}
		
		public object VisitReturnStatement(ReturnStatement returnStatement, object data)
		{
			outputFormatter.PrintToken(Tokens.Return);
			if (!returnStatement.Expression.IsNull) {
				outputFormatter.Space();
				nodeTracker.TrackedVisit(returnStatement.Expression, data);
			}
			outputFormatter.PrintToken(Tokens.Semicolon);
			return null;
		}
		
		public object VisitIfElseStatement(IfElseStatement ifElseStatement, object data)
		{
			outputFormatter.PrintToken(Tokens.If);
			if (this.prettyPrintOptions.IfParentheses) {
				outputFormatter.Space();
			}
			outputFormatter.PrintToken(Tokens.OpenParenthesis);
			nodeTracker.TrackedVisit(ifElseStatement.Condition, data);
			outputFormatter.PrintToken(Tokens.CloseParenthesis);
			
			PrintIfSection(ifElseStatement.TrueStatement);
			
			foreach (ElseIfSection elseIfSection in ifElseStatement.ElseIfSections) {
				nodeTracker.TrackedVisit(elseIfSection, data);
			}
			
			if (ifElseStatement.HasElseStatements) {
				outputFormatter.Indent();
				outputFormatter.PrintToken(Tokens.Else);
				PrintIfSection(ifElseStatement.FalseStatement);
			}
			
			return null;
		}
		
		void PrintIfSection(List<Statement> statements)
		{
			if (statements.Count != 1 || !(statements[0] is BlockStatement)) {
				outputFormatter.Space();
			}
			if (statements.Count != 1) {
				outputFormatter.PrintToken(Tokens.OpenCurlyBrace);
			}
			foreach (Statement stmt in statements) {
				nodeTracker.TrackedVisit(stmt, null);
			}
			if (statements.Count != 1) {
				outputFormatter.PrintToken(Tokens.CloseCurlyBrace);
			}
			if (statements.Count != 1 || !(statements[0] is BlockStatement)) {
				outputFormatter.Space();
			}
		}
		
		public object VisitElseIfSection(ElseIfSection elseIfSection, object data)
		{
			outputFormatter.PrintToken(Tokens.Else);
			outputFormatter.Space();
			outputFormatter.PrintToken(Tokens.If);
			if (prettyPrintOptions.IfParentheses) {
				outputFormatter.Space();
			}
			outputFormatter.PrintToken(Tokens.OpenParenthesis);
			nodeTracker.TrackedVisit(elseIfSection.Condition, data);
			outputFormatter.PrintToken(Tokens.CloseParenthesis);
			
			WriteEmbeddedStatement(elseIfSection.EmbeddedStatement);
			
			return null;
		}
		
		public object VisitForStatement(ForStatement forStatement, object data)
		{
			outputFormatter.PrintToken(Tokens.For);
			if (this.prettyPrintOptions.ForParentheses) {
				outputFormatter.Space();
			}
			outputFormatter.PrintToken(Tokens.OpenParenthesis);
			outputFormatter.DoIndent = false;
			outputFormatter.DoNewLine = false;
			outputFormatter.EmitSemicolon = false;
			for (int i = 0; i < forStatement.Initializers.Count; ++i) {
				INode node = (INode)forStatement.Initializers[i];
				nodeTracker.TrackedVisit(node, data);
				if (i + 1 < forStatement.Initializers.Count) {
					outputFormatter.PrintToken(Tokens.Comma);
				}
			}
			outputFormatter.EmitSemicolon = true;
			outputFormatter.PrintToken(Tokens.Semicolon);
			outputFormatter.EmitSemicolon = false;
			if (!forStatement.Condition.IsNull) {
				if (this.prettyPrintOptions.SpacesAfterSemicolon) {
					outputFormatter.Space();
				}
				nodeTracker.TrackedVisit(forStatement.Condition, data);
			}
			outputFormatter.EmitSemicolon = true;
			outputFormatter.PrintToken(Tokens.Semicolon);
			outputFormatter.EmitSemicolon = false;
			if (forStatement.Iterator != null && forStatement.Iterator.Count > 0) {
				if (this.prettyPrintOptions.SpacesAfterSemicolon) {
					outputFormatter.Space();
				}
				
				for (int i = 0; i < forStatement.Iterator.Count; ++i) {
					INode node = (INode)forStatement.Iterator[i];
					nodeTracker.TrackedVisit(node, data);
					if (i + 1 < forStatement.Iterator.Count) {
						outputFormatter.PrintToken(Tokens.Comma);
					}
				}
			}
			outputFormatter.PrintToken(Tokens.CloseParenthesis);
			outputFormatter.EmitSemicolon = true;
			outputFormatter.DoNewLine     = true;
			outputFormatter.DoIndent      = true;
			
			WriteEmbeddedStatement(forStatement.EmbeddedStatement);
			
			return null;
		}
		
		void WriteEmbeddedStatement(Statement statement)
		{
			if (statement is BlockStatement) {
				nodeTracker.TrackedVisit(statement, prettyPrintOptions.StatementBraceStyle);
			} else {
				++outputFormatter.IndentationLevel;
				outputFormatter.NewLine();
				nodeTracker.TrackedVisit(statement, null);
				outputFormatter.NewLine();
				--outputFormatter.IndentationLevel;
			}
		}
		
		public object VisitLabelStatement(LabelStatement labelStatement, object data)
		{
			outputFormatter.PrintIdentifier(labelStatement.Label);
			outputFormatter.PrintToken(Tokens.Colon);
			return null;
		}
		
		public object VisitGotoStatement(GotoStatement gotoStatement, object data)
		{
			outputFormatter.PrintToken(Tokens.Goto);
			outputFormatter.Space();
			outputFormatter.PrintIdentifier(gotoStatement.Label);
			outputFormatter.PrintToken(Tokens.Semicolon);
			return null;
		}
		
		public object VisitSwitchStatement(SwitchStatement switchStatement, object data)
		{
			outputFormatter.PrintToken(Tokens.Switch);
			if (this.prettyPrintOptions.SwitchParentheses) {
				outputFormatter.Space();
			}
			outputFormatter.PrintToken(Tokens.OpenParenthesis);
			nodeTracker.TrackedVisit(switchStatement.SwitchExpression, data);
			outputFormatter.PrintToken(Tokens.CloseParenthesis);
			outputFormatter.Space();
			outputFormatter.PrintToken(Tokens.OpenCurlyBrace);
			outputFormatter.NewLine();
			++outputFormatter.IndentationLevel;
			foreach (SwitchSection section in switchStatement.SwitchSections) {
				nodeTracker.TrackedVisit(section, data);
			}
			--outputFormatter.IndentationLevel;
			outputFormatter.Indent();
			outputFormatter.PrintToken(Tokens.CloseCurlyBrace);
			return null;
		}
		
		public object VisitSwitchSection(SwitchSection switchSection, object data)
		{
			foreach (CaseLabel label in switchSection.SwitchLabels) {
				nodeTracker.TrackedVisit(label, data);
			}
			
			++outputFormatter.IndentationLevel;
			foreach (Statement stmt in switchSection.Children) {
				outputFormatter.Indent();
				nodeTracker.TrackedVisit(stmt, data);
				outputFormatter.NewLine();
			}
			
			// Check if a 'break' should be auto inserted.
			if (switchSection.Children.Count == 0 ||
			    !(switchSection.Children[switchSection.Children.Count - 1] is BreakStatement ||
			      switchSection.Children[switchSection.Children.Count - 1] is ContinueStatement ||
			      switchSection.Children[switchSection.Children.Count - 1] is ReturnStatement)) {
				outputFormatter.Indent();
				outputFormatter.PrintToken(Tokens.Break);
				outputFormatter.PrintToken(Tokens.Semicolon);
				outputFormatter.NewLine();
			}
			
			--outputFormatter.IndentationLevel;
			return null;
		}
		
		public object VisitCaseLabel(CaseLabel caseLabel, object data)
		{
			outputFormatter.Indent();
			if (caseLabel.IsDefault) {
				outputFormatter.PrintToken(Tokens.Default);
			} else {
				outputFormatter.PrintToken(Tokens.Case);
				outputFormatter.Space();
				if (caseLabel.BinaryOperatorType != BinaryOperatorType.None) {
					Error(caseLabel, String.Format("Case labels with binary operators are unsupported : {0}", caseLabel.BinaryOperatorType));
				}
				nodeTracker.TrackedVisit(caseLabel.Label, data);
			}
			outputFormatter.PrintToken(Tokens.Colon);
			if (!caseLabel.ToExpression.IsNull) {
				PrimitiveExpression pl = caseLabel.Label as PrimitiveExpression;
				PrimitiveExpression pt = caseLabel.ToExpression as PrimitiveExpression;
				if (pl != null && pt != null && pl.Value is int && pt.Value is int) {
					int plv = (int)pl.Value;
					int prv = (int)pt.Value;
					if (plv < prv && plv + 12 > prv) {
						for (int i = plv + 1; i <= prv; i++) {
							outputFormatter.NewLine();
							outputFormatter.Indent();
							outputFormatter.PrintToken(Tokens.Case);
							outputFormatter.Space();
							outputFormatter.PrintText(i.ToString(NumberFormatInfo.InvariantInfo));
							outputFormatter.PrintToken(Tokens.Colon);
						}
					} else {
						outputFormatter.PrintText(" // TODO: to ");
						nodeTracker.TrackedVisit(caseLabel.ToExpression, data);
					}
				} else {
					outputFormatter.PrintText(" // TODO: to ");
					nodeTracker.TrackedVisit(caseLabel.ToExpression, data);
				}
			}
			outputFormatter.NewLine();
			return null;
		}
		
		public object VisitBreakStatement(BreakStatement breakStatement, object data)
		{
			outputFormatter.PrintToken(Tokens.Break);
			outputFormatter.PrintToken(Tokens.Semicolon);
			return null;
		}
		
		public object VisitStopStatement(StopStatement stopStatement, object data)
		{
			outputFormatter.PrintText("System.Diagnostics.Debugger.Break()");
			outputFormatter.PrintToken(Tokens.Semicolon);
			return null;
		}
		
		public object VisitResumeStatement(ResumeStatement resumeStatement, object data)
		{
			NotSupported(resumeStatement);
			return null;
		}
		
		public object VisitEndStatement(EndStatement endStatement, object data)
		{
			outputFormatter.PrintText("System.Environment.Exit(0)");
			outputFormatter.PrintToken(Tokens.Semicolon);
			return null;
		}
		
		public object VisitContinueStatement(ContinueStatement continueStatement, object data)
		{
			outputFormatter.PrintToken(Tokens.Continue);
			outputFormatter.PrintToken(Tokens.Semicolon);
			return null;
		}
		
		public object VisitGotoCaseStatement(GotoCaseStatement gotoCaseStatement, object data)
		{
			outputFormatter.PrintToken(Tokens.Goto);
			outputFormatter.Space();
			if (gotoCaseStatement.IsDefaultCase) {
				outputFormatter.PrintToken(Tokens.Default);
			} else {
				outputFormatter.PrintToken(Tokens.Case);
				outputFormatter.Space();
				nodeTracker.TrackedVisit(gotoCaseStatement.Expression, data);
			}
			outputFormatter.PrintToken(Tokens.Semicolon);
			return null;
		}
		
		void PrintLoopCheck(DoLoopStatement doLoopStatement)
		{
			outputFormatter.PrintToken(Tokens.While);
			if (this.prettyPrintOptions.WhileParentheses) {
				outputFormatter.Space();
			}
			outputFormatter.PrintToken(Tokens.OpenParenthesis);
			
			if (doLoopStatement.ConditionType == ConditionType.Until) {
				outputFormatter.PrintToken(Tokens.Not);
				outputFormatter.PrintToken(Tokens.OpenParenthesis);
			}
			
			if (doLoopStatement.Condition.IsNull) {
				outputFormatter.PrintToken(Tokens.True);
			} else {
				nodeTracker.TrackedVisit(doLoopStatement.Condition, null);
			}
			
			if (doLoopStatement.ConditionType == ConditionType.Until) {
				outputFormatter.PrintToken(Tokens.CloseParenthesis);
			}
			outputFormatter.PrintToken(Tokens.CloseParenthesis);
		}
		
		public object VisitDoLoopStatement(DoLoopStatement doLoopStatement, object data)
		{
			if (doLoopStatement.ConditionPosition == ConditionPosition.None) {
				Error(doLoopStatement, String.Format("Unknown condition position for loop : {0}.", doLoopStatement));
			}
			
			if (doLoopStatement.ConditionPosition == ConditionPosition.Start) {
				PrintLoopCheck(doLoopStatement);
			} else {
				outputFormatter.PrintToken(Tokens.Do);
			}
			
			WriteEmbeddedStatement(doLoopStatement.EmbeddedStatement);
			
			if (doLoopStatement.ConditionPosition == ConditionPosition.End) {
				outputFormatter.Indent();
				PrintLoopCheck(doLoopStatement);
				outputFormatter.PrintToken(Tokens.Semicolon);
				outputFormatter.NewLine();
			}
			
			return null;
		}
		
		public object VisitForeachStatement(ForeachStatement foreachStatement, object data)
		{
			outputFormatter.PrintToken(Tokens.Foreach);
			if (this.prettyPrintOptions.ForeachParentheses) {
				outputFormatter.Space();
			}
			outputFormatter.PrintToken(Tokens.OpenParenthesis);
			nodeTracker.TrackedVisit(foreachStatement.TypeReference, data);
			outputFormatter.Space();
			outputFormatter.PrintIdentifier(foreachStatement.VariableName);
			outputFormatter.Space();
			outputFormatter.PrintToken(Tokens.In);
			outputFormatter.Space();
			nodeTracker.TrackedVisit(foreachStatement.Expression, data);
			outputFormatter.PrintToken(Tokens.CloseParenthesis);
			
			WriteEmbeddedStatement(foreachStatement.EmbeddedStatement);
			
			return null;
		}
		
		public object VisitLockStatement(LockStatement lockStatement, object data)
		{
			outputFormatter.PrintToken(Tokens.Lock);
			if (this.prettyPrintOptions.LockParentheses) {
				outputFormatter.Space();
			}
			outputFormatter.PrintToken(Tokens.OpenParenthesis);
			nodeTracker.TrackedVisit(lockStatement.LockExpression, data);
			outputFormatter.PrintToken(Tokens.CloseParenthesis);
			
			WriteEmbeddedStatement(lockStatement.EmbeddedStatement);
			
			return null;
		}
		
		public object VisitUsingStatement(UsingStatement usingStatement, object data)
		{
			outputFormatter.PrintToken(Tokens.Using);
			if (this.prettyPrintOptions.UsingParentheses) {
				outputFormatter.Space();
			}
			outputFormatter.PrintToken(Tokens.OpenParenthesis);
			outputFormatter.DoIndent = false;
			outputFormatter.DoNewLine = false;
			outputFormatter.EmitSemicolon = false;
			
			nodeTracker.TrackedVisit(usingStatement.ResourceAcquisition, data);
			outputFormatter.DoIndent = true;
			outputFormatter.DoNewLine = true;
			outputFormatter.EmitSemicolon = true;
			
			outputFormatter.PrintToken(Tokens.CloseParenthesis);
			
			WriteEmbeddedStatement(usingStatement.EmbeddedStatement);
			
			return null;
		}
		
		public object VisitWithStatement(WithStatement withStatement, object data)
		{
			NotSupported(withStatement);
			return null;
		}
		
		public object VisitTryCatchStatement(TryCatchStatement tryCatchStatement, object data)
		{
			outputFormatter.PrintToken(Tokens.Try);
			WriteEmbeddedStatement(tryCatchStatement.StatementBlock);
			
			foreach (CatchClause catchClause in tryCatchStatement.CatchClauses) {
				nodeTracker.TrackedVisit(catchClause, data);
			}
			
			if (!tryCatchStatement.FinallyBlock.IsNull) {
				outputFormatter.Indent();
				outputFormatter.PrintToken(Tokens.Finally);
				WriteEmbeddedStatement(tryCatchStatement.FinallyBlock);
			}
			return null;
		}
		
		public object VisitCatchClause(CatchClause catchClause, object data)
		{
			outputFormatter.Indent();
			outputFormatter.PrintToken(Tokens.Catch);
			
			if (!catchClause.TypeReference.IsNull) {
				if (this.prettyPrintOptions.CatchParentheses) {
					outputFormatter.Space();
				}
				outputFormatter.PrintToken(Tokens.OpenParenthesis);
				outputFormatter.PrintIdentifier(catchClause.TypeReference.Type);
				if (catchClause.VariableName.Length > 0) {
					outputFormatter.Space();
					outputFormatter.PrintIdentifier(catchClause.VariableName);
				}
				outputFormatter.PrintToken(Tokens.CloseParenthesis);
			}
			WriteEmbeddedStatement(catchClause.StatementBlock);
			return null;
		}
		
		public object VisitThrowStatement(ThrowStatement throwStatement, object data)
		{
			outputFormatter.PrintToken(Tokens.Throw);
			if (!throwStatement.Expression.IsNull) {
				outputFormatter.Space();
				nodeTracker.TrackedVisit(throwStatement.Expression, data);
			}
			outputFormatter.PrintToken(Tokens.Semicolon);
			return null;
		}
		
		public object VisitFixedStatement(FixedStatement fixedStatement, object data)
		{
			outputFormatter.PrintToken(Tokens.Fixed);
			if (this.prettyPrintOptions.FixedParentheses) {
				outputFormatter.Space();
			}
			outputFormatter.PrintToken(Tokens.OpenParenthesis);
			nodeTracker.TrackedVisit(fixedStatement.TypeReference, data);
			outputFormatter.Space();
			AppendCommaSeparatedList(fixedStatement.PointerDeclarators);
			outputFormatter.PrintToken(Tokens.CloseParenthesis);
			
			WriteEmbeddedStatement(fixedStatement.EmbeddedStatement);
			return null;
		}
		
		public object VisitUnsafeStatement(UnsafeStatement unsafeStatement, object data)
		{
			outputFormatter.PrintToken(Tokens.Unsafe);
			WriteEmbeddedStatement(unsafeStatement.Block);
			return null;
		}
		
		public object VisitCheckedStatement(CheckedStatement checkedStatement, object data)
		{
			outputFormatter.PrintToken(Tokens.Checked);
			WriteEmbeddedStatement(checkedStatement.Block);
			return null;
		}
		
		public object VisitUncheckedStatement(UncheckedStatement uncheckedStatement, object data)
		{
			outputFormatter.PrintToken(Tokens.Unchecked);
			WriteEmbeddedStatement(uncheckedStatement.Block);
			return null;
		}
		
		public object VisitExitStatement(ExitStatement exitStatement, object data)
		{
			if (exitStatement.ExitType == ExitType.Function || exitStatement.ExitType == ExitType.Sub || exitStatement.ExitType == ExitType.Property) {
				outputFormatter.PrintToken(Tokens.Return);
			} else {
				outputFormatter.PrintToken(Tokens.Break);
			}
			outputFormatter.PrintToken(Tokens.Semicolon);
			outputFormatter.PrintText(" // TODO: might not be correct. Was : Exit " + exitStatement.ExitType);
			outputFormatter.NewLine();
			return null;
		}
		
		public object VisitForNextStatement(ForNextStatement forNextStatement, object data)
		{
			outputFormatter.PrintToken(Tokens.For);
			outputFormatter.Space();
			outputFormatter.PrintToken(Tokens.OpenParenthesis);
			if (!forNextStatement.TypeReference.IsNull) {
				nodeTracker.TrackedVisit(forNextStatement.TypeReference, data);
				outputFormatter.Space();
			}
			outputFormatter.PrintIdentifier(forNextStatement.VariableName);
			outputFormatter.Space();
			outputFormatter.PrintToken(Tokens.Assign);
			outputFormatter.Space();
			nodeTracker.TrackedVisit(forNextStatement.Start, data);
			outputFormatter.PrintToken(Tokens.Semicolon);
			outputFormatter.Space();
			outputFormatter.PrintIdentifier(forNextStatement.VariableName);
			outputFormatter.Space();
			PrimitiveExpression pe = forNextStatement.Step as PrimitiveExpression;
			if ((pe == null || !(pe.Value is int) || ((int)pe.Value) >= 0)
			    && !(forNextStatement.Step is UnaryOperatorExpression))
				outputFormatter.PrintToken(Tokens.LessEqual);
			else
				outputFormatter.PrintToken(Tokens.GreaterEqual);
			outputFormatter.Space();
			nodeTracker.TrackedVisit(forNextStatement.End, data);
			outputFormatter.PrintToken(Tokens.Semicolon);
			outputFormatter.Space();
			outputFormatter.PrintIdentifier(forNextStatement.VariableName);
			if (forNextStatement.Step.IsNull) {
				outputFormatter.PrintToken(Tokens.Increment);
			} else {
				outputFormatter.Space();
				outputFormatter.PrintToken(Tokens.PlusAssign);
				outputFormatter.Space();
				nodeTracker.TrackedVisit(forNextStatement.Step, data);
			}
			outputFormatter.PrintToken(Tokens.CloseParenthesis);
			
			WriteEmbeddedStatement(forNextStatement.EmbeddedStatement);
			return null;
		}
		#endregion
		
		#region Expressions
		public object VisitClassReferenceExpression(ClassReferenceExpression classReferenceExpression, object data)
		{
			NotSupported(classReferenceExpression);
			return null;
		}
		
		static string ConvertCharLiteral(char ch)
		{
			if (ch == '\'') return "\\'";
			return ConvertChar(ch);
		}
		
		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)) {
						return "\\u" + (int)ch;
					} else {
						return ch.ToString();
					}
			}
		}
		
		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();
		}
		
		public object VisitPrimitiveExpression(PrimitiveExpression primitiveExpression, object data)
		{
			if (primitiveExpression.Value == null) {
				outputFormatter.PrintToken(Tokens.Null);
				return null;
			}
			
			object val = primitiveExpression.Value;
			
			if (val is bool) {
				if ((bool)val) {
					outputFormatter.PrintToken(Tokens.True);
				} else {
					outputFormatter.PrintToken(Tokens.False);
				}
				return null;
			}
			
			if (val is string) {
				outputFormatter.PrintText('"' + ConvertString(val.ToString()) + '"');
				return null;
			}
			
			if (val is char) {
				outputFormatter.PrintText("'" + ConvertCharLiteral((char)val) + "'");
				return null;
			}
			
			if (val is decimal) {
				outputFormatter.PrintText(((decimal)val).ToString(NumberFormatInfo.InvariantInfo) + "m");
				return null;
			}
			
			if (val is float) {
				outputFormatter.PrintText(((float)val).ToString(NumberFormatInfo.InvariantInfo) + "f");
				return null;
			}
			
			if (val is double) {
				string text = ((double)val).ToString(NumberFormatInfo.InvariantInfo);
				if (text.IndexOf('.') < 0 && text.IndexOf('E') < 0)
					outputFormatter.PrintText(text + ".0");
				else
					outputFormatter.PrintText(text);
				return null;
			}
			
			if (val is IFormattable) {
				outputFormatter.PrintText(((IFormattable)val).ToString(null, NumberFormatInfo.InvariantInfo));
				if (val is uint || val is ulong) {
					outputFormatter.PrintText("u");
				}
				if (val is long || val is ulong) {
					outputFormatter.PrintText("l");
				}
			} else {
				outputFormatter.PrintText(val.ToString());
			}
			
			return null;
		}
		
		static bool IsNullLiteralExpression(Expression expr)
		{
			PrimitiveExpression pe = expr as PrimitiveExpression;
			if (pe == null) return false;
			return pe.Value == null;
		}
		
		public object VisitBinaryOperatorExpression(BinaryOperatorExpression binaryOperatorExpression, object data)
		{
			// VB-operators that require special representation:
			switch (binaryOperatorExpression.Op) {
				case BinaryOperatorType.ReferenceEquality:
				case BinaryOperatorType.ReferenceInequality:
					if (IsNullLiteralExpression(binaryOperatorExpression.Left) || IsNullLiteralExpression(binaryOperatorExpression.Right)) {
						// prefer a == null to object.ReferenceEquals(a, null)
						break;
					}
					
					if (binaryOperatorExpression.Op == BinaryOperatorType.ReferenceInequality)
						outputFormatter.PrintToken(Tokens.Not);
					outputFormatter.PrintText("object.ReferenceEquals");
					if (prettyPrintOptions.BeforeMethodCallParentheses) {
						outputFormatter.Space();
					}
					
					outputFormatter.PrintToken(Tokens.OpenParenthesis);
					nodeTracker.TrackedVisit(binaryOperatorExpression.Left, data);
					PrintFormattedComma();
					nodeTracker.TrackedVisit(binaryOperatorExpression.Right, data);
					outputFormatter.PrintToken(Tokens.CloseParenthesis);
					return null;
				case BinaryOperatorType.Power:
					outputFormatter.PrintText("Math.Pow");
					if (prettyPrintOptions.BeforeMethodCallParentheses) {
						outputFormatter.Space();
					}
					outputFormatter.PrintToken(Tokens.OpenParenthesis);
					nodeTracker.TrackedVisit(binaryOperatorExpression.Left, data);
					PrintFormattedComma();
					nodeTracker.TrackedVisit(binaryOperatorExpression.Right, data);
					outputFormatter.PrintToken(Tokens.CloseParenthesis);
					return null;
			}
			nodeTracker.TrackedVisit(binaryOperatorExpression.Left, data);
			switch (binaryOperatorExpression.Op) {
				case BinaryOperatorType.Add:
				case BinaryOperatorType.Concat: // translate Concatenation to +
					if (prettyPrintOptions.AroundAdditiveOperatorParentheses) {
						outputFormatter.Space();
					}
					outputFormatter.PrintToken(Tokens.Plus);
					if (prettyPrintOptions.AroundAdditiveOperatorParentheses) {
						outputFormatter.Space();
					}
					break;
					
				case BinaryOperatorType.Subtract:
					if (prettyPrintOptions.AroundAdditiveOperatorParentheses) {
						outputFormatter.Space();
					}
					outputFormatter.PrintToken(Tokens.Minus);
					if (prettyPrintOptions.AroundAdditiveOperatorParentheses) {
						outputFormatter.Space();
					}
					break;
					
				case BinaryOperatorType.Multiply:
					if (prettyPrintOptions.AroundMultiplicativeOperatorParentheses) {
						outputFormatter.Space();
					}
					outputFormatter.PrintToken(Tokens.Times);
					if (prettyPrintOptions.AroundMultiplicativeOperatorParentheses) {
						outputFormatter.Space();
					}
					break;
					
				case BinaryOperatorType.Divide:
				case BinaryOperatorType.DivideInteger:
					if (prettyPrintOptions.AroundMultiplicativeOperatorParentheses) {
						outputFormatter.Space();
					}
					outputFormatter.PrintToken(Tokens.Div);
					if (prettyPrintOptions.AroundMultiplicativeOperatorParentheses) {
						outputFormatter.Space();
					}
					break;
					
				case BinaryOperatorType.Modulus:
					if (prettyPrintOptions.AroundMultiplicativeOperatorParentheses) {
						outputFormatter.Space();
					}
					outputFormatter.PrintToken(Tokens.Mod);
					if (prettyPrintOptions.AroundMultiplicativeOperatorParentheses) {
						outputFormatter.Space();
					}
					break;
					
				case BinaryOperatorType.ShiftLeft:
					if (prettyPrintOptions.AroundShiftOperatorParentheses) {
						outputFormatter.Space();
					}
					outputFormatter.PrintToken(Tokens.ShiftLeft);
					if (prettyPrintOptions.AroundShiftOperatorParentheses) {
						outputFormatter.Space();
					}
					break;
					
				case BinaryOperatorType.ShiftRight:
					if (prettyPrintOptions.AroundShiftOperatorParentheses) {
						outputFormatter.Space();
					}
					outputFormatter.PrintToken(Tokens.GreaterThan);
					outputFormatter.PrintToken(Tokens.GreaterThan);
					if (prettyPrintOptions.AroundShiftOperatorParentheses) {
						outputFormatter.Space();
					}
					break;
					
				case BinaryOperatorType.BitwiseAnd:
					if (prettyPrintOptions.AroundBitwiseOperatorParentheses) {
						outputFormatter.Space();
					}
					outputFormatter.PrintToken(Tokens.BitwiseAnd);
					if (prettyPrintOptions.AroundBitwiseOperatorParentheses) {
						outputFormatter.Space();
					}
					break;
				case BinaryOperatorType.BitwiseOr:
					if (prettyPrintOptions.AroundBitwiseOperatorParentheses) {
						outputFormatter.Space();
					}
					outputFormatter.PrintToken(Tokens.BitwiseOr);
					if (prettyPrintOptions.AroundBitwiseOperatorParentheses) {
						outputFormatter.Space();
					}
					break;
				case BinaryOperatorType.ExclusiveOr:
					if (prettyPrintOptions.AroundBitwiseOperatorParentheses) {
						outputFormatter.Space();
					}
					outputFormatter.PrintToken(Tokens.Xor);
					if (prettyPrintOptions.AroundBitwiseOperatorParentheses) {
						outputFormatter.Space();
					}
					break;
					
				case BinaryOperatorType.LogicalAnd:
					if (prettyPrintOptions.AroundLogicalOperatorParentheses) {
						outputFormatter.Space();
					}
					outputFormatter.PrintToken(Tokens.LogicalAnd);
					if (prettyPrintOptions.AroundLogicalOperatorParentheses) {
						outputFormatter.Space();
					}
					break;
				case BinaryOperatorType.LogicalOr:
					if (prettyPrintOptions.AroundLogicalOperatorParentheses) {
						outputFormatter.Space();
					}
					outputFormatter.PrintToken(Tokens.LogicalOr);
					if (prettyPrintOptions.AroundLogicalOperatorParentheses) {
						outputFormatter.Space();
					}
					break;
					
				case BinaryOperatorType.Equality:
				case BinaryOperatorType.ReferenceEquality:
					if (prettyPrintOptions.AroundRelationalOperatorParentheses) {
						outputFormatter.Space();
					}
					outputFormatter.PrintToken(Tokens.Equal);
					if (prettyPrintOptions.AroundRelationalOperatorParentheses) {
						outputFormatter.Space();
					}
					break;
				case BinaryOperatorType.GreaterThan:
					if (prettyPrintOptions.AroundRelationalOperatorParentheses) {
						outputFormatter.Space();
					}
					outputFormatter.PrintToken(Tokens.GreaterThan);
					if (prettyPrintOptions.AroundRelationalOperatorParentheses) {
						outputFormatter.Space();
					}
					break;
				case BinaryOperatorType.GreaterThanOrEqual:
					if (prettyPrintOptions.AroundRelationalOperatorParentheses) {
						outputFormatter.Space();
					}
					outputFormatter.PrintToken(Tokens.GreaterEqual);
					if (prettyPrintOptions.AroundRelationalOperatorParentheses) {
						outputFormatter.Space();
					}
					break;
				case BinaryOperatorType.InEquality:
				case BinaryOperatorType.ReferenceInequality:
					if (prettyPrintOptions.AroundRelationalOperatorParentheses) {
						outputFormatter.Space();
					}
					outputFormatter.PrintToken(Tokens.NotEqual);
					if (prettyPrintOptions.AroundRelationalOperatorParentheses) {
						outputFormatter.Space();
					}
					break;
				case BinaryOperatorType.LessThan:
					if (prettyPrintOptions.AroundRelationalOperatorParentheses) {
						outputFormatter.Space();
					}
					outputFormatter.PrintToken(Tokens.LessThan);
					if (prettyPrintOptions.AroundRelationalOperatorParentheses) {
						outputFormatter.Space();
					}
					break;
				case BinaryOperatorType.LessThanOrEqual:
					if (prettyPrintOptions.AroundRelationalOperatorParentheses) {
						outputFormatter.Space();
					}
					outputFormatter.PrintToken(Tokens.LessEqual);
					if (prettyPrintOptions.AroundRelationalOperatorParentheses) {
						outputFormatter.Space();
					}
					break;
				case BinaryOperatorType.NullCoalescing:
					if (prettyPrintOptions.AroundRelationalOperatorParentheses) {
						outputFormatter.Space();
					}
					outputFormatter.PrintToken(Tokens.DoubleQuestion);
					if (prettyPrintOptions.AroundRelationalOperatorParentheses) {
						outputFormatter.Space();
					}
					break;
					
				default:
					Error(binaryOperatorExpression, String.Format("Unknown binary operator {0}", binaryOperatorExpression.Op));
					return null;
			}
			nodeTracker.TrackedVisit(binaryOperatorExpression.Right, data);
			return null;
		}
		
		public object VisitParenthesizedExpression(ParenthesizedExpression parenthesizedExpression, object data)
		{
			outputFormatter.PrintToken(Tokens.OpenParenthesis);
			nodeTracker.TrackedVisit(parenthesizedExpression.Expression, data);
			outputFormatter.PrintToken(Tokens.CloseParenthesis);
			return null;
		}
		
		public object VisitInvocationExpression(InvocationExpression invocationExpression, object data)
		{
			nodeTracker.TrackedVisit(invocationExpression.TargetObject, data);
			
			if (invocationExpression.TypeArguments != null && invocationExpression.TypeArguments.Count > 0) {
				outputFormatter.PrintToken(Tokens.LessThan);
				AppendCommaSeparatedList(invocationExpression.TypeArguments);
				outputFormatter.PrintToken(Tokens.GreaterThan);
			}
			
			if (prettyPrintOptions.BeforeMethodCallParentheses) {
				outputFormatter.Space();
			}
			
			outputFormatter.PrintToken(Tokens.OpenParenthesis);
			AppendCommaSeparatedList(invocationExpression.Arguments);
			outputFormatter.PrintToken(Tokens.CloseParenthesis);
			return null;
		}
		
		public object VisitIdentifierExpression(IdentifierExpression identifierExpression, object data)
		{
			outputFormatter.PrintIdentifier(identifierExpression.Identifier);
			return null;
		}
		
		public object VisitTypeReferenceExpression(TypeReferenceExpression typeReferenceExpression, object data)
		{
			nodeTracker.TrackedVisit(typeReferenceExpression.TypeReference, data);
			return null;
		}
		
		public object VisitUnaryOperatorExpression(UnaryOperatorExpression unaryOperatorExpression, object data)
		{
			switch (unaryOperatorExpression.Op) {
				case UnaryOperatorType.BitNot:
					outputFormatter.PrintToken(Tokens.BitwiseComplement);
					break;
				case UnaryOperatorType.Decrement:
					outputFormatter.PrintToken(Tokens.Decrement);
					break;
				case UnaryOperatorType.Increment:
					outputFormatter.PrintToken(Tokens.Increment);
					break;
				case UnaryOperatorType.Minus:
					outputFormatter.PrintToken(Tokens.Minus);
					break;
				case UnaryOperatorType.Not:
					outputFormatter.PrintToken(Tokens.Not);
					break;
				case UnaryOperatorType.Plus:
					outputFormatter.PrintToken(Tokens.Plus);
					break;
				case UnaryOperatorType.PostDecrement:
					nodeTracker.TrackedVisit(unaryOperatorExpression.Expression, data);
					outputFormatter.PrintToken(Tokens.Decrement);
					return null;
				case UnaryOperatorType.PostIncrement:
					nodeTracker.TrackedVisit(unaryOperatorExpression.Expression, data);
					outputFormatter.PrintToken(Tokens.Increment);
					return null;
				case UnaryOperatorType.Star:
					outputFormatter.PrintToken(Tokens.Times);
					break;
				case UnaryOperatorType.BitWiseAnd:
					outputFormatter.PrintToken(Tokens.BitwiseAnd);
					break;
				default:
					Error(unaryOperatorExpression, String.Format("Unknown unary operator {0}", unaryOperatorExpression.Op));
					return null;
			}
			nodeTracker.TrackedVisit(unaryOperatorExpression.Expression, data);
			return null;
		}
		
		public object VisitAssignmentExpression(AssignmentExpression assignmentExpression, object data)
		{
			nodeTracker.TrackedVisit(assignmentExpression.Left, data);
			if (this.prettyPrintOptions.AroundAssignmentParentheses) {
				outputFormatter.Space();
			}
			switch (assignmentExpression.Op) {
				case AssignmentOperatorType.Assign:
					outputFormatter.PrintToken(Tokens.Assign);
					break;
				case AssignmentOperatorType.Add:
					outputFormatter.PrintToken(Tokens.PlusAssign);
					break;
				case AssignmentOperatorType.Subtract:
					outputFormatter.PrintToken(Tokens.MinusAssign);
					break;
				case AssignmentOperatorType.Multiply:
					outputFormatter.PrintToken(Tokens.TimesAssign);
					break;
				case AssignmentOperatorType.Divide:
				case AssignmentOperatorType.DivideInteger:
					outputFormatter.PrintToken(Tokens.DivAssign);
					break;
				case AssignmentOperatorType.ShiftLeft:
					outputFormatter.PrintToken(Tokens.ShiftLeftAssign);
					break;
				case AssignmentOperatorType.ShiftRight:
					outputFormatter.PrintToken(Tokens.GreaterThan);
					outputFormatter.PrintToken(Tokens.GreaterEqual);
					break;
				case AssignmentOperatorType.ExclusiveOr:
					outputFormatter.PrintToken(Tokens.XorAssign);
					break;
				case AssignmentOperatorType.Modulus:
					outputFormatter.PrintToken(Tokens.ModAssign);
					break;
				case AssignmentOperatorType.BitwiseAnd:
					outputFormatter.PrintToken(Tokens.BitwiseAndAssign);
					break;
				case AssignmentOperatorType.BitwiseOr:
					outputFormatter.PrintToken(Tokens.BitwiseOrAssign);
					break;
				case AssignmentOperatorType.Power:
					outputFormatter.PrintToken(Tokens.Assign);
					if (this.prettyPrintOptions.AroundAssignmentParentheses) {
						outputFormatter.Space();
					}
					VisitBinaryOperatorExpression(new BinaryOperatorExpression(assignmentExpression.Left,
					                                                           BinaryOperatorType.Power,
					                                                           assignmentExpression.Right), data);
					return null;
				default:
					Error(assignmentExpression, String.Format("Unknown assignment operator {0}", assignmentExpression.Op));
					return null;
			}
			if (this.prettyPrintOptions.AroundAssignmentParentheses) {
				outputFormatter.Space();
			}
			nodeTracker.TrackedVisit(assignmentExpression.Right, data);
			return null;
		}
		
		public object VisitSizeOfExpression(SizeOfExpression sizeOfExpression, object data)
		{
			outputFormatter.PrintToken(Tokens.Sizeof);
			if (prettyPrintOptions.SizeOfParentheses) {
				outputFormatter.Space();
			}
			outputFormatter.PrintToken(Tokens.OpenParenthesis);
			nodeTracker.TrackedVisit(sizeOfExpression.TypeReference, data);
			outputFormatter.PrintToken(Tokens.CloseParenthesis);
			return null;
		}
		
		public object VisitTypeOfExpression(TypeOfExpression typeOfExpression, object data)
		{
			outputFormatter.PrintToken(Tokens.Typeof);
			if (prettyPrintOptions.TypeOfParentheses) {
				outputFormatter.Space();
			}
			outputFormatter.PrintToken(Tokens.OpenParenthesis);
			nodeTracker.TrackedVisit(typeOfExpression.TypeReference, data);
			outputFormatter.PrintToken(Tokens.CloseParenthesis);
			return null;
		}
		
		public object VisitDefaultValueExpression(DefaultValueExpression defaultValueExpression, object data)
		{
			outputFormatter.PrintToken(Tokens.Default);
			if (prettyPrintOptions.TypeOfParentheses) {
				outputFormatter.Space();
			}
			outputFormatter.PrintToken(Tokens.OpenParenthesis);
			nodeTracker.TrackedVisit(defaultValueExpression.TypeReference, data);
			outputFormatter.PrintToken(Tokens.CloseParenthesis);
			return null;
		}
		
		public object VisitTypeOfIsExpression(TypeOfIsExpression typeOfIsExpression, object data)
		{
			nodeTracker.TrackedVisit(typeOfIsExpression.Expression, data);
			outputFormatter.Space();
			outputFormatter.PrintToken(Tokens.Is);
			outputFormatter.Space();
			nodeTracker.TrackedVisit(typeOfIsExpression.TypeReference, data);
			return null;
		}
		
		public object VisitAddressOfExpression(AddressOfExpression addressOfExpression, object data)
		{
			// C# 2.0 can reference methods directly
			return nodeTracker.TrackedVisit(addressOfExpression.Expression, data);
		}
		
		public object VisitAnonymousMethodExpression(AnonymousMethodExpression anonymousMethodExpression, object data)
		{
			outputFormatter.PrintToken(Tokens.Delegate);
			
			if (anonymousMethodExpression.Parameters.Count > 0 || anonymousMethodExpression.HasParameterList) {
				outputFormatter.PrintToken(Tokens.OpenParenthesis);
				AppendCommaSeparatedList(anonymousMethodExpression.Parameters);
				outputFormatter.PrintToken(Tokens.CloseParenthesis);
			}
			OutputBlockAllowInline(anonymousMethodExpression.Body, this.prettyPrintOptions.MethodBraceStyle, false);
			return null;
		}
		
		public object VisitCheckedExpression(CheckedExpression checkedExpression, object data)
		{
			outputFormatter.PrintToken(Tokens.Checked);
			if (prettyPrintOptions.CheckedParentheses) {
				outputFormatter.Space();
			}
			
			outputFormatter.PrintToken(Tokens.OpenParenthesis);
			nodeTracker.TrackedVisit(checkedExpression.Expression, data);
			outputFormatter.PrintToken(Tokens.CloseParenthesis);
			return null;
		}
		
		public object VisitUncheckedExpression(UncheckedExpression uncheckedExpression, object data)
		{
			outputFormatter.PrintToken(Tokens.Unchecked);
			if (prettyPrintOptions.UncheckedParentheses) {
				outputFormatter.Space();
			}
			outputFormatter.PrintToken(Tokens.OpenParenthesis);
			nodeTracker.TrackedVisit(uncheckedExpression.Expression, data);
			outputFormatter.PrintToken(Tokens.CloseParenthesis);
			return null;
		}
		
		public object VisitPointerReferenceExpression(PointerReferenceExpression pointerReferenceExpression, object data)
		{
			nodeTracker.TrackedVisit(pointerReferenceExpression.TargetObject, data);
			outputFormatter.PrintToken(Tokens.Pointer);
			outputFormatter.PrintIdentifier(pointerReferenceExpression.Identifier);
			return null;
		}
		
		public object VisitCastExpression(CastExpression castExpression, object data)
		{
			if (castExpression.CastType == CastType.TryCast) {
				nodeTracker.TrackedVisit(castExpression.Expression, data);
				outputFormatter.Space();
				outputFormatter.PrintToken(Tokens.As);
				outputFormatter.Space();
				nodeTracker.TrackedVisit(castExpression.CastTo, data);
			} else {
				outputFormatter.PrintToken(Tokens.OpenParenthesis);
				nodeTracker.TrackedVisit(castExpression.CastTo, data);
				outputFormatter.PrintToken(Tokens.CloseParenthesis);
				if (this.prettyPrintOptions.SpacesAfterTypecast) {
					outputFormatter.Space();
				}
				nodeTracker.TrackedVisit(castExpression.Expression, data);
			}
			return null;
		}
		
		public object VisitStackAllocExpression(StackAllocExpression stackAllocExpression, object data)
		{
			outputFormatter.PrintToken(Tokens.Stackalloc);
			outputFormatter.Space();
			nodeTracker.TrackedVisit(stackAllocExpression.TypeReference, data);
			outputFormatter.PrintToken(Tokens.OpenSquareBracket);
			if (this.prettyPrintOptions.SpacesWithinBrackets) {
				outputFormatter.Space();
			}
			nodeTracker.TrackedVisit(stackAllocExpression.Expression, data);
			if (this.prettyPrintOptions.SpacesWithinBrackets) {
				outputFormatter.Space();
			}
			outputFormatter.PrintToken(Tokens.CloseSquareBracket);
			return null;
		}
		
		public object VisitIndexerExpression(IndexerExpression indexerExpression, object data)
		{
			nodeTracker.TrackedVisit(indexerExpression.TargetObject, data);
			outputFormatter.PrintToken(Tokens.OpenSquareBracket);
			if (this.prettyPrintOptions.SpacesWithinBrackets) {
				outputFormatter.Space();
			}
			AppendCommaSeparatedList(indexerExpression.Indexes);
			if (this.prettyPrintOptions.SpacesWithinBrackets) {
				outputFormatter.Space();
			}
			outputFormatter.PrintToken(Tokens.CloseSquareBracket);
			return null;
		}
		
		public object VisitThisReferenceExpression(ThisReferenceExpression thisReferenceExpression, object data)
		{
			outputFormatter.PrintToken(Tokens.This);
			return null;
		}
		
		public object VisitBaseReferenceExpression(BaseReferenceExpression baseReferenceExpression, object data) {
			outputFormatter.PrintToken(Tokens.Base);
			return null;
		}
		
		public object VisitObjectCreateExpression(ObjectCreateExpression objectCreateExpression, object data)
		{
			outputFormatter.PrintToken(Tokens.New);
			outputFormatter.Space();
			nodeTracker.TrackedVisit(objectCreateExpression.CreateType, data);
			if (prettyPrintOptions.NewParentheses) {
				outputFormatter.Space();
			}
			outputFormatter.PrintToken(Tokens.OpenParenthesis);
			AppendCommaSeparatedList(objectCreateExpression.Parameters);
			outputFormatter.PrintToken(Tokens.CloseParenthesis);
			return null;
		}
		
		public object VisitArrayCreateExpression(ArrayCreateExpression arrayCreateExpression, object data)
		{
			outputFormatter.PrintToken(Tokens.New);
			outputFormatter.Space();
			PrintTypeReferenceWithoutArray(arrayCreateExpression.CreateType);
			
			if (arrayCreateExpression.Arguments.Count > 0) {
				outputFormatter.PrintToken(Tokens.OpenSquareBracket);
				if (this.prettyPrintOptions.SpacesWithinBrackets) {
					outputFormatter.Space();
				}
				for (int i = 0; i < arrayCreateExpression.Arguments.Count; ++i) {
					if (i > 0) PrintFormattedComma();
					nodeTracker.TrackedVisit(arrayCreateExpression.Arguments[i], data);
				}
				if (this.prettyPrintOptions.SpacesWithinBrackets) {
					outputFormatter.Space();
				}
				outputFormatter.PrintToken(Tokens.CloseSquareBracket);
				PrintArrayRank(arrayCreateExpression.CreateType.RankSpecifier, 1);
			} else {
				PrintArrayRank(arrayCreateExpression.CreateType.RankSpecifier, 0);
			}
			
			if (!arrayCreateExpression.ArrayInitializer.IsNull) {
				outputFormatter.Space();
				nodeTracker.TrackedVisit(arrayCreateExpression.ArrayInitializer, data);
			}
			return null;
		}
		
		public object VisitFieldReferenceExpression(FieldReferenceExpression fieldReferenceExpression, object data)
		{
			Expression target = fieldReferenceExpression.TargetObject;
			
			if (target is BinaryOperatorExpression || target is CastExpression) {
				outputFormatter.PrintToken(Tokens.OpenParenthesis);
			}
			nodeTracker.TrackedVisit(target, data);
			if (target is BinaryOperatorExpression || target is CastExpression) {
				outputFormatter.PrintToken(Tokens.CloseParenthesis);
			}
			outputFormatter.PrintToken(Tokens.Dot);
			outputFormatter.PrintIdentifier(fieldReferenceExpression.FieldName);
			return null;
		}
		
		public object VisitDirectionExpression(DirectionExpression directionExpression, object data)
		{
			switch (directionExpression.FieldDirection) {
				case FieldDirection.Out:
					outputFormatter.PrintToken(Tokens.Out);
					outputFormatter.Space();
					break;
				case FieldDirection.Ref:
					outputFormatter.PrintToken(Tokens.Ref);
					outputFormatter.Space();
					break;
			}
			nodeTracker.TrackedVisit(directionExpression.Expression, data);
			return null;
		}
		
		public object VisitArrayInitializerExpression(ArrayInitializerExpression arrayInitializerExpression, object data)
		{
			outputFormatter.PrintToken(Tokens.OpenCurlyBrace);
			this.AppendCommaSeparatedList(arrayInitializerExpression.CreateExpressions);
			outputFormatter.PrintToken(Tokens.CloseCurlyBrace);
			return null;
		}
		
		public object VisitConditionalExpression(ConditionalExpression conditionalExpression, object data)
		{
			nodeTracker.TrackedVisit(conditionalExpression.Condition, data);
			if (this.prettyPrintOptions.ConditionalOperatorBeforeConditionSpace) {
				outputFormatter.Space();
			}
			outputFormatter.PrintToken(Tokens.Question);
			if (this.prettyPrintOptions.ConditionalOperatorAfterConditionSpace) {
				outputFormatter.Space();
			}
			nodeTracker.TrackedVisit(conditionalExpression.TrueExpression, data);
			if (this.prettyPrintOptions.ConditionalOperatorBeforeSeparatorSpace) {
				outputFormatter.Space();
			}
			outputFormatter.PrintToken(Tokens.Colon);
			if (this.prettyPrintOptions.ConditionalOperatorAfterSeparatorSpace) {
				outputFormatter.Space();
			}
			nodeTracker.TrackedVisit(conditionalExpression.FalseExpression, data);
			return null;
		}
		
		#endregion
		#endregion
		
		void OutputModifier(ParameterModifiers modifier, INode node)
		{
			switch (modifier) {
				case ParameterModifiers.None:
				case ParameterModifiers.In:
					break;
				case ParameterModifiers.Out:
					outputFormatter.PrintToken(Tokens.Out);
					outputFormatter.Space();
					break;
				case ParameterModifiers.Params:
					outputFormatter.PrintToken(Tokens.Params);
					outputFormatter.Space();
					break;
				case ParameterModifiers.Ref:
					outputFormatter.PrintToken(Tokens.Ref);
					outputFormatter.Space();
					break;
				case ParameterModifiers.Optional:
					Error(node, String.Format("Optional parameters aren't supported in C#"));
					break;
				default:
					Error(node, String.Format("Unsupported modifier : {0}", modifier));
					break;
			}
		}
		
		void OutputModifier(Modifiers modifier)
		{
			ArrayList tokenList = new ArrayList();
			if ((modifier & Modifiers.Unsafe) != 0) {
				tokenList.Add(Tokens.Unsafe);
			}
			if ((modifier & Modifiers.Public) != 0) {
				tokenList.Add(Tokens.Public);
			}
			if ((modifier & Modifiers.Private) != 0) {
				tokenList.Add(Tokens.Private);
			}
			if ((modifier & Modifiers.Protected) != 0) {
				tokenList.Add(Tokens.Protected);
			}
			if ((modifier & Modifiers.Static) != 0) {
				tokenList.Add(Tokens.Static);
			}
			if ((modifier & Modifiers.Internal) != 0) {
				tokenList.Add(Tokens.Internal);
			}
			if ((modifier & Modifiers.Override) != 0) {
				tokenList.Add(Tokens.Override);
			}
			if ((modifier & Modifiers.Abstract) != 0) {
				tokenList.Add(Tokens.Abstract);
			}
			if ((modifier & Modifiers.Virtual) != 0) {
				tokenList.Add(Tokens.Virtual);
			}
			if ((modifier & Modifiers.New) != 0) {
				tokenList.Add(Tokens.New);
			}
			if ((modifier & Modifiers.Sealed) != 0) {
				tokenList.Add(Tokens.Sealed);
			}
			if ((modifier & Modifiers.Extern) != 0) {
				tokenList.Add(Tokens.Extern);
			}
			if ((modifier & Modifiers.Const) != 0) {
				tokenList.Add(Tokens.Const);
			}
			if ((modifier & Modifiers.ReadOnly) != 0) {
				tokenList.Add(Tokens.Readonly);
			}
			if ((modifier & Modifiers.Volatile) != 0) {
				tokenList.Add(Tokens.Volatile);
			}
			if ((modifier & Modifiers.Fixed) != 0) {
				tokenList.Add(Tokens.Fixed);
			}
			outputFormatter.PrintTokenList(tokenList);
			
			if ((modifier & Modifiers.Partial) != 0) {
				outputFormatter.PrintText("partial ");
			}
		}
		
		public void AppendCommaSeparatedList<T>(ICollection<T> list) where T : class, INode
		{
			if (list != null) {
				int i = 0;
				foreach (T node in list) {
					nodeTracker.TrackedVisit(node, null);
					if (i + 1 < list.Count) {
						PrintFormattedComma();
					}
					if ((i + 1) % 10 == 0) {
						outputFormatter.NewLine();
						outputFormatter.Indent();
					}
					i++;
				}
			}
		}
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
Australia Australia
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions